예제 #1
0
def _change_access(course, user, level, action, send_email=True):
    """
    Change access of user.

    `level` is one of ['instructor', 'staff', 'beta']
    action is one of ['allow', 'revoke']

    NOTE: will create a group if it does not yet exist.
    """

    try:
        role = ROLES[level](course.id)
    except KeyError:
        raise ValueError("unrecognized level '{}'".format(level))

    if action == 'allow':
        if level == 'ccx_coach':
            email_params = get_email_params(course, True)
            enroll_email(
                course_id=course.id,
                student_email=user.email,
                auto_enroll=True,
                email_students=send_email,
                email_params=email_params,
            )
        role.add_users(user)
    elif action == 'revoke':
        role.remove_users(user)
    else:
        raise ValueError("unrecognized action '{}'".format(action))
예제 #2
0
    def make_ccx(self, max_students_allowed=200):
        """
        Overridden method to replicate (part of) the actual
        creation of ccx courses
        """
        ccx = super().make_ccx(max_students_allowed=max_students_allowed)
        ccx.structure_json = json.dumps(self.master_course_chapters)
        ccx.save()

        override_field_for_ccx(ccx, self.course, 'start', now())
        override_field_for_ccx(ccx, self.course, 'due', None)
        # Hide anything that can show up in the schedule
        hidden = 'visible_to_staff_only'
        for chapter in self.course.get_children():
            override_field_for_ccx(ccx, chapter, hidden, True)
            for sequential in chapter.get_children():
                override_field_for_ccx(ccx, sequential, hidden, True)
                for vertical in sequential.get_children():
                    override_field_for_ccx(ccx, vertical, hidden, True)
        # enroll the coach in the CCX
        ccx_course_key = CCXLocator.from_course_locator(self.course.id, ccx.id)
        email_params = get_email_params(
            self.course,
            auto_enroll=True,
            course_key=ccx_course_key,
            display_name=ccx.display_name
        )
        enroll_email(
            course_id=ccx_course_key,
            student_email=self.coach.email,
            auto_enroll=True,
            email_students=False,
            email_params=email_params,
        )
        return ccx
예제 #3
0
def _change_access(course, user, level, action, send_email=True):
    """
    Change access of user.

    `level` is one of ['instructor', 'staff', 'beta']
    action is one of ['allow', 'revoke']

    NOTE: will create a group if it does not yet exist.
    """

    try:
        role = ROLES[level](course.id)
    except KeyError:
        raise ValueError(u"unrecognized level '{}'".format(level))

    if action == 'allow':
        if level == 'ccx_coach':
            email_params = get_email_params(course, True)
            enroll_email(
                course_id=course.id,
                student_email=user.email,
                auto_enroll=True,
                email_students=send_email,
                email_params=email_params,
            )
        role.add_users(user)
    elif action == 'revoke':
        role.remove_users(user)
    else:
        raise ValueError(u"unrecognized action '{}'".format(action))
예제 #4
0
    def test_enroll_inactive_user(self, auto_enroll):
        before_ideal = SettableEnrollmentState(
            user=True,
            enrollment=False,
            allowed=False,
            auto_enroll=False,
        )
        print("checking initialization...")
        eobjs = before_ideal.create_user(self.course_key, is_active=False)
        before = EmailEnrollmentState(self.course_key, eobjs.email)
        self.assertEqual(before, before_ideal)

        print('running action...')
        enroll_email(self.course_key, eobjs.email, auto_enroll=auto_enroll)

        print('checking effects...')

        after_ideal = SettableEnrollmentState(
            user=True,
            enrollment=False,
            allowed=True,
            auto_enroll=auto_enroll,
        )
        after = EmailEnrollmentState(self.course_key, eobjs.email)
        self.assertEqual(after, after_ideal)
예제 #5
0
    def test_enroll_inactive_user_again(self, auto_enroll):
        course_key = CourseLocator('Robot', 'fAKE', 'C--se--ID')
        before_ideal = SettableEnrollmentState(
            user=True,
            enrollment=False,
            allowed=True,
            auto_enroll=auto_enroll,
        )
        print("checking initialization...")
        user = UserFactory()
        user.is_active = False
        user.save()
        eobjs = EnrollmentObjects(
            user.email, None, None,
            CourseEnrollmentAllowed.objects.create(email=user.email,
                                                   course_id=course_key,
                                                   auto_enroll=auto_enroll))
        before = EmailEnrollmentState(course_key, eobjs.email)
        self.assertEqual(before, before_ideal)

        print('running action...')
        enroll_email(self.course_key, eobjs.email, auto_enroll=auto_enroll)

        print('checking effects...')

        after_ideal = SettableEnrollmentState(
            user=True,
            enrollment=False,
            allowed=True,
            auto_enroll=auto_enroll,
        )
        after = EmailEnrollmentState(self.course_key, eobjs.email)
        self.assertEqual(after, after_ideal)
예제 #6
0
def auto_enroll_email(course_id, email, send_email=True):
    """
    Auto-enroll email in course.

    Based on lms.djangoapps.instructor.views.api.students_update_enrollment()
    """
    # Raises ValidationError if invalid
    validate_email(email)

    locator = CourseLocator.from_string(course_id)
    course = get_course_by_id(locator)

    # If we want to notify the newly enrolled student by email, fetch
    # the required parameters
    email_params = None
    language = None
    if send_email:
        email_params = get_email_params(course, True, secure=True)

        # Try to find out what language to send the email in.
        user = None
        try:
            user = User.objects.get(email=email)
        except User.DoesNotExist:
            pass
        else:
            language = get_user_email_language(user)

    # Enroll the email
    enroll_email(locator,
                 email,
                 auto_enroll=True,
                 email_students=send_email,
                 email_params=email_params,
                 language=language)
예제 #7
0
    def put(self, request, course_id):
        """
        Enroll a user in a course; requires staff access

        **Example Request**
            PUT /api/enrollment/v1/roster/course-v1:foo+bar+foobar
            {
                'email': '*****@*****.**',
                'email_students': false,
                'auto_enroll': true
            }
        """
        try:
            course_key = CourseKey.from_string(course_id)
        except InvalidKeyError:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    'message': u'Invalid or missing course_id',
                },
            )
        if not user_has_role(request.user, CourseStaffRole(course_key)):
            return Response(
                status=status.HTTP_403_FORBIDDEN,
                data={
                    'message':
                    u'User does not have permission to update enrollment for [{course_id}].'
                    .format(course_id=course_id, ),
                },
            )
        email = request.data.get('email')
        try:
            validate_email(email)
        except ValidationError:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    'message': u'Invalid email address',
                },
            )
        email_students = request.data.get('email_students',
                                          False) in ['true', 'True', True]
        auto_enroll = request.data.get('auto_enroll',
                                       False) in ['true', 'True', True]
        email_params = {}
        language = None
        if email_students:
            course = get_course_by_id(course_key)
            email_params = get_email_params(course, auto_enroll)
            if User.objects.filter(email=email).exists():
                user = User.objects.get(email=email)
                language = get_user_email_language(user)
        enroll_email(course_key,
                     email,
                     auto_enroll,
                     email_students,
                     email_params,
                     language=language)
        return Response(status=status.HTTP_204_NO_CONTENT)
