Skip to content

Commit fdd0ce1

Browse files
committed
feat: add spec con days and flexible unit dates
1 parent d0d3bcd commit fdd0ce1

File tree

16 files changed

+307
-14
lines changed

16 files changed

+307
-14
lines changed

app/api/entities/project_entity.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ class ProjectEntity < Grape::Entity
1010
expose :enrolled, unless: :for_student
1111
expose :target_grade
1212

13+
expose :spec_con_days
14+
1315
expose :submitted_grade, unless: :summary_only
1416
expose :portfolio_files, unless: :summary_only
1517
expose :compile_portfolio, unless: :summary_only

app/api/entities/unit_entity.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ def can_read_unit_config?(my_role)
4747
expose :allow_student_extension_requests, unless: :summary_only
4848
expose :extension_weeks_on_resubmit_request, unless: :summary_only, if: lambda { |unit, options| is_staff?(options[:my_role]) }
4949
expose :allow_student_change_tutorial, unless: :summary_only
50+
expose :allow_flexible_dates, unless: :summary_only
5051

5152
expose :learning_outcomes, using: LearningOutcomeEntity, as: :ilos, unless: :summary_only
5253
expose :tutorial_streams, using: TutorialStreamEntity, unless: :summary_only

app/api/extension_comments_api.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ class ExtensionCommentsApi < Grape::API
1919
error!({ error: 'Not authorised to request an extension for this task' }, 403)
2020
end
2121

22+
if project.unit.allow_flexible_dates
23+
error!({ error: 'Extensions are disabled for this unit.' }, 403)
24+
end
25+
2226
error!({ error: 'Extension weeks can not be 0.' }, 403) if params[:weeks_requested] == 0
2327

2428
max_duration = task.weeks_can_extend

app/api/projects_api.rb

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,23 @@ class ProjectsApi < Grape::API
3434
end
3535
end
3636

37+
desc 'Adjust special consideration days'
38+
params do
39+
requires :id, type: Integer, desc: 'The id of the project to adjust'
40+
requires :spec_con_days, type: Integer, desc: 'The number of special consideration days to add or remove'
41+
end
42+
put '/projects/:id/spec_con' do
43+
project = Project.find(params[:id])
44+
# Can access project and grant spec con
45+
unless authorise?(current_user, project, :get) && authorise?(current_user, project.unit, :grant_spec_con)
46+
error!({ error: 'You are not authorised to perform this action' }, 403)
47+
end
48+
49+
project.update!(spec_con_days: params['spec_con_days'])
50+
51+
present project, with: Entities::ProjectEntity, for_staff: true, summary_only: true, user: current_user, only: [:spec_con_days]
52+
end
53+
3754
desc 'Update a project'
3855
params do
3956
optional :trigger, type: String, desc: 'The update trigger'

app/api/tasks_api.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,44 @@ class TasksApi < Grape::API
109109
present true, Grape::Presenters::Presenter
110110
end
111111

112+
desc 'Update the planned date for a task - when date flexibility is allowed'
113+
params do
114+
requires :id, type: Integer, desc: 'The project id to locate'
115+
requires :task_definition_id, type: Integer, desc: 'The id of the task definition of the task to update in this project'
116+
requires :extensions, type: Integer, desc: 'The number of weeks to adjust the original planned date by'
117+
end
118+
put '/projects/:id/task_def_id/:task_definition_id/plan' do
119+
project = Project.find(params[:id])
120+
task_definition = project.unit.task_definitions.find(params[:task_definition_id])
121+
122+
# check the user can put this task
123+
if authorise? current_user, project, :make_submission
124+
# Check unit allows planned date changes
125+
unless project.unit.allow_flexible_dates
126+
error!({ error: 'This unit does not allow you to adjust due dates.' }, 403)
127+
end
128+
129+
task = project.task_for_task_definition(task_definition)
130+
131+
# update the planned date
132+
task.extensions = params[:extensions]
133+
task.save
134+
135+
TaskComment.create(
136+
task: task,
137+
user: current_user,
138+
comment: "Planned date adjusted to #{task.due_date.strftime('%d %b')}.",
139+
content_type: :plan,
140+
recipient: project.student,
141+
extension_weeks: params[:extensions]
142+
)
143+
144+
present task, with: Entities::TaskEntity, include_other_projects: true, update_only: true
145+
else
146+
error!({ error: "You are not permitted to adjust the plan." }, 403)
147+
end
148+
end
149+
112150
desc 'Update a task using its related project and task definition'
113151
params do
114152
# requires :id, type: Integer, desc: 'The project id to locate'

