Beispiel #1
0
 def test_fetch_video(self):
     video_value = 'test_video_id'
     with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id):
         CourseDetails.update_about_video(self.course, video_value, self.user.id)
     assert CourseDetails.fetch_youtube_video_id(self.course.id) == video_value
     video_url = CourseDetails.fetch_video_url(self.course.id)
     self.assertRegex(video_url, fr'http://.*{video_value}')
 def test_fetch_video(self):
     video_value = 'test_video_id'
     with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id):
         CourseDetails.update_about_video(self.course, video_value, self.user.id)
     self.assertEqual(CourseDetails.fetch_youtube_video_id(self.course.id), video_value)
     video_url = CourseDetails.fetch_video_url(self.course.id)
     self.assertRegexpMatches(video_url, r'http://.*{}'.format(video_value))
 def test_fetch_video(self):
     video_value = 'test_video_id'
     with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id):
         CourseDetails.update_about_video(self.course, video_value, self.user.id)
     self.assertEqual(CourseDetails.fetch_youtube_video_id(self.course.id), video_value)
     video_url = CourseDetails.fetch_video_url(self.course.id)
     self.assertRegexpMatches(video_url, r'http://.*{}'.format(video_value))
 def test_basic(self):
     expected_data = {
         'course_id': u'edX/toy/2012_Fall',
         'name': u'Toy Course',
         'number': u'toy',
         'org': u'edX',
         'short_description': u'A course about toys.',
         'media': {
             'course_image': {
                 'uri': u'/c4x/edX/toy/asset/just_a_test.jpg',
             },
             'course_video': {
                 'uri': u'http://www.youtube.com/watch?v=test_youtube_id',
             }
         },
         'start': u'2015-07-17T12:00:00Z',
         'start_type': u'timestamp',
         'start_display': u'July 17, 2015',
         'end': u'2015-09-19T18:00:00Z',
         'enrollment_start': u'2015-06-15T00:00:00Z',
         'enrollment_end': u'2015-07-15T00:00:00Z',
         'blocks_url': u'http://testserver/api/courses/v1/blocks/?course_id=edX%2Ftoy%2F2012_Fall',
         'effort': u'6 hours',
     }
     course = self.create_course()
     CourseDetails.update_about_video(course, 'test_youtube_id', self.staff_user.id)  # pylint: disable=no-member
     result = self._get_result(course)
     self.assertDictEqual(result, expected_data)
 def test_basic(self):
     expected_data = {
         'course_id': u'edX/toy/2012_Fall',
         'name': u'Toy Course',
         'number': u'toy',
         'org': u'edX',
         'short_description': u'A course about toys.',
         'media': {
             'course_image': {
                 'uri': u'/c4x/edX/toy/asset/just_a_test.jpg',
             },
             'course_video': {
                 'uri': u'http://www.youtube.com/watch?v=test_youtube_id',
             }
         },
         'start': u'2015-07-17T12:00:00Z',
         'start_type': u'timestamp',
         'start_display': u'July 17, 2015',
         'end': u'2015-09-19T18:00:00Z',
         'enrollment_start': u'2015-06-15T00:00:00Z',
         'enrollment_end': u'2015-07-15T00:00:00Z',
         'blocks_url':
         u'http://testserver/api/courses/v1/blocks/?course_id=edX%2Ftoy%2F2012_Fall',
         'effort': u'6 hours',
     }
     course = self.create_course()
     CourseDetails.update_about_video(course, 'test_youtube_id',
                                      self.staff_user.id)  # pylint: disable=no-member
     result = self._get_result(course)
     self.assertDictEqual(result, expected_data)
 def test_basic(self):
     course = self.create_course()
     CourseDetails.update_about_video(course, 'test_youtube_id',
                                      self.staff_user.id)
     with check_mongo_calls(self.expected_mongo_calls):
         result = self._get_result(course)
     self.assertDictEqual(result, self.expected_data)
 def test_fetch_about_attribute(self, attribute_name):
     attribute_value = 'test_value'
     with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred,
                                    self.course.id):
         CourseDetails.update_about_item(self.course, attribute_name,
                                         attribute_value, self.user.id)
     assert CourseDetails.fetch_about_attribute(
         self.course.id, attribute_name) == attribute_value
 def test_fetch_about_attribute_error(self):
     attribute_name = 'not_an_about_attribute'
     with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred,
                                    self.course.id):
         CourseDetails.update_about_item(self.course, attribute_name,
                                         'test_value', self.user.id)
     with pytest.raises(ValueError):
         CourseDetails.fetch_about_attribute(self.course.id, attribute_name)
    def test_toggle_pacing_during_course_run(self):
        SelfPacedConfiguration(enabled=True).save()
        self.course.start = datetime.datetime.now()
        self.store.update_item(self.course, self.user.id)

        details = CourseDetails.fetch(self.course.id)
        with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id):
            updated_details = CourseDetails.update_from_json(
                self.course.id, dict(details.__dict__, self_paced=True), self.user
            )
        self.assertFalse(updated_details.self_paced)
    def test_toggle_pacing_during_course_run(self):
        self.course.start = datetime.datetime.now()
        self.store.update_item(self.course, self.user.id)

        details = CourseDetails.fetch(self.course.id)
        with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred,
                                       self.course.id):
            updated_details = CourseDetails.update_from_json(
                self.course.id, dict(details.__dict__, self_paced=True),
                self.user)
        assert not updated_details.self_paced
Beispiel #11
0
def _create_new_course(subject, org, number, run, fields):
    """
    Create a new course.
    Raises DuplicateCourseError if the course already exists
    """
    org_data = get_organization_by_short_name(org)
    if not org_data and organizations_enabled():
        return
    store_for_new_course = modulestore().default_modulestore.get_modulestore_type()
    try:
        user = User.objects.get(username='******')
    except User.DoesNotExist:
        user = User.objects.create(
            username='******',
            email='*****@*****.**',
            first_name='coursecreator',
            last_name='coursecreator',
            is_active=True,
            is_staff=True
        )
        user.set_password('coursecreator')
        user.save()
    try:
        new_course = create_new_course_in_store(store_for_new_course, user, org, number, run, fields)

    except DuplicateCourseError:
        existing_course_key = SlashSeparatedCourseKey.from_deprecated_string('course-v1:'+org+'+'+number+'+'+run)
        new_course = get_course_by_id(existing_course_key)

    add_organization_course(org_data, new_course.id)

    # Set description and images for the course
    course_image_name, course_image_asset_path = store_jacket_image(
        new_course.id, settings.VODECLIC_COURSE_IMAGE_LOCATION,
        subject.get("id") + ".png"
    )
    additional_info = {
        'display_name': subject.get('title'),
        'language': subject.get('language', 'fr'),
        'short_description': subject.get('description', ''),
        'intro_video': None,
        'course_image_name': course_image_name,
        'course_image_asset_path': course_image_asset_path,
        'start_date': new_course.start,
        'end_date': new_course.end,
        'enrollment_start': new_course.start,
        'enrollment_end': new_course.end
    }

    CourseDetails.update_from_json(new_course.id, additional_info, user)
 def get_course_description(self,
                            bot,
                            chat_id,
                            course_name=None,
                            course_key=None,
                            enroll=None,
                            enroll_keyboard=False):
     """
     Get description of particular courses by Title or by course_id
     """
     bot.sendChatAction(chat_id=chat_id, action=ChatAction.TYPING)
     if enroll:
         result = CourseEnrollment.objects.get(id=enroll)
         results = [modulestore().get_course(result.course_id)]
         course_name = results[0].display_name_with_default
     elif course_key:
         results = [modulestore().get_course(course_key)]
         course_name = modulestore().get_course(
             course_key).display_name_with_default
     else:
         results = modulestore().get_courses()
         results = [
             course for course in results
             if course.scope_ids.block_type == 'course'
         ]
     for each in results:
         if each.display_name_with_default == course_name:
             message = truncate_course_info(
                 CourseDetails.fetch_about_attribute(each.id, 'overview'))
             if message == 'null':
                 bot.sendMessage(
                     chat_id=chat_id,
                     text="I'm sorry, but this course has no description")
             else:
                 bot.sendMessage(chat_id=chat_id,
                                 text="*Short course description*",
                                 parse_mode=telegram.ParseMode.MARKDOWN)
                 course_key = each.id
                 current_site = Site.objects.get_current()
                 course_title = modulestore().get_course(
                     course_key).display_name_with_default
                 course_url = '[%s](%scourses/%s/)' % (
                     course_title, current_site, each.id)
                 bot.sendMessage(chat_id=chat_id,
                                 text=course_url,
                                 parse_mode=telegram.ParseMode.MARKDOWN)
                 if enroll_keyboard:
                     reply_markup = InlineKeyboardMarkup([[
                         InlineKeyboardButton(
                             text='I like it and I want to enroll',
                             callback_data=json.dumps(
                                 {'key': str(course_key)}))
                     ]])
                     bot.sendMessage(chat_id=chat_id,
                                     text=message,
                                     reply_markup=reply_markup)
                 else:
                     bot.sendMessage(chat_id=chat_id, text=message)
             break
     bot.sendMessage(chat_id=chat_id, reply_markup=ReplyKeyboardHide())
 def test_virgin_fetch(self):
     details = CourseDetails.fetch(self.course.id)
     self.assertEqual(details.org, self.course.location.org,
                      "Org not copied into")
     self.assertEqual(details.course_id, self.course.location.course,
                      "Course_id not copied into")
     self.assertEqual(details.run, self.course.location.name,
                      "Course name not copied into")
     self.assertEqual(details.course_image_name, self.course.course_image)
     self.assertIsNotNone(details.start_date.tzinfo)
     self.assertIsNone(
         details.end_date,
         "end date somehow initialized " + str(details.end_date))
     self.assertIsNone(
         details.enrollment_start,
         "enrollment_start date somehow initialized " +
         str(details.enrollment_start))
     self.assertIsNone(
         details.enrollment_end,
         "enrollment_end date somehow initialized " +
         str(details.enrollment_end))
     self.assertIsNone(
         details.syllabus,
         "syllabus somehow initialized" + str(details.syllabus))
     self.assertIsNone(
         details.intro_video,
         "intro_video somehow initialized" + str(details.intro_video))
     self.assertIsNone(details.effort,
                       "effort somehow initialized" + str(details.effort))
     self.assertIsNone(
         details.language,
         "language somehow initialized" + str(details.language))
     self.assertFalse(details.self_paced)
