2016-04-22 06:09:15 +08:00
|
|
|
#
|
2017-04-28 03:45:05 +08:00
|
|
|
# Copyright (C) 2014 - present Instructure, Inc.
|
2016-04-22 06:09:15 +08:00
|
|
|
#
|
|
|
|
# This file is part of Canvas.
|
|
|
|
#
|
|
|
|
# Canvas is free software: you can redistribute it and/or modify it under
|
|
|
|
# the terms of the GNU Affero General Public License as published by the Free
|
|
|
|
# Software Foundation, version 3 of the License.
|
|
|
|
#
|
|
|
|
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
|
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
|
|
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
|
|
# details.
|
|
|
|
#
|
|
|
|
# You should have received a copy of the GNU Affero General Public License along
|
|
|
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
#
|
|
|
|
|
add grading period group model
add GradingPeriodGroup, and change associations between GradingPeriods,
GradingPeriodGroups, Courses, and Accounts. also adjust the grading
periods controller to account for addition of grading period groups
closes CNVS-16538
test plan:
-run bundle exec rake db:migrate, and bundle exec rake db:migrate RAILS_ENV=test
-verify the migrations successfully run
-open the rails console in sandbox: bundle exec rails c -s
-create a course, a few grading periods, and a grading period group. Add the grading periods to the group. Assign
the grading period group to the course.
$ course = Course.create
$ grading_period1 = GradingPeriod.create(weight: 25.0, start_date: Time.zone.now, end_date: 2.days.from_now)
$ grading_period2 = GradingPeriod.create(weight: 30.0, start_date: Time.zone.now, end_date: 2.days.from_now)
$ grading_period_group = GradingPeriodGroup.create()
$ grading_period_group.grading_periods << grading_period1
$ grading_period_group.grading_periods << grading_period2
$ grading_period_group.course = course
-verify the associations are working as expected, i.e. a GradingPeriodGroup has GradingPeriods, a GradingPeriod
belongs to a GradingPeriodGroup, and a GradingPeriodGroup belongs to a course or account.
$ grading_period_group.grading_periods #should return an array containing grading_period1 and grading_period2
$ grading_period1.grading_period_group #should return grading_period_group
$ grading_period2.grading_period_group #should return grading_period_group
$ grading_period_group.course #should return course
$ grading_period_group.account #should return nil (should not throw error)
Change-Id: I9d7465431dabd2afa18e7a8a33706b9a78a94cd1
Reviewed-on: https://gerrit.instructure.com/43512
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Josh Simpson <jsimpson@instructure.com>
QA-Review: Amber Taniuchi <amber@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
Product-Review: Spencer Olson <solson@instructure.com>
2014-10-30 02:42:41 +08:00
|
|
|
class GradingPeriodGroup < ActiveRecord::Base
|
2015-05-09 07:38:39 +08:00
|
|
|
include Canvas::SoftDeletable
|
add workflow state to grading period groups and grading period grades
add workflow state to grading period groups and grading period grades.
also add a default value of 'active' and a not-null constraint for
workflow state on grading periods, grading period groups, and grading
period grades. also add a validate method for grading period group
that ensures the group belongs to either a course or account. add a
not-null constraint for grading period group id on grading periods. add
an index for workflow_state on grading period groups, grading periods,
and grading period grades.
closes CNVS-18995
test plan:
run migrations. in rails console:
$ bundle exec rake db:migrate
$ bundle exec rake db:migrate RAILS_ENV=test
Grading Period Groups:
- you should not be able to create a Grading Period Group without
assigning it either a course or account. If you don't supply a
workflow state when you create a grading period group, it should
default to 'active'.
$ g = GradingPeriodGroup.create
$ g.valid? #should return false
$ g = Account.default.grading_period_groups.create
$ g.valid? #should return true
$ g.workflow_state #should return 'active'
$ new_course = Course.create
$ g = new_course.grading_period_groups.create
$ g.valid? #should return true
$ g.workflow_state #should return 'active'
- when you delete a grading period group, it should do a 'soft delete',
which means it should set its workflow_state to 'deleted' instead of
actually deleting it from the database
$ g = Account.default.grading_period_groups.create
$ g.destroy
$ g.workflow_state #should return 'deleted'
- when you delete a grading period group, it should also soft delete
any grading periods that belong to it.
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ gp_group.destroy
$ gp_group.workflow_state #should return 'deleted'
$ gp.workflow_state #should return 'deleted'
Grading Periods:
- you should no longer be able to create a grading period without
giving it a grading_period_group id. also, if you don't give it
a workflow_state, it should default to 'active'. when you
delete a grading period it should do a 'soft delete'.
$ g = GradingPeriod.create(start_date: Time.now, end_date: 1.month.from_now)
$ g.valid? #should return false
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ gp.valid? #should return true
$ gp.workflow_state #should return 'active'
$ gp.destroy
$ gp.workflow_state #should return 'deleted'
- when you delete a grading period, it should also do a 'soft delete'
on any owned grading period grades. Enrollments are tricky to make
via the rails console, so i'm just grabbing one here that was already
made -- you should be able to do the same. if you don't have any
enrollments created, create one via Canvas and then come back to
the rails console.
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ enrollment = Enrollment.first
$ gp_grade = gp.grading_period_grades.create(
enrollment_id: enrollment)
$ gp_grade.workflow_state #should return 'active'
$ gp.destroy
$ gp.workflow_state #should return 'deleted'
$ gp_grade.workflow_state #should return 'deleted'
Grading Period Grades:
- these should now 'soft delete' as well. they require a grading period
and an enrollment to be created (no change here, this has always been
the case).
$ enrollment = Enrollment.first
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ gp_grade = gp.grading_period_grades.create(
enrollment_id: enrollment)
$ gp_grade.workflow_state #should return 'active'
$ gp_grade.destroy
$ gp_grade.workflow_state #should return 'deleted'
Change-Id: Ic397a03beca4782c0c80e486673c7cfef59d38e5
Reviewed-on: https://gerrit.instructure.com/49754
Reviewed-by: Josh Simpson <jsimpson@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
QA-Review: Robert Lamb <rlamb@instructure.com>
Tested-by: Jenkins
Product-Review: Spencer Olson <solson@instructure.com>
2015-03-06 07:36:04 +08:00
|
|
|
|
2016-06-14 04:52:06 +08:00
|
|
|
belongs_to :root_account, inverse_of: :grading_period_groups, foreign_key: :account_id, class_name: "Account"
|
2016-05-10 01:04:04 +08:00
|
|
|
belongs_to :course
|
change delayed job behavior when grading period is updated
If a grading period or grading period group is updated, we were
previously creating a delayed-job-per-course for grade recalculation
and a delayed-job-per-course for DueDateCacher recalculation, with no
limit on how many of those jobs could be run in parallel.
Now, we create a delayed-job-per-1000-courses for grade recalculation,
and a delayed-job-per-1000-courses for DueDateCacher recalculation, and
the number of jobs that can be run in parallel are limited with an
n_strand.
closes GRADE-805
Test Plan:
1. Verify cached due dates and scores (grading period and overall) are
recalulated when:
a) Creating, updating, and deleting a Grading Period Set.
b) Creating, updating, and deleting a Grading Period.
2. When creating/updating a Grading Period or a Grading Period Group
such that a score + due date recalculation occurs, verify:
a) Enrollment term delayed jobs
(EnrollmentTerm#recompute_scores_for_batch) are being stranded by
GradingPeriodGroup, and a job is being created for each 1000
courses that need to be operated on in that term.
b) Score recalculation delayed jobs are not being triggered (because
the score recalculation is happening in the delayed job triggered
in step a above).
c) Due date recalculation delayed jobs are not being triggered
(because the due date recalculation is happening in the delayed
job triggered in step a above).
Change-Id: I99610d0559a449ad08b9209646490f7fa1cdf33b
Reviewed-on: https://gerrit.instructure.com/138508
Reviewed-by: Shahbaz Javeed <sjaveed@instructure.com>
Tested-by: Jenkins
Reviewed-by: Derek Bender <djbender@instructure.com>
Product-Review: Keith T. Garner <kgarner@instructure.com>
QA-Review: Keith T. Garner <kgarner@instructure.com>
2018-01-20 04:56:28 +08:00
|
|
|
has_many :grading_periods
|
2016-05-10 01:04:04 +08:00
|
|
|
has_many :enrollment_terms, inverse_of: :grading_period_group
|
add grading period group model
add GradingPeriodGroup, and change associations between GradingPeriods,
GradingPeriodGroups, Courses, and Accounts. also adjust the grading
periods controller to account for addition of grading period groups
closes CNVS-16538
test plan:
-run bundle exec rake db:migrate, and bundle exec rake db:migrate RAILS_ENV=test
-verify the migrations successfully run
-open the rails console in sandbox: bundle exec rails c -s
-create a course, a few grading periods, and a grading period group. Add the grading periods to the group. Assign
the grading period group to the course.
$ course = Course.create
$ grading_period1 = GradingPeriod.create(weight: 25.0, start_date: Time.zone.now, end_date: 2.days.from_now)
$ grading_period2 = GradingPeriod.create(weight: 30.0, start_date: Time.zone.now, end_date: 2.days.from_now)
$ grading_period_group = GradingPeriodGroup.create()
$ grading_period_group.grading_periods << grading_period1
$ grading_period_group.grading_periods << grading_period2
$ grading_period_group.course = course
-verify the associations are working as expected, i.e. a GradingPeriodGroup has GradingPeriods, a GradingPeriod
belongs to a GradingPeriodGroup, and a GradingPeriodGroup belongs to a course or account.
$ grading_period_group.grading_periods #should return an array containing grading_period1 and grading_period2
$ grading_period1.grading_period_group #should return grading_period_group
$ grading_period2.grading_period_group #should return grading_period_group
$ grading_period_group.course #should return course
$ grading_period_group.account #should return nil (should not throw error)
Change-Id: I9d7465431dabd2afa18e7a8a33706b9a78a94cd1
Reviewed-on: https://gerrit.instructure.com/43512
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Josh Simpson <jsimpson@instructure.com>
QA-Review: Amber Taniuchi <amber@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
Product-Review: Spencer Olson <solson@instructure.com>
2014-10-30 02:42:41 +08:00
|
|
|
|
2016-06-14 04:52:06 +08:00
|
|
|
validate :associated_with_course_or_root_account, if: :active?
|
add workflow state to grading period groups and grading period grades
add workflow state to grading period groups and grading period grades.
also add a default value of 'active' and a not-null constraint for
workflow state on grading periods, grading period groups, and grading
period grades. also add a validate method for grading period group
that ensures the group belongs to either a course or account. add a
not-null constraint for grading period group id on grading periods. add
an index for workflow_state on grading period groups, grading periods,
and grading period grades.
closes CNVS-18995
test plan:
run migrations. in rails console:
$ bundle exec rake db:migrate
$ bundle exec rake db:migrate RAILS_ENV=test
Grading Period Groups:
- you should not be able to create a Grading Period Group without
assigning it either a course or account. If you don't supply a
workflow state when you create a grading period group, it should
default to 'active'.
$ g = GradingPeriodGroup.create
$ g.valid? #should return false
$ g = Account.default.grading_period_groups.create
$ g.valid? #should return true
$ g.workflow_state #should return 'active'
$ new_course = Course.create
$ g = new_course.grading_period_groups.create
$ g.valid? #should return true
$ g.workflow_state #should return 'active'
- when you delete a grading period group, it should do a 'soft delete',
which means it should set its workflow_state to 'deleted' instead of
actually deleting it from the database
$ g = Account.default.grading_period_groups.create
$ g.destroy
$ g.workflow_state #should return 'deleted'
- when you delete a grading period group, it should also soft delete
any grading periods that belong to it.
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ gp_group.destroy
$ gp_group.workflow_state #should return 'deleted'
$ gp.workflow_state #should return 'deleted'
Grading Periods:
- you should no longer be able to create a grading period without
giving it a grading_period_group id. also, if you don't give it
a workflow_state, it should default to 'active'. when you
delete a grading period it should do a 'soft delete'.
$ g = GradingPeriod.create(start_date: Time.now, end_date: 1.month.from_now)
$ g.valid? #should return false
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ gp.valid? #should return true
$ gp.workflow_state #should return 'active'
$ gp.destroy
$ gp.workflow_state #should return 'deleted'
- when you delete a grading period, it should also do a 'soft delete'
on any owned grading period grades. Enrollments are tricky to make
via the rails console, so i'm just grabbing one here that was already
made -- you should be able to do the same. if you don't have any
enrollments created, create one via Canvas and then come back to
the rails console.
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ enrollment = Enrollment.first
$ gp_grade = gp.grading_period_grades.create(
enrollment_id: enrollment)
$ gp_grade.workflow_state #should return 'active'
$ gp.destroy
$ gp.workflow_state #should return 'deleted'
$ gp_grade.workflow_state #should return 'deleted'
Grading Period Grades:
- these should now 'soft delete' as well. they require a grading period
and an enrollment to be created (no change here, this has always been
the case).
$ enrollment = Enrollment.first
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ gp_grade = gp.grading_period_grades.create(
enrollment_id: enrollment)
$ gp_grade.workflow_state #should return 'active'
$ gp_grade.destroy
$ gp_grade.workflow_state #should return 'deleted'
Change-Id: Ic397a03beca4782c0c80e486673c7cfef59d38e5
Reviewed-on: https://gerrit.instructure.com/49754
Reviewed-by: Josh Simpson <jsimpson@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
QA-Review: Robert Lamb <rlamb@instructure.com>
Tested-by: Jenkins
Product-Review: Spencer Olson <solson@instructure.com>
2015-03-06 07:36:04 +08:00
|
|
|
|
timeout when editing grading periods sets with many courses
The issue occured on a term with a large number of courses (~2000)
when a grading period set is attached or detached from a term,
or is attached to a term and its weighted flag changes. These
events trigger grade recalculation on all assignments in the term.
While the grade recalculation jobs each run in the background,
the loop which submits those jobs runs in the foreground.
To fix this issue, the loop that enqueues one job for each course
should itself be a background job, if running in production mode.
fixes CNVS-36070
[ci-coverage]
Test Plan
1. Seed local canvas with 100 courses, each with a few submissions
Go to admin Grading window, edit grading period
Use browser network timing window to measure response time
100 Courses, simulating production (delayed job)
change weighted flag: 0.21s, 0.30s
detach term from gpg: 0.13s, 0.13s
attach term to gpg: 0.15s, 0.17s
100 Courses, not simulating production (immediate)
change weighted flag: 4.11s
detach term from gpg: 7.95s
attach term to gpg: 5.06s
In each case, verify that scores were recalulated properly
Change-Id: I08674d3871d0d70c1f5ea569e241343c7d9ca6d8
Reviewed-on: https://gerrit.instructure.com/111657
Tested-by: Jenkins
Reviewed-by: Derek Bender <djbender@instructure.com>
Reviewed-by: Neil Gupta <ngupta@instructure.com>
QA-Review: KC Naegle <knaegle@instructure.com>
Product-Review: Keith T. Garner <kgarner@instructure.com>
2017-05-13 03:49:58 +08:00
|
|
|
after_save :recompute_course_scores, if: :weighted_actually_changed?
|
2018-03-21 05:11:50 +08:00
|
|
|
after_save :recache_grading_period, if: :saved_change_to_course_id?
|
change delayed job behavior when grading period is updated
If a grading period or grading period group is updated, we were
previously creating a delayed-job-per-course for grade recalculation
and a delayed-job-per-course for DueDateCacher recalculation, with no
limit on how many of those jobs could be run in parallel.
Now, we create a delayed-job-per-1000-courses for grade recalculation,
and a delayed-job-per-1000-courses for DueDateCacher recalculation, and
the number of jobs that can be run in parallel are limited with an
n_strand.
closes GRADE-805
Test Plan:
1. Verify cached due dates and scores (grading period and overall) are
recalulated when:
a) Creating, updating, and deleting a Grading Period Set.
b) Creating, updating, and deleting a Grading Period.
2. When creating/updating a Grading Period or a Grading Period Group
such that a score + due date recalculation occurs, verify:
a) Enrollment term delayed jobs
(EnrollmentTerm#recompute_scores_for_batch) are being stranded by
GradingPeriodGroup, and a job is being created for each 1000
courses that need to be operated on in that term.
b) Score recalculation delayed jobs are not being triggered (because
the score recalculation is happening in the delayed job triggered
in step a above).
c) Due date recalculation delayed jobs are not being triggered
(because the due date recalculation is happening in the delayed
job triggered in step a above).
Change-Id: I99610d0559a449ad08b9209646490f7fa1cdf33b
Reviewed-on: https://gerrit.instructure.com/138508
Reviewed-by: Shahbaz Javeed <sjaveed@instructure.com>
Tested-by: Jenkins
Reviewed-by: Derek Bender <djbender@instructure.com>
Product-Review: Keith T. Garner <kgarner@instructure.com>
QA-Review: Keith T. Garner <kgarner@instructure.com>
2018-01-20 04:56:28 +08:00
|
|
|
after_destroy :cleanup_associations_and_recompute_scores_later
|
2016-06-15 03:44:40 +08:00
|
|
|
|
add grading period group model
add GradingPeriodGroup, and change associations between GradingPeriods,
GradingPeriodGroups, Courses, and Accounts. also adjust the grading
periods controller to account for addition of grading period groups
closes CNVS-16538
test plan:
-run bundle exec rake db:migrate, and bundle exec rake db:migrate RAILS_ENV=test
-verify the migrations successfully run
-open the rails console in sandbox: bundle exec rails c -s
-create a course, a few grading periods, and a grading period group. Add the grading periods to the group. Assign
the grading period group to the course.
$ course = Course.create
$ grading_period1 = GradingPeriod.create(weight: 25.0, start_date: Time.zone.now, end_date: 2.days.from_now)
$ grading_period2 = GradingPeriod.create(weight: 30.0, start_date: Time.zone.now, end_date: 2.days.from_now)
$ grading_period_group = GradingPeriodGroup.create()
$ grading_period_group.grading_periods << grading_period1
$ grading_period_group.grading_periods << grading_period2
$ grading_period_group.course = course
-verify the associations are working as expected, i.e. a GradingPeriodGroup has GradingPeriods, a GradingPeriod
belongs to a GradingPeriodGroup, and a GradingPeriodGroup belongs to a course or account.
$ grading_period_group.grading_periods #should return an array containing grading_period1 and grading_period2
$ grading_period1.grading_period_group #should return grading_period_group
$ grading_period2.grading_period_group #should return grading_period_group
$ grading_period_group.course #should return course
$ grading_period_group.account #should return nil (should not throw error)
Change-Id: I9d7465431dabd2afa18e7a8a33706b9a78a94cd1
Reviewed-on: https://gerrit.instructure.com/43512
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Josh Simpson <jsimpson@instructure.com>
QA-Review: Amber Taniuchi <amber@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
Product-Review: Spencer Olson <solson@instructure.com>
2014-10-30 02:42:41 +08:00
|
|
|
set_policy do
|
2016-04-27 07:25:23 +08:00
|
|
|
given do |user|
|
2016-04-22 06:09:15 +08:00
|
|
|
(course || root_account).grants_right?(user, :read)
|
2016-04-27 07:25:23 +08:00
|
|
|
end
|
add grading period group model
add GradingPeriodGroup, and change associations between GradingPeriods,
GradingPeriodGroups, Courses, and Accounts. also adjust the grading
periods controller to account for addition of grading period groups
closes CNVS-16538
test plan:
-run bundle exec rake db:migrate, and bundle exec rake db:migrate RAILS_ENV=test
-verify the migrations successfully run
-open the rails console in sandbox: bundle exec rails c -s
-create a course, a few grading periods, and a grading period group. Add the grading periods to the group. Assign
the grading period group to the course.
$ course = Course.create
$ grading_period1 = GradingPeriod.create(weight: 25.0, start_date: Time.zone.now, end_date: 2.days.from_now)
$ grading_period2 = GradingPeriod.create(weight: 30.0, start_date: Time.zone.now, end_date: 2.days.from_now)
$ grading_period_group = GradingPeriodGroup.create()
$ grading_period_group.grading_periods << grading_period1
$ grading_period_group.grading_periods << grading_period2
$ grading_period_group.course = course
-verify the associations are working as expected, i.e. a GradingPeriodGroup has GradingPeriods, a GradingPeriod
belongs to a GradingPeriodGroup, and a GradingPeriodGroup belongs to a course or account.
$ grading_period_group.grading_periods #should return an array containing grading_period1 and grading_period2
$ grading_period1.grading_period_group #should return grading_period_group
$ grading_period2.grading_period_group #should return grading_period_group
$ grading_period_group.course #should return course
$ grading_period_group.account #should return nil (should not throw error)
Change-Id: I9d7465431dabd2afa18e7a8a33706b9a78a94cd1
Reviewed-on: https://gerrit.instructure.com/43512
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Josh Simpson <jsimpson@instructure.com>
QA-Review: Amber Taniuchi <amber@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
Product-Review: Spencer Olson <solson@instructure.com>
2014-10-30 02:42:41 +08:00
|
|
|
can :read
|
|
|
|
|
2016-04-27 07:25:23 +08:00
|
|
|
given do |user|
|
2016-04-22 06:09:15 +08:00
|
|
|
root_account &&
|
|
|
|
root_account.associated_user?(user)
|
2016-04-27 07:25:23 +08:00
|
|
|
end
|
set up permissions for grading periods
closes CNVS-18438
test plan:
1. create a root-account, a sub-account (belonging to the root-account),
and a course belonging to the root-account (not belonging to the
sub-account). Create an admin for your root-account and an admin for
your sub-account, and a teacher and student for your course.
2. create grading periods for the root-account, sub-account,
and course. For the example below i'm using the ids 1, 5, and 10
for the account, sub-account, and course, respectively.
In rails console:
$ root_gp_group = Account.find(1).grading_period_groups.create!
$ sub_gp_group = Account.find(5).grading_period_groups.create!
$ course_gp_group = Course.find(10).grading_period_groups.create!
$ root_gp = root_gp_group.grading_periods.create!(
start_date: Time.now, end_date: 2.days.from_now, weight: 0.50)
$ sub_gp = sub_gp_group.grading_periods.create!(
start_date: Time.now, end_date: 2.days.from_now, weight: 0.50)
$ course_gp = root_gp_group.grading_periods.create!(
start_date: Time.now, end_date: 2.days.from_now, weight: 0.50)
3. check the permissions for your root-admin, sub-admin, teacher,
and student (while still in rails console). example below assumes
root-admin, sub-admin, teacher, and student ids are 100, 200, 300,
and 400 respectively.
$ root_admin = User.find(100)
$ sub_admin = User.find(200)
$ teacher = User.find(300)
$ student = User.find(400)
$ root_gp.rights_status(root_admin, :read, :manage)
-- should return {read: true, manage: true}
$ root_gp.rights_status(sub_admin, :read, :manage)
-- should return {read: true, manage: false}
$ root_gp.rights_status(teacher, :read, :manage)
-- should return {read: true, manage: false}
$ root_gp.rights_status(student, :read, :manage)
-- should return {read: true, manage: false}
$ sub_gp.rights_status(root_admin, :read, :manage)
-- should return {read: true, manage: true}
$ sub_gp.rights_status(sub_admin, :read, :manage)
-- should return {read: true, manage: true}
$ sub_gp.rights_status(teacher, :read, :manage)
-- should return {read: false, manage: false}
$ sub_gp.rights_status(student, :read, :manage)
-- should return {read: false, manage: false}
$ course_gp.rights_status(root_admin, :read, :manage)
-- should return {read: true, manage: true}
$ course_gp.rights_status(sub_admin, :read, :manage)
-- should return {read: false, manage: false}
$ course_gp.rights_status(teacher, :read, :manage)
-- should return {read: true, manage: true}
$ course_gp.rights_status(student, :read, :manage)
-- should return {read: true, manage: false}
Change-Id: Ib5262ebcaa0554096ac9ddaacab017d45717bea6
Reviewed-on: https://gerrit.instructure.com/48524
Tested-by: Jenkins
Reviewed-by: Cameron Sutter <csutter@instructure.com>
QA-Review: Amber Taniuchi <amber@instructure.com>
Product-Review: Spencer Olson <solson@instructure.com>
2015-02-10 02:23:23 +08:00
|
|
|
can :read
|
|
|
|
|
2016-04-27 07:25:23 +08:00
|
|
|
given do |user|
|
2016-04-22 06:09:15 +08:00
|
|
|
(course || root_account).grants_right?(user, :manage)
|
2016-04-27 07:25:23 +08:00
|
|
|
end
|
|
|
|
can :update and can :delete
|
|
|
|
|
|
|
|
given do |user|
|
2016-04-22 06:09:15 +08:00
|
|
|
root_account &&
|
|
|
|
root_account.grants_right?(user, :manage)
|
2016-04-27 07:25:23 +08:00
|
|
|
end
|
|
|
|
can :create
|
set up permissions for grading periods
closes CNVS-18438
test plan:
1. create a root-account, a sub-account (belonging to the root-account),
and a course belonging to the root-account (not belonging to the
sub-account). Create an admin for your root-account and an admin for
your sub-account, and a teacher and student for your course.
2. create grading periods for the root-account, sub-account,
and course. For the example below i'm using the ids 1, 5, and 10
for the account, sub-account, and course, respectively.
In rails console:
$ root_gp_group = Account.find(1).grading_period_groups.create!
$ sub_gp_group = Account.find(5).grading_period_groups.create!
$ course_gp_group = Course.find(10).grading_period_groups.create!
$ root_gp = root_gp_group.grading_periods.create!(
start_date: Time.now, end_date: 2.days.from_now, weight: 0.50)
$ sub_gp = sub_gp_group.grading_periods.create!(
start_date: Time.now, end_date: 2.days.from_now, weight: 0.50)
$ course_gp = root_gp_group.grading_periods.create!(
start_date: Time.now, end_date: 2.days.from_now, weight: 0.50)
3. check the permissions for your root-admin, sub-admin, teacher,
and student (while still in rails console). example below assumes
root-admin, sub-admin, teacher, and student ids are 100, 200, 300,
and 400 respectively.
$ root_admin = User.find(100)
$ sub_admin = User.find(200)
$ teacher = User.find(300)
$ student = User.find(400)
$ root_gp.rights_status(root_admin, :read, :manage)
-- should return {read: true, manage: true}
$ root_gp.rights_status(sub_admin, :read, :manage)
-- should return {read: true, manage: false}
$ root_gp.rights_status(teacher, :read, :manage)
-- should return {read: true, manage: false}
$ root_gp.rights_status(student, :read, :manage)
-- should return {read: true, manage: false}
$ sub_gp.rights_status(root_admin, :read, :manage)
-- should return {read: true, manage: true}
$ sub_gp.rights_status(sub_admin, :read, :manage)
-- should return {read: true, manage: true}
$ sub_gp.rights_status(teacher, :read, :manage)
-- should return {read: false, manage: false}
$ sub_gp.rights_status(student, :read, :manage)
-- should return {read: false, manage: false}
$ course_gp.rights_status(root_admin, :read, :manage)
-- should return {read: true, manage: true}
$ course_gp.rights_status(sub_admin, :read, :manage)
-- should return {read: false, manage: false}
$ course_gp.rights_status(teacher, :read, :manage)
-- should return {read: true, manage: true}
$ course_gp.rights_status(student, :read, :manage)
-- should return {read: true, manage: false}
Change-Id: Ib5262ebcaa0554096ac9ddaacab017d45717bea6
Reviewed-on: https://gerrit.instructure.com/48524
Tested-by: Jenkins
Reviewed-by: Cameron Sutter <csutter@instructure.com>
QA-Review: Amber Taniuchi <amber@instructure.com>
Product-Review: Spencer Olson <solson@instructure.com>
2015-02-10 02:23:23 +08:00
|
|
|
end
|
|
|
|
|
2016-04-27 10:10:14 +08:00
|
|
|
def self.for(account)
|
2017-03-07 08:41:20 +08:00
|
|
|
raise ArgumentError.new("argument is not an Account") unless account.is_a?(Account)
|
2016-04-27 10:10:14 +08:00
|
|
|
root_account = account.root_account? ? account : account.root_account
|
2016-06-14 04:52:06 +08:00
|
|
|
root_account.grading_period_groups.active
|
2016-04-27 10:10:14 +08:00
|
|
|
end
|
|
|
|
|
2017-03-07 08:41:20 +08:00
|
|
|
def self.for_course(context)
|
|
|
|
course_group = GradingPeriodGroup.find_by(course_id: context, workflow_state: :active)
|
|
|
|
return course_group if course_group.present?
|
|
|
|
|
|
|
|
account_group = context.enrollment_term.grading_period_group
|
|
|
|
account_group.nil? || account_group.deleted? ? nil : account_group
|
|
|
|
end
|
|
|
|
|
change delayed job behavior when grading period is updated
If a grading period or grading period group is updated, we were
previously creating a delayed-job-per-course for grade recalculation
and a delayed-job-per-course for DueDateCacher recalculation, with no
limit on how many of those jobs could be run in parallel.
Now, we create a delayed-job-per-1000-courses for grade recalculation,
and a delayed-job-per-1000-courses for DueDateCacher recalculation, and
the number of jobs that can be run in parallel are limited with an
n_strand.
closes GRADE-805
Test Plan:
1. Verify cached due dates and scores (grading period and overall) are
recalulated when:
a) Creating, updating, and deleting a Grading Period Set.
b) Creating, updating, and deleting a Grading Period.
2. When creating/updating a Grading Period or a Grading Period Group
such that a score + due date recalculation occurs, verify:
a) Enrollment term delayed jobs
(EnrollmentTerm#recompute_scores_for_batch) are being stranded by
GradingPeriodGroup, and a job is being created for each 1000
courses that need to be operated on in that term.
b) Score recalculation delayed jobs are not being triggered (because
the score recalculation is happening in the delayed job triggered
in step a above).
c) Due date recalculation delayed jobs are not being triggered
(because the due date recalculation is happening in the delayed
job triggered in step a above).
Change-Id: I99610d0559a449ad08b9209646490f7fa1cdf33b
Reviewed-on: https://gerrit.instructure.com/138508
Reviewed-by: Shahbaz Javeed <sjaveed@instructure.com>
Tested-by: Jenkins
Reviewed-by: Derek Bender <djbender@instructure.com>
Product-Review: Keith T. Garner <kgarner@instructure.com>
QA-Review: Keith T. Garner <kgarner@instructure.com>
2018-01-20 04:56:28 +08:00
|
|
|
def recompute_scores_for_each_term(update_all_grading_period_scores, term_ids: nil)
|
|
|
|
terms = term_ids ? EnrollmentTerm.where(id: term_ids) : enrollment_terms.active
|
|
|
|
|
|
|
|
terms.find_each do |term|
|
|
|
|
term.recompute_course_scores_later(
|
|
|
|
update_all_grading_period_scores: update_all_grading_period_scores,
|
|
|
|
strand_identifier: "GradingPeriodGroup:#{global_id}"
|
|
|
|
)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
add workflow state to grading period groups and grading period grades
add workflow state to grading period groups and grading period grades.
also add a default value of 'active' and a not-null constraint for
workflow state on grading periods, grading period groups, and grading
period grades. also add a validate method for grading period group
that ensures the group belongs to either a course or account. add a
not-null constraint for grading period group id on grading periods. add
an index for workflow_state on grading period groups, grading periods,
and grading period grades.
closes CNVS-18995
test plan:
run migrations. in rails console:
$ bundle exec rake db:migrate
$ bundle exec rake db:migrate RAILS_ENV=test
Grading Period Groups:
- you should not be able to create a Grading Period Group without
assigning it either a course or account. If you don't supply a
workflow state when you create a grading period group, it should
default to 'active'.
$ g = GradingPeriodGroup.create
$ g.valid? #should return false
$ g = Account.default.grading_period_groups.create
$ g.valid? #should return true
$ g.workflow_state #should return 'active'
$ new_course = Course.create
$ g = new_course.grading_period_groups.create
$ g.valid? #should return true
$ g.workflow_state #should return 'active'
- when you delete a grading period group, it should do a 'soft delete',
which means it should set its workflow_state to 'deleted' instead of
actually deleting it from the database
$ g = Account.default.grading_period_groups.create
$ g.destroy
$ g.workflow_state #should return 'deleted'
- when you delete a grading period group, it should also soft delete
any grading periods that belong to it.
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ gp_group.destroy
$ gp_group.workflow_state #should return 'deleted'
$ gp.workflow_state #should return 'deleted'
Grading Periods:
- you should no longer be able to create a grading period without
giving it a grading_period_group id. also, if you don't give it
a workflow_state, it should default to 'active'. when you
delete a grading period it should do a 'soft delete'.
$ g = GradingPeriod.create(start_date: Time.now, end_date: 1.month.from_now)
$ g.valid? #should return false
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ gp.valid? #should return true
$ gp.workflow_state #should return 'active'
$ gp.destroy
$ gp.workflow_state #should return 'deleted'
- when you delete a grading period, it should also do a 'soft delete'
on any owned grading period grades. Enrollments are tricky to make
via the rails console, so i'm just grabbing one here that was already
made -- you should be able to do the same. if you don't have any
enrollments created, create one via Canvas and then come back to
the rails console.
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ enrollment = Enrollment.first
$ gp_grade = gp.grading_period_grades.create(
enrollment_id: enrollment)
$ gp_grade.workflow_state #should return 'active'
$ gp.destroy
$ gp.workflow_state #should return 'deleted'
$ gp_grade.workflow_state #should return 'deleted'
Grading Period Grades:
- these should now 'soft delete' as well. they require a grading period
and an enrollment to be created (no change here, this has always been
the case).
$ enrollment = Enrollment.first
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ gp_grade = gp.grading_period_grades.create(
enrollment_id: enrollment)
$ gp_grade.workflow_state #should return 'active'
$ gp_grade.destroy
$ gp_grade.workflow_state #should return 'deleted'
Change-Id: Ic397a03beca4782c0c80e486673c7cfef59d38e5
Reviewed-on: https://gerrit.instructure.com/49754
Reviewed-by: Josh Simpson <jsimpson@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
QA-Review: Robert Lamb <rlamb@instructure.com>
Tested-by: Jenkins
Product-Review: Spencer Olson <solson@instructure.com>
2015-03-06 07:36:04 +08:00
|
|
|
private
|
2016-05-10 01:04:04 +08:00
|
|
|
|
load grading period scores instead of computing on-the-fly
grading period scores on the /grades page are now loaded instead of
computed on-the-fly.
closes CNVS-34128
test plan:
This test plan mirrors that of 74d948ff to ensure the /grades page
continues to display correct grading period grades (even though
they are now loaded instead of computed on-the-fly)
- Setup -
1. At the account-level, create a new grading period set that uses
weighted grading periods. Attach the default enrollment term to this
set.
2. Create a grading period (GP1) that runs from January 1, 2017 to June
30, 2017. Give it a weight of 75%.
3. Create a grading period (GP2) that runs from July 1, 2017 to
December 31, 2017. Give it a weight of 25%.
4. Create a course that belongs to the default enrollment term from
step 1. Enroll one student in the course. Make sure that student is
enrolled in at least one other course.
5. In the course settings, enable Multiple Grading Periods and enable
Display ‘All Grading Period’ Totals.
6. In the course, create an assignment (Assignment in GP1) that is
worth 10 points and due for everyone on March 15, 2017.
7. In the course, create an assignment (Assignment in GP2) that is
worth 10 points and due for everyone on September 15, 2017.
8. Go to the gradebook and give the student 5/10 on Assignment in GP1
and 10/10 on Assignment in GP2. Ignore the totals that show up in
the gradebook.
- Grade Verification -
1. Sign in as the student and go to the /grades page.
2. Verify the grade for GP1 is 50%.
3. Verify the grade for GP2 is 100%.
4. Verify the grade for ‘All Grading Periods’ is 62.5%.
5. Sign in as the account admin. Change the weight for GP1 to 20% and
change the weight for GP2 to 40%.
6. Sign in as the student and go to the /grades page.
7. Verify the grade for GP1 is 50%.
8. Verify the grade for GP2 is 100%.
9. Verify the grade for ‘All Grading Periods’ is 83.33%.
10. Sign in as the account admin. Change the weight for GP1 to 100% and
change the weight for GP2 to 100%.
11. Sign in as the student and go to the /grades page.
12. Verify the grade for GP1 is 50%.
13. Verify the grade for GP2 is 100%.
14. Verify the grade for ‘All Grading Periods’ is 150%.
15. Sign in as the account admin. Change the weight for GP1 to 100% and
change the weight for GP2 to 0%.
16. Sign in as the student and go to the /grades page.
17. Verify the grade for GP1 is 50%.
18. Verify the grade for GP2 is 100%.
19. Verify the grade for ‘All Grading Periods’ is 50%.
20. Sign in as the account admin. Change the weight for GP1 to 0% and
change the weight for GP2 to 0%.
21. Sign in as the student and go to the /grades page.
22. Verify the grade for GP1 is 50%.
23. Verify the grade for GP2 is 100%.
24. Verify the grade for ‘All Grading Periods’ is 0%.
25. Sign in as the account admin. Uncheck the box on the grading period
set for ‘weighting’.
26. Sign in as the student and go to the /grades page.
27. Verify the grade for GP1 is 50%.
28. Verify the grade for GP2 is 100%.
29. Verify the grade for ‘All Grading Periods’ is 75%.
Change-Id: Ia0f436f2df10484eab881bd8d11c0cad14784217
Reviewed-on: https://gerrit.instructure.com/98808
Tested-by: Jenkins
Reviewed-by: Jeremy Neander <jneander@instructure.com>
Reviewed-by: Keith T. Garner <kgarner@instructure.com>
QA-Review: KC Naegle <knaegle@instructure.com>
Product-Review: Keith T. Garner <kgarner@instructure.com>
2017-01-05 05:41:45 +08:00
|
|
|
def recompute_course_scores
|
|
|
|
return course.recompute_student_scores(update_all_grading_period_scores: false) if course_id.present?
|
|
|
|
|
change delayed job behavior when grading period is updated
If a grading period or grading period group is updated, we were
previously creating a delayed-job-per-course for grade recalculation
and a delayed-job-per-course for DueDateCacher recalculation, with no
limit on how many of those jobs could be run in parallel.
Now, we create a delayed-job-per-1000-courses for grade recalculation,
and a delayed-job-per-1000-courses for DueDateCacher recalculation, and
the number of jobs that can be run in parallel are limited with an
n_strand.
closes GRADE-805
Test Plan:
1. Verify cached due dates and scores (grading period and overall) are
recalulated when:
a) Creating, updating, and deleting a Grading Period Set.
b) Creating, updating, and deleting a Grading Period.
2. When creating/updating a Grading Period or a Grading Period Group
such that a score + due date recalculation occurs, verify:
a) Enrollment term delayed jobs
(EnrollmentTerm#recompute_scores_for_batch) are being stranded by
GradingPeriodGroup, and a job is being created for each 1000
courses that need to be operated on in that term.
b) Score recalculation delayed jobs are not being triggered (because
the score recalculation is happening in the delayed job triggered
in step a above).
c) Due date recalculation delayed jobs are not being triggered
(because the due date recalculation is happening in the delayed
job triggered in step a above).
Change-Id: I99610d0559a449ad08b9209646490f7fa1cdf33b
Reviewed-on: https://gerrit.instructure.com/138508
Reviewed-by: Shahbaz Javeed <sjaveed@instructure.com>
Tested-by: Jenkins
Reviewed-by: Derek Bender <djbender@instructure.com>
Product-Review: Keith T. Garner <kgarner@instructure.com>
QA-Review: Keith T. Garner <kgarner@instructure.com>
2018-01-20 04:56:28 +08:00
|
|
|
recompute_scores_for_each_term(false)
|
load grading period scores instead of computing on-the-fly
grading period scores on the /grades page are now loaded instead of
computed on-the-fly.
closes CNVS-34128
test plan:
This test plan mirrors that of 74d948ff to ensure the /grades page
continues to display correct grading period grades (even though
they are now loaded instead of computed on-the-fly)
- Setup -
1. At the account-level, create a new grading period set that uses
weighted grading periods. Attach the default enrollment term to this
set.
2. Create a grading period (GP1) that runs from January 1, 2017 to June
30, 2017. Give it a weight of 75%.
3. Create a grading period (GP2) that runs from July 1, 2017 to
December 31, 2017. Give it a weight of 25%.
4. Create a course that belongs to the default enrollment term from
step 1. Enroll one student in the course. Make sure that student is
enrolled in at least one other course.
5. In the course settings, enable Multiple Grading Periods and enable
Display ‘All Grading Period’ Totals.
6. In the course, create an assignment (Assignment in GP1) that is
worth 10 points and due for everyone on March 15, 2017.
7. In the course, create an assignment (Assignment in GP2) that is
worth 10 points and due for everyone on September 15, 2017.
8. Go to the gradebook and give the student 5/10 on Assignment in GP1
and 10/10 on Assignment in GP2. Ignore the totals that show up in
the gradebook.
- Grade Verification -
1. Sign in as the student and go to the /grades page.
2. Verify the grade for GP1 is 50%.
3. Verify the grade for GP2 is 100%.
4. Verify the grade for ‘All Grading Periods’ is 62.5%.
5. Sign in as the account admin. Change the weight for GP1 to 20% and
change the weight for GP2 to 40%.
6. Sign in as the student and go to the /grades page.
7. Verify the grade for GP1 is 50%.
8. Verify the grade for GP2 is 100%.
9. Verify the grade for ‘All Grading Periods’ is 83.33%.
10. Sign in as the account admin. Change the weight for GP1 to 100% and
change the weight for GP2 to 100%.
11. Sign in as the student and go to the /grades page.
12. Verify the grade for GP1 is 50%.
13. Verify the grade for GP2 is 100%.
14. Verify the grade for ‘All Grading Periods’ is 150%.
15. Sign in as the account admin. Change the weight for GP1 to 100% and
change the weight for GP2 to 0%.
16. Sign in as the student and go to the /grades page.
17. Verify the grade for GP1 is 50%.
18. Verify the grade for GP2 is 100%.
19. Verify the grade for ‘All Grading Periods’ is 50%.
20. Sign in as the account admin. Change the weight for GP1 to 0% and
change the weight for GP2 to 0%.
21. Sign in as the student and go to the /grades page.
22. Verify the grade for GP1 is 50%.
23. Verify the grade for GP2 is 100%.
24. Verify the grade for ‘All Grading Periods’ is 0%.
25. Sign in as the account admin. Uncheck the box on the grading period
set for ‘weighting’.
26. Sign in as the student and go to the /grades page.
27. Verify the grade for GP1 is 50%.
28. Verify the grade for GP2 is 100%.
29. Verify the grade for ‘All Grading Periods’ is 75%.
Change-Id: Ia0f436f2df10484eab881bd8d11c0cad14784217
Reviewed-on: https://gerrit.instructure.com/98808
Tested-by: Jenkins
Reviewed-by: Jeremy Neander <jneander@instructure.com>
Reviewed-by: Keith T. Garner <kgarner@instructure.com>
QA-Review: KC Naegle <knaegle@instructure.com>
Product-Review: Keith T. Garner <kgarner@instructure.com>
2017-01-05 05:41:45 +08:00
|
|
|
end
|
|
|
|
|
timeout when editing grading periods sets with many courses
The issue occured on a term with a large number of courses (~2000)
when a grading period set is attached or detached from a term,
or is attached to a term and its weighted flag changes. These
events trigger grade recalculation on all assignments in the term.
While the grade recalculation jobs each run in the background,
the loop which submits those jobs runs in the foreground.
To fix this issue, the loop that enqueues one job for each course
should itself be a background job, if running in production mode.
fixes CNVS-36070
[ci-coverage]
Test Plan
1. Seed local canvas with 100 courses, each with a few submissions
Go to admin Grading window, edit grading period
Use browser network timing window to measure response time
100 Courses, simulating production (delayed job)
change weighted flag: 0.21s, 0.30s
detach term from gpg: 0.13s, 0.13s
attach term to gpg: 0.15s, 0.17s
100 Courses, not simulating production (immediate)
change weighted flag: 4.11s
detach term from gpg: 7.95s
attach term to gpg: 5.06s
In each case, verify that scores were recalulated properly
Change-Id: I08674d3871d0d70c1f5ea569e241343c7d9ca6d8
Reviewed-on: https://gerrit.instructure.com/111657
Tested-by: Jenkins
Reviewed-by: Derek Bender <djbender@instructure.com>
Reviewed-by: Neil Gupta <ngupta@instructure.com>
QA-Review: KC Naegle <knaegle@instructure.com>
Product-Review: Keith T. Garner <kgarner@instructure.com>
2017-05-13 03:49:58 +08:00
|
|
|
handle_asynchronously_if_production(
|
|
|
|
:recompute_course_scores,
|
|
|
|
singleton: proc { |g| "grading_period_group:recompute:GradingPeriodGroup:#{g.global_id}" }
|
|
|
|
)
|
|
|
|
|
|
|
|
def weighted_actually_changed?
|
2018-03-21 05:11:50 +08:00
|
|
|
!self.new_record? && saved_change_to_weighted?
|
timeout when editing grading periods sets with many courses
The issue occured on a term with a large number of courses (~2000)
when a grading period set is attached or detached from a term,
or is attached to a term and its weighted flag changes. These
events trigger grade recalculation on all assignments in the term.
While the grade recalculation jobs each run in the background,
the loop which submits those jobs runs in the foreground.
To fix this issue, the loop that enqueues one job for each course
should itself be a background job, if running in production mode.
fixes CNVS-36070
[ci-coverage]
Test Plan
1. Seed local canvas with 100 courses, each with a few submissions
Go to admin Grading window, edit grading period
Use browser network timing window to measure response time
100 Courses, simulating production (delayed job)
change weighted flag: 0.21s, 0.30s
detach term from gpg: 0.13s, 0.13s
attach term to gpg: 0.15s, 0.17s
100 Courses, not simulating production (immediate)
change weighted flag: 4.11s
detach term from gpg: 7.95s
attach term to gpg: 5.06s
In each case, verify that scores were recalulated properly
Change-Id: I08674d3871d0d70c1f5ea569e241343c7d9ca6d8
Reviewed-on: https://gerrit.instructure.com/111657
Tested-by: Jenkins
Reviewed-by: Derek Bender <djbender@instructure.com>
Reviewed-by: Neil Gupta <ngupta@instructure.com>
QA-Review: KC Naegle <knaegle@instructure.com>
Product-Review: Keith T. Garner <kgarner@instructure.com>
2017-05-13 03:49:58 +08:00
|
|
|
end
|
|
|
|
|
2017-04-19 11:09:10 +08:00
|
|
|
def recache_grading_period
|
|
|
|
DueDateCacher.recompute_course(course) if course
|
2018-03-21 05:11:50 +08:00
|
|
|
DueDateCacher.recompute_course(course_id_before_last_save) if course_id_before_last_save
|
2017-04-19 11:09:10 +08:00
|
|
|
end
|
|
|
|
|
2016-06-14 04:52:06 +08:00
|
|
|
def associated_with_course_or_root_account
|
2016-05-10 01:04:04 +08:00
|
|
|
if course_id.blank? && account_id.blank?
|
2016-06-14 04:52:06 +08:00
|
|
|
errors.add(:course_id, t("cannot be nil when account_id is nil"))
|
|
|
|
errors.add(:account_id, t("cannot be nil when course_id is nil"))
|
2016-05-10 01:04:04 +08:00
|
|
|
elsif course_id.present? && account_id.present?
|
add workflow state to grading period groups and grading period grades
add workflow state to grading period groups and grading period grades.
also add a default value of 'active' and a not-null constraint for
workflow state on grading periods, grading period groups, and grading
period grades. also add a validate method for grading period group
that ensures the group belongs to either a course or account. add a
not-null constraint for grading period group id on grading periods. add
an index for workflow_state on grading period groups, grading periods,
and grading period grades.
closes CNVS-18995
test plan:
run migrations. in rails console:
$ bundle exec rake db:migrate
$ bundle exec rake db:migrate RAILS_ENV=test
Grading Period Groups:
- you should not be able to create a Grading Period Group without
assigning it either a course or account. If you don't supply a
workflow state when you create a grading period group, it should
default to 'active'.
$ g = GradingPeriodGroup.create
$ g.valid? #should return false
$ g = Account.default.grading_period_groups.create
$ g.valid? #should return true
$ g.workflow_state #should return 'active'
$ new_course = Course.create
$ g = new_course.grading_period_groups.create
$ g.valid? #should return true
$ g.workflow_state #should return 'active'
- when you delete a grading period group, it should do a 'soft delete',
which means it should set its workflow_state to 'deleted' instead of
actually deleting it from the database
$ g = Account.default.grading_period_groups.create
$ g.destroy
$ g.workflow_state #should return 'deleted'
- when you delete a grading period group, it should also soft delete
any grading periods that belong to it.
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ gp_group.destroy
$ gp_group.workflow_state #should return 'deleted'
$ gp.workflow_state #should return 'deleted'
Grading Periods:
- you should no longer be able to create a grading period without
giving it a grading_period_group id. also, if you don't give it
a workflow_state, it should default to 'active'. when you
delete a grading period it should do a 'soft delete'.
$ g = GradingPeriod.create(start_date: Time.now, end_date: 1.month.from_now)
$ g.valid? #should return false
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ gp.valid? #should return true
$ gp.workflow_state #should return 'active'
$ gp.destroy
$ gp.workflow_state #should return 'deleted'
- when you delete a grading period, it should also do a 'soft delete'
on any owned grading period grades. Enrollments are tricky to make
via the rails console, so i'm just grabbing one here that was already
made -- you should be able to do the same. if you don't have any
enrollments created, create one via Canvas and then come back to
the rails console.
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ enrollment = Enrollment.first
$ gp_grade = gp.grading_period_grades.create(
enrollment_id: enrollment)
$ gp_grade.workflow_state #should return 'active'
$ gp.destroy
$ gp.workflow_state #should return 'deleted'
$ gp_grade.workflow_state #should return 'deleted'
Grading Period Grades:
- these should now 'soft delete' as well. they require a grading period
and an enrollment to be created (no change here, this has always been
the case).
$ enrollment = Enrollment.first
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ gp_grade = gp.grading_period_grades.create(
enrollment_id: enrollment)
$ gp_grade.workflow_state #should return 'active'
$ gp_grade.destroy
$ gp_grade.workflow_state #should return 'deleted'
Change-Id: Ic397a03beca4782c0c80e486673c7cfef59d38e5
Reviewed-on: https://gerrit.instructure.com/49754
Reviewed-by: Josh Simpson <jsimpson@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
QA-Review: Robert Lamb <rlamb@instructure.com>
Tested-by: Jenkins
Product-Review: Spencer Olson <solson@instructure.com>
2015-03-06 07:36:04 +08:00
|
|
|
errors.add(:course_id, t("cannot be present when account_id is present"))
|
|
|
|
errors.add(:account_id, t("cannot be present when course_id is present"))
|
2016-06-14 04:52:06 +08:00
|
|
|
elsif root_account && !root_account.root_account?
|
|
|
|
errors.add(:account_id, t("must belong to a root account"))
|
|
|
|
elsif root_account && root_account.deleted?
|
|
|
|
errors.add(:account_id, t("must belong to an active root account"))
|
|
|
|
elsif course && course.deleted?
|
|
|
|
errors.add(:course_id, t("must belong to an active course"))
|
add workflow state to grading period groups and grading period grades
add workflow state to grading period groups and grading period grades.
also add a default value of 'active' and a not-null constraint for
workflow state on grading periods, grading period groups, and grading
period grades. also add a validate method for grading period group
that ensures the group belongs to either a course or account. add a
not-null constraint for grading period group id on grading periods. add
an index for workflow_state on grading period groups, grading periods,
and grading period grades.
closes CNVS-18995
test plan:
run migrations. in rails console:
$ bundle exec rake db:migrate
$ bundle exec rake db:migrate RAILS_ENV=test
Grading Period Groups:
- you should not be able to create a Grading Period Group without
assigning it either a course or account. If you don't supply a
workflow state when you create a grading period group, it should
default to 'active'.
$ g = GradingPeriodGroup.create
$ g.valid? #should return false
$ g = Account.default.grading_period_groups.create
$ g.valid? #should return true
$ g.workflow_state #should return 'active'
$ new_course = Course.create
$ g = new_course.grading_period_groups.create
$ g.valid? #should return true
$ g.workflow_state #should return 'active'
- when you delete a grading period group, it should do a 'soft delete',
which means it should set its workflow_state to 'deleted' instead of
actually deleting it from the database
$ g = Account.default.grading_period_groups.create
$ g.destroy
$ g.workflow_state #should return 'deleted'
- when you delete a grading period group, it should also soft delete
any grading periods that belong to it.
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ gp_group.destroy
$ gp_group.workflow_state #should return 'deleted'
$ gp.workflow_state #should return 'deleted'
Grading Periods:
- you should no longer be able to create a grading period without
giving it a grading_period_group id. also, if you don't give it
a workflow_state, it should default to 'active'. when you
delete a grading period it should do a 'soft delete'.
$ g = GradingPeriod.create(start_date: Time.now, end_date: 1.month.from_now)
$ g.valid? #should return false
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ gp.valid? #should return true
$ gp.workflow_state #should return 'active'
$ gp.destroy
$ gp.workflow_state #should return 'deleted'
- when you delete a grading period, it should also do a 'soft delete'
on any owned grading period grades. Enrollments are tricky to make
via the rails console, so i'm just grabbing one here that was already
made -- you should be able to do the same. if you don't have any
enrollments created, create one via Canvas and then come back to
the rails console.
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ enrollment = Enrollment.first
$ gp_grade = gp.grading_period_grades.create(
enrollment_id: enrollment)
$ gp_grade.workflow_state #should return 'active'
$ gp.destroy
$ gp.workflow_state #should return 'deleted'
$ gp_grade.workflow_state #should return 'deleted'
Grading Period Grades:
- these should now 'soft delete' as well. they require a grading period
and an enrollment to be created (no change here, this has always been
the case).
$ enrollment = Enrollment.first
$ gp_group = Account.default.grading_period_groups.create
$ gp = gp_group.grading_periods.create(
start_date: Time.now,
end_date: 1.month.from_now)
$ gp_grade = gp.grading_period_grades.create(
enrollment_id: enrollment)
$ gp_grade.workflow_state #should return 'active'
$ gp_grade.destroy
$ gp_grade.workflow_state #should return 'deleted'
Change-Id: Ic397a03beca4782c0c80e486673c7cfef59d38e5
Reviewed-on: https://gerrit.instructure.com/49754
Reviewed-by: Josh Simpson <jsimpson@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
QA-Review: Robert Lamb <rlamb@instructure.com>
Tested-by: Jenkins
Product-Review: Spencer Olson <solson@instructure.com>
2015-03-06 07:36:04 +08:00
|
|
|
end
|
|
|
|
end
|
make grading periods feature flag a course level flag
make the grading periods feature flag a course level flag, and also
'unlock' the account level grading periods. now, a teacher can edit
account level periods, but when they click 'save' it will create
a new course-level grading period instead of altering the original
account-level period. also added a link to the feature flag settings
page if there is only one grading period on the page. in addition,
if only template periods are being shown on the page and you're
logged in as a teacher, added a message that notifies the user
that the periods were created by an administrator for them.
closes CNVS-18741
closes CNVS-19692
test plan:
this commit makes substantial changes to the way grading periods are
being displayed, deleted, and saved on the
'accounts/:account_id/grading_standards' page and the
'courses/:course_id/grading_standards' page. users should still be able
to create/update/delete grading periods without problems on those pages.
in addition, this commit makes changes to the feature flag settings pages
for admins and teachers. make sure the feature flags are working correctly
(try setting the MGP flag to 'on', 'off', and 'allow' as an admin and see
how it affects the feature flag options for sub-accounts and teachers).
Change-Id: I0b442e708a8049180b55a86098e30a2c64673eda
Reviewed-on: https://gerrit.instructure.com/51594
Tested-by: Jenkins
Reviewed-by: Josh Simpson <jsimpson@instructure.com>
QA-Review: Robert Lamb <rlamb@instructure.com>
Product-Review: Spencer Olson <solson@instructure.com>
2015-04-01 02:04:09 +08:00
|
|
|
|
change delayed job behavior when grading period is updated
If a grading period or grading period group is updated, we were
previously creating a delayed-job-per-course for grade recalculation
and a delayed-job-per-course for DueDateCacher recalculation, with no
limit on how many of those jobs could be run in parallel.
Now, we create a delayed-job-per-1000-courses for grade recalculation,
and a delayed-job-per-1000-courses for DueDateCacher recalculation, and
the number of jobs that can be run in parallel are limited with an
n_strand.
closes GRADE-805
Test Plan:
1. Verify cached due dates and scores (grading period and overall) are
recalulated when:
a) Creating, updating, and deleting a Grading Period Set.
b) Creating, updating, and deleting a Grading Period.
2. When creating/updating a Grading Period or a Grading Period Group
such that a score + due date recalculation occurs, verify:
a) Enrollment term delayed jobs
(EnrollmentTerm#recompute_scores_for_batch) are being stranded by
GradingPeriodGroup, and a job is being created for each 1000
courses that need to be operated on in that term.
b) Score recalculation delayed jobs are not being triggered (because
the score recalculation is happening in the delayed job triggered
in step a above).
c) Due date recalculation delayed jobs are not being triggered
(because the due date recalculation is happening in the delayed
job triggered in step a above).
Change-Id: I99610d0559a449ad08b9209646490f7fa1cdf33b
Reviewed-on: https://gerrit.instructure.com/138508
Reviewed-by: Shahbaz Javeed <sjaveed@instructure.com>
Tested-by: Jenkins
Reviewed-by: Derek Bender <djbender@instructure.com>
Product-Review: Keith T. Garner <kgarner@instructure.com>
QA-Review: Keith T. Garner <kgarner@instructure.com>
2018-01-20 04:56:28 +08:00
|
|
|
def cleanup_associations_and_recompute_scores_later
|
|
|
|
root_account_id = course_id ? course.root_account.global_id : root_account.global_id
|
|
|
|
send_later_if_production_enqueue_args(
|
|
|
|
:cleanup_associations_and_recompute_scores,
|
|
|
|
{
|
|
|
|
strand: "GradingPeriodGroup#cleanup_associations_and_recompute_scores:Account#{root_account_id}",
|
|
|
|
max_attempts: 1,
|
|
|
|
priority: Delayed::LOW_PRIORITY
|
|
|
|
}
|
|
|
|
)
|
|
|
|
end
|
|
|
|
|
|
|
|
def cleanup_associations_and_recompute_scores
|
|
|
|
periods_to_destroy = grading_periods.active
|
|
|
|
update_in_batches(periods_to_destroy, workflow_state: :deleted)
|
|
|
|
|
|
|
|
scores_to_destroy = Score.active.where(grading_period_id: periods_to_destroy)
|
|
|
|
update_in_batches(scores_to_destroy, workflow_state: :deleted)
|
|
|
|
|
|
|
|
# Legacy Grading Period support. Grading Periods can no longer have a course_id.
|
|
|
|
if course_id.present?
|
|
|
|
course.recompute_student_scores(update_all_grading_period_scores: true, run_immediately: true)
|
|
|
|
DueDateCacher.recompute_course(course, run_immediately: true)
|
|
|
|
else
|
|
|
|
term_ids = enrollment_terms.pluck(:id)
|
|
|
|
update_in_batches(enrollment_terms, grading_period_group_id: nil)
|
|
|
|
recompute_scores_for_each_term(true, term_ids: term_ids)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def update_in_batches(scope, updates)
|
|
|
|
scope.find_ids_in_ranges(batch_size: 1000) do |min_id, max_id|
|
|
|
|
scope.where(id: min_id..max_id).update_all(updates.reverse_merge({ updated_at: Time.zone.now }))
|
|
|
|
end
|
2016-06-15 03:44:40 +08:00
|
|
|
end
|
add grading period group model
add GradingPeriodGroup, and change associations between GradingPeriods,
GradingPeriodGroups, Courses, and Accounts. also adjust the grading
periods controller to account for addition of grading period groups
closes CNVS-16538
test plan:
-run bundle exec rake db:migrate, and bundle exec rake db:migrate RAILS_ENV=test
-verify the migrations successfully run
-open the rails console in sandbox: bundle exec rails c -s
-create a course, a few grading periods, and a grading period group. Add the grading periods to the group. Assign
the grading period group to the course.
$ course = Course.create
$ grading_period1 = GradingPeriod.create(weight: 25.0, start_date: Time.zone.now, end_date: 2.days.from_now)
$ grading_period2 = GradingPeriod.create(weight: 30.0, start_date: Time.zone.now, end_date: 2.days.from_now)
$ grading_period_group = GradingPeriodGroup.create()
$ grading_period_group.grading_periods << grading_period1
$ grading_period_group.grading_periods << grading_period2
$ grading_period_group.course = course
-verify the associations are working as expected, i.e. a GradingPeriodGroup has GradingPeriods, a GradingPeriod
belongs to a GradingPeriodGroup, and a GradingPeriodGroup belongs to a course or account.
$ grading_period_group.grading_periods #should return an array containing grading_period1 and grading_period2
$ grading_period1.grading_period_group #should return grading_period_group
$ grading_period2.grading_period_group #should return grading_period_group
$ grading_period_group.course #should return course
$ grading_period_group.account #should return nil (should not throw error)
Change-Id: I9d7465431dabd2afa18e7a8a33706b9a78a94cd1
Reviewed-on: https://gerrit.instructure.com/43512
Tested-by: Jenkins <jenkins@instructure.com>
Reviewed-by: Josh Simpson <jsimpson@instructure.com>
QA-Review: Amber Taniuchi <amber@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
Product-Review: Spencer Olson <solson@instructure.com>
2014-10-30 02:42:41 +08:00
|
|
|
end
|