enrollment.py 4.55 KB
Newer Older
1 2 3 4 5 6
"""
Enrollment operations for use by instructor APIs.

Does not include any access control, be sure to check access before calling.
"""

7
import json
8 9
from django.contrib.auth.models import User
from student.models import CourseEnrollment, CourseEnrollmentAllowed
10
from courseware.models import StudentModule
11 12


13 14 15 16
class EmailEnrollmentState(object):
    """ Store the complete enrollment state of an email in a class """
    def __init__(self, course_id, email):
        exists_user = User.objects.filter(email=email).exists()
17 18 19 20 21
        if exists_user:
            user = User.objects.get(email=email)
            exists_ce = CourseEnrollment.is_enrolled(user, course_id)
        else:
            exists_ce = False
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57
        ceas = CourseEnrollmentAllowed.objects.filter(course_id=course_id, email=email).all()
        exists_allowed = len(ceas) > 0
        state_auto_enroll = exists_allowed and ceas[0].auto_enroll

        self.user = exists_user
        self.enrollment = exists_ce
        self.allowed = exists_allowed
        self.auto_enroll = bool(state_auto_enroll)

    def __repr__(self):
        return "{}(user={}, enrollment={}, allowed={}, auto_enroll={})".format(
            self.__class__.__name__,
            self.user,
            self.enrollment,
            self.allowed,
            self.auto_enroll,
        )

    def to_dict(self):
        """
        example: {
            'user': False,
            'enrollment': False,
            'allowed': True,
            'auto_enroll': True,
        }
        """
        return {
            'user': self.user,
            'enrollment': self.enrollment,
            'allowed': self.allowed,
            'auto_enroll': self.auto_enroll,
        }


def enroll_email(course_id, student_email, auto_enroll=False):
58
    """
59
    Enroll a student by email.
60

61 62 63 64
    `student_email` is student's emails e.g. "foo@bar.com"
    `auto_enroll` determines what is put in CourseEnrollmentAllowed.auto_enroll
        if auto_enroll is set, then when the email registers, they will be
        enrolled in the course automatically.
65

66 67
    returns two EmailEnrollmentState's
        representing state before and after the action.
68 69
    """

70
    previous_state = EmailEnrollmentState(course_id, student_email)
71

72
    if previous_state.user:
73
        CourseEnrollment.enroll_by_email(student_email, course_id)
74 75 76 77
    else:
        cea, _ = CourseEnrollmentAllowed.objects.get_or_create(course_id=course_id, email=student_email)
        cea.auto_enroll = auto_enroll
        cea.save()
78

79 80 81
    after_state = EmailEnrollmentState(course_id, student_email)

    return previous_state, after_state
82 83


84
def unenroll_email(course_id, student_email):
85
    """
86
    Unenroll a student by email.
87

88
    `student_email` is student's emails e.g. "foo@bar.com"
89

90 91
    returns two EmailEnrollmentState's
        representing state before and after the action.
92 93
    """

94 95 96
    previous_state = EmailEnrollmentState(course_id, student_email)

    if previous_state.enrollment:
97
        CourseEnrollment.unenroll_by_email(student_email, course_id)
98 99 100 101 102

    if previous_state.allowed:
        CourseEnrollmentAllowed.objects.get(course_id=course_id, email=student_email).delete()

    after_state = EmailEnrollmentState(course_id, student_email)
103

104
    return previous_state, after_state
105 106


Miles Steele committed
107
def reset_student_attempts(course_id, student, module_state_key, delete_module=False):
108 109 110 111 112 113
    """
    Reset student attempts for a problem. Optionally deletes all student state for the specified problem.

    In the previous instructor dashboard it was possible to modify/delete
    modules that were not problems. That has been disabled for safety.

114 115 116 117 118
    `student` is a User
    `problem_to_reset` is the name of a problem e.g. 'L2Node1'.
    To build the module_state_key 'problem/' and course information will be appended to `problem_to_reset`.

    Throws ValueError if `problem_state` is invalid JSON.
119 120 121 122 123 124 125 126 127 128 129 130
    """
    module_to_reset = StudentModule.objects.get(student_id=student.id,
                                                course_id=course_id,
                                                module_state_key=module_state_key)

    if delete_module:
        module_to_reset.delete()
    else:
        _reset_module_attempts(module_to_reset)


def _reset_module_attempts(studentmodule):
131 132 133 134 135
    """
    Reset the number of attempts on a studentmodule.

    Throws ValueError if `problem_state` is invalid JSON.
    """
136 137 138 139 140 141 142 143
    # load the state json
    problem_state = json.loads(studentmodule.state)
    # old_number_of_attempts = problem_state["attempts"]
    problem_state["attempts"] = 0

    # save
    studentmodule.state = json.dumps(problem_state)
    studentmodule.save()