예제 #8
0
def ccx_students_enrolling_center(action, identifiers, email_students, course_key, email_params, coach):
    """
    Function to enroll/add or unenroll/revoke students.

    This function exists for backwards compatibility: in CCX there are
    two different views to manage students that used to implement
    a different logic. Now the logic has been reconciled at the point that
    this function can be used by both.
    The two different views can be merged after some UI refactoring.

    Arguments:
        action (str): type of action to perform (add, Enroll, revoke, Unenroll)
        identifiers (list): list of students username/email
        email_students (bool): Flag to send an email to students
        course_key (CCXLocator): a CCX course key
        email_params (dict): dictionary of settings for the email to be sent
        coach (User): ccx coach

    Returns:
        list: list of error
    """
    errors = []

    if action == 'Enroll' or action == 'add':
        ccx_course_overview = CourseOverview.get_from_id(course_key)
        course_locator = course_key.to_course_locator()
        staff = CourseStaffRole(course_locator).users_with_role()
        admins = CourseInstructorRole(course_locator).users_with_role()

        for identifier in identifiers:
            must_enroll = False
            try:
                email, student = get_valid_student_with_email(identifier)
                if student:
                    must_enroll = student in staff or student in admins or student == coach
            except CCXUserValidationException as exp:
                log.info("%s", exp)
                errors.append("{0}".format(exp))
                continue

            if CourseEnrollment.objects.is_course_full(ccx_course_overview) and not must_enroll:
                error = _('The course is full: the limit is {max_student_enrollments_allowed}').format(
                    max_student_enrollments_allowed=ccx_course_overview.max_student_enrollments_allowed)
                log.info("%s", error)
                errors.append(error)
                break
            enroll_email(course_key, email, auto_enroll=True, email_students=email_students, email_params=email_params)
    elif action == 'Unenroll' or action == 'revoke':
        for identifier in identifiers:
            try:
                email, __ = get_valid_student_with_email(identifier)
            except CCXUserValidationException as exp:
                log.info("%s", exp)
                errors.append("{0}".format(exp))
                continue
            unenroll_email(course_key, email, email_students=email_students, email_params=email_params)
    return errors
예제 #9
0
def ccx_students_enrolling_center(action, identifiers, email_students, course_key, email_params, coach):
    """
    Function to enroll or unenroll/revoke students.

    Arguments:
        action (str): type of action to perform (Enroll, Unenroll/revoke)
        identifiers (list): list of students username/email
        email_students (bool): Flag to send an email to students
        course_key (CCXLocator): a CCX course key
        email_params (dict): dictionary of settings for the email to be sent
        coach (User): ccx coach

    Returns:
        list: list of error
    """
    errors = []

    if action == 'Enroll':
        ccx_course_overview = CourseOverview.get_from_id(course_key)
        course_locator = course_key.to_course_locator()
        staff = CourseStaffRole(course_locator).users_with_role()
        admins = CourseInstructorRole(course_locator).users_with_role()

        for identifier in identifiers:
            must_enroll = False
            try:
                email, student = get_valid_student_with_email(identifier)
                if student:
                    must_enroll = student in staff or student in admins or student == coach
            except CCXUserValidationException as exp:
                log.info("%s", exp)
                errors.append("{0}".format(exp))
                continue

            if CourseEnrollment.objects.is_course_full(ccx_course_overview) and not must_enroll:
                error = _('The course is full: the limit is {max_student_enrollments_allowed}').format(
                    max_student_enrollments_allowed=ccx_course_overview.max_student_enrollments_allowed)
                log.info("%s", error)
                errors.append(error)
                break
            enroll_email(course_key, email, auto_enroll=True, email_students=email_students, email_params=email_params)
    elif action == 'Unenroll' or action == 'revoke':
        for identifier in identifiers:
            try:
                email, __ = get_valid_student_with_email(identifier)
            except CCXUserValidationException as exp:
                log.info("%s", exp)
                errors.append("{0}".format(exp))
                continue
            unenroll_email(course_key, email, email_students=email_students, email_params=email_params)
    return errors
예제 #10
0
    def put(self, request, course_id):
        """
        Enroll a user in a course; requires staff access

        **Example Request**
            PUT /api/enrollment/v1/roster/course-v1:foo+bar+foobar
            {
                'email': '*****@*****.**',
                'email_students': false,
                'auto_enroll': true
            }
        """
        try:
            course_key = CourseKey.from_string(course_id)
        except InvalidKeyError:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    'message': u'Invalid or missing course_id',
                },
            )
        if not user_has_role(request.user, CourseStaffRole(course_key)):
            return Response(
                status=status.HTTP_403_FORBIDDEN,
                data={
                    'message': u'User does not have permission to update enrollment for [{course_id}].'.format(
                        course_id=course_id,
                    ),
                },
            )
        email = request.data.get('email')
        try:
            validate_email(email)
        except ValidationError:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    'message': u'Invalid email address',
                },
            )

        email_students, auto_enroll, email_params, language = self.api_params_helper(request, course_key, email)
        enroll_email(
            course_key, email, auto_enroll, email_students, email_params, language=language
        )
        return Response(status=status.HTTP_204_NO_CONTENT)
예제 #11
0
    def test_enroll(self):
        before_ideal = SettableEnrollmentState(user=True,
                                               enrollment=False,
                                               allowed=False,
                                               auto_enroll=False)

        after_ideal = SettableEnrollmentState(user=True,
                                              enrollment=True,
                                              allowed=False,
                                              auto_enroll=False)

        action = lambda email: enroll_email(self.course_key, email)

        return self._run_state_change_test(before_ideal, after_ideal, action)
def add_affiliate_course_enrollments(sender, instance, **kwargs):  # pylint: disable=unused-argument
    """
    Allow staff or instructor level access to affiliate member into
    all affiliate courses if they are staff or instructor member.
    """
    if not instance.role == AffiliateMembership.CCX_COACH:
        for ccx in instance.affiliate.courses:
            ccx_locator = CCXLocator.from_course_locator(ccx.course_id, ccx.id)
            course = get_course_by_id(ccx_locator)

            try:
                with transaction.atomic():
                    allow_access(course, instance.member, instance.role, False)
            except IntegrityError:
                LOG.error('IntegrityError: Allow access failed.')

    # FastTrac main course and Facilitator Guide course
    course_overviews = CourseOverview.objects.exclude(id__startswith='ccx-')

    # Program Director and Course Manager needs to be a CCX coach on FastTrac course
    if instance.role in AffiliateMembership.STAFF_ROLES:
        for course_overview in course_overviews:
            course_id = course_overview.id
            course = get_course_by_id(course_id)

            try:
                with transaction.atomic():
                    allow_access(course, instance.member, AffiliateMembership.CCX_COACH, False)
            except IntegrityError:
                LOG.error('IntegrityError: CCX coach failed.')

    elif instance.role == AffiliateMembership.CCX_COACH:
        for course_overview in course_overviews:
            course_id = course_overview.id

            enroll_email(course_id, instance.member.email, auto_enroll=True)