Beispiel #14
0
 def get_overview(self, course_overview):
     """
     Get the representation for SerializerMethodField `overview`
     """
     # Note: This makes a call to the modulestore, unlike the other
     # fields from CourseSerializer, which get their data
     # from the CourseOverview object in SQL.
     return CourseDetails.fetch_about_attribute(course_overview.id, 'overview')
 def get_overview(self, course_overview):
     """
     Get the representation for SerializerMethodField `overview`
     """
     # Note: This makes a call to the modulestore, unlike the other
     # fields from CourseSerializer, which get their data
     # from the CourseOverview object in SQL.
     return CourseDetails.fetch_about_attribute(course_overview.id, 'overview')
Beispiel #16
0
    def test_changes_on_webview(self):
        # Prepare attributes to check for
        CourseDetails.update_about_item(self.course, 'short_description',
                                        'Edraak Test Description',
                                        self.user.id)

        # Creating a certificate
        self._add_course_certificates(count=1, signatory_count=2)
        self._create_edraak_test_template()
        test_url = get_certificate_url(user_id=self.user.id,
                                       course_id=unicode(self.course.id))

        # Getting certificate as HTML
        response = self.client.get(test_url)

        # Verifying contents
        self.assertContains(response, 'Edraak Template')
        self.assertContains(response,
                            'course_description: Edraak Test Description')
Beispiel #17
0
 def get_minimum_age(self, course_overview):
     """
     Get the representation for SerializerMethodField `minimum_age`
     Represents the minimum enrollment age for the course
     """
     # Note: This makes a call to the modulestore, unlike the other
     # fields from CourseSerializer, which get their data
     # from the CourseOverview object in SQL.
     courseDetails = CourseDetails.fetch(course_overview.id)
     return courseDetails.minimum_age
Beispiel #18
0
    def test_updates_values_in_mongo_should_be_updated_in_sql(self):
        """ Test that a already existing course is correctly updated
            by update_course management command.
        """
        mongo_course = CourseFactory.create(short_description='test')
        # short_description field is required by FUN Course model
        CourseDetails.update_about_item(
            mongo_course, 'short_description', u"Short description", None)

        self.assertFalse(FUNCourse.objects.all().exists())
        call_command('update_courses', course_id=unicode(mongo_course.id))

        self.assertTrue(u"Short description",
            FUNCourse.objects.get(key=mongo_course.id).short_description)

        CourseDetails.update_about_item(
            mongo_course, 'short_description', u"Short description changed",
            None)
        call_command('update_courses', course_id=unicode(mongo_course.id))

        self.assertEqual(
            u"Short description changed",
            FUNCourse.objects.get(key=mongo_course.id).short_description)
 def get_course_description(
     self, bot, chat_id, course_name=None, course_key=None, enroll=None, enroll_keyboard=False
 ):
     """
     Get description of particular courses by Title or by course_id
     """
     bot.sendChatAction(chat_id=chat_id, action=ChatAction.TYPING)
     if enroll:
         result = CourseEnrollment.objects.get(id=enroll)
         results = [modulestore().get_course(result.course_id)]
         course_name = results[0].display_name_with_default
     elif course_key:
         results = [modulestore().get_course(course_key)]
         course_name = modulestore().get_course(course_key).display_name_with_default
     else:
         results = modulestore().get_courses()
         results = [course for course in results if course.scope_ids.block_type == "course"]
     for each in results:
         if each.display_name_with_default == course_name:
             message = truncate_course_info(CourseDetails.fetch_about_attribute(each.id, "overview"))
             if message == "null":
                 bot.sendMessage(chat_id=chat_id, text="I'm sorry, but this course has no description")
             else:
                 bot.sendMessage(
                     chat_id=chat_id, text="*Short course description*", parse_mode=telegram.ParseMode.MARKDOWN
                 )
                 course_key = each.id
                 current_site = Site.objects.get_current()
                 course_title = modulestore().get_course(course_key).display_name_with_default
                 course_url = "[%s](%scourses/%s/)" % (course_title, current_site, each.id)
                 bot.sendMessage(chat_id=chat_id, text=course_url, parse_mode=telegram.ParseMode.MARKDOWN)
                 if enroll_keyboard:
                     reply_markup = InlineKeyboardMarkup(
                         [
                             [
                                 InlineKeyboardButton(
                                     text="I like it and I want to enroll",
                                     callback_data=json.dumps({"key": str(course_key)}),
                                 )
                             ]
                         ]
                     )
                     bot.sendMessage(chat_id=chat_id, text=message, reply_markup=reply_markup)
                 else:
                     bot.sendMessage(chat_id=chat_id, text=message)
             break
     bot.sendMessage(chat_id=chat_id, reply_markup=ReplyKeyboardHide())
Beispiel #20
0
def get_coursed_and_create_matrix():
    results = [course for course in modulestore().get_courses() if course.scope_ids.block_type == "course"]
    new_matrix = TfidMatrixAllCourses.objects.all().first() or TfidMatrixAllCourses()
    print new_matrix.matrix.shape[0] != len(results)
    if new_matrix.matrix.shape[0] != len(results):
        all_courses = [re.sub("<[^>]*>", "", CourseDetails.fetch_about_attribute(x.id, "overview")) for x in results]

        MatrixEdxCoursesId.objects.all().delete()
        map(lambda x: MatrixEdxCoursesId.objects.create(course_key=x.id, course_index=results.index(x)), results)

        stemmer = snowballstemmer.stemmer("english")
        courses_stem = [" ".join(stemmer.stemWords(x.split())) for x in all_courses]

        vect = TfidfVectorizer(stop_words=get_stop_words(), lowercase=True, dtype=np.float32)
        matrix = vect.fit_transform(courses_stem)
        new_matrix.matrix = matrix
        new_matrix.save()
