2020-10-27 00:50:13 +08:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
2011-02-01 09:57:29 +08:00
|
|
|
#
|
2017-04-28 04:03:05 +08:00
|
|
|
# Copyright (C) 2011 - present Instructure, Inc.
|
2011-02-01 09:57:29 +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/>.
|
|
|
|
#
|
|
|
|
|
2011-07-02 06:16:13 +08:00
|
|
|
class EnrollmentsFromUserList
|
2011-02-01 09:57:29 +08:00
|
|
|
class << self
|
2011-07-02 07:36:41 +08:00
|
|
|
def process(list, course, opts = {})
|
|
|
|
EnrollmentsFromUserList.new(course, opts).process(list)
|
2011-02-01 09:57:29 +08:00
|
|
|
end
|
|
|
|
end
|
2016-09-29 02:05:12 +08:00
|
|
|
|
2011-02-01 09:57:29 +08:00
|
|
|
attr_reader :students, :course
|
2016-09-29 02:05:12 +08:00
|
|
|
|
2011-07-02 07:36:41 +08:00
|
|
|
def initialize(course, opts = {})
|
|
|
|
@course = course
|
|
|
|
@enrollment_type = opts[:enrollment_type] || "StudentEnrollment"
|
2014-09-08 20:48:45 +08:00
|
|
|
@role = opts[:role]
|
2011-07-02 07:36:41 +08:00
|
|
|
@limit = opts[:limit]
|
2014-09-18 01:29:06 +08:00
|
|
|
@section = (opts[:course_section_id].present? ? @course.course_sections.active.where(id: opts[:course_section_id].to_i).first : nil) || @course.default_section
|
2011-12-09 08:02:47 +08:00
|
|
|
@limit_privileges_to_course_section = opts[:limit_privileges_to_course_section]
|
2011-07-02 07:36:41 +08:00
|
|
|
@enrolled_users = {}
|
2018-09-14 00:34:39 +08:00
|
|
|
@updating_user = opts[:updating_user]
|
2011-02-01 09:57:29 +08:00
|
|
|
end
|
2016-09-29 02:05:12 +08:00
|
|
|
|
2011-07-02 07:36:41 +08:00
|
|
|
def process(list)
|
2017-11-07 02:20:16 +08:00
|
|
|
raise ArgumentError, "Must provide a UserList or Array (of user tokens)" unless list.is_a?(UserList) || list.is_a?(Array)
|
2021-09-23 00:25:11 +08:00
|
|
|
|
2011-07-02 07:36:41 +08:00
|
|
|
@enrollments = []
|
2016-03-04 00:58:03 +08:00
|
|
|
@user_ids_to_touch = []
|
2011-07-02 07:36:41 +08:00
|
|
|
|
2016-09-29 02:05:12 +08:00
|
|
|
users =
|
|
|
|
if list.is_a?(UserList)
|
|
|
|
list.addresses.slice!(0, @limit) if @limit
|
|
|
|
list.users
|
|
|
|
else
|
|
|
|
# list of user ids
|
2017-11-07 02:20:16 +08:00
|
|
|
User.from_tokens(list)
|
2016-09-29 02:05:12 +08:00
|
|
|
end
|
2023-12-08 03:55:41 +08:00
|
|
|
users.each_slice(50) do |users_slice|
|
2016-03-04 00:58:03 +08:00
|
|
|
@course.transaction do
|
2017-11-11 05:53:44 +08:00
|
|
|
Enrollment.suspend_callbacks(:set_update_cached_due_dates) do
|
2021-11-04 05:36:34 +08:00
|
|
|
users_slice.each { |user| enroll_user(user) }
|
2016-03-04 00:58:03 +08:00
|
|
|
end
|
2013-09-11 05:18:05 +08:00
|
|
|
end
|
2016-03-04 00:58:03 +08:00
|
|
|
end
|
2019-07-03 05:15:39 +08:00
|
|
|
if @enrollments.present?
|
2016-03-04 00:58:03 +08:00
|
|
|
@course.transaction do
|
2018-05-02 05:18:31 +08:00
|
|
|
user_ids = @enrollments.map(&:user_id).uniq
|
2023-06-16 10:40:01 +08:00
|
|
|
SubmissionLifecycleManager.recompute_users_for_course(
|
2019-07-03 05:15:39 +08:00
|
|
|
user_ids,
|
|
|
|
@course,
|
|
|
|
nil,
|
|
|
|
executing_user: @updating_user,
|
|
|
|
update_grades: true
|
|
|
|
)
|
2013-09-11 05:18:05 +08:00
|
|
|
end
|
|
|
|
end
|
2016-03-04 00:58:03 +08:00
|
|
|
@user_ids_to_touch.uniq.each_slice(100) do |user_ids|
|
|
|
|
User.where(id: user_ids).touch_all
|
2018-03-13 21:29:11 +08:00
|
|
|
User.where(id: UserObservationLink.where(user_id: user_ids).select(:observer_id)).touch_all
|
2016-03-04 00:58:03 +08:00
|
|
|
end
|
|
|
|
|
refactor user creation/invitations closes #5833
fixes #5573, #5572, #5753
* communication channels are now only unique within a single user
* UserList changes
* Always resolve pseudonym#unique_ids
* Support looking up by SMS CCs
* Option to either require e-mails match an existing CC,
or e-mails that don't match a Pseudonym will always be
returned unattached (relying on better merging behavior
to not have a gazillion accounts created)
* Method to return users, creating new ones (*without* a
Pseudonym) if necessary. (can't create with a pseudonym,
since Pseudonym#unique_id is still unique, I can't have
multiple outstanding users with the same unique_id)
* EnrollmentsFromUserList is mostly gutted, now using UserList's
functionality directy.
* Use UserList for adding account admins, removing the now
unused Account#add_admin => User#find_by_email/User#assert_by_email
codepath
* Update UsersController#create to not worry about duplicate
communication channels
* Remove AccountsController#add_user, and just use
UsersController#create
* Change SIS::UserImporter to send out a merge opportunity
e-mail if a conflicting CC is found (but still create the CC)
* In /profile, don't worry about conflicting CCs (the CC confirmation
process will now allow merging)
* Remove CommunicationChannelsController#try_merge and #merge
* For the non-simple case of CoursesController#enrollment_invitation
redirect to /register (CommunicationsChannelController#confirm)
* Remove CoursesController#transfer_enrollment
* Move PseudonymsController#registration_confirmation to
CommunicationChannelsController#confirm (have to be able to
register an account without a Pseudonym yet)
* Fold the old direct confirm functionality in, if there are
no available merge opportunities
* Allow merging the new account with the currently logged in user
* Allow changing the Pseudonym#unique_id when registering a new
account (since there might be conflicts)
* Display a list of merge opportunities based on conflicting
communication channels
* Provide link(s) to log in as the other user,
redirecting back to the registration page after login is
complete (to complete the merge as the current user)
* Remove several assert_* methods that are no longer needed
* Update PseudonymSessionsController a bit to deal with the new
way of dealing with conflicting CCs (especially CCs from LDAP),
and to redirect back to the registration/confirmation page when
attempting to do a merge
* Expose the open_registration setting; use it to control if
inviting users to a course is able to create new users
Change-Id: If2f38818a71af656854d3bf8431ddbf5dcb84691
Reviewed-on: https://gerrit.instructure.com/6149
Tested-by: Hudson <hudson@instructure.com>
Reviewed-by: Jacob Fugal <jacob@instructure.com>
2011-10-13 04:30:48 +08:00
|
|
|
@enrollments
|
2011-07-02 07:36:41 +08:00
|
|
|
end
|
2016-09-29 02:05:12 +08:00
|
|
|
|
2011-07-02 07:36:41 +08:00
|
|
|
protected
|
2016-09-29 02:05:12 +08:00
|
|
|
|
2011-07-02 07:36:41 +08:00
|
|
|
def enroll_user(user)
|
|
|
|
return unless user
|
|
|
|
return if @enrolled_users.key?(user.id)
|
2021-09-23 00:25:11 +08:00
|
|
|
|
2011-07-02 07:36:41 +08:00
|
|
|
@enrolled_users[user.id] = true
|
2016-03-04 00:58:03 +08:00
|
|
|
enrollment = @course.enroll_user(user,
|
|
|
|
@enrollment_type,
|
|
|
|
section: @section,
|
|
|
|
limit_privileges_to_course_section: @limit_privileges_to_course_section,
|
|
|
|
allow_multiple_enrollments: true,
|
|
|
|
role: @role,
|
|
|
|
skip_touch_user: true)
|
|
|
|
if enrollment
|
|
|
|
@enrollments << enrollment
|
|
|
|
if enrollment.need_touch_user
|
|
|
|
@user_ids_to_touch << enrollment.user_id
|
|
|
|
@user_ids_to_touch << enrollment.associated_user_id if enrollment.associated_user_id
|
|
|
|
end
|
2011-07-02 07:36:41 +08:00
|
|
|
end
|
|
|
|
end
|
2011-02-01 09:57:29 +08:00
|
|
|
end
|