예제 #13
0
    def test_enroll_nouser_change_autoenroll(self):
        before_ideal = SettableEnrollmentState(
            user=False,
            enrollment=False,
            allowed=True,
            auto_enroll=True,
        )

        after_ideal = SettableEnrollmentState(
            user=False,
            enrollment=False,
            allowed=True,
            auto_enroll=False,
        )

        action = lambda email: enroll_email(self.course_key, email, auto_enroll=False)

        return self._run_state_change_test(before_ideal, after_ideal, action)
예제 #14
0
    def post(self, request, *args, **kwargs):

        course_id = request.POST.get('course_id', False)
        try:
            course_id = SlashSeparatedCourseKey.from_deprecated_string(
                course_id)
        except Exception:
            course_id = None

        if not course_id:
            self.msg = u"课程ID错误"
            context = {'msg': self.msg, 'datatable': self.make_datatable()}
            return render_to_response(self.template_name, context)
        elif not request.POST.get('identifiers'):
            self.msg = u"邮箱用户名错误"
            context = {'msg': self.msg, 'datatable': self.make_datatable()}
            return render_to_response(self.template_name, context)

        action = request.POST.get('action')
        identifiers_raw = request.POST.get('identifiers')
        identifiers = _split_input_list(identifiers_raw)
        auto_enroll = _get_boolean_param(request, 'auto_enroll')
        email_students = _get_boolean_param(request, 'email_students')
        is_white_label = CourseMode.is_white_label(course_id)
        reason = request.POST.get('reason')

        if is_white_label:
            if not reason:
                self.msg = "400"
                context = {'msg': self.msg, 'datatable': self.make_datatable()}
                return render_to_response(self.template_name, context)

        enrollment_obj = None
        state_transition = DEFAULT_TRANSITION_STATE

        email_params = {}
        if email_students:
            course = get_course_by_id(course_id)
            email_params = get_email_params(course,
                                            auto_enroll,
                                            secure=request.is_secure())

        results = []
        for identifier in identifiers:
            # First try to get a user object from the identifer
            user = None
            email = None
            language = None
            try:
                user = get_student_from_identifier(identifier)
            except User.DoesNotExist:
                email = identifier
            else:
                email = user.email
                language = get_user_email_language(user)

            try:
                # Use django.core.validators.validate_email to check email address
                # validity (obviously, cannot check if email actually /exists/,
                # simply that it is plausibly valid)
                validate_email(email)  # Raises ValidationError if invalid
                if action == 'enroll':
                    before, after, enrollment_obj = enroll_email(
                        course_id,
                        email,
                        auto_enroll,
                        email_students,
                        email_params,
                        language=language)
                    before_enrollment = before.to_dict()['enrollment']
                    before_user_registered = before.to_dict()['user']
                    before_allowed = before.to_dict()['allowed']
                    after_enrollment = after.to_dict()['enrollment']
                    after_allowed = after.to_dict()['allowed']

                    if before_user_registered:
                        if after_enrollment:
                            if before_enrollment:
                                state_transition = ENROLLED_TO_ENROLLED
                            else:
                                if before_allowed:
                                    state_transition = ALLOWEDTOENROLL_TO_ENROLLED
                                else:
                                    state_transition = UNENROLLED_TO_ENROLLED
                    else:
                        if after_allowed:
                            state_transition = UNENROLLED_TO_ALLOWEDTOENROLL

                elif action == 'unenroll':
                    before, after = unenroll_email(course_id,
                                                   email,
                                                   email_students,
                                                   email_params,
                                                   language=language)
                    before_enrollment = before.to_dict()['enrollment']
                    before_allowed = before.to_dict()['allowed']
                    enrollment_obj = CourseEnrollment.get_enrollment(
                        user, course_id)

                    if before_enrollment:
                        state_transition = ENROLLED_TO_UNENROLLED
                    else:
                        if before_allowed:
                            state_transition = ALLOWEDTOENROLL_TO_UNENROLLED
                        else:
                            state_transition = UNENROLLED_TO_UNENROLLED

                else:
                    return HttpResponseBadRequest(
                        strip_tags("Unrecognized action '{}'".format(action)))

            except ValidationError:
                # Flag this email as an error if invalid, but continue checking
                # the remaining in the list
                results.append({
                    'identifier': identifier,
                    'invalidIdentifier': True,
                })

            except Exception as exc:  # pylint: disable=broad-except
                # catch and log any exceptions
                # so that one error doesn't cause a 500.
                log.exception(u"Error while #{}ing student")
                log.exception(exc)
                results.append({
                    'identifier': identifier,
                    'error': True,
                })

            else:
                ManualEnrollmentAudit.create_manual_enrollment_audit(
                    request.user, email, state_transition, reason,
                    enrollment_obj)
                results.append({
                    'identifier': identifier,
                    'before': before.to_dict(),
                    'after': after.to_dict(),
                })

        invalid_id = []
        valid_id = []

        for result in results:
            if ('error' in result) or ('invalidIdentifier' in result):
                invalid_id.append(result['identifier'])
            else:
                valid_id.append(result['identifier'])

        invalid_message = [
            "{} 无效 <br>".format(i.encode('utf-8')) for i in invalid_id
        ]
        valid_message = []

        action = "选课" if action == "enroll" else "弃选"

        for i in valid_id:
            if action == "弃选":
                valid_message.append("{0}  {1} 成功 <br>".format(i, action))
                continue
            if email_students:
                valid_message.append("{0}  {1} 成功,并向他发送电子邮件 <br>".format(
                    i, action))
            else:
                valid_message.append("{0}  {1} 成功<br>".format(i, action))
        invalid_message.extend(valid_message)

        self.msg = "".join(invalid_message)

        context = {'msg': self.msg, 'datatable': self.make_datatable()}
        return render_to_response(self.template_name, context)
