def parse_activity_scores(self, activity_attempt):
        if activity_attempt.source == 'tag-assessment':
            data = transforms.loads(activity_attempt.data)

            timestamp = int(
            (activity_attempt.recorded_on - datetime.datetime(1970, 1, 1)).total_seconds())

            questions = self.params['questions_by_usage_id']
            valid_question_ids = self.params['valid_question_ids']
            assessment_weights = self.params['assessment_weights']
            group_to_questions = self.params['group_to_questions']

            student_answers = self.activity_scores.get(Student.get_student_by_user_id(activity_attempt.user_id).email, {})

            answers = event_transforms.unpack_check_answers(
                data, questions, valid_question_ids, assessment_weights,
                group_to_questions, timestamp)

            #add score to right lesson
            question_info = questions[data['instanceid']]
            unit_answers = student_answers.get(question_info['unit'], {})
            lesson_answers = unit_answers.get(question_info['lesson'], {})

            for answer in answers:
                question_answer_dict = {}
                question_answer_dict['unit_id'] = answer.unit_id
                question_answer_dict['lesson_id'] = answer.lesson_id
                question_answer_dict['sequence'] = answer.sequence
                question_answer_dict['question_id'] = answer.question_id
                question_answer_dict['question_type'] = answer.question_type
                question_answer_dict['timestamp'] = answer.timestamp
                question_answer_dict['answers'] = answer.answers
                question_answer_dict['score'] = answer.score
                question_answer_dict['weighted_score'] = answer.weighted_score
                question_answer_dict['tallied'] = answer.tallied

                if answer.sequence in lesson_answers and lesson_answers[answer.sequence] < timestamp:
                    lesson_answers[answer.sequence] = question_answer_dict
                elif answer.sequence not in lesson_answers:
                    lesson_answers[answer.sequence] = question_answer_dict

            unit_answers[question_info['lesson']] = lesson_answers
            student_answers[question_info['unit']] = unit_answers

            self.activity_scores[Student.get_student_by_user_id(activity_attempt.user_id).email] = student_answers

        return self.activity_scores
Пример #2
0
    def map(self, event):
        # Find out whether this event is relevant to this unit.
        data = transforms.loads(event.data)

        url = data['location']
        parsed = urlparse.urlparse(url)
        unit = urlparse.parse_qs(parsed.query)['unit'][0]
        if int(unit) != int(self.unit):
            return

        student = Student.get_student_by_user_id(event.user_id)

        self.add_row({
            'name': student.name,
            'email': student.key().name(),
            'index': data['index'],
            'answer': data['value'],
            })
Пример #3
0
    def map(self, event):
        # Find out whether this event is relevant to this unit.
        data = transforms.loads(event.data)

        url = data['location']
        parsed = urlparse.urlparse(url)
        unit = urlparse.parse_qs(parsed.query)['unit'][0]
        if int(unit) != int(self.unit):
            return

        student = Student.get_student_by_user_id(event.user_id)

        self.add_row({
            'name': student.name,
            'email': student.key().name(),
            'index': data['index'],
            'answer': data['value'],
        })
Пример #4
0
    def post(self):
        """Handles POST requests."""
        user = self.personalize_page_and_get_user()
        if not user:
            self.redirect(users.create_login_url(self.request.uri),
                          normalize=False)
            return

        if not self.assert_xsrf_token_or_fail(self.request, 'register-post'):
            return

        can_register = self.app_context.get_environ(
        )['reg_form']['can_register']
        if not can_register:
            self.template_value['course_status'] = 'full'
        else:
            name = self.request.get('form01')
            additional_fields = transforms.dumps(self.request.POST.items())

            # create new or re-enroll old student
            student = Student.get_by_email(user.email())
            if not student:
                student = Student(key_name=user.email())
                student.user_id = user.user_id()

            student_by_uid = Student.get_student_by_user_id(user.user_id())
            is_valid_student = (student_by_uid is None
                                or student_by_uid.user_id == student.user_id)
            assert is_valid_student, (
                'Student\'s email and user id do not match.')

            student.user_id = user.user_id()
            student.is_enrolled = True
            student.name = name
            student.age = self.request.get('form02')
            student.additional_fields = additional_fields
            student.put()

        # Render registration confirmation page
        self.template_value['navbar'] = {'registration': True}
        self.render('confirmation.html')