Beispiel #21
0
def get_coursed_and_create_matrix():
    results = [course for course in modulestore().get_courses() if
               course.scope_ids.block_type == 'course']
    new_matrix = TfidMatrixAllCourses.objects.all().first() or TfidMatrixAllCourses()
    print new_matrix.matrix.shape[0] != len(results)
    if new_matrix.matrix.shape[0] != len(results):
        all_courses = [re.sub('<[^>]*>', '', CourseDetails.fetch_about_attribute(x.id, 'overview')) for x in results]

        MatrixEdxCoursesId.objects.all().delete()
        map(lambda x: MatrixEdxCoursesId.objects.create(course_key=x.id, course_index=results.index(x)), results)

        stemmer = snowballstemmer.stemmer('english')
        courses_stem = [' '.join(stemmer.stemWords(x.split())) for x in all_courses]

        vect = TfidfVectorizer(stop_words=get_stop_words(), lowercase=True, dtype=np.float32)
        matrix = vect.fit_transform(courses_stem)
        new_matrix.matrix = matrix
        new_matrix.save()
Beispiel #22
0
    def update_course(self, mongo_course, assign_universities=False):
        '''
        For the given course, we create or update the corresponding
        course in SQL Course table.
        '''

        course_handler = CourseHandler(mongo_course)
        key = course_handler.key
        self.stdout.write('Updating data for course {}\n'.format(key))
        course, was_created = Course.objects.get_or_create(key=key)
        if was_created or assign_universities:
            university = course_handler.assign_university(course)
            if university:
                self.stdout.write(
                    '\t University assigned to "{}"\n'.format(key))
            else:
                self.stdout.write(
                    '\t No university assigned to "{}"\n'.format(key))
        course.is_active = True
        course.university_display_name = course_handler.university_name
        course.title = course_handler.title
        course.image_url = course_handler.image_url
        thumbnails_info = {}
        for thumbnail_alias, thumbnails_options in \
                courses_settings.FUN_THUMBNAIL_OPTIONS.items():
            thumbnail = course_handler.make_thumbnail(thumbnails_options)
            if thumbnail:
                thumbnails_info[thumbnail_alias] = thumbnail.url
        course.thumbnails_info = thumbnails_info
        course.start_date = mongo_course.start
        course.enrollment_start_date = mongo_course.enrollment_start
        course.enrollment_end_date = mongo_course.enrollment_end
        course.end_date = mongo_course.end

        course_key = CourseKey.from_string(key)
        course.short_description = CourseDetails.fetch_about_attribute(
            course_key,
            'short_description',
        )

        course.save()
        del course
        self.stdout.write('Updated course {}\n'.format(key))
        return None
 def test_virgin_fetch(self):
     details = CourseDetails.fetch(self.course.id)
     self.assertEqual(details.org, self.course.location.org, "Org not copied into")
     self.assertEqual(details.course_id, self.course.location.course, "Course_id not copied into")
     self.assertEqual(details.run, self.course.location.name, "Course name not copied into")
     self.assertEqual(details.course_image_name, self.course.course_image)
     self.assertIsNotNone(details.start_date.tzinfo)
     self.assertIsNone(details.end_date, "end date somehow initialized " + str(details.end_date))
     self.assertIsNone(
         details.enrollment_start, "enrollment_start date somehow initialized " + str(details.enrollment_start)
     )
     self.assertIsNone(
         details.enrollment_end, "enrollment_end date somehow initialized " + str(details.enrollment_end)
     )
     self.assertIsNone(details.syllabus, "syllabus somehow initialized" + str(details.syllabus))
     self.assertIsNone(details.intro_video, "intro_video somehow initialized" + str(details.intro_video))
     self.assertIsNone(details.effort, "effort somehow initialized" + str(details.effort))
     self.assertIsNone(details.language, "language somehow initialized" + str(details.language))
     self.assertFalse(details.self_paced)
Beispiel #24
0
 def test_virgin_fetch(self):
     details = CourseDetails.fetch(self.course.id)
     assert details.org == self.course.location.org, 'Org not copied into'
     assert details.course_id == self.course.location.course, 'Course_id not copied into'
     assert details.run == self.course.location.block_id, 'Course name not copied into'
     assert details.course_image_name == self.course.course_image
     assert details.start_date.tzinfo is not None
     assert details.end_date is None, ('end date somehow initialized ' + str(details.end_date))
     assert details.enrollment_start is None,\
         ('enrollment_start date somehow initialized ' + str(details.enrollment_start))
     assert details.enrollment_end is None,\
         ('enrollment_end date somehow initialized ' + str(details.enrollment_end))
     assert details.certificate_available_date is None,\
         ('certificate_available_date date somehow initialized ' + str(details.certificate_available_date))
     assert details.syllabus is None, ('syllabus somehow initialized' + str(details.syllabus))
     assert details.intro_video is None, ('intro_video somehow initialized' + str(details.intro_video))
     assert details.effort is None, ('effort somehow initialized' + str(details.effort))
     assert details.language is None, ('language somehow initialized' + str(details.language))
     assert not details.self_paced
Beispiel #25
0
    def update_course(self, mongo_course, assign_universities=False):
        '''
        For the given course, we create or update the corresponding
        course in SQL Course table.
        '''

        course_handler = CourseHandler(mongo_course)
        key = course_handler.key
        self.stdout.write('Updating data for course {}\n'.format(key))
        course, was_created = Course.objects.get_or_create(key=key)
        if was_created or assign_universities:
            university = course_handler.assign_university(course)
            if university:
                self.stdout.write('\t University assigned to "{}"\n'.format(key))
            else:
                self.stdout.write('\t No university assigned to "{}"\n'.format(key))
        course.is_active = True
        course.university_display_name = course_handler.university_name
        course.title = course_handler.title
        course.image_url = course_handler.image_url
        thumbnails_info = {}
        for thumbnail_alias, thumbnails_options in \
                courses_settings.FUN_THUMBNAIL_OPTIONS.items():
            thumbnail = course_handler.make_thumbnail(thumbnails_options)
            if thumbnail:
                thumbnails_info[thumbnail_alias] = thumbnail.url
        course.thumbnails_info = thumbnails_info
        course.start_date = mongo_course.start
        course.enrollment_start_date = mongo_course.enrollment_start
        course.enrollment_end_date = mongo_course.enrollment_end
        course.end_date = mongo_course.end

        course_key = CourseKey.from_string(key)
        course.short_description = CourseDetails.fetch_about_attribute(
            course_key,
            'short_description',
        )

        course.save()
        del course
        self.stdout.write('Updated course {}\n'.format(key))
        return None