def create_ccx(request, course, ccx=None):
    """
    Create a new CCX
    """
    name = request.POST.get('name')

    if hasattr(course, 'ccx_connector') and course.ccx_connector:
        # if ccx connector url is set in course settings then inform user that he can
        # only create ccx by using ccx connector url.
        context = get_ccx_creation_dict(course)
        messages.error(request, context['use_ccx_con_error_message'])
        return render_to_response('ccx/coach_dashboard.html', context)

    # prevent CCX objects from being created for deprecated course ids.
    if course.id.deprecated:
        messages.error(
            request,
            _("You cannot create a CCX from a course using a deprecated id. "
              "Please create a rerun of this course in the studio to allow "
              "this action."))
        url = reverse('ccx_coach_dashboard', kwargs={'course_id': course.id})
        return redirect(url)

    ccx = CustomCourseForEdX(course_id=course.id,
                             coach=request.user,
                             display_name=name)
    ccx.save()

    # Make sure start/due are overridden for entire course
    start = TODAY().replace(tzinfo=pytz.UTC)
    override_field_for_ccx(ccx, course, 'start', start)
    override_field_for_ccx(ccx, course, 'due', None)

    # Enforce a static limit for the maximum amount of students that can be enrolled
    override_field_for_ccx(ccx, course, 'max_student_enrollments_allowed',
                           settings.CCX_MAX_STUDENTS_ALLOWED)
    # Save display name explicitly
    override_field_for_ccx(ccx, course, 'display_name', name)

    # Hide anything that can show up in the schedule
    hidden = 'visible_to_staff_only'
    for chapter in course.get_children():
        override_field_for_ccx(ccx, chapter, hidden, True)
        for sequential in chapter.get_children():
            override_field_for_ccx(ccx, sequential, hidden, True)
            for vertical in sequential.get_children():
                override_field_for_ccx(ccx, vertical, hidden, True)

    ccx_id = CCXLocator.from_course_locator(course.id, str(ccx.id))

    # Create forum roles
    seed_permissions_roles(ccx_id)
    # Assign administrator forum role to CCX coach
    assign_role(ccx_id, request.user, FORUM_ROLE_ADMINISTRATOR)

    url = reverse('ccx_coach_dashboard', kwargs={'course_id': ccx_id})

    # Enroll the coach in the course
    email_params = get_email_params(course,
                                    auto_enroll=True,
                                    course_key=ccx_id,
                                    display_name=ccx.display_name)
    enroll_email(
        course_id=ccx_id,
        student_email=request.user.email,
        auto_enroll=True,
        email_students=True,
        email_params=email_params,
    )

    assign_staff_role_to_ccx(ccx_id, request.user, course.id)
    add_master_course_staff_to_ccx(course, ccx_id, ccx.display_name)

    # using CCX object as sender here.
    responses = SignalHandler.course_published.send(
        sender=ccx,
        course_key=CCXLocator.from_course_locator(course.id, str(ccx.id)))
    for rec, response in responses:
        log.info(
            'Signal fired when course is published. Receiver: %s. Response: %s',
            rec, response)

    return redirect(url)
예제 #16
0
def create_ccx(request, course, ccx=None):
    """
    Create a new CCX
    """
    name = request.POST.get('name')

    if hasattr(course, 'ccx_connector') and course.ccx_connector:
        # if ccx connector url is set in course settings then inform user that he can
        # only create ccx by using ccx connector url.
        context = get_ccx_creation_dict(course)
        messages.error(request, context['use_ccx_con_error_message'])
        return render_to_response('ccx/coach_dashboard.html', context)

    # prevent CCX objects from being created for deprecated course ids.
    if course.id.deprecated:
        messages.error(request, _(
            "You cannot create a CCX from a course using a deprecated id. "
            "Please create a rerun of this course in the studio to allow "
            "this action."))
        url = reverse('ccx_coach_dashboard', kwargs={'course_id': course.id})
        return redirect(url)

    ccx = CustomCourseForEdX(
        course_id=course.id,
        coach=request.user,
        display_name=name)
    ccx.save()

    # Make sure start/due are overridden for entire course
    start = TODAY().replace(tzinfo=pytz.UTC)
    override_field_for_ccx(ccx, course, 'start', start)
    override_field_for_ccx(ccx, course, 'due', None)

    # Enforce a static limit for the maximum amount of students that can be enrolled
    override_field_for_ccx(ccx, course, 'max_student_enrollments_allowed', settings.CCX_MAX_STUDENTS_ALLOWED)

    # Hide anything that can show up in the schedule
    hidden = 'visible_to_staff_only'
    for chapter in course.get_children():
        override_field_for_ccx(ccx, chapter, hidden, True)
        for sequential in chapter.get_children():
            override_field_for_ccx(ccx, sequential, hidden, True)
            for vertical in sequential.get_children():
                override_field_for_ccx(ccx, vertical, hidden, True)

    ccx_id = CCXLocator.from_course_locator(course.id, unicode(ccx.id))

    # Create forum roles
    seed_permissions_roles(ccx_id)
    # Assign administrator forum role to CCX coach
    assign_role(ccx_id, request.user, FORUM_ROLE_ADMINISTRATOR)

    url = reverse('ccx_coach_dashboard', kwargs={'course_id': ccx_id})

    # Enroll the coach in the course
    email_params = get_email_params(course, auto_enroll=True, course_key=ccx_id, display_name=ccx.display_name)
    enroll_email(
        course_id=ccx_id,
        student_email=request.user.email,
        auto_enroll=True,
        email_students=True,
        email_params=email_params,
    )

    assign_staff_role_to_ccx(ccx_id, request.user, course.id)
    add_master_course_staff_to_ccx(course, ccx_id, ccx.display_name)

    # using CCX object as sender here.
    responses = SignalHandler.course_published.send(
        sender=ccx,
        course_key=CCXLocator.from_course_locator(course.id, unicode(ccx.id))
    )
    for rec, response in responses:
        log.info('Signal fired when course is published. Receiver: %s. Response: %s', rec, response)

    return redirect(url)
예제 #17
0
    def patch(self, request, ccx_course_id=None):
        """
        Modifies a CCX course.

        Args:
            request (Request): Django request object.
            ccx_course_id (string): URI element specifying the CCX course location.
        """
        ccx_course_object, ccx_course_key, error_code, http_status = self.get_object(
            ccx_course_id, is_ccx=True)
        if ccx_course_object is None:
            return Response(status=http_status,
                            data={'error_code': error_code})

        master_course_id = request.data.get('master_course_id')
        if master_course_id is not None and str(
                ccx_course_object.course_id) != master_course_id:
            return Response(
                status=status.HTTP_403_FORBIDDEN,
                data={'error_code': 'master_course_id_change_not_allowed'})

        valid_input, field_errors = get_valid_input(request.data,
                                                    ignore_missing=True)
        if field_errors:
            return Response(status=status.HTTP_400_BAD_REQUEST,
                            data={'field_errors': field_errors})

        # get the master course key and master course object
        master_course_object, master_course_key, _, _ = get_valid_course(
            str(ccx_course_object.course_id))

        with transaction.atomic():
            # update the display name
            if 'display_name' in valid_input:
                ccx_course_object.display_name = valid_input['display_name']
            # check if the coach has changed and in case update it
            old_coach = None
            if 'coach_email' in valid_input:
                try:
                    coach = User.objects.get(email=valid_input['coach_email'])
                except User.DoesNotExist:
                    return Response(
                        status=status.HTTP_404_NOT_FOUND,
                        data={'error_code': 'coach_user_does_not_exist'})
                if ccx_course_object.coach.id != coach.id:
                    old_coach = ccx_course_object.coach
                    ccx_course_object.coach = coach
            if 'course_modules' in valid_input:
                if valid_input.get('course_modules'):
                    if not valid_course_modules(valid_input['course_modules'],
                                                master_course_key):
                        return Response(
                            status=status.HTTP_400_BAD_REQUEST,
                            data={
                                'error_code':
                                'course_module_list_not_belonging_to_master_course'
                            })
                # course_modules to be stored in a json stringified field
                ccx_course_object.structure_json = json.dumps(
                    valid_input.get('course_modules'))
            ccx_course_object.save()
            # update the overridden field for the maximum amount of students
            if 'max_students_allowed' in valid_input:
                override_field_for_ccx(ccx_course_object,
                                       ccx_course_object.course,
                                       'max_student_enrollments_allowed',
                                       valid_input['max_students_allowed'])
            # if the coach has changed, update the permissions
            if old_coach is not None:
                # make the new ccx coach a coach on the master course
                make_user_coach(coach, master_course_key)
                # enroll the coach in the ccx
                email_params = get_email_params(
                    master_course_object,
                    auto_enroll=True,
                    course_key=ccx_course_key,
                    display_name=ccx_course_object.display_name)
                enroll_email(
                    course_id=ccx_course_key,
                    student_email=coach.email,
                    auto_enroll=True,
                    email_students=True,
                    email_params=email_params,
                )
                # make the new coach staff on the CCX
                assign_staff_role_to_ccx(ccx_course_key, coach,
                                         master_course_object.id)

        # using CCX object as sender here.
        responses = SignalHandler.course_published.send(
            sender=ccx_course_object, course_key=ccx_course_key)
        for rec, response in responses:
            log.info(
                'Signal fired when course is published. Receiver: %s. Response: %s',
                rec, response)

        return Response(status=status.HTTP_204_NO_CONTENT, )
