Merge pull request #4031 from edx/sarina/other-ok-fixes
Sarina/other ok fixes
This commit is contained in:
@@ -22,7 +22,7 @@ from selenium.common.exceptions import (
|
||||
from selenium.webdriver.support import expected_conditions as EC
|
||||
from selenium.webdriver.common.by import By
|
||||
from selenium.webdriver.support.ui import WebDriverWait
|
||||
from nose.tools import assert_true # pylint: disable=E0611
|
||||
from nose.tools import assert_true # pylint: disable=no-name-in-module
|
||||
|
||||
|
||||
REQUIREJS_WAIT = {
|
||||
@@ -305,6 +305,25 @@ def css_has_text(css_selector, text, index=0, strip=False):
|
||||
return actual_text == text
|
||||
|
||||
|
||||
@world.absorb
|
||||
def css_contains_text(css_selector, partial_text, index=0):
|
||||
"""
|
||||
Return a boolean indicating whether the element with `css_selector`
|
||||
contains `partial_text`.
|
||||
|
||||
If there are multiple elements matching the css selector,
|
||||
use `index` to indicate which one.
|
||||
"""
|
||||
# If we're expecting a non-empty string, give the page
|
||||
# a chance to fill in text fields.
|
||||
if partial_text:
|
||||
wait_for(lambda _: css_text(css_selector, index=index))
|
||||
|
||||
actual_text = css_text(css_selector, index=index)
|
||||
|
||||
return partial_text in actual_text
|
||||
|
||||
|
||||
@world.absorb
|
||||
def css_has_value(css_selector, value, index=0):
|
||||
"""
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
"""
|
||||
Generate a report of certificate statuses
|
||||
"""
|
||||
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from certificates.models import GeneratedCertificate
|
||||
from django.contrib.auth.models import User
|
||||
from optparse import make_option
|
||||
from django.conf import settings
|
||||
from opaque_keys import InvalidKeyError
|
||||
from xmodule.course_module import CourseDescriptor
|
||||
from xmodule.modulestore.keys import CourseKey
|
||||
from xmodule.modulestore.locations import SlashSeparatedCourseKey
|
||||
from xmodule.modulestore.django import modulestore
|
||||
from django.db.models import Count
|
||||
|
||||
@@ -12,7 +19,7 @@ class Command(BaseCommand):
|
||||
|
||||
help = """
|
||||
|
||||
Generate a certificate status report for all courses that have ended.
|
||||
Generate a certificate status report for a given course.
|
||||
This command does not do anything other than report the current
|
||||
certificate status.
|
||||
|
||||
@@ -34,81 +41,89 @@ class Command(BaseCommand):
|
||||
dest='course',
|
||||
default=None,
|
||||
help='Only generate for COURSE_ID'),
|
||||
)
|
||||
|
||||
def _ended_courses(self):
|
||||
for course_id in [course # all courses in COURSE_LISTINGS
|
||||
for sub in settings.COURSE_LISTINGS
|
||||
for course in settings.COURSE_LISTINGS[sub]]:
|
||||
course = modulestore().get_course(course_id)
|
||||
if course.has_ended():
|
||||
yield course_id
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
|
||||
# Find all courses that have ended
|
||||
|
||||
if options['course']:
|
||||
ended_courses = [options['course']]
|
||||
try:
|
||||
course_id = CourseKey.from_string(options['course'])
|
||||
except InvalidKeyError:
|
||||
print("Course id {} could not be parsed as a CourseKey; falling back to SSCK.from_dep_str".format(options['course']))
|
||||
course_id = SlashSeparatedCourseKey.from_deprecated_string(options['course'])
|
||||
else:
|
||||
ended_courses = self._ended_courses()
|
||||
raise CommandError("You must specify a course")
|
||||
|
||||
cert_data = {}
|
||||
|
||||
for course_id in ended_courses:
|
||||
# find students who are active
|
||||
# number of enrolled students = downloadable + notpassing
|
||||
print "Looking up certificate states for {0}".format(options['course'])
|
||||
enrolled_current = User.objects.filter(
|
||||
courseenrollment__course_id=course_id,
|
||||
courseenrollment__is_active=True
|
||||
)
|
||||
enrolled_total = User.objects.filter(
|
||||
courseenrollment__course_id=course_id
|
||||
)
|
||||
verified_enrolled = GeneratedCertificate.objects.filter(
|
||||
course_id__exact=course_id, mode__exact='verified'
|
||||
)
|
||||
honor_enrolled = GeneratedCertificate.objects.filter(
|
||||
course_id__exact=course_id, mode__exact='honor'
|
||||
)
|
||||
audit_enrolled = GeneratedCertificate.objects.filter(
|
||||
course_id__exact=course_id, mode__exact='audit'
|
||||
)
|
||||
|
||||
# find students who are active
|
||||
# enrolled students are always downloable + notpassing
|
||||
print "Looking up certificate states for {0}".format(course_id)
|
||||
enrolled_current = User.objects.filter(
|
||||
courseenrollment__course_id=course_id,
|
||||
courseenrollment__is_active=True)
|
||||
enrolled_total = User.objects.filter(
|
||||
courseenrollment__course_id=course_id)
|
||||
verified_enrolled = GeneratedCertificate.objects.filter(
|
||||
course_id__exact=course_id, mode__exact='verified')
|
||||
honor_enrolled = GeneratedCertificate.objects.filter(
|
||||
course_id__exact=course_id, mode__exact='honor')
|
||||
audit_enrolled = GeneratedCertificate.objects.filter(
|
||||
course_id__exact=course_id, mode__exact='audit')
|
||||
cert_data[course_id] = {
|
||||
'enrolled_current': enrolled_current.count(),
|
||||
'enrolled_total': enrolled_total.count(),
|
||||
'verified_enrolled': verified_enrolled.count(),
|
||||
'honor_enrolled': honor_enrolled.count(),
|
||||
'audit_enrolled': audit_enrolled.count()
|
||||
}
|
||||
|
||||
cert_data[course_id] = {'enrolled_current': enrolled_current.count(),
|
||||
'enrolled_total': enrolled_total.count(),
|
||||
'verified_enrolled': verified_enrolled.count(),
|
||||
'honor_enrolled': honor_enrolled.count(),
|
||||
'audit_enrolled': audit_enrolled.count()}
|
||||
status_tally = GeneratedCertificate.objects.filter(
|
||||
course_id__exact=course_id
|
||||
).values('status').annotate(
|
||||
dcount=Count('status')
|
||||
)
|
||||
|
||||
status_tally = GeneratedCertificate.objects.filter(
|
||||
course_id__exact=course_id).values('status').annotate(
|
||||
dcount=Count('status'))
|
||||
cert_data[course_id].update(
|
||||
{status['status']: status['dcount']
|
||||
for status in status_tally})
|
||||
cert_data[course_id].update(
|
||||
{status['status']: status['dcount']
|
||||
for status in status_tally})
|
||||
|
||||
mode_tally = GeneratedCertificate.objects.filter(
|
||||
course_id__exact=course_id,
|
||||
status__exact='downloadable').values('mode').annotate(
|
||||
dcount=Count('mode'))
|
||||
cert_data[course_id].update(
|
||||
{mode['mode']: mode['dcount']
|
||||
for mode in mode_tally})
|
||||
mode_tally = GeneratedCertificate.objects.filter(
|
||||
course_id__exact=course_id,
|
||||
status__exact='downloadable'
|
||||
).values('mode').annotate(
|
||||
dcount=Count('mode')
|
||||
)
|
||||
cert_data[course_id].update(
|
||||
{mode['mode']: mode['dcount']
|
||||
for mode in mode_tally}
|
||||
)
|
||||
|
||||
# all states we have seen far all courses
|
||||
status_headings = sorted(set(
|
||||
[status for course in cert_data
|
||||
for status in cert_data[course]]))
|
||||
for status in cert_data[course]])
|
||||
)
|
||||
|
||||
# print the heading for the report
|
||||
print "{:>26}".format("course ID"),
|
||||
print ' '.join(["{:>16}".format(heading)
|
||||
for heading in status_headings])
|
||||
for heading in status_headings]
|
||||
)
|
||||
|
||||
# print the report
|
||||
for course_id in cert_data:
|
||||
print "{0:>26}".format(course_id[0:24]),
|
||||
for heading in status_headings:
|
||||
if heading in cert_data[course_id]:
|
||||
print "{:>16}".format(cert_data[course_id][heading]),
|
||||
else:
|
||||
print " " * 16,
|
||||
print
|
||||
print "{0:>26}".format(course_id.to_deprecated_string()),
|
||||
for heading in status_headings:
|
||||
if heading in cert_data[course_id]:
|
||||
print "{:>16}".format(cert_data[course_id][heading]),
|
||||
else:
|
||||
print " " * 16,
|
||||
print
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
# pylint: disable=C0111
|
||||
# pylint: disable=W0621
|
||||
|
||||
from lettuce import world, steps
|
||||
from nose.tools import assert_in, assert_equals, assert_true
|
||||
from nose.tools import assert_in, assert_true # pylint: disable=no-name-in-module
|
||||
|
||||
from common import i_am_registered_for_the_course, visit_scenario_item
|
||||
from problems_setup import add_problem_to_course, answer_problem
|
||||
@@ -90,6 +92,7 @@ class ConditionalSteps(object):
|
||||
assert_true(world.css_visible('.hidden-contents'))
|
||||
else:
|
||||
assert_true(world.is_css_not_present('.hidden-contents'))
|
||||
assert_true(world.css_contains_text('.conditional-message', 'must be attempted before this will become visible.')) # sarina
|
||||
|
||||
def answer_poll(self, step, answer):
|
||||
r' I answer the conditioned poll "([^"]*)"$'
|
||||
@@ -116,4 +119,4 @@ class ConditionalSteps(object):
|
||||
return
|
||||
|
||||
|
||||
ConditionalSteps()
|
||||
ConditionalSteps()
|
||||
|
||||
@@ -5,11 +5,11 @@ from django.core.urlresolvers import reverse
|
||||
def _message(reqm, message):
|
||||
return message.format(link="<a href={url}>{url_name}</a>".format(
|
||||
url = reverse('jump_to', kwargs=dict(course_id=reqm.course_id.to_deprecated_string(),
|
||||
location=reqm.location.url())),
|
||||
location=reqm.location.to_deprecated_string())),
|
||||
url_name = reqm.display_name_with_default))
|
||||
%>
|
||||
% if message:
|
||||
% for reqm in module.required_modules:
|
||||
<p>${_message(reqm, message)}</p>
|
||||
<p class="conditional-message">${_message(reqm, message)}</p>
|
||||
% endfor
|
||||
% endif
|
||||
|
||||
Reference in New Issue
Block a user