Пример #5
0
    def post(self):
        """Handles POST requests."""
        user = self.personalize_page_and_get_user()
        if not user:
            self.redirect(
                users.create_login_url(self.request.uri), normalize=False)
            return

        if not self.assert_xsrf_token_or_fail(self.request, 'register-post'):
            return

        can_register = self.app_context.get_environ(
            )['reg_form']['can_register']
        if not can_register:
            self.template_value['course_status'] = 'full'
        else:
            name = self.request.get('form01')
            additional_fields = transforms.dumps(self.request.POST.items())

            # create new or re-enroll old student
            student = Student.get_by_email(user.email())
            if not student:
                student = Student(key_name=user.email())
                student.user_id = user.user_id()

            student_by_uid = Student.get_student_by_user_id(user.user_id())
            is_valid_student = (student_by_uid is None or
                                student_by_uid.user_id == student.user_id)
            assert is_valid_student, (
                'Student\'s email and user id do not match.')

            student.user_id = user.user_id()
            student.is_enrolled = True
            student.name = name
            student.additional_fields = additional_fields
            student.put()

        # Render registration confirmation page
        self.template_value['navbar'] = {'registration': True}
        self.render('confirmation.html')
Пример #6
0
    def post(self):
        """Handles POST requests."""
        user = self.personalize_page_and_get_user()
        if not user:
            self.redirect(users.create_login_url(self.request.uri), normalize=False)
            return

        if not self.assert_xsrf_token_or_fail(self.request, "register-post"):
            return

        can_register = self.app_context.get_environ()["reg_form"]["can_register"]
        if not can_register:
            self.template_value["course_status"] = "full"
        else:
            name = self.request.get("form01")
            additional_fields = transforms.dumps(self.request.POST.items())

            # create new or re-enroll old student
            student = Student.get_by_email(user.email())
            if not student:
                student = Student(key_name=user.email())
                student.user_id = user.user_id()

            student_by_uid = Student.get_student_by_user_id(user.user_id())
            is_valid_student = student_by_uid is None or student_by_uid.user_id == student.user_id
            assert is_valid_student, "Student's email and user id do not match."

            student.user_id = user.user_id()
            student.is_enrolled = True
            student.name = name
            student.age = self.request.get("formAge")
            student.additional_fields = additional_fields
            student.put()

        # Render registration confirmation page
        self.template_value["navbar"] = {"registration": True}
        self.render("confirmation.html")
    def get_activity_scores(cls, student_user_ids, course, force_refresh = False):
        """Retrieve activity data for student using EventEntity"""

        #instantiate parser object
        cached_date = datetime.datetime.now()
        activityParser = ActivityScoreParser()

        if force_refresh:
            activityParser.params = activityParser.build_additional_mapper_params(course.app_context)

            for user_id in student_user_ids:
                mapper = models_utils.QueryMapper(
                    EventEntity.all().filter('user_id in', [user_id]), batch_size=500, report_every=1000)

                def map_fn(activity_attempt):
                    activityParser.parse_activity_scores(activity_attempt)

                mapper.run(map_fn)

            activityParser.build_missing_scores()

            #Lets cache results for each student
            for user_id in student_user_ids:
                cached_student_data = {}
                cached_student_data['date'] = cached_date
                cached_student_data['scores'] = activityParser.activity_scores.get(Student.get_student_by_user_id(
                    user_id).email, {})
                MemcacheManager.set(cls._memcache_key_for_student(Student.get_student_by_user_id(user_id).email),
                                    cached_student_data)
        else:
            uncached_students = []
            for student_id in student_user_ids:
                scores_for_student = MemcacheManager.get(cls._memcache_key_for_student(Student.get_student_by_user_id(
                    student_id).email))
                if scores_for_student:
                    cached_date = scores_for_student['date']
                    activityParser.activity_scores[student_id] = scores_for_student['scores']
                else:
                    uncached_students.append(student_id)
            if len(uncached_students) > 0:
                if cached_date == None or datetime.datetime.now() < cached_date:
                    cached_date = datetime.datetime.now()

                activityParser.params = activityParser.build_additional_mapper_params(course.app_context)

                for user_id in uncached_students:
                    mapper = models_utils.QueryMapper(
                        EventEntity.all().filter('user_id in', [user_id]), batch_size=500, report_every=1000)

                    def map_fn(activity_attempt):
                        activityParser.parse_activity_scores(activity_attempt)

                    mapper.run(map_fn)

                activityParser.build_missing_scores()

                #Lets cache results for each student
                for user_id in uncached_students:
                    cached_student_data = {}
                    cached_student_data['date'] = cached_date
                    cached_student_data['scores'] = activityParser.activity_scores.get(Student.get_student_by_user_id(
                        user_id).email, {})
                    MemcacheManager.set(cls._memcache_key_for_student(Student.get_student_by_user_id(user_id).email),
                                        cached_student_data)

        score_data = {}
        score_data['date'] = cached_date
        score_data['scores'] = activityParser.activity_scores

        return score_data