예제 #18
0
    def post(self, request):
        """
        Creates a new CCX course for a given Master Course.

        Args:
            request (Request): Django request object.

        Return:
            A JSON serialized representation a newly created CCX course.
        """
        master_course_id = request.data.get('master_course_id')
        master_course_object, master_course_key, error_code, http_status = get_valid_course(
            master_course_id, advanced_course_check=True)
        if master_course_object is None:
            return Response(status=http_status,
                            data={'error_code': error_code})

        # validating the rest of the input
        valid_input, field_errors = get_valid_input(request.data)
        if field_errors:
            return Response(status=status.HTTP_400_BAD_REQUEST,
                            data={'field_errors': field_errors})

        try:
            # Retired users should effectively appear to not exist when
            # attempts are made to modify them, so a direct User model email
            # lookup is sufficient here.  This corner case relies on the fact
            # that we scramble emails immediately during user lock-out.  Of
            # course, the normal cases are that the email just never existed,
            # or it is currently associated with an active account.
            coach = User.objects.get(email=valid_input['coach_email'])
        except User.DoesNotExist:
            return Response(status=status.HTTP_404_NOT_FOUND,
                            data={'error_code': 'coach_user_does_not_exist'})

        if valid_input.get('course_modules'):
            if not valid_course_modules(valid_input['course_modules'],
                                        master_course_key):
                return Response(
                    status=status.HTTP_400_BAD_REQUEST,
                    data={
                        'error_code':
                        'course_module_list_not_belonging_to_master_course'
                    })
        # prepare the course_modules to be stored in a json stringified field
        course_modules_json = json.dumps(valid_input.get('course_modules'))

        with transaction.atomic():
            ccx_course_object = CustomCourseForEdX(
                course_id=master_course_object.id,
                coach=coach,
                display_name=valid_input['display_name'],
                structure_json=course_modules_json)
            ccx_course_object.save()

            # Make sure start/due are overridden for entire course
            start = TODAY().replace(tzinfo=pytz.UTC)
            override_field_for_ccx(ccx_course_object, master_course_object,
                                   'start', start)
            override_field_for_ccx(ccx_course_object, master_course_object,
                                   'due', None)

            # Enforce a static limit for the maximum amount of students that can be enrolled
            override_field_for_ccx(ccx_course_object, master_course_object,
                                   'max_student_enrollments_allowed',
                                   valid_input['max_students_allowed'])

            # Hide anything that can show up in the schedule
            hidden = 'visible_to_staff_only'
            for chapter in master_course_object.get_children():
                override_field_for_ccx(ccx_course_object, chapter, hidden,
                                       True)
                for sequential in chapter.get_children():
                    override_field_for_ccx(ccx_course_object, sequential,
                                           hidden, True)
                    for vertical in sequential.get_children():
                        override_field_for_ccx(ccx_course_object, vertical,
                                               hidden, True)

            # make the coach user a coach on the master course
            make_user_coach(coach, master_course_key)

            # pull the ccx course key
            ccx_course_key = CCXLocator.from_course_locator(
                master_course_object.id, str(ccx_course_object.id))
            # enroll the coach in the newly created ccx
            email_params = get_email_params(
                master_course_object,
                auto_enroll=True,
                course_key=ccx_course_key,
                display_name=ccx_course_object.display_name)
            enroll_email(
                course_id=ccx_course_key,
                student_email=coach.email,
                auto_enroll=True,
                email_students=True,
                email_params=email_params,
            )
            # assign staff role for the coach to the newly created ccx
            assign_staff_role_to_ccx(ccx_course_key, coach,
                                     master_course_object.id)
            # assign staff role for all the staff and instructor of the master course to the newly created ccx
            add_master_course_staff_to_ccx(master_course_object,
                                           ccx_course_key,
                                           ccx_course_object.display_name,
                                           send_email=False)

        serializer = self.get_serializer(ccx_course_object)

        # using CCX object as sender here.
        responses = SignalHandler.course_published.send(
            sender=ccx_course_object, course_key=ccx_course_key)
        for rec, response in responses:
            log.info(
                'Signal fired when course is published. Receiver: %s. Response: %s',
                rec, response)
        return Response(status=status.HTTP_201_CREATED, data=serializer.data)