app/api/units_api.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ class UnitsApi < Grape::API
8181
optional :enable_sync_enrolments, type: Boolean, desc: 'Sync student enrolments automatically if supported by deployment'
8282
optional :draft_task_definition_id, type: Integer, desc: 'Indicates the ID of the task definition used as the "draft learning summary task"'
8383
optional :portfolio_auto_generation_date, type: Date, desc: 'Indicates a date where student portfolio will automatically compile'
84+
optional :allow_flexible_dates, type: Boolean, desc: 'Can turn on/off flexible dates for tasks in this unit'
8485
optional :allow_student_extension_requests, type: Boolean, desc: 'Can turn on/off student extension requests'
8586
optional :allow_student_change_tutorial, type: Boolean, desc: 'Can turn on/off student ability to change tutorials'
8687
optional :extension_weeks_on_resubmit_request, type: Integer, desc: 'Determines the number of weeks extension on a resubmit request'
@@ -112,6 +113,7 @@ class UnitsApi < Grape::API
112113
:enable_sync_enrolments,
113114
:draft_task_definition_id,
114115
:portfolio_auto_generation_date,
116+
:allow_flexible_dates,
115117
:allow_student_extension_requests,
116118
:extension_weeks_on_resubmit_request,
117119
:allow_student_change_tutorial,
@@ -155,6 +157,7 @@ class UnitsApi < Grape::API
155157
optional :send_notifications, type: Boolean, desc: 'Indicates if emails should be sent on updates each week', default: true
156158
optional :enable_sync_timetable, type: Boolean, desc: 'Sync to timetable automatically if supported by deployment', default: true
157159
optional :enable_sync_enrolments, type: Boolean, desc: 'Sync student enrolments automatically if supported by deployment', default: true
160+
optional :allow_flexible_dates, type: Boolean, desc: 'Can turn on/off flexible dates for tasks in this unit', default: true
158161
optional :allow_student_extension_requests, type: Boolean, desc: 'Can turn on/off student extension requests', default: true
159162
optional :extension_weeks_on_resubmit_request, type: Integer, desc: 'Determines the number of weeks extension on a resubmit request', default: 1
160163
optional :portfolio_auto_generation_date, type: Date, desc: 'Indicates a date where student portfolio will automatically compile'
@@ -183,6 +186,7 @@ class UnitsApi < Grape::API
183186
:send_notifications,
184187
:enable_sync_timetable,
185188
:enable_sync_enrolments,
189+
:allow_flexible_dates,
186190
:allow_student_extension_requests,
187191
:extension_weeks_on_resubmit_request,
188192
:portfolio_auto_generation_date,

app/models/project.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ class Project < ApplicationRecord
3333
before_destroy :can_destroy?
3434

3535
validates :grade_rationale, length: { maximum: 4095, allow_blank: true }
36+
validates :spec_con_days, presence: true, numericality: { only_integer: true, greater_than_or_equal_to: 0 }, if: :spec_con_days_changed?
3637

3738
validate :tutorial_enrolment_same_campus, if: :will_save_change_to_enrolled?
3839

