Files
edx-platform/lms/djangoapps/ccx/utils.py
Carlos de la Guardia 9ddee93401 MIT: CCX. Code Quality fixes
add doc strings; fix pep8 warning
address some minor issues brought up by the code review process
2015-04-10 23:30:26 -04:00

308 lines
10 KiB
Python

"""
CCX Enrollment operations for use by Coach APIs.
Does not include any access control, be sure to check access before calling.
"""
import logging
from courseware.courses import get_course_about_section # pylint: disable=import-error
from courseware.courses import get_course_by_id # pylint: disable=import-error
from django.contrib.auth.models import User
from django.conf import settings
from django.core.urlresolvers import reverse
from django.core.mail import send_mail
from edxmako.shortcuts import render_to_string # pylint: disable=import-error
from microsite_configuration import microsite # pylint: disable=import-error
from xmodule.modulestore.django import modulestore
from xmodule.error_module import ErrorDescriptor
from .models import (
CcxMembership,
CcxFutureMembership,
)
from .overrides import get_current_ccx
log = logging.getLogger("edx.ccx")
class EmailEnrollmentState(object):
""" Store the complete enrollment state of an email in a class """
def __init__(self, ccx, email):
exists_user = User.objects.filter(email=email).exists()
if exists_user:
user = User.objects.get(email=email)
ccx_member = CcxMembership.objects.filter(ccx=ccx, student=user)
in_ccx = ccx_member.exists()
full_name = user.profile.name
else:
user = None
in_ccx = False
full_name = None
self.user = exists_user
self.member = user
self.full_name = full_name
self.in_ccx = in_ccx
def __repr__(self):
return "{}(user={}, member={}, in_ccx={})".format(
self.__class__.__name__,
self.user,
self.member,
self.in_ccx,
)
def to_dict(self):
""" return dict with membership and ccx info """
return {
'user': self.user,
'member': self.member,
'in_ccx': self.in_ccx,
}
def enroll_email(ccx, student_email, auto_enroll=False, email_students=False, email_params=None):
"""
Send email to newly enrolled student
"""
if email_params is None:
email_params = get_email_params(ccx, True)
previous_state = EmailEnrollmentState(ccx, student_email)
if previous_state.user:
user = User.objects.get(email=student_email)
if not previous_state.in_ccx:
membership = CcxMembership(
ccx=ccx, student=user, active=True
)
membership.save()
elif auto_enroll:
# activate existing memberships
membership = CcxMembership.objects.get(student=user, ccx=ccx)
membership.active = True
membership.save()
if email_students:
email_params['message'] = 'enrolled_enroll'
email_params['email_address'] = student_email
email_params['full_name'] = previous_state.full_name
send_mail_to_student(student_email, email_params)
else:
membership = CcxFutureMembership(
ccx=ccx, auto_enroll=auto_enroll, email=student_email
)
membership.save()
if email_students:
email_params['message'] = 'allowed_enroll'
email_params['email_address'] = student_email
send_mail_to_student(student_email, email_params)
after_state = EmailEnrollmentState(ccx, student_email)
return previous_state, after_state
def unenroll_email(ccx, student_email, email_students=False, email_params=None):
"""
send email to unenrolled students
"""
if email_params is None:
email_params = get_email_params(ccx, True)
previous_state = EmailEnrollmentState(ccx, student_email)
if previous_state.in_ccx:
CcxMembership.objects.get(
ccx=ccx, student=previous_state.member
).delete()
if email_students:
email_params['message'] = 'enrolled_unenroll'
email_params['email_address'] = student_email
email_params['full_name'] = previous_state.full_name
send_mail_to_student(student_email, email_params)
else:
if CcxFutureMembership.objects.filter(
ccx=ccx, email=student_email).exists():
CcxFutureMembership.objects.get(
ccx=ccx, email=student_email
).delete()
if email_students:
email_params['message'] = 'allowed_unenroll'
email_params['email_address'] = student_email
send_mail_to_student(student_email, email_params)
after_state = EmailEnrollmentState(ccx, student_email)
return previous_state, after_state
def get_email_params(ccx, auto_enroll, secure=True):
"""
get parameters for enrollment emails
"""
protocol = 'https' if secure else 'http'
course_id = ccx.course_id
stripped_site_name = microsite.get_value(
'SITE_NAME',
settings.SITE_NAME
)
registration_url = u'{proto}://{site}{path}'.format(
proto=protocol,
site=stripped_site_name,
path=reverse('register_user')
)
course_url = u'{proto}://{site}{path}'.format(
proto=protocol,
site=stripped_site_name,
path=reverse(
'course_root',
kwargs={'course_id': course_id.to_deprecated_string()}
)
)
course_about_url = None
if not settings.FEATURES.get('ENABLE_MKTG_SITE', False):
course_about_url = u'{proto}://{site}{path}'.format(
proto=protocol,
site=stripped_site_name,
path=reverse(
'about_course',
kwargs={'course_id': course_id.to_deprecated_string()}
)
)
email_params = {
'site_name': stripped_site_name,
'registration_url': registration_url,
'course': ccx,
'auto_enroll': auto_enroll,
'course_url': course_url,
'course_about_url': course_about_url,
}
return email_params
def send_mail_to_student(student, param_dict):
"""
Check parameters, set text template and send email to student
"""
if 'course' in param_dict:
param_dict['course_name'] = param_dict['course'].display_name
param_dict['site_name'] = microsite.get_value(
'SITE_NAME',
param_dict['site_name']
)
subject = None
message = None
message_type = param_dict['message']
email_template_dict = {
'allowed_enroll': (
'ccx/enroll_email_allowedsubject.txt',
'ccx/enroll_email_allowedmessage.txt'
),
'enrolled_enroll': (
'ccx/enroll_email_enrolledsubject.txt',
'ccx/enroll_email_enrolledmessage.txt'
),
'allowed_unenroll': (
'ccx/unenroll_email_subject.txt',
'ccx/unenroll_email_allowedmessage.txt'
),
'enrolled_unenroll': (
'ccx/unenroll_email_subject.txt',
'ccx/unenroll_email_enrolledmessage.txt'
),
}
subject_template, message_template = email_template_dict.get(
message_type, (None, None)
)
if subject_template is not None and message_template is not None:
subject = render_to_string(subject_template, param_dict)
message = render_to_string(message_template, param_dict)
if subject and message:
message = message.strip()
subject = ''.join(subject.splitlines())
from_address = microsite.get_value(
'email_from_address',
settings.DEFAULT_FROM_EMAIL
)
send_mail(
subject,
message,
from_address,
[student],
fail_silently=False
)
def get_all_ccx_for_user(user):
"""return all CCXS to which the user is registered
Returns a list of dicts: {
ccx_name: <formatted title of CCX course>
ccx_url: <url to view this CCX>
ccx_active: True if this ccx is currently the 'active' one
mooc_name: <formatted title of the MOOC course for this CCX>
mooc_url: <url to view this MOOC>
}
"""
if user.is_anonymous():
return []
current_active_ccx = get_current_ccx()
memberships = []
for membership in CcxMembership.memberships_for_user(user):
course = get_course_by_id(membership.ccx.course_id)
ccx = membership.ccx
ccx_title = ccx.display_name
mooc_title = get_course_about_section(course, 'title')
url = reverse(
'switch_active_ccx',
args=[course.id.to_deprecated_string(), membership.ccx.id]
)
mooc_url = reverse(
'switch_active_ccx',
args=[course.id.to_deprecated_string(), ]
)
memberships.append({
'ccx_name': ccx_title,
'ccx_url': url,
'active': membership.ccx == current_active_ccx,
'mooc_name': mooc_title,
'mooc_url': mooc_url,
})
return memberships
def get_ccx_membership_triplets(user, course_org_filter, org_filter_out_set):
"""
Get the relevant set of (CustomCourseForEdX, CcxMembership, Course)
triplets to be displayed on a student's dashboard.
"""
# only active memberships for now
for membership in CcxMembership.memberships_for_user(user):
ccx = membership.ccx
store = modulestore()
with store.bulk_operations(ccx.course_id):
course = store.get_course(ccx.course_id)
if course and not isinstance(course, ErrorDescriptor):
# if we are in a Microsite, then filter out anything that is not
# attributed (by ORG) to that Microsite
if course_org_filter and course_org_filter != course.location.org:
continue
# Conversely, if we are not in a Microsite, then let's filter out any enrollments
# with courses attributed (by ORG) to Microsites
elif course.location.org in org_filter_out_set:
continue
yield (ccx, membership, course)
else:
log.error("User {0} enrolled in {2} course {1}".format( # pylint: disable=logging-format-interpolation
user.username, ccx.course_id, "broken" if course else "non-existent"
))