app/services/course/user_invitation_service.rb
# frozen_string_literal: true
# Provides a service object for inviting users into a course.
class Course::UserInvitationService
include ParseInvitationConcern
include ProcessInvitationConcern
include EmailInvitationConcern
# Constructor for the user invitation service object.
#
# @param [CourseUser|nil] current_course_user The course user performing this action.
# @param [User] current_user The user performing this action.
# @param [Course] current_course The user performing this action for which course.
def initialize(current_course_user, current_user, current_course)
@current_course_user = current_course_user
@current_user = current_user
@current_course = current_course
@current_instance = current_course.instance
end
# Invites users to the given course.
#
# The result of the transaction is both saving the course as well as validating validity
# because Rails does not handle duplicate nested attribute uniqueness constraints.
#
# @param [Array<Hash>|File|TempFile] users Invites the given users.
# @return [Array<Integer>|nil] An array containing the the size of new_invitations, existing_invitations,
# new_course_users and existing_course_users, duplicate_users respectively if success. nil when fail.
# @raise [CSV::MalformedCSVError] When the file provided is invalid.
def invite(users)
new_invitations = nil
existing_invitations = nil
new_course_users = nil
existing_course_users = nil
duplicate_users = nil
success = Course.transaction do
new_invitations, existing_invitations,
new_course_users, existing_course_users, duplicate_users = invite_users(users)
raise ActiveRecord::Rollback unless new_invitations.all?(&:save)
raise ActiveRecord::Rollback unless new_course_users.all?(&:save)
true
end
send_registered_emails(new_course_users) if success
send_invitation_emails(new_invitations) if success
success ? [new_invitations, existing_invitations, new_course_users, existing_course_users, duplicate_users] : nil
end
# Resends invitation emails to CourseUsers to the given course.
# This method disregards CourseUsers that do not have an 'invited' status.
#
# @param [Array<Course::UserInvitation>] invitations An array of invitations to be resent.
# @return [Boolean] True if there were no errors in sending invitations.
# If all provided CourseUsers have already registered, method also returns true.
def resend_invitation(invitations)
invitations.blank? ? true : send_invitation_emails(invitations)
end
private
# Invites the given users into the course.
#
# @param [Array<Hash>|File|TempFile] users Invites the given users.
# @return
# [
# Array<(Array<Course::UserInvitation>,
# Array<Course::UserInvitation>,
# Array<CourseUser>,
# Array<CourseUser>)>,
# Array<Hash>,
# ]
# A tuple containing the users newly invited, already invited,
# newly registered and already registered, and duplicate users respectively.
# @raise [CSV::MalformedCSVError] When the file provided is invalid.
def invite_users(users)
users, duplicate_users = parse_invitations(users)
process_invitations(users) + [duplicate_users]
end
end