Beispiel #26
0
 def setUpClass(cls):
     super().setUpClass()
     cls.course = CourseFactory.create()
     cls.course_without_about = CourseFactory.create(
         catalog_visibility=CATALOG_VISIBILITY_NONE)
     cls.course_with_about = CourseFactory.create(
         catalog_visibility=CATALOG_VISIBILITY_ABOUT)
     cls.purchase_course = CourseFactory.create(
         org='MITx', number='buyme', display_name='Course To Buy')
     CourseDetails.update_about_item(cls.course, 'overview',
                                     'OOGIE BLOOGIE', None)
     CourseDetails.update_about_item(cls.course_without_about, 'overview',
                                     'WITHOUT ABOUT', None)
     CourseDetails.update_about_item(cls.course_with_about, 'overview',
                                     'WITH ABOUT', None)
 def test_update_and_fetch(self):
     jsondetails = CourseDetails.fetch(self.course.id)
     jsondetails.syllabus = "<a href='foo'>bar</a>"
     # encode - decode to convert date fields and other data which changes form
     with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred,
                                    self.course.id):
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).syllabus,
             jsondetails.syllabus, "After set syllabus")
         jsondetails.short_description = "Short Description"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).short_description,
             jsondetails.short_description, "After set short_description")
         jsondetails.overview = "Overview"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).overview,
             jsondetails.overview, "After set overview")
         jsondetails.intro_video = "intro_video"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).intro_video,
             jsondetails.intro_video, "After set intro_video")
         jsondetails.effort = "effort"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).effort,
             jsondetails.effort, "After set effort")
         jsondetails.self_paced = True
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).self_paced,
             jsondetails.self_paced)
         jsondetails.start_date = datetime.datetime(2010,
                                                    10,
                                                    1,
                                                    0,
                                                    tzinfo=UTC)
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).start_date,
             jsondetails.start_date)
         jsondetails.end_date = datetime.datetime(2011,
                                                  10,
                                                  1,
                                                  0,
                                                  tzinfo=UTC)
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).end_date,
             jsondetails.end_date)
         jsondetails.certificate_available_date = datetime.datetime(
             2010, 10, 1, 0, tzinfo=UTC)
         self.assertEqual(
             CourseDetails.update_from_json(
                 self.course.id, jsondetails.__dict__,
                 self.user).certificate_available_date,
             jsondetails.certificate_available_date)
         jsondetails.course_image_name = "an_image.jpg"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).course_image_name,
             jsondetails.course_image_name)
         jsondetails.banner_image_name = "an_image.jpg"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).banner_image_name,
             jsondetails.banner_image_name)
         jsondetails.video_thumbnail_image_name = "an_image.jpg"
         self.assertEqual(
             CourseDetails.update_from_json(
                 self.course.id, jsondetails.__dict__,
                 self.user).video_thumbnail_image_name,
             jsondetails.video_thumbnail_image_name)
         jsondetails.language = "hr"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).language,
             jsondetails.language)
         jsondetails.learning_info = ["test", "test"]
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).learning_info,
             jsondetails.learning_info)
         jsondetails.instructor_info = {
             "instructors": [{
                 "name": "test",
                 "title": "test",
                 "organization": "test",
                 "image": "test",
                 "bio": "test"
             }]
         }
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).instructor_info,
             jsondetails.instructor_info)
 def test_update_and_fetch(self):
     SelfPacedConfiguration(enabled=True).save()
     jsondetails = CourseDetails.fetch(self.course.id)
     jsondetails.syllabus = "<a href='foo'>bar</a>"
     # encode - decode to convert date fields and other data which changes form
     with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred,
                                    self.course.id):
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).syllabus,
             jsondetails.syllabus, "After set syllabus")
         jsondetails.short_description = "Short Description"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).short_description,
             jsondetails.short_description, "After set short_description")
         jsondetails.overview = "Overview"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).overview,
             jsondetails.overview, "After set overview")
         jsondetails.intro_video = "intro_video"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).intro_video,
             jsondetails.intro_video, "After set intro_video")
         jsondetails.effort = "effort"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).effort,
             jsondetails.effort, "After set effort")
         jsondetails.self_paced = True
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).self_paced,
             jsondetails.self_paced)
         jsondetails.start_date = datetime.datetime(2010,
                                                    10,
                                                    1,
                                                    0,
                                                    tzinfo=UTC())
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).start_date,
             jsondetails.start_date)
         jsondetails.end_date = datetime.datetime(2011,
                                                  10,
                                                  1,
                                                  0,
                                                  tzinfo=UTC())
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).end_date,
             jsondetails.end_date)
         jsondetails.course_image_name = "an_image.jpg"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).course_image_name,
             jsondetails.course_image_name)
         jsondetails.language = "hr"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id,
                                            jsondetails.__dict__,
                                            self.user).language,
             jsondetails.language)
Beispiel #29
0
 def get_effort(self, course):
     """
     Get the representation for SerializerMethodField `effort`
     """
     return CourseDetails.fetch_effort(course.id)
Beispiel #30
0
    def _create_or_update(cls, course):
        """
        Creates or updates a CourseOverview object from a CourseDescriptor.

        Does not touch the database, simply constructs and returns an overview
        from the given course.

        Arguments:
            course (CourseDescriptor): any course descriptor object

        Returns:
            CourseOverview: created or updated overview extracted from the given course
        """
        from lms.djangoapps.certificates.api import get_active_web_certificate
        from openedx.core.lib.courses import course_image_url

        # Workaround for a problem discovered in https://openedx.atlassian.net/browse/TNL-2806.
        # If the course has a malformed grading policy such that
        # course._grading_policy['GRADE_CUTOFFS'] = {}, then
        # course.lowest_passing_grade will raise a ValueError.
        # Work around this for now by defaulting to None.
        try:
            lowest_passing_grade = course.lowest_passing_grade
        except ValueError:
            lowest_passing_grade = None

        display_name = course.display_name
        start = course.start
        end = course.end
        max_student_enrollments_allowed = course.max_student_enrollments_allowed
        if isinstance(course.id, CCXLocator):
            from lms.djangoapps.ccx.utils import get_ccx_from_ccx_locator
            ccx = get_ccx_from_ccx_locator(course.id)
            display_name = ccx.display_name
            start = ccx.start
            end = ccx.due
            max_student_enrollments_allowed = ccx.max_student_enrollments_allowed

        course_overview = cls.objects.filter(id=course.id)
        if course_overview.exists():
            log.info(u'Updating course overview for %s.',
                     six.text_type(course.id))
            course_overview = course_overview.first()
        else:
            log.info(u'Creating course overview for %s.',
                     six.text_type(course.id))
            course_overview = cls()

        course_overview.version = cls.VERSION
        course_overview.id = course.id
        course_overview._location = course.location
        course_overview.org = course.location.org
        course_overview.display_name = display_name
        course_overview.display_number_with_default = course.display_number_with_default
        course_overview.display_org_with_default = course.display_org_with_default

        course_overview.start = start
        course_overview.end = end
        course_overview.advertised_start = course.advertised_start
        course_overview.announcement = course.announcement

        course_overview.course_image_url = course_image_url(course)
        course_overview.social_sharing_url = course.social_sharing_url

        course_overview.certificates_display_behavior = course.certificates_display_behavior
        course_overview.certificates_show_before_end = course.certificates_show_before_end
        course_overview.cert_html_view_enabled = course.cert_html_view_enabled
        course_overview.has_any_active_web_certificate = (
            get_active_web_certificate(course) is not None)
        course_overview.cert_name_short = course.cert_name_short
        course_overview.cert_name_long = course.cert_name_long
        course_overview.certificate_available_date = course.certificate_available_date
        course_overview.lowest_passing_grade = lowest_passing_grade
        course_overview.end_of_course_survey_url = course.end_of_course_survey_url

        course_overview.days_early_for_beta = course.days_early_for_beta
        course_overview.mobile_available = course.mobile_available
        course_overview.visible_to_staff_only = course.visible_to_staff_only
        course_overview._pre_requisite_courses_json = json.dumps(
            course.pre_requisite_courses)

        course_overview.enrollment_start = course.enrollment_start
        course_overview.enrollment_end = course.enrollment_end
        course_overview.enrollment_domain = course.enrollment_domain
        course_overview.invitation_only = course.invitation_only
        course_overview.max_student_enrollments_allowed = max_student_enrollments_allowed

        course_overview.catalog_visibility = course.catalog_visibility
        course_overview.short_description = CourseDetails.fetch_about_attribute(
            course.id, 'short_description')
        course_overview.effort = CourseDetails.fetch_about_attribute(
            course.id, 'effort')
        course_overview.course_video_url = CourseDetails.fetch_video_url(
            course.id)
        course_overview.self_paced = course.self_paced

        if not CatalogIntegration.is_enabled():
            course_overview.language = course.language

        return course_overview
Beispiel #31
0
 def test_validate_certificate_settings_v1(self, stored_date,
                                           stored_behavior, expected_date,
                                           expected_behavior):
     """Test that method just returns passed in arguments if v2 is off"""
     assert CourseDetails.validate_certificate_settings(
         stored_date, stored_behavior) == (expected_date, expected_behavior)
 def test_fetch_about_attribute_error(self):
     attribute_name = 'not_an_about_attribute'
     with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id):
         CourseDetails.update_about_item(self.course, attribute_name, 'test_value', self.user.id)
     with self.assertRaises(ValueError):
         CourseDetails.fetch_about_attribute(self.course.id, attribute_name)
 def test_fetch_about_attribute(self, attribute_name):
     attribute_value = 'test_value'
     with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id):
         CourseDetails.update_about_item(self.course, attribute_name, attribute_value, self.user.id)
     self.assertEqual(CourseDetails.fetch_about_attribute(self.course.id, attribute_name), attribute_value)
Beispiel #34
0
    def _create_from_course(cls, course):
        """
        Creates a CourseOverview object from a CourseDescriptor.

        Does not touch the database, simply constructs and returns an overview
        from the given course.

        Arguments:
            course (CourseDescriptor): any course descriptor object

        Returns:
            CourseOverview: overview extracted from the given course
        """
        from lms.djangoapps.certificates.api import get_active_web_certificate
        from openedx.core.lib.courses import course_image_url

        log.info('Creating course overview for %s.', unicode(course.id))

        # Workaround for a problem discovered in https://openedx.atlassian.net/browse/TNL-2806.
        # If the course has a malformed grading policy such that
        # course._grading_policy['GRADE_CUTOFFS'] = {}, then
        # course.lowest_passing_grade will raise a ValueError.
        # Work around this for now by defaulting to None.
        try:
            lowest_passing_grade = course.lowest_passing_grade
        except ValueError:
            lowest_passing_grade = None

        display_name = course.display_name
        start = course.start
        end = course.end
        max_student_enrollments_allowed = course.max_student_enrollments_allowed
        if isinstance(course.id, CCXLocator):
            from lms.djangoapps.ccx.utils import get_ccx_from_ccx_locator
            ccx = get_ccx_from_ccx_locator(course.id)
            display_name = ccx.display_name
            start = ccx.start
            end = ccx.due
            max_student_enrollments_allowed = ccx.max_student_enrollments_allowed

        return cls(
            version=cls.VERSION,
            id=course.id,
            _location=course.location,
            org=course.location.org,
            display_name=display_name,
            display_number_with_default=course.display_number_with_default,
            display_org_with_default=course.display_org_with_default,

            start=start,
            end=end,
            advertised_start=course.advertised_start,
            announcement=course.announcement,

            course_image_url=course_image_url(course),
            social_sharing_url=course.social_sharing_url,

            certificates_display_behavior=course.certificates_display_behavior,
            certificates_show_before_end=course.certificates_show_before_end,
            cert_html_view_enabled=course.cert_html_view_enabled,
            has_any_active_web_certificate=(get_active_web_certificate(course) is not None),
            cert_name_short=course.cert_name_short,
            cert_name_long=course.cert_name_long,
            lowest_passing_grade=lowest_passing_grade,
            end_of_course_survey_url=course.end_of_course_survey_url,

            days_early_for_beta=course.days_early_for_beta,
            mobile_available=course.mobile_available,
            visible_to_staff_only=course.visible_to_staff_only,
            _pre_requisite_courses_json=json.dumps(course.pre_requisite_courses),

            enrollment_start=course.enrollment_start,
            enrollment_end=course.enrollment_end,
            enrollment_domain=course.enrollment_domain,
            invitation_only=course.invitation_only,
            max_student_enrollments_allowed=max_student_enrollments_allowed,

            catalog_visibility=course.catalog_visibility,
            short_description=CourseDetails.fetch_about_attribute(course.id, 'short_description'),
            effort=CourseDetails.fetch_about_attribute(course.id, 'effort'),
            course_video_url=CourseDetails.fetch_video_url(course.id),
            self_paced=course.self_paced,
        )
Beispiel #35
0
    def _create_from_course(cls, course):
        """
        Creates a CourseOverview object from a CourseDescriptor.

        Does not touch the database, simply constructs and returns an overview
        from the given course.

        Arguments:
            course (CourseDescriptor): any course descriptor object

        Returns:
            CourseOverview: overview extracted from the given course
        """
        from lms.djangoapps.certificates.api import get_active_web_certificate
        from openedx.core.lib.courses import course_image_url

        log.info('Creating course overview for %s.', unicode(course.id))

        # Workaround for a problem discovered in https://openedx.atlassian.net/browse/TNL-2806.
        # If the course has a malformed grading policy such that
        # course._grading_policy['GRADE_CUTOFFS'] = {}, then
        # course.lowest_passing_grade will raise a ValueError.
        # Work around this for now by defaulting to None.
        try:
            lowest_passing_grade = course.lowest_passing_grade
        except ValueError:
            lowest_passing_grade = None

        display_name = course.display_name
        start = course.start
        end = course.end
        max_student_enrollments_allowed = course.max_student_enrollments_allowed
        if isinstance(course.id, CCXLocator):
            from lms.djangoapps.ccx.utils import get_ccx_from_ccx_locator
            ccx = get_ccx_from_ccx_locator(course.id)
            display_name = ccx.display_name
            start = ccx.start
            end = ccx.due
            max_student_enrollments_allowed = ccx.max_student_enrollments_allowed

        return cls(
            version=cls.VERSION,
            id=course.id,
            _location=course.location,
            org=course.location.org,
            display_name=display_name,
            display_number_with_default=course.display_number_with_default,
            display_org_with_default=course.display_org_with_default,
            start=start,
            end=end,
            advertised_start=course.advertised_start,
            announcement=course.announcement,
            course_image_url=course_image_url(course),
            social_sharing_url=course.social_sharing_url,
            certificates_display_behavior=course.certificates_display_behavior,
            certificates_show_before_end=course.certificates_show_before_end,
            cert_html_view_enabled=course.cert_html_view_enabled,
            has_any_active_web_certificate=(get_active_web_certificate(course)
                                            is not None),
            cert_name_short=course.cert_name_short,
            cert_name_long=course.cert_name_long,
            lowest_passing_grade=lowest_passing_grade,
            end_of_course_survey_url=course.end_of_course_survey_url,
            days_early_for_beta=course.days_early_for_beta,
            mobile_available=course.mobile_available,
            visible_to_staff_only=course.visible_to_staff_only,
            _pre_requisite_courses_json=json.dumps(
                course.pre_requisite_courses),
            enrollment_start=course.enrollment_start,
            enrollment_end=course.enrollment_end,
            enrollment_domain=course.enrollment_domain,
            invitation_only=course.invitation_only,
            max_student_enrollments_allowed=max_student_enrollments_allowed,
            catalog_visibility=course.catalog_visibility,
            short_description=CourseDetails.fetch_about_attribute(
                course.id, 'short_description'),
            effort=CourseDetails.fetch_about_attribute(course.id, 'effort'),
            course_video_url=CourseDetails.fetch_video_url(course.id),
            self_paced=course.self_paced,
        )