Пример #8
0
    def get_markup_for_basic_analytics(self, job):
        """Renders markup for basic enrollment and assessment analytics."""
        subtemplate_values = {}
        errors = []
        stats_calculated = False
        update_message = safe_dom.Text('')

        if not job:
            update_message = safe_dom.Text(
                'Enrollment/assessment statistics have not been calculated '
                'yet.')
        else:
            if job.status_code == jobs.STATUS_CODE_COMPLETED:
                stats = transforms.loads(job.output)
                stats_calculated = True

                #event = EventEntity().all().fetch(limit=400)
                cr = courses.Course(self).get_units()

                subtemplate_values['enrolled'] = stats['enrollment'][
                    'enrolled']
                subtemplate_values['unenrolled'] = (
                    stats['enrollment']['unenrolled'])
                subtemplate_values['submissions'] = stats['id']

                scores = []
                total_records = 0
                names = []
                submissions = {}
                students = {}
                data = []

                for key, value in stats['id'].items():
                    students[key] = value

                course = courses.Course(self)
                problems = course.get_assessment_list()
                assessments = dict((a.unit_id, a.title) for a in problems)

                lesson_list = []
                unit_list = []
                units = course.get_units()
                for u in units:
                    lessons = course.get_lessons(u.unit_id)
                    for l in lessons:
                        single = {}
                        single['lesson_unit'] = l.unit_id
                        single['lesson_id'] = l.lesson_id
                        single['lesson_title'] = l.title
                        lesson_list.append(single)
                    if u.type == 'U':
                        un = {}
                        un['index'] = u._index
                        un['id'] = u.unit_id
                        un['title'] = u.title
                        unit_list.append(un)

                tmp_unit = {}
                for l in lesson_list:
                    tmp_unit[l['lesson_unit']] = []

                for l in lesson_list:
                    tmp_unit[l['lesson_unit']].append(l)

                struct = []
                for key, value in tmp_unit.items():
                    unit = {}
                    for u in unit_list:
                        if u['index'] == key:
                            unit['id'] = u['id']
                            unit['title'] = u['title']
                    unit['lessons'] = value
                    unit['lesson_count'] = len(value)
                    struct.append(unit)

                for sname, sid in students.items():
                    st = Student.get_student_by_user_id(sid)
                    sc = course.get_all_scores(st)
                    data.append({'name': sname, 'scores': sc})

                for key, value in stats['scores'].items():
                    total_records += value[0]
                    avg = round(value[1] / value[0], 1) if value[0] else 0
                    scores.append({
                        'key': key,
                        'completed': value[0],
                        'avg': avg
                    })

                subtemplate_values['scores'] = scores
                subtemplate_values['total_records'] = total_records
                subtemplate_values['names'] = names
                subtemplate_values['data'] = data
                subtemplate_values['struct'] = struct

                update_message = safe_dom.Text(
                    """
                    Enrollment and assessment statistics were last updated at
                    %s in about %s second(s).""" %
                    (job.updated_on.strftime(HUMAN_READABLE_TIME_FORMAT),
                     job.execution_time_sec))
            elif job.status_code == jobs.STATUS_CODE_FAILED:
                update_message = safe_dom.NodeList().append(
                    safe_dom.Text("""
                        There was an error updating enrollment/assessment
                        statistics. Here is the message:""")).append(
                        safe_dom.Element('br')).append(
                            safe_dom.Element('blockquote').add_child(
                                safe_dom.Element('pre').add_text('\n%s' %
                                                                 job.output)))
            else:
                update_message = safe_dom.Text(
                    'Enrollment and assessment statistics update started at %s'
                    ' and is running now. Please come back shortly.' %
                    job.updated_on.strftime(HUMAN_READABLE_TIME_FORMAT))

        subtemplate_values['stats_calculated'] = stats_calculated
        subtemplate_values['errors'] = errors
        subtemplate_values['update_message'] = update_message

        return jinja2.utils.Markup(
            self.get_template('basic_analytics.html',
                              [os.path.dirname(__file__)]).render(
                                  subtemplate_values, autoescape=True))
