diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index a1034bc296..093f2f5360 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -1,13 +1,13 @@ """ Student Views """ -import datetime import logging import re import uuid import time import json from collections import defaultdict +from datetime import datetime from pytz import UTC from django.conf import settings @@ -42,6 +42,7 @@ from edxmako.shortcuts import render_to_response, render_to_string from mako.exceptions import TopLevelLookupException from course_modes.models import CourseMode + from student.models import ( Registration, UserProfile, PendingNameChange, PendingEmailChange, CourseEnrollment, unique_id_for_user, @@ -64,6 +65,7 @@ from collections import namedtuple from courseware.courses import get_courses, sort_by_announcement from courseware.access import has_access +from courseware.models import course_modified_times from django_comment_common.models import Role @@ -226,7 +228,7 @@ def single_course_reverification_info(user, course, enrollment): # pylint: disa ReverifyInfo: (course_id, course_name, course_number, date, status) OR, None: None if there is no re-verification info for this enrollment """ - window = MidcourseReverificationWindow.get_window(course.id, datetime.datetime.now(UTC)) + window = MidcourseReverificationWindow.get_window(course.id, datetime.now(UTC)) # If there's no window OR the user is not verified, we don't get reverification info if (not window) or (enrollment.mode != "verified"): @@ -244,6 +246,8 @@ def get_course_enrollment_pairs(user, course_org_filter, org_filter_out_set): Get the relevant set of (Course, CourseEnrollment) pairs to be displayed on a student's dashboard. """ + pairs = [] + for enrollment in CourseEnrollment.enrollments_for_user(user): course = modulestore().get_course(enrollment.course_id) if course and not isinstance(course, ErrorDescriptor): @@ -257,12 +261,18 @@ def get_course_enrollment_pairs(user, course_org_filter, org_filter_out_set): elif course.location.org in org_filter_out_set: continue - yield (course, enrollment) + pairs.append((course, enrollment)) else: log.error("User {0} enrolled in {2} course {1}".format( user.username, enrollment.course_id, "broken" if course else "non-existent" )) + ## Sort pairs in order of courseware access. If I am actively using a course, it should bubble up to the top. + modified_times_map = course_modified_times(user, [p[0].scope_ids.usage_id for p in pairs]) + def key_function(x): + return modified_times_map.get(unicode(x[0].scope_ids.usage_id), datetime.min) + pairs.sort(key=key_function, reverse=True) + return pairs def _cert_info(user, course, cert_status): """ @@ -429,7 +439,7 @@ def complete_course_mode_info(course_id, enrollment): mode_info['show_upsell'] = True # if there is an expiration date, find out how long from now it is if modes['verified'].expiration_datetime: - today = datetime.datetime.now(UTC).date() + today = datetime.now(UTC).date() mode_info['days_for_upsell'] = (modes['verified'].expiration_datetime.date() - today).days return mode_info @@ -1167,7 +1177,7 @@ def disable_account_ajax(request): context['message'] = _("Unexpected account status") return JsonResponse(context, status=400) user_account.changed_by = request.user - user_account.standing_last_changed_at = datetime.datetime.now(UTC) + user_account.standing_last_changed_at = datetime.now(UTC) user_account.save() return JsonResponse(context) @@ -1552,7 +1562,7 @@ def create_account(request, post_override=None): # pylint: disable-msg=too-many if do_external_auth: eamap.user = new_user - eamap.dtsignup = datetime.datetime.now(UTC) + eamap.dtsignup = datetime.now(UTC) eamap.save() AUDIT_LOG.info("User registered with external_auth %s", post_vars['username']) AUDIT_LOG.info('Updated ExternalAuthMap for %s to be %s', post_vars['username'], eamap) @@ -1980,7 +1990,7 @@ def confirm_email_change(request, key): # pylint: disable=unused-argument meta = u_prof.get_meta() if 'old_emails' not in meta: meta['old_emails'] = [] - meta['old_emails'].append([user.email, datetime.datetime.now(UTC).isoformat()]) + meta['old_emails'].append([user.email, datetime.now(UTC).isoformat()]) u_prof.set_meta(meta) u_prof.save() # Send it to the old email... @@ -2100,7 +2110,7 @@ def accept_name_change_by_id(uid): meta = u_prof.get_meta() if 'old_names' not in meta: meta['old_names'] = [] - meta['old_names'].append([u_prof.name, pnc.rationale, datetime.datetime.now(UTC).isoformat()]) + meta['old_names'].append([u_prof.name, pnc.rationale, datetime.now(UTC).isoformat()]) u_prof.set_meta(meta) u_prof.name = pnc.new_name diff --git a/lms/djangoapps/courseware/models.py b/lms/djangoapps/courseware/models.py index cb471dd79c..b9b8bb2a1c 100644 --- a/lms/djangoapps/courseware/models.py +++ b/lms/djangoapps/courseware/models.py @@ -93,6 +93,12 @@ class StudentModule(models.Model): return unicode(repr(self)) +def course_modified_times(user, ids): + ''' Returns the times when a given studentmodule was last modified. + ''' + results = StudentModule.objects.filter(student=user, module_state_key__in=ids).values_list('module_state_key', 'modified') + return dict(results) + class StudentModuleHistory(models.Model): """Keeps a complete history of state changes for a given XModule for a given Student. Right now, we restrict this to problems so that the table doesn't diff --git a/lms/templates/dashboard.html b/lms/templates/dashboard.html index b431e79351..837d800051 100644 --- a/lms/templates/dashboard.html +++ b/lms/templates/dashboard.html @@ -291,7 +291,7 @@
-

${_("Current Courses")}

+

${_("Courses")}

${_("ordered by recent activity")}
% if len(course_enrollment_pairs) > 0: