class VideoIntervals(models.Model): student = models.CharField(max_length=32, db_index=True) #course_key course_key = CourseKeyField(max_length=255, db_index=True) #OLD course_key = models.CharField(max_length=255, db_index=True) module_key = LocationKeyField(max_length=255, db_index=True) # Module's display name display_name = models.CharField(max_length=255, db_index=True) hist_xaxis = models.TextField(db_index=False) hist_yaxis = models.TextField(db_index=False) class Meta: unique_together = (('student', 'module_key'), ) def __repr__(self): return 'VideoIntervals<%r>' % ({ 'student': self.student, 'course_key': self.course_key, 'module_key': self.module_key, 'display_name': self.display_name, 'hist_xaxis': self.hist_xaxis, 'hist_yaxis': self.hist_yaxis, }, ) def __unicode__(self): return unicode(repr(self))
class CourseUserGroup(models.Model): """ This model represents groups of users in a course. Groups may have different types, which may be treated specially. For example, a user can be in at most one cohort per course, and cohorts are used to split up the forums by group. """ class Meta: unique_together = (('name', 'course_id'), ) name = models.CharField(max_length=255, help_text=("What is the name of this group? " "Must be unique within a course.")) users = models.ManyToManyField(User, db_index=True, related_name='course_groups', help_text="Who is in this group?") # Note: groups associated with particular runs of a course. E.g. Fall 2012 and Spring # 2013 versions of 6.00x will have separate groups. course_id = CourseKeyField(max_length=255, db_index=True, help_text="Which course is this group associated with?") # For now, only have group type 'cohort', but adding a type field to support # things like 'question_discussion', 'friends', 'off-line-class', etc COHORT = 'cohort' GROUP_TYPE_CHOICES = ((COHORT, 'Cohort'),) group_type = models.CharField(max_length=20, choices=GROUP_TYPE_CHOICES)
class CertificateGenerationHistory(TimeStampedModel): """ Model for storing Certificate Generation History. """ course_id = CourseKeyField(max_length=255) generated_by = models.ForeignKey(User) instructor_task = models.ForeignKey(InstructorTask) is_regeneration = models.BooleanField(default=False) def get_task_name(self): """ Return "regenerated" if record corresponds to Certificate Regeneration task, otherwise returns 'generated' """ # Translators: This is a past-tense verb that is used for task action messages. return _("regenerated") if self.is_regeneration else _("generated") def get_certificate_generation_candidates(self): """ Return the candidates for certificate generation task. It could either be students or certificate statuses depending upon the nature of certificate generation task. Returned value could be one of the following, 1. "All learners" Certificate Generation task was initiated for all learners of the given course. 2. Comma separated list of certificate statuses, This usually happens when instructor regenerates certificates. 3. "for exceptions", This is the case when instructor generates certificates for white-listed students. """ task_input = self.instructor_task.task_input if not task_input.strip(): # if task input is empty, it means certificates were generated for all learners # Translators: This string represents task was executed for all learners. return _("All learners") task_input_json = json.loads(task_input) # get statuses_to_regenerate from task_input convert statuses to human readable strings and return statuses = task_input_json.get('statuses_to_regenerate', None) if statuses: readable_statuses = [ CertificateStatuses.readable_statuses.get(status) for status in statuses if CertificateStatuses.readable_statuses.get(status) is not None ] return ", ".join(readable_statuses) # If "student_set" is present in task_input, then this task only # generates certificates for white listed students. Note that # this key used to be "students", so we include that in this conditional # for backwards compatibility. if 'student_set' in task_input_json or 'students' in task_input_json: # Translators: This string represents task was executed for students having exceptions. return _("For exceptions") else: return _("All learners") class Meta(object): app_label = "certificates" def __unicode__(self): return u"certificates %s by %s on %s for %s" % \ ("regenerated" if self.is_regeneration else "generated", self.generated_by, self.created, self.course_id)
class SortGrades(models.Model): SORT_TYPES = ( ('GS', 'GRADED_SECTIONS'), ('WS', 'WEIGHT_SECTIONS'), ) # Section description course_id = CourseKeyField(max_length=255, db_index=True) sort_type = models.CharField(max_length=32, choices=SORT_TYPES, default='GS') category = models.CharField(max_length=255, default='') label = models.CharField(max_length=255, default='') name = models.CharField(max_length=255, default='') # Sort grades num_not = models.IntegerField() num_fail = models.IntegerField() num_pass = models.IntegerField() num_prof = models.IntegerField() # Date last_calc = models.DateTimeField(auto_now=True) class Meta: unique_together = (('label', 'course_id', 'sort_type'), )
class StudentTimeTracker(TimeStampedModel): """ This records how many milliseconds did user spend on a particular unit in course. """ course_id = CourseKeyField(db_index=True, max_length=255) unit_location = LocationKeyField(max_length=255, db_index=True) student = models.ForeignKey(User, db_index=True) time_duration = models.IntegerField(blank=True, null=True) class Meta(object): app_label = "courseware" unique_together = (('course_id', 'unit_location', 'student'), ) @classmethod def update_time(cls, course_id, unit_location, student, time_duration): # Used to be a get_or_create() here, but Django's get_or_create() # has pecularities when unique_together is introduced so it is # broken down into a try-except block to omit those issues. try: student_time_tracker = cls.objects.get(course_id=course_id, unit_location=unit_location, student=student) except cls.DoesNotExist: student_time_tracker = cls.objects.create( course_id=course_id, unit_location=unit_location, student=student) if student_time_tracker.time_duration: student_time_tracker.time_duration = student_time_tracker.time_duration + long( time_duration) else: student_time_tracker.time_duration = time_duration student_time_tracker.save()
class CourseRegistrationCode(models.Model): """ This table contains registration codes With registration code, a user can register for a course for free """ code = models.CharField(max_length=32, db_index=True, unique=True) course_id = CourseKeyField(max_length=255, db_index=True) transaction_group_name = models.CharField(max_length=255, db_index=True, null=True, blank=True) created_by = models.ForeignKey(User, related_name='created_by_user') created_at = models.DateTimeField(default=datetime.now(pytz.utc)) @classmethod @transaction.commit_on_success def free_user_enrollment(cls, cart): """ Here we enroll the user free for all courses available in shopping cart """ cart_items = cart.orderitem_set.all().select_subclasses() if cart_items: for item in cart_items: CourseEnrollment.enroll(cart.user, item.course_id) log.info("Enrolled '{0}' in free course '{1}'" .format(cart.user.email, item.course_id)) # pylint: disable=E1101 item.status = 'purchased' item.save() cart.status = 'purchased' cart.purchase_time = datetime.now(pytz.utc) cart.save()
class CourseProbVidProgress(models.Model): # Constants for student_id ALL_STUDENTS = -1 PROF_GROUP = -2 PASS_GROUP = -3 FAIL_GROUP = -4 # Progress type PROGRESS_TYPE = (('PROB', 'problem'), ('VID', 'video')) # Data student_id = models.IntegerField() course_id = CourseKeyField(max_length=255, db_index=True) progress = models.CharField(max_length=20000, default='') type = models.CharField(max_length=32, choices=PROGRESS_TYPE, default='PROB') start_time = models.DateTimeField(auto_now=False, null=True, default=None) end_time = models.DateTimeField(auto_now=False, null=True, default=None) delta = models.FloatField() # Date last_calc = models.DateTimeField(auto_now=True) class Meta: unique_together = (('student_id', 'course_id', 'type'), )
class GradedAssignment(models.Model): """ Model representing a single launch of a graded assignment by an individual user. There will be a row created here only if the LTI consumer may require a result to be returned from the LTI launch (determined by the presence of the lis_result_sourcedid parameter in the launch POST). There will be only one row created for a given usage/consumer combination; repeated launches of the same content by the same user from the same LTI consumer will not add new rows to the table. Some LTI-specified fields use the prefix lis_; this refers to the IMS Learning Information Services standard from which LTI inherits some properties """ user = models.ForeignKey(User, db_index=True) course_key = CourseKeyField(max_length=255, db_index=True) usage_key = UsageKeyField(max_length=255, db_index=True) outcome_service = models.ForeignKey(OutcomeService) lis_result_sourcedid = models.CharField(max_length=255, db_index=True) version_number = models.IntegerField(default=0) class Meta(object): """ Uniqueness constraints. """ unique_together = ('outcome_service', 'lis_result_sourcedid')
class CustomCourseForEdX(models.Model): """ A Custom Course. """ course_id = CourseKeyField(max_length=255, db_index=True) display_name = models.CharField(max_length=255) coach = models.ForeignKey(User, db_index=True)
class CourseAuthorization(models.Model): """ Enable the course email feature on a course-by-course basis. """ # The course that these features are attached to. course_id = CourseKeyField(max_length=255, db_index=True, unique=True) # Whether or not to enable instructor email email_enabled = models.BooleanField(default=False) @classmethod def instructor_email_enabled(cls, course_id): """ Returns whether or not email is enabled for the given course id. If email has not been explicitly enabled, returns False. """ # If settings.FEATURES['REQUIRE_COURSE_EMAIL_AUTH'] is # set to False, then we enable email for every course. if not settings.FEATURES['REQUIRE_COURSE_EMAIL_AUTH']: return True try: record = cls.objects.get(course_id=course_id) return record.email_enabled except cls.DoesNotExist: return False def __unicode__(self): not_en = "Not " if self.email_enabled: not_en = "" # pylint: disable=no-member return u"Course '{}': Instructor Email {}Enabled".format(self.course_id.to_deprecated_string(), not_en)
class CourseModesArchive(models.Model): """ Store the past values of course_mode that a course had in the past. We decided on having separate model, because there is a uniqueness contraint on (course_mode, course_id) field pair in CourseModes. Having a separate table allows us to have an audit trail of any changes such as course price changes """ # the course that this mode is attached to course_id = CourseKeyField(max_length=255, db_index=True) # the reference to this mode that can be used by Enrollments to generate # similar behavior for the same slug across courses mode_slug = models.CharField(max_length=100) # The 'pretty' name that can be translated and displayed mode_display_name = models.CharField(max_length=255) # minimum price in USD that we would like to charge for this mode of the course min_price = models.IntegerField(default=0) # the suggested prices for this mode suggested_prices = models.CommaSeparatedIntegerField(max_length=255, blank=True, default='') # the currency these prices are in, using lower case ISO currency codes currency = models.CharField(default="usd", max_length=8) # turn this mode off after the given expiration date expiration_date = models.DateField(default=None, null=True, blank=True) expiration_datetime = models.DateTimeField(default=None, null=True, blank=True)
class GeneratedCertificate(models.Model): MODES = Choices('verified', 'honor', 'audit') user = models.ForeignKey(User) course_id = CourseKeyField(max_length=255, blank=True, default=None) verify_uuid = models.CharField(max_length=32, blank=True, default='') download_uuid = models.CharField(max_length=32, blank=True, default='') download_url = models.CharField(max_length=128, blank=True, default='') grade = models.CharField(max_length=5, blank=True, default='') key = models.CharField(max_length=32, blank=True, default='') distinction = models.BooleanField(default=False) status = models.CharField(max_length=32, default='unavailable') mode = models.CharField(max_length=32, choices=MODES, default=MODES.honor) name = models.CharField(blank=True, max_length=255) created_date = models.DateTimeField(auto_now_add=True, default=datetime.now) modified_date = models.DateTimeField(auto_now=True, default=datetime.now) error_reason = models.CharField(max_length=512, blank=True, default='') class Meta: unique_together = (('user', 'course_id'), ) @classmethod def certificate_for_student(cls, student, course_id): """ This returns the certificate for a student for a particular course or None if no such certificate exits. """ try: return cls.objects.get(user=student, course_id=course_id) except cls.DoesNotExist: pass return None
class CreditCourse(models.Model): """Model for tracking a credit course.""" course_key = CourseKeyField(max_length=255, db_index=True, unique=True) enabled = models.BooleanField(default=False) @classmethod def is_credit_course(cls, course_key): """ Check that given course is credit or not Args: course_key(CourseKey): The course identifier Returns: Bool True if the course is marked credit else False """ return cls.objects.filter(course_key=course_key, enabled=True).exists() @classmethod def get_credit_course(cls, course_key): """ Get the credit course if exists for the given course_key Args: course_key(CourseKey): The course identifier Raises: DoesNotExist if no CreditCourse exists for the given course key. Returns: CreditCourse if one exists for the given course key. """ return cls.objects.get(course_key=course_key, enabled=True)
class CourseTeam(models.Model): """This model represents team related info.""" team_id = models.CharField(max_length=255, unique=True) name = models.CharField(max_length=255) is_active = models.BooleanField(default=True) course_id = CourseKeyField(max_length=255, db_index=True) topic_id = models.CharField(max_length=255, db_index=True, blank=True) date_created = models.DateTimeField(auto_now_add=True) # last_activity is computed through a query description = models.CharField(max_length=300) country = CountryField(blank=True) language = LanguageField( blank=True, help_text=ugettext_lazy("Optional language the team uses as ISO 639-1 code."), ) users = models.ManyToManyField(User, db_index=True, related_name='teams', through='CourseTeamMembership') @classmethod def create(cls, name, course_id, description, topic_id=None, country=None, language=None): """Create a complete CourseTeam object. Args: name (str): The name of the team to be created. course_id (str): The ID string of the course associated with this team. description (str): A description of the team. topic_id (str): An optional identifier for the topic the team formed around. country (str, optional): An optional country where the team is based, as ISO 3166-1 code. language (str, optional): An optional language which the team uses, as ISO 639-1 code. """ team_id = generate_unique_readable_id(name, cls.objects.all(), 'team_id') course_team = cls( team_id=team_id, name=name, course_id=course_id, topic_id=topic_id if topic_id else '', description=description, country=country if country else '', language=language if language else '', ) return course_team def add_user(self, user): """Adds the given user to the CourseTeam.""" if not CourseEnrollment.is_enrolled(user, self.course_id): raise NotEnrolledInCourseForTeam if CourseTeamMembership.objects.filter(user=user, team__course_id=self.course_id).exists(): raise AlreadyOnTeamInCourse return CourseTeamMembership.objects.create( user=user, team=self )
class BadgeAssertion(models.Model): """ Tracks badges on our side of the badge baking transaction """ user = models.ForeignKey(User) course_id = CourseKeyField(max_length=255, blank=True, default=None) # Mode a badge was awarded for. mode = models.CharField(max_length=100) data = JSONField() @property def image_url(self): """ Get the image for this assertion. """ return self.data['image'] @property def assertion_url(self): """ Get the public URL for the assertion. """ return self.data['json']['id'] class Meta(object): """ Meta information for Django's construction of the model. """ unique_together = (('course_id', 'user', 'mode'),)
class CourseCohortsSettings(models.Model): """ This model represents cohort settings for courses. """ is_cohorted = models.BooleanField(default=False) course_id = CourseKeyField( unique=True, max_length=255, db_index=True, help_text="Which course are these settings associated with?", ) _cohorted_discussions = models.TextField(db_column='cohorted_discussions', null=True, blank=True) # JSON list # pylint: disable=invalid-name always_cohort_inline_discussions = models.BooleanField(default=True) @property def cohorted_discussions(self): """Jsonify the cohorted_discussions""" return json.loads(self._cohorted_discussions) @cohorted_discussions.setter def cohorted_discussions(self, value): """Un-Jsonify the cohorted_discussions""" self._cohorted_discussions = json.dumps(value)
class CourseAuthorization(models.Model): """ Enable the course email feature on a course-by-course basis. """ class Meta(object): app_label = "bulk_email" # The course that these features are attached to. course_id = CourseKeyField(max_length=255, db_index=True, unique=True) # Whether or not to enable instructor email email_enabled = models.BooleanField(default=False) @classmethod def instructor_email_enabled(cls, course_id): """ Returns whether or not email is enabled for the given course id. """ try: record = cls.objects.get(course_id=course_id) return record.email_enabled except cls.DoesNotExist: return False def __unicode__(self): not_en = "Not " if self.email_enabled: not_en = "" # pylint: disable=no-member return u"Course '{}': Instructor Email {}Enabled".format( self.course_id.to_deprecated_string(), not_en)
class VerificationCheckpoint(models.Model): """Represents a point at which a user is challenged to reverify his or her identity. Each checkpoint is uniquely identified by a (course_id, checkpoint_name) tuple. """ CHECKPOINT_CHOICES = ( ("midterm", "midterm"), ("final", "final"), ) course_id = CourseKeyField(max_length=255, db_index=True) checkpoint_name = models.CharField(max_length=32, choices=CHECKPOINT_CHOICES) photo_verification = models.ManyToManyField( SoftwareSecurePhotoVerification) class Meta: # pylint: disable=missing-docstring, old-style-class unique_together = (('course_id', 'checkpoint_name'), ) def add_verification_attempt(self, verification_attempt): """ Add the verification attempt in M2M relation of photo_verification Arguments: verification_attempt(SoftwareSecurePhotoVerification): SoftwareSecurePhotoVerification object Returns: None """ self.photo_verification.add(verification_attempt) # pylint: disable=no-member def get_user_latest_status(self, user_id): """ Return the latest status of the given checkpoint attempt by user Args: user_id(str): Id of user Returns: VerificationStatus object if found any else None """ try: return self.checkpoint_status.filter(user_id=user_id).latest() # pylint: disable=E1101 except ObjectDoesNotExist: return None @classmethod def get_verification_checkpoint(cls, course_id, checkpoint_name): """Get the verification checkpoint for given course_id and checkpoint name Arguments: course_id(CourseKey): CourseKey checkpoint_name(str): checkpoint name Returns: VerificationCheckpoint object if exists otherwise None """ try: return cls.objects.get(course_id=course_id, checkpoint_name=checkpoint_name) except cls.DoesNotExist: return None
class CourseStruct(models.Model): SECTION_TYPES = ( ('chapter', 'chapter'), ('sequential', 'sequential'), ('vertical', 'vertical'), ) # Section description course_id = CourseKeyField(max_length=255, db_index=True) module_state_key = LocationKeyField(max_length=255, db_column='module_id') name = models.CharField(max_length=255) section_type = models.CharField(max_length=32, choices=SECTION_TYPES, default='chapter', db_index=True) index = models.IntegerField() father = models.ForeignKey('self', limit_choices_to={'section_type': 'chapter'}, blank=True, null=True) # Data graded = models.BooleanField(default=False) released = models.BooleanField(default=False) class Meta: unique_together = (('module_state_key', 'course_id'), ) # Set fahter to null if section_type is chapter def __init__(self, *args, **kwargs): super(CourseStruct, self).__init__(*args, **kwargs) self.section_type = self.module_state_key.category
class EmbargoedCourse(models.Model): """ Enable course embargo on a course-by-course basis. """ objects = NoneToEmptyManager() # The course to embargo course_id = CourseKeyField(max_length=255, db_index=True, unique=True) # Whether or not to embargo embargoed = models.BooleanField(default=False) @classmethod def is_embargoed(cls, course_id): """ Returns whether or not the given course id is embargoed. If course has not been explicitly embargoed, returns False. """ try: record = cls.objects.get(course_id=course_id) return record.embargoed except cls.DoesNotExist: return False def __unicode__(self): not_em = "Not " if self.embargoed: not_em = "" # pylint: disable=no-member return u"Course '{}' is {}Embargoed".format( self.course_id.to_deprecated_string(), not_em)
class VerifiedTrackCohortedCourse(models.Model): """ Tracks which courses have verified track auto-cohorting enabled. """ course_key = CourseKeyField( max_length=255, db_index=True, unique=True, help_text=ugettext_lazy(u"The course key for the course we would like to be auto-cohorted.") ) enabled = models.BooleanField() def __unicode__(self): return u"Course: {}, enabled: {}".format(unicode(self.course_key), self.enabled) @classmethod def is_verified_track_cohort_enabled(cls, course_key): """ Checks whether or not verified track cohort is enabled for the given course. Args: course_key (CourseKey): a course key representing the course we want to check Returns: True if the course has verified track cohorts is enabled False if not """ try: return cls.objects.get(course_key=course_key).enabled except cls.DoesNotExist: return False
class StudentProgressHistory(TimeStampedModel): """ A running audit trail for the StudentProgress model. Listens for post_save events and creates/stores copies of progress entries. """ user = models.ForeignKey(User, db_index=True) course_id = CourseKeyField(db_index=True, max_length=255, blank=True) completions = models.IntegerField()
class CourseSoftware(models.Model): name = models.CharField(max_length=255) full_name = models.CharField(max_length=255) url = models.CharField(max_length=255) course_id = CourseKeyField(max_length=255) def __unicode__(self): return u'{0} for {1}'.format(self.name, self.course_id)
class UniversityID(models.Model): user = models.ForeignKey(User) course_key = CourseKeyField(max_length=255, db_index=True) university_id = models.CharField(verbose_name=_('Student University ID'), max_length=100) section_number = models.CharField(verbose_name=_('Section Number'), max_length=10) date_created = models.DateTimeField(default=timezone.now) # Will be used in `get_marked_university_ids()` method to mark # duplicate entries. is_conflicted = False def get_full_name(self): try: user_profile = UserProfile.objects.get(user=self.user) return user_profile.name except UserProfile.DoesNotExist: return None def get_email(self): return self.user.email def __unicode__(self): return u'{user} - {course_key} - {university_id}'.format( user=self.user, course_key=self.course_key, university_id=self.university_id, ) @classmethod def get_marked_university_ids(cls, course_key): queryset = cls.objects.filter(course_key=course_key) queryset = queryset.order_by('university_id') def cleanup_id(id): """ Trim an ID to make it easier to compare. """ return id.strip().lower() entries = list(queryset) for i, entry in enumerate(entries): if i > 0: # Avoid IndexError prev_entry = entries[i - 1] if cleanup_id(entry.university_id) == cleanup_id( prev_entry.university_id): entry.is_conflicted = True prev_entry.is_conflicted = True return entries class Meta: unique_together = ( 'user', 'course_key', )
class CourseVideos(models.Model): video_name = models.CharField(max_length=255) video_module_ids = LocationKeyField(max_length=255, db_index=True) video_duration = models.TextField(db_index=False) course_key = CourseKeyField(max_length=255, db_index=True, null=True) class Meta: app_label = 'learning_analytics' db_table = 'learning_analytics_coursevideos'
class CourseActionState(models.Model): """ A django model for maintaining state data for course actions that take a long time. For example: course copying (reruns), import, export, and validation. """ class Meta: """ For performance reasons, we disable "concrete inheritance", by making the Model base class abstract. With the "abstract base class" inheritance model, tables are only created for derived models, not for the parent classes. This way, we don't have extra overhead of extra tables and joins that would otherwise happen with the multi-table inheritance model. """ abstract = True # FIELDS # Created is the time this action was initiated created_time = models.DateTimeField(auto_now_add=True) # Updated is the last time this entry was modified updated_time = models.DateTimeField(auto_now=True) # User who initiated the course action created_user = models.ForeignKey( User, # allow NULL values in case the action is not initiated by a user (e.g., a background thread) null=True, # set on_delete to SET_NULL to prevent this model from being deleted in the event the user is deleted on_delete=models.SET_NULL, # add a '+' at the end to prevent a backward relation from the User model related_name='created_by_user+' ) # User who last updated the course action updated_user = models.ForeignKey( User, # allow NULL values in case the action is not updated by a user (e.g., a background thread) null=True, # set on_delete to SET_NULL to prevent this model from being deleted in the event the user is deleted on_delete=models.SET_NULL, # add a '+' at the end to prevent a backward relation from the User model related_name='updated_by_user+' ) # Course that is being acted upon course_key = CourseKeyField(max_length=255, db_index=True) # Action that is being taken on the course action = models.CharField(max_length=100, db_index=True) # Current state of the action. state = models.CharField(max_length=50) # MANAGERS objects = CourseActionStateManager()
class UniversityIDSettings(models.Model): """ This model stores university id settings for each course. """ course_key = CourseKeyField(primary_key=True, max_length=255, db_index=True) registration_end_date = models.DateField(null=True, blank=True, verbose_name=_('Registration End Date')) terms_and_conditions = models.TextField(null=True, blank=True, verbose_name=_('Terms and Conditions')) def __unicode__(self): return unicode(self.course_key)
class VerifiedTrackCohortedCourse(models.Model): """ Tracks which courses have verified track auto-cohorting enabled. """ course_key = CourseKeyField( max_length=255, db_index=True, unique=True, help_text=ugettext_lazy( u"The course key for the course we would like to be auto-cohorted." )) verified_cohort_name = models.CharField( max_length=100, default=DEFAULT_VERIFIED_COHORT_NAME) enabled = models.BooleanField() def __unicode__(self): return u"Course: {}, enabled: {}".format(unicode(self.course_key), self.enabled) @classmethod def verified_cohort_name_for_course(cls, course_key): """ Returns the given cohort name for the specific course. Args: course_key (CourseKey): a course key representing the course we want the verified cohort name for Returns: The cohort name if the course key has one associated to it. None otherwise. """ try: config = cls.objects.get(course_key=course_key) return config.verified_cohort_name except cls.DoesNotExist: return None @classmethod def is_verified_track_cohort_enabled(cls, course_key): """ Checks whether or not verified track cohort is enabled for the given course. Args: course_key (CourseKey): a course key representing the course we want to check Returns: True if the course has verified track cohorts is enabled False if not """ try: return cls.objects.get(course_key=course_key).enabled except cls.DoesNotExist: return False
class CertificateTemplate(TimeStampedModel): """A set of custom web certificate templates. Web certificate templates are Django web templates to replace PDF certificate. A particular course may have several kinds of certificate templates (e.g. honor and verified). """ name = models.CharField( max_length=255, help_text=_(u'Name of template.'), ) description = models.CharField( max_length=255, null=True, blank=True, help_text=_(u'Description and/or admin notes.'), ) template = models.TextField( help_text=_(u'Django template HTML.'), ) organization_id = models.IntegerField( null=True, blank=True, db_index=True, help_text=_(u'Organization of template.'), ) course_key = CourseKeyField( max_length=255, null=True, blank=True, db_index=True, ) mode = models.CharField( max_length=125, choices=GeneratedCertificate.MODES, default=GeneratedCertificate.MODES.honor, null=True, blank=True, help_text=_(u'The course mode for this template.'), ) is_active = models.BooleanField( help_text=_(u'On/Off switch.'), default=False, ) def __unicode__(self): return u'%s' % (self.name, ) class Meta(object): get_latest_by = 'created' unique_together = (('organization_id', 'course_key', 'mode'),) app_label = "certificates"
class CourseStructure(TimeStampedModel): course_id = CourseKeyField(max_length=255, db_index=True, unique=True, verbose_name='Course ID') # Right now the only thing we do with the structure doc is store it and # send it on request. If we need to store a more complex data model later, # we can do so and build a migration. The only problem with a normalized # data model for this is that it will likely involve hundreds of rows, and # we'd have to be careful about caching. structure_json = CompressedTextField(verbose_name='Structure JSON', blank=True, null=True) @property def structure(self): if self.structure_json: return json.loads(self.structure_json) return None @property def ordered_blocks(self): """ Return the blocks in the order with which they're seen in the courseware. Parents are ordered before children. """ if self.structure: ordered_blocks = OrderedDict() self._traverse_tree(self.structure['root'], self.structure['blocks'], ordered_blocks) return ordered_blocks def _traverse_tree(self, block, unordered_structure, ordered_blocks, parent=None): """ Traverses the tree and fills in the ordered_blocks OrderedDict with the blocks in the order that they appear in the course. """ # find the dictionary entry for the current node cur_block = unordered_structure[block] if parent: cur_block['parent'] = parent ordered_blocks[block] = cur_block for child_node in cur_block['children']: self._traverse_tree(child_node, unordered_structure, ordered_blocks, parent=block)