Пример #9
0
    def post(self):
        """Handles POST requests."""
        user = self.personalize_page_and_get_user()
        if not user:
            self.redirect(
                users.create_login_url(self.request.uri), normalize=False)
            return

        if not self.assert_xsrf_token_or_fail(self.request, 'register-post'):
            return

        can_register = self.app_context.get_environ(
            )['reg_form']['can_register']
        if not can_register:
            self.template_value['course_status'] = 'full'
        else:
            missing = self.find_missing_fields(self.request.POST)
            if missing:
                self.template_value['navbar'] = {'registration': True}
                self.template_value['content'] = '''
                <div class="gcb-col-11 gcb-aside">
                <h2>Something is missing...</h2>
                <p>You didn't fill out all the required fields in the registration form.
                Please use your browser's BACK button, and complete the form before
                submitting.</p>

                <p>Missing: {0}</p>

                <p>Thanks!</p>
                </div>
                '''.format(", ".join(missing))
                self.render('bare.html')
                return

            # We accept the form.  Now populate the student model:

            # create new or re-enroll old student
            student = Student.get_by_email(user.email())
            if not student:
                student = Student(key_name=user.email())
                student.user_id = user.user_id()

            student_by_uid = Student.get_student_by_user_id(user.user_id())
            is_valid_student = (student_by_uid is None or
                                student_by_uid.user_id == student.user_id)
            assert is_valid_student, (
                'Student\'s email and user id do not match.')

            student.user_id = user.user_id()
            student.is_enrolled = True

            string_fields = ('name', 'location_city',
                    'location_state', 'location_country',
                    'education_level', 'role',
                    'other_role')

            for field in string_fields:
                setattr(student, field, self.request.POST.get(field, None))

            string_list_fields = ('grade_levels', 'title_and_setting',
                    'research_area', 'faculty_area', 'student_subject')

            for field in string_list_fields:
                raw = self.request.POST.get(field, '')
                if len(raw) > 0:
                    values = [s.strip() for s in raw.split(',')]
                    setattr(student, field, values)

            student.put()

            # now that we're in full registration, don't subscribe to pre-reg any more
            #mailchimp.subscribe('pre-reg', user.email(), student.name)

            self.redirect('confirm')
            return

        # Render registration confirmation page
        self.template_value['navbar'] = {'registration': True}
        self.render('confirmation.html')
Пример #10
0
    def get_markup_for_basic_analytics(self, job):
        """Renders markup for basic enrollment and assessment analytics."""
        subtemplate_values = {}
        errors = []
        stats_calculated = False
        update_message = safe_dom.Text('')

        if not job:
            update_message = safe_dom.Text(
                'Enrollment/assessment statistics have not been calculated '
                'yet.')
        else:
            if job.status_code == jobs.STATUS_CODE_COMPLETED:
                stats = transforms.loads(job.output)
                stats_calculated = True

                #event = EventEntity().all().fetch(limit=400)
                cr = courses.Course(self).get_units()

                subtemplate_values['enrolled'] = stats['enrollment']['enrolled']
                subtemplate_values['unenrolled'] = (
                    stats['enrollment']['unenrolled'])
                subtemplate_values['submissions'] =  stats['id']

                scores = []
                total_records = 0
                names = []
                submissions = {}
                students = {}
                data = []

                for key, value in stats['id'].items():
                    students[key] = value

                course = courses.Course(self)
                problems = course.get_assessment_list()
                assessments = dict( (a.unit_id, a.title) for a in problems)

                lesson_list = []
                unit_list = []
                units = course.get_units()
                for u in units:
                    lessons = course.get_lessons(u.unit_id)    
                    for l in lessons:
                        single = {}
                        single['lesson_unit'] = l.unit_id
                        single['lesson_id'] = l.lesson_id
                        single['lesson_title'] = l.title
                        lesson_list.append(single)
                    if u.type == 'U':
                        un = {}
                        un['index'] = u._index
                        un['id'] = u.unit_id
                        un['title'] = u.title
                        unit_list.append(un)

                tmp_unit = {}
                for l in lesson_list:
                    tmp_unit[l['lesson_unit']] = []

                for l in lesson_list:
                    tmp_unit[l['lesson_unit']].append(l)

                struct = []
                for key, value in tmp_unit.items():
                    unit = {}
                    for u in unit_list:
                        if u['index'] == key:
                            unit['id'] = u['id']
                            unit['title'] = u['title']
                    unit['lessons'] = value
                    unit['lesson_count'] = len(value)
                    struct.append(unit)

                for sname, sid in students.items():
                    st = Student.get_student_by_user_id(sid)
                    sc = course.get_all_scores(st)
                    data.append({'name': sname, 'scores': sc})
                
                for key, value in stats['scores'].items():
                    total_records += value[0]
                    avg = round(value[1] / value[0], 1) if value[0] else 0
                    scores.append({'key': key, 'completed': value[0],
                                   'avg': avg})

                subtemplate_values['scores'] = scores
                subtemplate_values['total_records'] = total_records
                subtemplate_values['names'] = names
                subtemplate_values['data'] = data
                subtemplate_values['struct'] = struct

                update_message = safe_dom.Text("""
                    Enrollment and assessment statistics were last updated at
                    %s in about %s second(s).""" % (
                        job.updated_on.strftime(HUMAN_READABLE_TIME_FORMAT),
                        job.execution_time_sec))
            elif job.status_code == jobs.STATUS_CODE_FAILED:
                update_message = safe_dom.NodeList().append(
                    safe_dom.Text("""
                        There was an error updating enrollment/assessment
                        statistics. Here is the message:""")
                ).append(
                    safe_dom.Element('br')
                ).append(
                    safe_dom.Element('blockquote').add_child(
                        safe_dom.Element('pre').add_text('\n%s' % job.output)))
            else:
                update_message = safe_dom.Text(
                    'Enrollment and assessment statistics update started at %s'
                    ' and is running now. Please come back shortly.' %
                    job.updated_on.strftime(HUMAN_READABLE_TIME_FORMAT))

        subtemplate_values['stats_calculated'] = stats_calculated
        subtemplate_values['errors'] = errors
        subtemplate_values['update_message'] = update_message

        return jinja2.utils.Markup(self.get_template(
            'basic_analytics.html', [os.path.dirname(__file__)]
        ).render(subtemplate_values, autoescape=True))