예제 #19
0
    def patch(self, request, ccx_course_id=None):
        """
        Modifies a CCX course.

        Args:
            request (Request): Django request object.
            ccx_course_id (string): URI element specifying the CCX course location.
        """
        ccx_course_object, ccx_course_key, error_code, http_status = self.get_object(ccx_course_id, is_ccx=True)
        if ccx_course_object is None:
            return Response(
                status=http_status,
                data={
                    'error_code': error_code
                }
            )

        master_course_id = request.data.get('master_course_id')
        if master_course_id is not None and unicode(ccx_course_object.course_id) != master_course_id:
            return Response(
                status=status.HTTP_403_FORBIDDEN,
                data={
                    'error_code': 'master_course_id_change_not_allowed'
                }
            )

        valid_input, field_errors = get_valid_input(request.data, ignore_missing=True)
        if field_errors:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    'field_errors': field_errors
                }
            )

        # get the master course key and master course object
        master_course_object, master_course_key, _, _ = get_valid_course(unicode(ccx_course_object.course_id))

        with transaction.atomic():
            # update the display name
            if 'display_name' in valid_input:
                ccx_course_object.display_name = valid_input['display_name']
            # check if the coach has changed and in case update it
            old_coach = None
            if 'coach_email' in valid_input:
                try:
                    coach = User.objects.get(email=valid_input['coach_email'])
                except User.DoesNotExist:
                    return Response(
                        status=status.HTTP_404_NOT_FOUND,
                        data={
                            'error_code': 'coach_user_does_not_exist'
                        }
                    )
                if ccx_course_object.coach.id != coach.id:
                    old_coach = ccx_course_object.coach
                    ccx_course_object.coach = coach
            if 'course_modules' in valid_input:
                if valid_input.get('course_modules'):
                    if not valid_course_modules(valid_input['course_modules'], master_course_key):
                        return Response(
                            status=status.HTTP_400_BAD_REQUEST,
                            data={
                                'error_code': 'course_module_list_not_belonging_to_master_course'
                            }
                        )
                # course_modules to be stored in a json stringified field
                ccx_course_object.structure_json = json.dumps(valid_input.get('course_modules'))
            ccx_course_object.save()
            # update the overridden field for the maximum amount of students
            if 'max_students_allowed' in valid_input:
                override_field_for_ccx(
                    ccx_course_object,
                    ccx_course_object.course,
                    'max_student_enrollments_allowed',
                    valid_input['max_students_allowed']
                )
            # if the coach has changed, update the permissions
            if old_coach is not None:
                # make the new ccx coach a coach on the master course
                make_user_coach(coach, master_course_key)
                # enroll the coach in the ccx
                email_params = get_email_params(
                    master_course_object,
                    auto_enroll=True,
                    course_key=ccx_course_key,
                    display_name=ccx_course_object.display_name
                )
                enroll_email(
                    course_id=ccx_course_key,
                    student_email=coach.email,
                    auto_enroll=True,
                    email_students=True,
                    email_params=email_params,
                )
                # make the new coach staff on the CCX
                assign_staff_role_to_ccx(ccx_course_key, coach, master_course_object.id)

        # using CCX object as sender here.
        responses = SignalHandler.course_published.send(
            sender=ccx_course_object,
            course_key=ccx_course_key
        )
        for rec, response in responses:
            log.info('Signal fired when course is published. Receiver: %s. Response: %s', rec, response)

        return Response(
            status=status.HTTP_204_NO_CONTENT,
        )
예제 #20
0
    def post(self, request):
        """
        Creates a new CCX course for a given Master Course.

        Args:
            request (Request): Django request object.

        Return:
            A JSON serialized representation a newly created CCX course.
        """
        master_course_id = request.data.get('master_course_id')
        master_course_object, master_course_key, error_code, http_status = get_valid_course(
            master_course_id,
            advanced_course_check=True
        )
        if master_course_object is None:
            return Response(
                status=http_status,
                data={
                    'error_code': error_code
                }
            )

        # validating the rest of the input
        valid_input, field_errors = get_valid_input(request.data)
        if field_errors:
            return Response(
                status=status.HTTP_400_BAD_REQUEST,
                data={
                    'field_errors': field_errors
                }
            )

        try:
            # Retired users should effectively appear to not exist when
            # attempts are made to modify them, so a direct User model email
            # lookup is sufficient here.  This corner case relies on the fact
            # that we scramble emails immediately during user lock-out.  Of
            # course, the normal cases are that the email just never existed,
            # or it is currently associated with an active account.
            coach = User.objects.get(email=valid_input['coach_email'])
        except User.DoesNotExist:
            return Response(
                status=status.HTTP_404_NOT_FOUND,
                data={
                    'error_code': 'coach_user_does_not_exist'
                }
            )

        if valid_input.get('course_modules'):
            if not valid_course_modules(valid_input['course_modules'], master_course_key):
                return Response(
                    status=status.HTTP_400_BAD_REQUEST,
                    data={
                        'error_code': 'course_module_list_not_belonging_to_master_course'
                    }
                )
        # prepare the course_modules to be stored in a json stringified field
        course_modules_json = json.dumps(valid_input.get('course_modules'))

        with transaction.atomic():
            ccx_course_object = CustomCourseForEdX(
                course_id=master_course_object.id,
                coach=coach,
                display_name=valid_input['display_name'],
                structure_json=course_modules_json
            )
            ccx_course_object.save()

            # Make sure start/due are overridden for entire course
            start = TODAY().replace(tzinfo=pytz.UTC)
            override_field_for_ccx(ccx_course_object, master_course_object, 'start', start)
            override_field_for_ccx(ccx_course_object, master_course_object, 'due', None)

            # Enforce a static limit for the maximum amount of students that can be enrolled
            override_field_for_ccx(
                ccx_course_object,
                master_course_object,
                'max_student_enrollments_allowed',
                valid_input['max_students_allowed']
            )

            # Hide anything that can show up in the schedule
            hidden = 'visible_to_staff_only'
            for chapter in master_course_object.get_children():
                override_field_for_ccx(ccx_course_object, chapter, hidden, True)
                for sequential in chapter.get_children():
                    override_field_for_ccx(ccx_course_object, sequential, hidden, True)
                    for vertical in sequential.get_children():
                        override_field_for_ccx(ccx_course_object, vertical, hidden, True)

            # make the coach user a coach on the master course
            make_user_coach(coach, master_course_key)

            # pull the ccx course key
            ccx_course_key = CCXLocator.from_course_locator(master_course_object.id, unicode(ccx_course_object.id))
            # enroll the coach in the newly created ccx
            email_params = get_email_params(
                master_course_object,
                auto_enroll=True,
                course_key=ccx_course_key,
                display_name=ccx_course_object.display_name
            )
            enroll_email(
                course_id=ccx_course_key,
                student_email=coach.email,
                auto_enroll=True,
                email_students=True,
                email_params=email_params,
            )
            # assign staff role for the coach to the newly created ccx
            assign_staff_role_to_ccx(ccx_course_key, coach, master_course_object.id)
            # assign staff role for all the staff and instructor of the master course to the newly created ccx
            add_master_course_staff_to_ccx(
                master_course_object,
                ccx_course_key,
                ccx_course_object.display_name,
                send_email=False
            )

        serializer = self.get_serializer(ccx_course_object)

        # using CCX object as sender here.
        responses = SignalHandler.course_published.send(
            sender=ccx_course_object,
            course_key=ccx_course_key
        )
        for rec, response in responses:
            log.info('Signal fired when course is published. Receiver: %s. Response: %s', rec, response)
        return Response(
            status=status.HTTP_201_CREATED,
            data=serializer.data
        )