Beispiel #36
0
    def _create_or_update(cls, course):  # lint-amnesty, pylint: disable=too-many-statements
        """
        Creates or updates a CourseOverview object from a CourseBlock.

        Does not touch the database, simply constructs and returns an overview
        from the given course.

        Arguments:
            course (CourseBlock): any course descriptor object

        Returns:
            CourseOverview: created or updated overview extracted from the given course
        """
        from lms.djangoapps.certificates.api import get_active_web_certificate
        from openedx.core.lib.courses import course_image_url

        # Workaround for a problem discovered in https://openedx.atlassian.net/browse/TNL-2806.
        # If the course has a malformed grading policy such that
        # course._grading_policy['GRADE_CUTOFFS'] = {}, then
        # course.lowest_passing_grade will raise a ValueError.
        # Work around this for now by defaulting to None.
        try:
            lowest_passing_grade = course.lowest_passing_grade
        except ValueError:
            lowest_passing_grade = None

        display_name = course.display_name
        start = course.start
        end = course.end
        max_student_enrollments_allowed = course.max_student_enrollments_allowed
        if isinstance(course.id, CCXLocator):
            from lms.djangoapps.ccx.utils import get_ccx_from_ccx_locator
            ccx = get_ccx_from_ccx_locator(course.id)
            display_name = ccx.display_name
            start = ccx.start
            end = ccx.due
            max_student_enrollments_allowed = ccx.max_student_enrollments_allowed

        course_overview = cls.objects.filter(id=course.id)
        if course_overview.exists():
            log.info('Updating course overview for %s.', str(course.id))
            course_overview = course_overview.first()
            # MySQL ignores casing, but CourseKey doesn't. To prevent multiple
            # courses with different cased keys from overriding each other, we'll
            # check for equality here in python.
            if course_overview.id != course.id:
                raise CourseOverviewCaseMismatchException(
                    course_overview.id, course.id)
        else:
            log.info('Creating course overview for %s.', str(course.id))
            course_overview = cls()

        course_overview.version = cls.VERSION
        course_overview.id = course.id
        course_overview._location = course.location  # lint-amnesty, pylint: disable=protected-access
        course_overview.org = course.location.org
        course_overview.display_name = display_name
        course_overview.display_number_with_default = course.display_number_with_default
        course_overview.display_org_with_default = course.display_org_with_default

        course_overview.start = start
        course_overview.end = end
        course_overview.advertised_start = course.advertised_start
        course_overview.announcement = course.announcement

        course_overview.banner_image_url = course_image_url(
            course, 'banner_image')
        course_overview.course_image_url = course_image_url(course)
        course_overview.social_sharing_url = course.social_sharing_url

        updated_available_date, updated_display_behavior = CourseDetails.validate_certificate_settings(
            course.certificate_available_date,
            course.certificates_display_behavior)

        course_overview.certificates_display_behavior = updated_display_behavior
        course_overview.certificate_available_date = updated_available_date
        course_overview.certificates_show_before_end = course.certificates_show_before_end
        course_overview.cert_html_view_enabled = course.cert_html_view_enabled
        course_overview.has_any_active_web_certificate = (
            get_active_web_certificate(course) is not None)
        course_overview.cert_name_short = course.cert_name_short
        course_overview.cert_name_long = course.cert_name_long
        course_overview.lowest_passing_grade = lowest_passing_grade
        course_overview.end_of_course_survey_url = course.end_of_course_survey_url

        course_overview.days_early_for_beta = course.days_early_for_beta
        course_overview.mobile_available = course.mobile_available
        course_overview.visible_to_staff_only = course.visible_to_staff_only
        course_overview._pre_requisite_courses_json = json.dumps(
            course.pre_requisite_courses)  # lint-amnesty, pylint: disable=protected-access

        course_overview.enrollment_start = course.enrollment_start
        course_overview.enrollment_end = course.enrollment_end
        course_overview.enrollment_domain = course.enrollment_domain
        course_overview.invitation_only = course.invitation_only
        course_overview.max_student_enrollments_allowed = max_student_enrollments_allowed

        course_overview.catalog_visibility = course.catalog_visibility
        course_overview.short_description = CourseDetails.fetch_about_attribute(
            course.id, 'short_description')
        course_overview.effort = CourseDetails.fetch_about_attribute(
            course.id, 'effort')
        course_overview.course_video_url = CourseDetails.fetch_video_url(
            course.id)
        course_overview.self_paced = course.self_paced

        course_overview.has_highlights = cls._get_course_has_highlights(course)

        course_overview.enable_proctored_exams = course.enable_proctored_exams
        course_overview.proctoring_provider = course.proctoring_provider
        course_overview.proctoring_escalation_email = course.proctoring_escalation_email
        course_overview.allow_proctoring_opt_out = course.allow_proctoring_opt_out

        course_overview.entrance_exam_enabled = course.entrance_exam_enabled
        # entrance_exam_id defaults to None in the course object, but '' is more reasonable for a string field
        course_overview.entrance_exam_id = course.entrance_exam_id or ''
        # Despite it being a float, the course object defaults to an int. So we will detect that case and update
        # it to be a float like everything else.
        if isinstance(course.entrance_exam_minimum_score_pct, int):
            course_overview.entrance_exam_minimum_score_pct = course.entrance_exam_minimum_score_pct / 100
        else:
            course_overview.entrance_exam_minimum_score_pct = course.entrance_exam_minimum_score_pct

        if not CatalogIntegration.is_enabled():
            course_overview.language = course.language

        return course_overview
Beispiel #37
0
 def test_validate_certificate_settings_v2(self, stored_date,
                                           stored_behavior, expected_date,
                                           expected_behavior):
     assert CourseDetails.validate_certificate_settings(
         stored_date, stored_behavior) == (expected_date, expected_behavior)
    def recommend(self, bot, chat_id, telegram_user):
        telegram_id = telegram_user.telegram_id
        if not LearningPredictionForUser.objects.filter(telegram_user=telegram_user):
            bot.sendMessage(
                chat_id=chat_id,
                text="It seems like I see you for the first time,"
                " please answer a few questions, so I'll be know more about you",
            )
            prediction.get_test_courses(telegram_id)
        test_courses = LearningPredictionForUser.objects.get(telegram_user=telegram_user).get_list()
        if len(test_courses) > 0:
            course_id = MatrixEdxCoursesId.objects.filter(course_index=test_courses[0]).first().course_key
            course_key = CourseKey.from_string(course_id)
            reply_markup = InlineKeyboardMarkup(
                [
                    [
                        InlineKeyboardButton(
                            text="I like it!", callback_data=json.dumps({"method": "learning", "kwargs": {}})
                        )
                    ],
                    [
                        InlineKeyboardButton(
                            text="Hmmm. I don't like at all!",
                            callback_data=json.dumps({"method": "learning", "kwargs": {"is_positive": False}}),
                        )
                    ],
                ]
            )
        else:
            predicted_course_id = prediction.prediction(telegram_id)

            if predicted_course_id == -1:
                bot.sendMessage(chat_id=chat_id, text="It seems like you have enrolled to all courses we have for now")
                return

            predicted_course_key = (
                MatrixEdxCoursesId.objects.filter(course_index=predicted_course_id).first().course_key
            )
            bot.sendMessage(chat_id=chat_id, text="Now I'm going to recommend you some great courses")
            course_key = CourseKey.from_string(predicted_course_key)

            course_for_user = PredictionForUser.objects.get_or_create(telegram_user=telegram_user)[0]
            course_for_user.prediction_course = predicted_course_key
            course_for_user.save()
            reply_markup = InlineKeyboardMarkup(
                [
                    [
                        InlineKeyboardButton(
                            text="I like it and I want to enroll",
                            callback_data=json.dumps({"method": "enroll", "kwargs": {}}),
                        )
                    ],
                    [
                        InlineKeyboardButton(
                            text="I like it but will eroll another time",
                            callback_data=json.dumps({"method": "not_enroll", "kwargs": {}}),
                        )
                    ],
                    [
                        InlineKeyboardButton(
                            text="What the shit is this (I don't like it)",
                            callback_data=json.dumps({"method": "wrong_predict", "kwargs": {}}),
                        )
                    ],
                ]
            )

        course_description = CourseDetails.fetch_about_attribute(course_key, "overview")
        course_title = modulestore().get_course(course_key).display_name_with_default
        bot.sendMessage(chat_id=chat_id, text="*%s*" % course_title, parse_mode=telegram.ParseMode.MARKDOWN)
        bot.sendMessage(chat_id=chat_id, text=truncate_course_info(course_description), reply_markup=reply_markup)
Beispiel #39
0
 def test_basic(self):
     course = self.create_course()
     CourseDetails.update_about_video(course, 'test_youtube_id', self.staff_user.id)
     with check_mongo_calls(self.expected_mongo_calls):
         result = self._get_result(course)
     self.assertDictEqual(result, self.expected_data)
 def test_update_and_fetch(self):
     SelfPacedConfiguration(enabled=True).save()
     jsondetails = CourseDetails.fetch(self.course.id)
     jsondetails.syllabus = "<a href='foo'>bar</a>"
     # encode - decode to convert date fields and other data which changes form
     with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id):
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).syllabus,
             jsondetails.syllabus, "After set syllabus"
         )
         jsondetails.short_description = "Short Description"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).short_description,
             jsondetails.short_description, "After set short_description"
         )
         jsondetails.overview = "Overview"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).overview,
             jsondetails.overview, "After set overview"
         )
         jsondetails.intro_video = "intro_video"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).intro_video,
             jsondetails.intro_video, "After set intro_video"
         )
         jsondetails.effort = "effort"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).effort,
             jsondetails.effort, "After set effort"
         )
         jsondetails.self_paced = True
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).self_paced,
             jsondetails.self_paced
         )
         jsondetails.start_date = datetime.datetime(2010, 10, 1, 0, tzinfo=UTC())
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).start_date,
             jsondetails.start_date
         )
         jsondetails.end_date = datetime.datetime(2011, 10, 1, 0, tzinfo=UTC())
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).end_date,
             jsondetails.end_date
         )
         jsondetails.certificate_available_date = datetime.datetime(2010, 10, 1, 0, tzinfo=UTC())
         self.assertEqual(
             CourseDetails.update_from_json(
                 self.course.id, jsondetails.__dict__, self.user
             ).certificate_available_date,
             jsondetails.certificate_available_date
         )
         jsondetails.course_image_name = "an_image.jpg"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).course_image_name,
             jsondetails.course_image_name
         )
         jsondetails.banner_image_name = "an_image.jpg"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).banner_image_name,
             jsondetails.banner_image_name
         )
         jsondetails.video_thumbnail_image_name = "an_image.jpg"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).video_thumbnail_image_name,
             jsondetails.video_thumbnail_image_name
         )
         jsondetails.language = "hr"
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).language,
             jsondetails.language
         )
         jsondetails.learning_info = ["test", "test"]
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).learning_info,
             jsondetails.learning_info
         )
         jsondetails.instructor_info = {
             "instructors": [
                 {
                     "name": "test",
                     "title": "test",
                     "organization": "test",
                     "image": "test",
                     "bio": "test"
                 }
             ]
         }
         self.assertEqual(
             CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).instructor_info,
             jsondetails.instructor_info
         )