@@ -64,7 +65,7 @@ def self.permissions
6465
# What can admins do with projects?
6566
admin_role_permissions = [
6667
:get,
67-
:get_submission
68+
:get_submission,
6869
]
6970
# What can auditors do with projects?
7071
auditor_role_permissions = [

app/models/task.rb

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ def for_definition_with_quality?
157157
end
158158

159159
def has_requested_extension?
160-
extensions > 0 && will_save_change_to_extensions? && extensions > extensions_in_database
160+
extensions != 0 && will_save_change_to_extensions? && extensions != extensions_in_database
161161
end
162162

163163
def must_have_quality_pts
@@ -169,7 +169,7 @@ def must_have_quality_pts
169169
# Ensure that extensions do not exceed the defined due date
170170
def extensions_must_end_with_due_date
171171
# First check the raw extension date - but allow it to be up to a week later in case due date and target date are on different days
172-
if raw_extension_date.to_date - 7.days >= task_definition.due_date.to_date
172+
if raw_extension_date - 7.days >= max_date_with_spec_con_days
173173
errors.add(:extensions, "have exceeded deadline for task. Work must be submitted within current timeframe. Work submitted after current due date will be assessed in the portfolio")
174174
end
175175
end
@@ -259,21 +259,26 @@ def processing_pdf?
259259

260260
# Get the raw extension date - with extensions representing weeks
261261
def raw_extension_date
262-
target_date + extensions.weeks
262+
target_date.to_date + extensions.weeks
263+
end
264+
265+
def max_date_with_spec_con_days
266+
task_definition.due_date.to_date + project.spec_con_days.days
263267
end
264268

265269
# Get the adjusted extension date, which ensures it is never past the due date
266270
def extension_date
267271
result = raw_extension_date
268-
return task_definition.due_date if result > task_definition.due_date
272+
max_date = max_date_with_spec_con_days
273+
return max_date if result > max_date
269274

270275
return result
271276
end
272277

273278
# The student can apply for an extension if the current extension date is
274279
# before the task's due date
275280
def can_apply_for_extension?
276-
raw_extension_date.to_date < task_definition.due_date.to_date
281+
raw_extension_date < max_date_with_spec_con_days
277282
end
278283

279284
def tutor
@@ -308,15 +313,18 @@ def apply_for_extension(user, text, weeks)
308313
end
309314

310315
def weeks_can_extend
311-
deadline = task_definition.due_date.to_date
312-
current_due = raw_extension_date.to_date
316+
deadline = max_date_with_spec_con_days
317+
current_due = raw_extension_date
313318

314319
diff = deadline - current_due
315320
(diff.to_f / 7).ceil
316321
end
317322

318323
# Add an extension to the task
319324
def grant_extension(by_user, weeks)
325+
# Only used when extensions are allowed - not if the student manages the dates
326+
return if unit.allow_flexible_dates
327+
320328
weeks_to_extend = [weeks, weeks_can_extend].min
321329
return false unless weeks_to_extend > 0
322330

@@ -643,7 +651,9 @@ def engage(engagement_status)
643651
def submitted_before_due?
644652
return true if due_date.blank?
645653

646-
to_same_day_anywhere_on_earth(due_date) >= self.submission_date
654+
# When using flexible dates, we need to check against the deadline
655+
check_date = unit.allow_flexible_dates ? max_date_with_spec_con_days : due_date
656+
to_same_day_anywhere_on_earth(check_date) >= self.submission_date
647657
end
648658

649659
#

app/models/unit.rb

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ def self.permissions
4444
:download_unit_csv,
4545
:update,
4646
:employ_staff,
47+
:grant_spec_con,
4748
:add_tutorial,
4849
:add_task_def,
4950
:provide_feedback,
@@ -76,7 +77,8 @@ def self.permissions
7677
:exceed_capacity,
7778
:get_los,
7879
:create_feedback_chips,
79-
:get_feedback_chips
80+
:get_feedback_chips,
81+
:grant_spec_con
8082
]
8183

8284
# What can auditors do with units?
@@ -450,12 +452,14 @@ def student_query(enrolled)
450452
'projects.compile_portfolio',
451453
'projects.grade',
452454
'projects.grade_rationale',
455+
'projects.spec_con_days',
453456
)
454457
.select(
455458
'projects.id AS project_id',
456459
'projects.enrolled AS enrolled',
457460
'projects.task_stats AS task_stats',
458461
'projects.campus_id AS campus_id',
462+
'projects.spec_con_days AS spec_con_days',
459463
'users.first_name AS first_name',
460464
'users.last_name AS last_name',
461465
'users.nickname AS nickname',
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
class AddSpecCon < ActiveRecord::Migration[8.0]
2+
def change
3+
add_column :projects, :spec_con_days, :integer, default: 0, null: false
4+
add_column :units, :allow_flexible_dates, :boolean, default: false, null: false
5+
add_column :units, :portfolio_due_date, :datetime
6+
end
7+
end

0 commit comments

Comments
 (0)