예제 #21
0
def enroll_user_to_course(request_info, course_id, username_or_email):
    """
    Look up the given user, and if successful, enroll them to the specified course.

    Arguments:
        request_info (dict): Dict containing task request information
        course_id (str): The ID string of the course
        username_or_email: user's username or email string

    Returns:
        User object (or None if user in not registered,
        and whether the user is already enrolled or not

    """
    # First try to get a user object from the identifier (email)
    user = None
    user_already_enrolled = False
    language = None
    email_students = True
    auto_enroll = True
    thread_site = Site.objects.get(domain=request_info['host'])
    thread_author = User.objects.get(username=request_info['username'])

    try:
        user = get_student_from_identifier(username_or_email)
    except User.DoesNotExist:
        email = username_or_email
    else:
        email = user.email
        language = get_user_email_language(user)

    if user:
        course_enrollment = CourseEnrollment.get_enrollment(
            user=user, course_key=course_id)
        if course_enrollment:
            user_already_enrolled = True
            # Set the enrollment to active if its not already active
            if not course_enrollment.is_active:
                course_enrollment.update_enrollment(is_active=True)

    if not user or not user_already_enrolled:
        course = get_course_by_id(course_id, depth=0)
        try:
            with emulate_http_request(site=thread_site, user=thread_author):
                email_params = get_email_params(course, auto_enroll)
                __ = enroll_email(course_id,
                                  email,
                                  auto_enroll,
                                  email_students,
                                  email_params,
                                  language=language)
                if user:
                    TASK_LOG.info(
                        u'User %s enrolled successfully in course %s via CSV bulk enrollment',
                        username_or_email, course_id)
        except:
            TASK_LOG.exception(
                u'There was an error enrolling user %s in course %s via CSV bulk enrollment',
                username_or_email, course_id)
            return None, None

    return user, user_already_enrolled
예제 #22
0
def add_master_course_staff_to_ccx(master_course,
                                   ccx_key,
                                   display_name,
                                   send_email=True):
    """
    Add staff and instructor roles on ccx to all the staff and instructors members of master course.

    Arguments:
        master_course (CourseBlockWithMixins): Master course instance.
        ccx_key (CCXLocator): CCX course key.
        display_name (str): ccx display name for email.
        send_email (bool): flag to switch on or off email to the users on access grant.

    """
    list_staff = list_with_level(master_course.id, 'staff')
    list_instructor = list_with_level(master_course.id, 'instructor')

    with ccx_course(ccx_key) as course_ccx:
        email_params = get_email_params(course_ccx,
                                        auto_enroll=True,
                                        course_key=ccx_key,
                                        display_name=display_name)
        list_staff_ccx = list_with_level(course_ccx.id, 'staff')
        list_instructor_ccx = list_with_level(course_ccx.id, 'instructor')
        for staff in list_staff:
            # this call should be idempotent
            if staff not in list_staff_ccx:
                try:
                    # Enroll the staff in the ccx
                    enroll_email(
                        course_id=ccx_key,
                        student_email=staff.email,
                        auto_enroll=True,
                        email_students=send_email,
                        email_params=email_params,
                    )

                    # allow 'staff' access on ccx to staff of master course
                    allow_access(course_ccx, staff, 'staff')
                except CourseEnrollmentException:
                    log.warning(
                        "Unable to enroll staff %s to course with id %s",
                        staff.email, ccx_key)
                    continue
                except SMTPException:
                    continue

        for instructor in list_instructor:
            # this call should be idempotent
            if instructor not in list_instructor_ccx:
                try:
                    # Enroll the instructor in the ccx
                    enroll_email(
                        course_id=ccx_key,
                        student_email=instructor.email,
                        auto_enroll=True,
                        email_students=send_email,
                        email_params=email_params,
                    )

                    # allow 'instructor' access on ccx to instructor of master course
                    allow_access(course_ccx, instructor, 'instructor')
                except CourseEnrollmentException:
                    log.warning(
                        "Unable to enroll instructor %s to course with id %s",
                        instructor.email, ccx_key)
                    continue
                except SMTPException:
                    continue
예제 #23
0
def ccx_students_enrolling_center(action, identifiers, email_students,
                                  course_key, email_params, coach):
    """
    Function to enroll/add or unenroll/revoke students.

    This function exists for backwards compatibility: in CCX there are
    two different views to manage students that used to implement
    a different logic. Now the logic has been reconciled at the point that
    this function can be used by both.
    The two different views can be merged after some UI refactoring.

    Arguments:
        action (str): type of action to perform (add, Enroll, revoke, Unenroll)
        identifiers (list): list of students username/email
        email_students (bool): Flag to send an email to students
        course_key (CCXLocator): a CCX course key
        email_params (dict): dictionary of settings for the email to be sent
        coach (User): ccx coach

    Returns:
        list: list of error
    """
    errors = []

    if action == 'Enroll' or action == 'add':
        ccx_course_overview = CourseOverview.get_from_id(course_key)
        course_locator = course_key.to_course_locator()
        staff = CourseStaffRole(course_locator).users_with_role()
        admins = CourseInstructorRole(course_locator).users_with_role()

        for identifier in identifiers:
            must_enroll = False
            try:
                email, student = get_valid_student_with_email(identifier)
                if student:
                    must_enroll = student in staff or student in admins or student == coach
            except CCXUserValidationException as exp:
                log.info("%s", exp)
                errors.append("{0}".format(exp))
                continue

            if CourseEnrollment.objects.is_course_full(
                    ccx_course_overview) and not must_enroll:
                error = _(
                    'The course is full: the limit is {max_student_enrollments_allowed}'
                ).format(max_student_enrollments_allowed=ccx_course_overview.
                         max_student_enrollments_allowed)
                log.info("%s", error)
                errors.append(error)
                break
            enroll_email(course_key,
                         email,
                         auto_enroll=True,
                         email_students=email_students,
                         email_params=email_params)
    elif action == 'Unenroll' or action == 'revoke':
        for identifier in identifiers:
            try:
                email, __ = get_valid_student_with_email(identifier)
            except CCXUserValidationException as exp:
                log.info("%s", exp)
                errors.append("{0}".format(exp))
                continue
            unenroll_email(course_key,
                           email,
                           email_students=email_students,
                           email_params=email_params)
    return errors