Beispiel #41
0
    def check_course_overview_against_course(self, course):
        """
        Compares a CourseOverview object against its corresponding
        CourseDescriptor object.

        Specifically, given a course, test that data within the following three
        objects match each other:
         - the CourseDescriptor itself
         - a CourseOverview that was newly constructed from _create_or_update
         - a CourseOverview that was loaded from the MySQL database

        Arguments:
            course (CourseDescriptor): the course to be checked.
        """

        def get_seconds_since_epoch(date_time):
            """
            Returns the number of seconds between the Unix Epoch and the given
                datetime. If the given datetime is None, return None.

            Arguments:
                date_time (datetime): the datetime in question.
            """
            if date_time is None:
                return None
            epoch = datetime.datetime.utcfromtimestamp(0).replace(tzinfo=pytz.utc)
            return math.floor((date_time - epoch).total_seconds())

        # Load the CourseOverview from the cache twice. The first load will be a cache miss (because the cache
        # is empty) so the course will be newly created with CourseOverview._create_or_update. The second
        # load will be a cache hit, so the course will be loaded from the cache.
        course_overview_cache_miss = CourseOverview.get_from_id(course.id)
        course_overview_cache_hit = CourseOverview.get_from_id(course.id)

        # Test if value of these attributes match between the three objects
        fields_to_test = [
            'id',
            'display_name',
            'display_number_with_default',
            'display_org_with_default',
            'advertised_start',
            'social_sharing_url',
            'certificates_display_behavior',
            'certificates_show_before_end',
            'cert_name_short',
            'cert_name_long',
            'lowest_passing_grade',
            'end_of_course_survey_url',
            'mobile_available',
            'visible_to_staff_only',
            'location',
            'number',
            'url_name',
            'display_name_with_default',
            'display_name_with_default_escaped',
            'start_date_is_still_default',
            'pre_requisite_courses',
            'enrollment_domain',
            'invitation_only',
            'max_student_enrollments_allowed',
            'catalog_visibility',
        ]
        for attribute_name in fields_to_test:
            course_value = getattr(course, attribute_name)
            cache_miss_value = getattr(course_overview_cache_miss, attribute_name)
            cache_hit_value = getattr(course_overview_cache_hit, attribute_name)
            self.assertEqual(course_value, cache_miss_value)
            self.assertEqual(cache_miss_value, cache_hit_value)

        # Test if return values for all methods are equal between the three objects
        methods_to_test = [
            ('clean_id', ()),
            ('clean_id', ('#',)),
            ('has_ended', ()),
            ('has_started', ()),
            ('may_certify', ()),
        ]
        for method_name, method_args in methods_to_test:
            course_value = getattr(course, method_name)(*method_args)
            cache_miss_value = getattr(course_overview_cache_miss, method_name)(*method_args)
            cache_hit_value = getattr(course_overview_cache_hit, method_name)(*method_args)
            self.assertEqual(course_value, cache_miss_value)
            self.assertEqual(cache_miss_value, cache_hit_value)

        # Other values to test

        # Note: we test the time-related attributes here instead of in
        # fields_to_test, because we run into trouble while testing datetimes
        # for equality. When writing and reading dates from databases, the
        # resulting values are often off by fractions of a second. So, as a
        # workaround, we simply test if the start and end times are the same
        # number of seconds from the Unix epoch.
        time_field_accessor = lambda object, field_name: get_seconds_since_epoch(getattr(object, field_name))

        # The course about fields are accessed through the CourseDetail
        # class for the course module, and stored as attributes on the
        # CourseOverview objects.
        course_about_accessor = lambda object, field_name: CourseDetails.fetch_about_attribute(object.id, field_name)

        others_to_test = [
            ('start', time_field_accessor, time_field_accessor),
            ('end', time_field_accessor, time_field_accessor),
            ('enrollment_start', time_field_accessor, time_field_accessor),
            ('enrollment_end', time_field_accessor, time_field_accessor),
            ('announcement', time_field_accessor, time_field_accessor),

            ('short_description', course_about_accessor, getattr),
            ('effort', course_about_accessor, getattr),
            (
                'video',
                lambda c, __: CourseDetails.fetch_video_url(c.id),
                lambda c, __: c.course_video_url,
            ),
            (
                'course_image_url',
                lambda c, __: course_image_url(c),
                getattr,
            ),
            (
                'has_any_active_web_certificate',
                lambda c, field_name: get_active_web_certificate(c) is not None,
                getattr,
            ),
        ]
        for attribute_name, course_accessor, course_overview_accessor in others_to_test:
            course_value = course_accessor(course, attribute_name)
            cache_miss_value = course_overview_accessor(course_overview_cache_miss, attribute_name)
            cache_hit_value = course_overview_accessor(course_overview_cache_hit, attribute_name)
            self.assertEqual(course_value, cache_miss_value)
            self.assertEqual(cache_miss_value, cache_hit_value)

        # test tabs for both cached miss and cached hit courses
        for course_overview in [course_overview_cache_miss, course_overview_cache_hit]:
            course_overview_tabs = course_overview.tabs.all()
            course_resp_tabs = {tab.tab_id for tab in course_overview_tabs}
            self.assertEqual(self.COURSE_OVERVIEW_TABS, course_resp_tabs)
Beispiel #42
0
def get_course_details(course_id):
    course_descriptor = get_course_by_id(course_id)
    course = CourseDetails.populate(course_descriptor)
    return course
Beispiel #43
0
    def get_student_info(self, email):
        if User.objects.filter(email=email).exists():
            student = User.objects.get(email=email)
            # List of courses user is enrolled to
            org_filter_out_set = ''
            course_org_filter = ''
            course_enrollments = list(
                get_course_enrollments(student, course_org_filter,
                                       org_filter_out_set))

            #last login data_email
            last_login_brut = str(student.last_login)
            last_login = last_login_brut.split('.')

            #Check if microsite admin
            if MicrositeAdminManager.objects.filter(user=student).exists():
                check_admin_microsite = True
                microsite_key = MicrositeAdminManager.objects.get(
                    user=student).microsite_id
                microsite_admin_org = Microsite.objects.get(
                    pk=microsite_key).key
            else:
                check_admin_microsite = False

            #Check wich course invited first
            if CourseEnrollment.objects.filter(user=student).exists():
                course_id = CourseEnrollment.objects.filter(
                    user=student).order_by('-created')[0].course_id
                user_org = str(course_id).split('+')[0].replace(
                    "course-v1:", "")
            else:
                user_org = "No organization found for user"

            #Course counters
            compteur_progress = 0
            compteur_finish = 0
            compteur_start = 0
            compteur_certified = 0

            progress_courses = []
            finish_courses = []
            start_courses = []
            certified_courses = []

            _now = int(datetime.datetime.now().strftime("%s"))

            if len(course_enrollments) > 0:
                #For each course user is enrolled to
                for dashboard_index, enrollment in enumerate(
                        course_enrollments):
                    course_id = enrollment.course_overview.id
                    user_id = student.id
                    course_tma = get_course_by_id(enrollment.course_id)
                    try:
                        course_grade_factory = CourseGradeFactory().create(
                            student, course_tma)
                        passed = course_grade_factory.passed
                        percent = course_grade_factory.percent
                    except:
                        passed = False
                        percent = 0
                    course_progression = get_overall_progress(
                        user_id, course_id)
                    try:
                        _end = int(
                            enrollment.course_overview.end.strftime("%s"))
                    except:
                        _end = 0
                    _progress = True
                    if _end > 0 and _end < _now:
                        _progress = False

                    #storing student results for this class
                    q = {}
                    q['passed'] = passed
                    q['percent'] = float(int(percent * 1000) / 10)
                    q['course_id'] = str(enrollment.course_id)
                    q['duration'] = CourseDetails.fetch(
                        enrollment.course_id).effort
                    q['required'] = course_tma.is_required_atp
                    q['content_data'] = course_tma.content_data
                    q['category'] = course_tma.categ
                    q['display_name_with_default'] = enrollment.course_overview.display_name_with_default
                    q['course_progression'] = course_progression

                    if passed == True:
                        compteur_certified += 1
                        certified_courses.append(q)
                    if course_progression > 0 and course_progression < 100 and passed == False and _progress == True:
                        compteur_progress += 1
                        progress_courses.append(q)
                    elif course_progression == 100 or passed or _progress == False:
                        compteur_finish += 1
                        finish_courses.append(q)
                    elif course_progression == 0 and _progress == True:
                        compteur_start += 1
                        start_courses.append(q)

            #Candidate status
            if student.is_staff:
                status = "Staff"
            elif check_admin_microsite:
                status = "Admin Microsite"
            else:
                status = "Student"

            context = {
                'student_id': student.id,
                'status': status,
                'student_mail': student.email,
                'student_name': student.first_name + " " + student.last_name,
                'progress_courses': compteur_progress,
                #'progress_courses': progress_courses,
                'finished_courses': compteur_finish,
                #'finish_courses': finish_courses,
                'started_courses': compteur_start,
                #'start_courses':start_courses,
                'certified_courses': compteur_certified,
                #'certified_course' : certified_courses,
                'user_org': user_org,
                'last login': last_login[0]
            }
            if check_admin_microsite:
                context['microsite_admin_org'] = microsite_admin_org

        else:
            if UserPreprofile.objects.filter(email=email).exists():
                user = UserPreprofile.objects.get(email=email)
                if CourseEnrollmentAllowed.objects.filter(
                        email=email).exists():
                    profile = CourseEnrollmentAllowed.objects.filter(
                        email=email).order_by('-created')
                    course_id = profile[0].course_id
                    user_org = str(course_id).split('+')[0].replace(
                        "course-v1:", "")
                else:
                    user_org = "No organization found for user"

                context = {
                    'student_mail': email,
                    'student_name': user.first_name + " " + user.last_name,
                    'status': "User preregistered on platform",
                    'user_org': user_org
                }
            else:
                context = {
                    'student_mail': email,
                    'status': "Unknown user",
                }

        return context