예제 #24
0
    def task_generate_user(self):
        task_input = self.request
        valid_rows = task_input.get("valid_rows")
        microsite = task_input.get("microsite")

        requester_id = task_input.get("requester_id")
        _requester_user = User.objects.get(pk=requester_id)
        self.site_name = task_input.get('site_name') + ' '

        log.warning(
            u'tma_dashboard.task_generate_user inscription users pour le microsite : '
            + microsite)
        log.warning(
            u'tma_dashboard.task_generate_user inscription users par le username '
            + _requester_user.username + ' email : ' + _requester_user.email)
        generated_passwords = []
        _generates = []
        _failed = []
        warnings = []

        #Get all keys from register form
        register_keys = []
        register_form = task_input.get("register_form")
        for _key in register_form:
            register_keys.append(_key.get('name'))

        # for white labels we use 'shopping cart' which uses CourseMode.DEFAULT_SHOPPINGCART_MODE_SLUG as
        # course mode for creating course enrollments.
        if CourseMode.is_white_label(self.course_key):
            course_mode = CourseMode.DEFAULT_SHOPPINGCART_MODE_SLUG
        else:
            course_mode = None

        #TREATING EACH USER
        for _user in valid_rows:
            #get current users values
            try:
                email = _user.get('email')
                username = email.split('@')[0].replace('-', '').replace(
                    '.', '').replace('_', '')[0:10] + '_' + random_string(5)
                first_name = str(_user.get("first_name"))
                last_name = str(_user.get("last_name"))
                complete_name = first_name + ' ' + last_name

                #check valid email
                email_params = get_email_params(self.course, True, secure=True)
                new_course_url = 'https://' + self.site_name.replace(
                    ' ', '') + '/dashboard/' + str(self.course.id)
                email_params.update({
                    'site_name': self.site_name,
                    'course_url': new_course_url,
                })
            except:
                _failed.append({
                    'email':
                    email,
                    'response':
                    _('Invalid info {email_address}.').format(
                        email_address=email)
                })
            try:
                validate_email(email)
            except ValidationError:
                _failed.append({
                    'email':
                    email,
                    'response':
                    _('Invalid email {email_address}.').format(
                        email_address=email)
                })

            if User.objects.filter(email=email).exists():
                # ENROLL EXISTING USER TO COURSE
                user = User.objects.get(email=email)
                # see if it is an exact match with email and username if it's not an exact match then just display a warning message, but continue onwards
                if not User.objects.filter(email=email,
                                           username=username).exists():
                    warning_message = _(
                        'An account with email {email} exists but the provided username {username} '
                        'is different. Enrolling anyway with {email}.').format(
                            email=email, username=username)

                    warnings.append({
                        'username': username,
                        'email': email,
                        'response': warning_message
                    })
                    log.warning(u'email %s already exist', email)
                else:
                    log.info(
                        u"user already exists with username '%s' and email '%s'",
                        username, email)
                # enroll a user if it is not already enrolled.
                if not CourseEnrollment.is_enrolled(user, self.course_key):
                    create_manual_course_enrollment(
                        user=user,
                        course_id=self.course_key,
                        mode=course_mode,
                        enrolled_by=_requester_user,
                        reason='Enrolling via csv upload',
                        state_transition=UNENROLLED_TO_ENROLLED,
                    )
                    enroll_email(course_id=self.course_key,
                                 student_email=email,
                                 auto_enroll=True,
                                 email_students=True,
                                 email_params=email_params)
            else:
                # CREATE NEW ACCOUNT
                password = self.generate_unique_password(generated_passwords)
                #generate custom_field
                custom_field = {}
                for key, value in _user.items():
                    #assurer que la key est presente dans la liste des key et non presente dans les custom_fields actuels
                    if (key in register_keys) and (not key
                                                   in custom_field.keys()):
                        custom_field[key] = value

                created_user = self.create_and_enroll_user(
                    email, username, custom_field, password, complete_name,
                    self.course_id, course_mode, _requester_user, email_params,
                    first_name, last_name)
                #maj de l'info
                if created_user != '':
                    _generates.append({
                        "id": created_user.id,
                        "email": created_user.email
                    })
                else:
                    _failed.append({
                        "email": email,
                        "reponse": "creation failed"
                    })
        log.warning(
            u'tma_dashboard.task_generate_user fin inscription users pour le microsite : '
            + microsite)
        log.warning(
            u'tma_dashboard.task_generate_user fin inscription users par le username '
            + _requester_user.username + ' email : ' + _requester_user.email)

        #Send an email to requester with potential failures
        status_text = ''
        if not _failed:
            status_text = 'Tous les utilisateurs ont bien été créés et/ou inscrits au cours.'
        else:
            status_text = "Une erreur s'est produite lors de l'inscription des utilisateurs suivants :<ul>"
            for user in _failed:
                status_text += "<li>" + user['email'] + "</li>"
            status_text += "</ul><p>Merci de remonter le problème au service IT pour identifier l'erreur sur ces profils. Les autres profils utilisateur ont été correctement créés et/ou inscrits au cours.</p>"

        course = get_course_by_id(self.course_key)

        html = "<html><head></head><body><p>Bonjour,<br><br> L'inscription par CSV de vos utilisateurs au cours " + course.display_name_with_default + " sur le microsite " + microsite + " est maintenant terminée.<br> " + status_text + "<br><br>The MOOC Agency<br></p></body></html>"
        part2 = MIMEText(html.encode('utf-8'), 'html', 'utf-8')
        fromaddr = "*****@*****.**"
        toaddr = _requester_user.email
        msg = MIMEMultipart()
        msg['From'] = fromaddr
        msg['To'] = toaddr
        msg['Subject'] = "Import utilisateurs csv"
        part = MIMEBase('application', 'octet-stream')
        server = smtplib.SMTP('mail3.themoocagency.com', 25)
        server.starttls()
        server.login('contact', 'waSwv6Eqer89')
        msg.attach(part2)
        text = msg.as_string()
        server.sendmail(fromaddr, toaddr, text)
        server.quit()

        retour = {
            "requester": _requester_user.email,
            "_generates": _generates,
            "_failed": _failed,
            "warning": warnings
        }

        return retour
예제 #25
0
def add_master_course_staff_to_ccx(master_course, ccx_key, display_name, send_email=True):
    """
    Add staff and instructor roles on ccx to all the staff and instructors members of master course.

    Arguments:
        master_course (CourseDescriptorWithMixins): Master course instance.
        ccx_key (CCXLocator): CCX course key.
        display_name (str): ccx display name for email.
        send_email (bool): flag to switch on or off email to the users on access grant.

    """
    list_staff = list_with_level(master_course, 'staff')
    list_instructor = list_with_level(master_course, 'instructor')

    with ccx_course(ccx_key) as course_ccx:
        email_params = get_email_params(course_ccx, auto_enroll=True, course_key=ccx_key, display_name=display_name)
        list_staff_ccx = list_with_level(course_ccx, 'staff')
        list_instructor_ccx = list_with_level(course_ccx, 'instructor')
        for staff in list_staff:
            # this call should be idempotent
            if staff not in list_staff_ccx:
                try:
                    # Enroll the staff in the ccx
                    enroll_email(
                        course_id=ccx_key,
                        student_email=staff.email,
                        auto_enroll=True,
                        email_students=send_email,
                        email_params=email_params,
                    )

                    # allow 'staff' access on ccx to staff of master course
                    allow_access(course_ccx, staff, 'staff')
                except CourseEnrollmentException:
                    log.warning(
                        "Unable to enroll staff %s to course with id %s",
                        staff.email,
                        ccx_key
                    )
                    continue
                except SMTPException:
                    continue

        for instructor in list_instructor:
            # this call should be idempotent
            if instructor not in list_instructor_ccx:
                try:
                    # Enroll the instructor in the ccx
                    enroll_email(
                        course_id=ccx_key,
                        student_email=instructor.email,
                        auto_enroll=True,
                        email_students=send_email,
                        email_params=email_params,
                    )

                    # allow 'instructor' access on ccx to instructor of master course
                    allow_access(course_ccx, instructor, 'instructor')
                except CourseEnrollmentException:
                    log.warning(
                        "Unable to enroll instructor %s to course with id %s",
                        instructor.email,
                        ccx_key
                    )
                    continue
                except SMTPException:
                    continue