Beispiel #44
0
def course_info_to_ccxcon(course_key):
    """
    Function that gathers informations about the course and
    makes a post request to a CCXCon with the data.

    Args:
        course_key (CourseLocator): the master course key
    """

    try:
        course = get_course_by_id(course_key)
    except Http404:
        log.error('Master Course with key "%s" not found', unicode(course_key))
        return
    if not course.enable_ccx:
        log.debug('ccx not enabled for course key "%s"', unicode(course_key))
        return
    if not course.ccx_connector:
        log.debug('ccx connector not defined for course key "%s"', unicode(course_key))
        return
    if not is_valid_url(course.ccx_connector):
        log.error(
            'ccx connector URL "%s" for course key "%s" is not a valid URL.',
            course.ccx_connector, unicode(course_key)
        )
        return
    # get the oauth credential for this URL
    try:
        ccxcon = CCXCon.objects.get(url=course.ccx_connector)
    except CCXCon.DoesNotExist:
        log.error('ccx connector Oauth credentials not configured for URL "%s".', course.ccx_connector)
        return

    # get an oauth client with a valid token

    oauth_ccxcon = get_oauth_client(
        server_token_url=urlparse.urljoin(course.ccx_connector, CCXCON_TOKEN_URL),
        client_id=ccxcon.oauth_client_id,
        client_secret=ccxcon.oauth_client_secret
    )

    # get the entire list of instructors
    course_instructors = CourseInstructorRole(course.id).users_with_role()
    # get anonymous ids for each of them
    course_instructors_ids = [anonymous_id_for_user(user, course_key) for user in course_instructors]
    # extract the course details
    course_details = CourseDetails.fetch(course_key)

    payload = {
        'course_id': unicode(course_key),
        'title': course.display_name,
        'author_name': None,
        'overview': course_details.overview,
        'description': course_details.short_description,
        'image_url': course_details.course_image_asset_path,
        'instructors': course_instructors_ids
    }
    headers = {'content-type': 'application/json'}

    # make the POST request
    add_course_url = urlparse.urljoin(course.ccx_connector, CCXCON_COURSEXS_URL)
    resp = oauth_ccxcon.post(
        url=add_course_url,
        json=payload,
        headers=headers,
        timeout=CCXCON_REQUEST_TIMEOUT
    )

    if resp.status_code >= 500:
        raise CCXConnServerError('Server returned error Status: %s, Content: %s', resp.status_code, resp.content)
    if resp.status_code >= 400:
        log.error("Error creating course on ccxcon. Status: %s, Content: %s", resp.status_code, resp.content)
    # this API performs a POST request both for POST and PATCH, but the POST returns 201 and the PATCH returns 200
    elif resp.status_code != HTTP_200_OK and resp.status_code != HTTP_201_CREATED:
        log.error('Server returned unexpected status code %s', resp.status_code)
    else:
        log.debug('Request successful. Status: %s, Content: %s', resp.status_code, resp.content)
    def test_update_and_fetch(self):
        jsondetails = CourseDetails.fetch(self.course.id)
        jsondetails.syllabus = "<a href='foo'>bar</a>"
        # encode - decode to convert date fields and other data which changes form
        with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred,
                                       self.course.id):
            assert CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).syllabus ==\
                   jsondetails.syllabus, 'After set syllabus'
            jsondetails.short_description = "Short Description"
            assert CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).short_description ==\
                   jsondetails.short_description, 'After set short_description'
            jsondetails.overview = "Overview"
            assert CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).overview ==\
                   jsondetails.overview, 'After set overview'
            jsondetails.intro_video = "intro_video"
            assert CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).intro_video ==\
                   jsondetails.intro_video, 'After set intro_video'
            jsondetails.about_sidebar_html = "About Sidebar HTML"
            assert CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user)\
                .about_sidebar_html == jsondetails.about_sidebar_html, 'After set about_sidebar_html'
            jsondetails.effort = "effort"
            assert CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).effort ==\
                   jsondetails.effort, 'After set effort'
            jsondetails.self_paced = True
            assert CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).self_paced ==\
                   jsondetails.self_paced
            jsondetails.start_date = datetime.datetime(2010,
                                                       10,
                                                       1,
                                                       0,
                                                       tzinfo=UTC)
            assert CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).start_date ==\
                   jsondetails.start_date
            jsondetails.end_date = datetime.datetime(2011,
                                                     10,
                                                     1,
                                                     0,
                                                     tzinfo=UTC)
            assert CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).end_date ==\
                   jsondetails.end_date
            jsondetails.certificate_available_date = datetime.datetime(
                2010, 10, 1, 0, tzinfo=UTC)
            assert CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user)\
                .certificate_available_date == jsondetails.certificate_available_date
            jsondetails.course_image_name = "an_image.jpg"
            assert CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).course_image_name ==\
                   jsondetails.course_image_name
            jsondetails.banner_image_name = "an_image.jpg"
            assert CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).banner_image_name ==\
                   jsondetails.banner_image_name
            jsondetails.video_thumbnail_image_name = "an_image.jpg"
            assert CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user)\
                .video_thumbnail_image_name == jsondetails.video_thumbnail_image_name
            jsondetails.language = "hr"
            assert CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).language ==\
                   jsondetails.language
            jsondetails.learning_info = ["test", "test"]
            assert CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).learning_info ==\
                   jsondetails.learning_info

            jsondetails.instructor_info = {
                "instructors": [{
                    "name": "test",
                    "title": "test",
                    "organization": "test",
                    "image": "test",
                    "bio": "test"
                }]
            }
            assert CourseDetails.update_from_json(self.course.id, jsondetails.__dict__, self.user).instructor_info ==\
                   jsondetails.instructor_info
 def test_fetch_effort(self):
     effort_value = 'test_hours_of_effort'
     with self.store.branch_setting(ModuleStoreEnum.Branch.draft_preferred, self.course.id):
         CourseDetails.update_about_item(self.course, 'effort', effort_value, self.user.id)
     self.assertEqual(CourseDetails.fetch_effort(self.course.id), effort_value)