Ejemplo n.º 1
0
class Book(models.Model):
    title = CharField(max_length=255)
    desc = TextField()
    created_at = DateTimeField(auto_now_add=True)
    updated_at = DateTimeField(auto_now=True)
Ejemplo n.º 2
0
class CourseOverview(TimeStampedModel):
    """
    Model for storing and caching basic information about a course.

    This model contains basic course metadata such as an ID, display name,
    image URL, and any other information that would be necessary to display
    a course as part of:
        user dashboard (enrolled courses)
        course catalog (courses to enroll in)
        course about (meta data about the course)
    """
    class Meta(object):
        app_label = 'course_overviews'

    # IMPORTANT: Bump this whenever you modify this model and/or add a migration.
    VERSION = 4

    # Cache entry versioning.
    version = IntegerField()

    # Course identification
    id = CourseKeyField(db_index=True, primary_key=True, max_length=255)
    _location = UsageKeyField(max_length=255)
    org = TextField(max_length=255, default='outdated_entry')
    display_name = TextField(null=True)
    display_number_with_default = TextField()
    display_org_with_default = TextField()

    # Start/end dates
    start = DateTimeField(null=True)
    end = DateTimeField(null=True)
    advertised_start = TextField(null=True)
    announcement = DateTimeField(null=True)

    # URLs
    course_image_url = TextField()
    social_sharing_url = TextField(null=True)
    end_of_course_survey_url = TextField(null=True)

    # Certification data
    certificates_display_behavior = TextField(null=True)
    certificates_show_before_end = BooleanField(default=False)
    cert_html_view_enabled = BooleanField(default=False)
    has_any_active_web_certificate = BooleanField(default=False)
    cert_name_short = TextField()
    cert_name_long = TextField()

    # Grading
    lowest_passing_grade = DecimalField(max_digits=5,
                                        decimal_places=2,
                                        null=True)

    # Access parameters
    days_early_for_beta = FloatField(null=True)
    mobile_available = BooleanField(default=False)
    visible_to_staff_only = BooleanField(default=False)
    _pre_requisite_courses_json = TextField(
    )  # JSON representation of list of CourseKey strings

    # Enrollment details
    enrollment_start = DateTimeField(null=True)
    enrollment_end = DateTimeField(null=True)
    enrollment_domain = TextField(null=True)
    invitation_only = BooleanField(default=False)
    max_student_enrollments_allowed = IntegerField(null=True)

    # Catalog information
    catalog_visibility = TextField(null=True)
    short_description = TextField(null=True)
    course_video_url = TextField(null=True)
    effort = TextField(null=True)
    self_paced = BooleanField(default=False)

    @classmethod
    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,
        )

    @classmethod
    def load_from_module_store(cls, course_id):
        """
        Load a CourseDescriptor, create a new CourseOverview from it, cache the
        overview, and return it.

        Arguments:
            course_id (CourseKey): the ID of the course overview to be loaded.

        Returns:
            CourseOverview: overview of the requested course.

        Raises:
            - CourseOverview.DoesNotExist if the course specified by course_id
                was not found.
            - IOError if some other error occurs while trying to load the
                course from the module store.
        """
        store = modulestore()
        with store.bulk_operations(course_id):
            course = store.get_course(course_id)
            if isinstance(course, CourseDescriptor):
                course_overview = cls._create_from_course(course)
                try:
                    with transaction.atomic():
                        course_overview.save()
                        CourseOverviewTab.objects.bulk_create([
                            CourseOverviewTab(tab_id=tab.tab_id,
                                              course_overview=course_overview)
                            for tab in course.tabs
                        ])
                        CourseOverviewImageSet.create_for_course(
                            course_overview, course)

                except IntegrityError:
                    # There is a rare race condition that will occur if
                    # CourseOverview.get_from_id is called while a
                    # another identical overview is already in the process
                    # of being created.
                    # One of the overviews will be saved normally, while the
                    # other one will cause an IntegrityError because it tries
                    # to save a duplicate.
                    # (see: https://openedx.atlassian.net/browse/TNL-2854).
                    pass
                return course_overview
            elif course is not None:
                raise IOError(
                    "Error while loading course {} from the module store: {}",
                    unicode(course_id), course.error_msg if isinstance(
                        course, ErrorDescriptor) else unicode(course))
            else:
                raise cls.DoesNotExist()

    @classmethod
    def get_from_id(cls, course_id):
        """
        Load a CourseOverview object for a given course ID.

        First, we try to load the CourseOverview from the database. If it
        doesn't exist, we load the entire course from the modulestore, create a
        CourseOverview object from it, and then cache it in the database for
        future use.

        Arguments:
            course_id (CourseKey): the ID of the course overview to be loaded.

        Returns:
            CourseOverview: overview of the requested course.

        Raises:
            - CourseOverview.DoesNotExist if the course specified by course_id
                was not found.
            - IOError if some other error occurs while trying to load the
                course from the module store.
        """
        try:
            course_overview = cls.objects.select_related('image_set').get(
                id=course_id)
            if course_overview.version < cls.VERSION:
                # Throw away old versions of CourseOverview, as they might contain stale data.
                course_overview.delete()
                course_overview = None
        except cls.DoesNotExist:
            course_overview = None

        # Regenerate the thumbnail images if they're missing (either because
        # they were never generated, or because they were flushed out after
        # a change to CourseOverviewImageConfig.
        if course_overview and not hasattr(course_overview, 'image_set'):
            CourseOverviewImageSet.create_for_course(course_overview)

        return course_overview or cls.load_from_module_store(course_id)

    def clean_id(self, padding_char='='):
        """
        Returns a unique deterministic base32-encoded ID for the course.

        Arguments:
            padding_char (str): Character used for padding at end of base-32
                                -encoded string, defaulting to '='
        """
        return course_metadata_utils.clean_course_key(self.location.course_key,
                                                      padding_char)

    @property
    def location(self):
        """
        Returns the UsageKey of this course.

        UsageKeyField has a strange behavior where it fails to parse the "run"
        of a course out of the serialized form of a Mongo Draft UsageKey. This
        method is a wrapper around _location attribute that fixes the problem
        by calling map_into_course, which restores the run attribute.
        """
        if self._location.run is None:
            self._location = self._location.map_into_course(self.id)
        return self._location

    @property
    def number(self):
        """
        Returns this course's number.

        This is a "number" in the sense of the "course numbers" that you see at
        lots of universities. For example, given a course
        "Intro to Computer Science" with the course key "edX/CS-101/2014", the
        course number would be "CS-101"
        """
        return course_metadata_utils.number_for_course_location(self.location)

    @property
    def url_name(self):
        """
        Returns this course's URL name.
        """
        return course_metadata_utils.url_name_for_course_location(
            self.location)

    @property
    def display_name_with_default(self):
        """
        Return reasonable display name for the course.
        """
        return course_metadata_utils.display_name_with_default(self)

    @property
    def display_name_with_default_escaped(self):
        """
        DEPRECATED: use display_name_with_default

        Return html escaped reasonable display name for the course.

        Note: This newly introduced method should not be used.  It was only
        introduced to enable a quick search/replace and the ability to slowly
        migrate and test switching to display_name_with_default, which is no
        longer escaped.
        """
        return course_metadata_utils.display_name_with_default_escaped(self)

    def has_started(self):
        """
        Returns whether the the course has started.
        """
        return course_metadata_utils.has_course_started(self.start)

    def has_ended(self):
        """
        Returns whether the course has ended.
        """
        return course_metadata_utils.has_course_ended(self.end)

    def starts_within(self, days):
        """
        Returns True if the course starts with-in given number of days otherwise returns False.
        """

        return course_metadata_utils.course_starts_within(self.start, days)

    def start_datetime_text(self, format_string="SHORT_DATE"):
        """
        Returns the desired text corresponding the course's start date and
        time in UTC.  Prefers .advertised_start, then falls back to .start.
        """
        return course_metadata_utils.course_start_datetime_text(
            self.start, self.advertised_start, format_string, ugettext,
            strftime_localized)

    @property
    def start_date_is_still_default(self):
        """
        Checks if the start date set for the course is still default, i.e.
        .start has not been modified, and .advertised_start has not been set.
        """
        return course_metadata_utils.course_start_date_is_default(
            self.start,
            self.advertised_start,
        )

    def end_datetime_text(self, format_string="SHORT_DATE"):
        """
        Returns the end date or datetime for the course formatted as a string.
        """
        return course_metadata_utils.course_end_datetime_text(
            self.end, format_string, strftime_localized)

    @property
    def sorting_score(self):
        """
        Returns a tuple that can be used to sort the courses according
        the how "new" they are. The "newness" score is computed using a
        heuristic that takes into account the announcement and
        (advertised) start dates of the course if available.

        The lower the number the "newer" the course.
        """
        return course_metadata_utils.sorting_score(self.start,
                                                   self.advertised_start,
                                                   self.announcement)

    @property
    def start_type(self):
        """
        Returns the type of the course's 'start' field.
        """
        if self.advertised_start:
            return u'string'
        elif self.start != DEFAULT_START_DATE:
            return u'timestamp'
        else:
            return u'empty'

    @property
    def start_display(self):
        """
        Returns the display value for the course's start date.
        """
        if self.advertised_start:
            return self.advertised_start
        elif self.start != DEFAULT_START_DATE:
            return defaultfilters.date(self.start, "DATE_FORMAT")
        else:
            return None

    def may_certify(self):
        """
        Returns whether it is acceptable to show the student a certificate
        download link.
        """
        return course_metadata_utils.may_certify_for_course(
            self.certificates_display_behavior,
            self.certificates_show_before_end, self.has_ended())

    @property
    def pre_requisite_courses(self):
        """
        Returns a list of ID strings for this course's prerequisite courses.
        """
        return json.loads(self._pre_requisite_courses_json)

    @classmethod
    def get_select_courses(cls, course_keys):
        """
        Returns CourseOverview objects for the given course_keys.
        """
        course_overviews = []

        log.info('Generating course overview for %d courses.',
                 len(course_keys))
        log.debug(
            'Generating course overview(s) for the following courses: %s',
            course_keys)

        for course_key in course_keys:
            try:
                course_overviews.append(CourseOverview.get_from_id(course_key))
            except Exception as ex:  # pylint: disable=broad-except
                log.exception(
                    'An error occurred while generating course overview for %s: %s',
                    unicode(course_key),
                    ex.message,
                )

        log.info('Finished generating course overviews.')

        return course_overviews

    @classmethod
    def get_all_courses(cls, org=None, filter_=None):
        """
        Returns all CourseOverview objects in the database.

        Arguments:
            org (string): Optional parameter that allows case-insensitive
                filtering by organization.
            filter_ (dict): Optional parameter that allows custom filtering.
        """
        # Note: If a newly created course is not returned in this QueryList,
        # make sure the "publish" signal was emitted when the course was
        # created. For tests using CourseFactory, use emit_signals=True.
        course_overviews = CourseOverview.objects.all()

        if org:
            # In rare cases, courses belonging to the same org may be accidentally assigned
            # an org code with a different casing (e.g., Harvardx as opposed to HarvardX).
            # Case-insensitive exact matching allows us to deal with this kind of dirty data.
            course_overviews = course_overviews.filter(org__iexact=org)

        if filter_:
            course_overviews = course_overviews.filter(**filter_)

        return course_overviews

    @classmethod
    def get_all_course_keys(cls):
        """
        Returns all course keys from course overviews.
        """
        return [
            CourseKey.from_string(course_overview['id'])
            for course_overview in CourseOverview.objects.values('id')
        ]

    def is_discussion_tab_enabled(self):
        """
        Returns True if course has discussion tab and is enabled
        """
        tabs = self.tabs.all()
        # creates circular import; hence explicitly referenced is_discussion_enabled
        for tab in tabs:
            if tab.tab_id == "discussion" and django_comment_client.utils.is_discussion_enabled(
                    self.id):
                return True
        return False

    @property
    def image_urls(self):
        """
        Return a dict with all known URLs for this course image.

        Current resolutions are:
          raw = original upload from the user
          small = thumbnail with dimensions CourseOverviewImageConfig.current().small
          large = thumbnail with dimensions CourseOverviewImageConfig.current().large

        If no thumbnails exist, the raw (originally uploaded) image will be
        returned for all resolutions.
        """
        # This is either the raw image that the course team uploaded, or the
        # settings.DEFAULT_COURSE_ABOUT_IMAGE_URL if they didn't specify one.
        raw_image_url = self.course_image_url

        # Default all sizes to return the raw image if there is no
        # CourseOverviewImageSet associated with this CourseOverview. This can
        # happen because we're disabled via CourseOverviewImageConfig.
        urls = {
            'raw': raw_image_url,
            'small': raw_image_url,
            'large': raw_image_url,
        }

        # If we do have a CourseOverviewImageSet, we still default to the raw
        # images if our thumbnails are blank (might indicate that there was a
        # processing error of some sort while trying to generate thumbnails).
        if hasattr(
                self,
                'image_set') and CourseOverviewImageConfig.current().enabled:
            urls['small'] = self.image_set.small_url or raw_image_url
            urls['large'] = self.image_set.large_url or raw_image_url

        return urls

    @property
    def pacing(self):
        """ Returns the pacing for the course.

        Potential values:
            self: Self-paced courses
            instructor: Instructor-led courses
        """
        return 'self' if self.self_paced else 'instructor'

    def __unicode__(self):
        """Represent ourselves with the course key."""
        return unicode(self.id)
Ejemplo n.º 3
0
 def test_DateTimeField(self):
     lazy_func = lazy(lambda: datetime.datetime.now(), datetime.datetime)
     self.assertIsInstance(DateTimeField().get_prep_value(lazy_func()),
                           datetime.datetime)
Ejemplo n.º 4
0
class Message(models.Model):
    msg = TextField(max_length=250)
    ip_addr = GenericIPAddressField(blank=True, null=True)
    timestamp = DateTimeField(auto_now_add=True, blank=True, null=True)
Ejemplo n.º 5
0
class User(AbstractUser):
    created_at = DateTimeField(auto_now_add=True)
    updated_at = DateTimeField(auto_now=True)
Ejemplo n.º 6
0
class WishListEntry(Model):
    item = ForeignKey(Item)
    wish_list = ForeignKey(WishList)
    date = DateTimeField(default=datetime_now)
Ejemplo n.º 7
0
class AutomatedTask(BaseAuditModel):
    agent = models.ForeignKey(
        "agents.Agent",
        related_name="autotasks",
        on_delete=models.CASCADE,
        null=True,
        blank=True,
    )
    policy = models.ForeignKey(
        Policy,
        related_name="autotasks",
        null=True,
        blank=True,
        on_delete=models.CASCADE,
    )
    script = models.ForeignKey(
        "scripts.Script",
        null=True,
        blank=True,
        related_name="autoscript",
        on_delete=models.CASCADE,
    )
    script_args = ArrayField(
        models.CharField(max_length=255, null=True, blank=True),
        null=True,
        blank=True,
        default=list,
    )
    assigned_check = models.ForeignKey(
        "checks.Check",
        null=True,
        blank=True,
        related_name="assignedtask",
        on_delete=models.SET_NULL,
    )
    name = models.CharField(max_length=255)
    run_time_bit_weekdays = models.IntegerField(null=True, blank=True)
    # run_time_days is deprecated, use bit weekdays
    run_time_days = ArrayField(
        models.IntegerField(choices=RUN_TIME_DAY_CHOICES, null=True, blank=True),
        null=True,
        blank=True,
        default=list,
    )
    run_time_minute = models.CharField(max_length=5, null=True, blank=True)
    task_type = models.CharField(
        max_length=100, choices=TASK_TYPE_CHOICES, default="manual"
    )
    run_time_date = DateTimeField(null=True, blank=True)
    remove_if_not_scheduled = models.BooleanField(default=False)
    managed_by_policy = models.BooleanField(default=False)
    parent_task = models.PositiveIntegerField(null=True, blank=True)
    win_task_name = models.CharField(max_length=255, null=True, blank=True)
    timeout = models.PositiveIntegerField(default=120)
    retcode = models.IntegerField(null=True, blank=True)
    stdout = models.TextField(null=True, blank=True)
    stderr = models.TextField(null=True, blank=True)
    execution_time = models.CharField(max_length=100, default="0.0000")
    last_run = models.DateTimeField(null=True, blank=True)
    enabled = models.BooleanField(default=True)
    sync_status = models.CharField(
        max_length=100, choices=SYNC_STATUS_CHOICES, default="notsynced"
    )

    def __str__(self):
        return self.name

    @property
    def schedule(self):
        if self.task_type == "manual":
            return "Manual"
        elif self.task_type == "checkfailure":
            return "Every time check fails"
        elif self.task_type == "runonce":
            return f'Run once on {self.run_time_date.strftime("%m/%d/%Y %I:%M%p")}'
        elif self.task_type == "scheduled":
            run_time_nice = dt.datetime.strptime(
                self.run_time_minute, "%H:%M"
            ).strftime("%I:%M %p")

            days = bitdays_to_string(self.run_time_bit_weekdays)
            return f"{days} at {run_time_nice}"

    @property
    def last_run_as_timezone(self):
        if self.last_run is not None and self.agent is not None:
            return self.last_run.astimezone(
                pytz.timezone(self.agent.timezone)
            ).strftime("%b-%d-%Y - %H:%M")

        return self.last_run

    @staticmethod
    def generate_task_name():
        chars = string.ascii_letters
        return "TacticalRMM_" + "".join(random.choice(chars) for i in range(35))

    @staticmethod
    def serialize(task):
        # serializes the task and returns json
        from .serializers import TaskSerializer

        return TaskSerializer(task).data

    def create_policy_task(self, agent=None, policy=None):
        from .tasks import create_win_task_schedule

        # exit if neither are set or if both are set
        if not agent and not policy or agent and policy:
            return

        assigned_check = None

        if agent and self.assigned_check:
            assigned_check = agent.agentchecks.get(parent_check=self.assigned_check.pk)
        elif policy and self.assigned_check:
            assigned_check = policy.policychecks.get(name=self.assigned_check.name)

        task = AutomatedTask.objects.create(
            agent=agent,
            policy=policy,
            managed_by_policy=bool(agent),
            parent_task=(self.pk if agent else None),
            script=self.script,
            script_args=self.script_args,
            assigned_check=assigned_check,
            name=self.name,
            run_time_days=self.run_time_days,
            run_time_minute=self.run_time_minute,
            run_time_bit_weekdays=self.run_time_bit_weekdays,
            run_time_date=self.run_time_date,
            task_type=self.task_type,
            win_task_name=self.win_task_name,
            timeout=self.timeout,
            enabled=self.enabled,
            remove_if_not_scheduled=self.remove_if_not_scheduled,
        )

        create_win_task_schedule.delay(task.pk)
Ejemplo n.º 8
0
class Notification(models.Model):
    type = CharField(max_length=127)
    atime = DateTimeField(null=True, default=datetime.now())
Ejemplo n.º 9
0
class AssignmentGradeHistory(models.Model):
    user = ForeignKey(User, related_name="u_grade_h")
    grader = ForeignKey(User, related_name="g_grade_h")
    ctime = DateTimeField(default=datetime.now())
    grade = IntegerField()
    source = ForeignKey(Source)
Ejemplo n.º 10
0
class UserSetting(models.Model):
    user = ForeignKey(User)
    setting = ForeignKey(DefaultSetting)
    value = IntegerField()
    ctime = DateTimeField(default=datetime.now)
Ejemplo n.º 11
0
class FileDownload(models.Model):
    ctime = DateTimeField(default=datetime.now())
    user = ForeignKey(User)
    source = ForeignKey(Source)
    annotated = BooleanField()
Ejemplo n.º 12
0
class Idle(models.Model):
    session = ForeignKey(Session)
    t1 = DateTimeField()
    t2 = DateTimeField()
Ejemplo n.º 13
0
class CommentSeen(models.Model):
    comment = ForeignKey(Comment)
    session = ForeignKey(Session, null=True)
    user = ForeignKey(
        User)  #duplicate (cf session) but inlined for performance
    ctime = DateTimeField(default=datetime.now)
Ejemplo n.º 14
0
class Session(models.Model):
    user = ForeignKey(User)
    ctime = DateTimeField(default=datetime.now)
    lastactivity = DateTimeField(default=datetime.now, null=True)
    ip = CharField(max_length=63, blank=True, null=True)
    clienttime = DateTimeField(blank=True, null=True)
Ejemplo n.º 15
0
 def __init__(self, expression, output_field=DateTimeField(), **extra):
     super().__init__(expression, output_field=output_field, **extra)
Ejemplo n.º 16
0
class Ticket(models.Model):
    aussteller_id = CharField(max_length=20)
    zeitstempel = DateTimeField()

    # TICKET GELÖSCHT
    def _löschen(self, pj):
        Ticket_Gelöscht.objects.using(pj.db_bezeichnung()).create(
            ticket=self, gelöscht=True, zeitstempel=timezone.now())

    def _entlöschen(self, pj):
        Ticket_Gelöscht.objects.using(pj.db_bezeichnung()).create(
            ticket=self, gelöscht=False, zeitstempel=timezone.now())

    def _gelöscht(self, pj):
        try:
            return Ticket_Gelöscht.objects.using(pj.db_bezeichnung()).filter(
                ticket=self).latest('zeitstempel').gelöscht
        except ObjectDoesNotExist:
            return False

    # TICKET BEZEICHNUNG
    def _bezeichnung_ändern(self, pj, bezeichnung_neu):
        Ticket_Bezeichnung.objects.using(pj.db_bezeichnung()).create(
            ticket=self,
            bezeichnung=bezeichnung_neu,
            zeitstempel=timezone.now(),
        )

    def _bezeichnung(self, pj):
        return Ticket_Bezeichnung.objects.using(pj.db_bezeichnung()).filter(
            ticket=self).latest('zeitstempel').bezeichnung

    # TICKET STATUS AUSSTELLER
    def _ausstellerstatus(self, pj):
        ticket_ausstellerstatus = Ticket_Ausstellerstatus.objects.using(
            pj.db_bezeichnung()).filter(ticket=self).latest('zeitstempel')
        return ticket_ausstellerstatus.status

    # TICKET X-KOORDINATE
    def _x_koordinate_ändern(self, pj, plan, x_koordinate_neu):
        ti_pl = Ticket_Plan.objects.using(pj.db_bezeichnung()).get(ticket=self,
                                                                   plan=plan)
        Ticket_Plan_X.objects.using(pj.db_bezeichnung()).create(
            ticket_plan=ti_pl,
            x_koordinate=x_koordinate_neu,
            zeitstempel=timezone.now())

    def _x_koordinate(self, pj, plan):
        ti_pl = Ticket_Plan.objects.using(pj.db_bezeichnung()).get(ticket=self,
                                                                   plan=plan)
        return Ticket_Plan_X.objects.using(pj.db_bezeichnung()).filter(
            ticket_plan=ti_pl).latest('zeitstempel').x_koordinate

    # TICKET Y-KOORDINATE
    def _y_koordinate_ändern(self, pj, plan, y_koordinate_neu):
        ti_pl = Ticket_Plan.objects.using(pj.db_bezeichnung()).get(ticket=self,
                                                                   plan=plan)
        Ticket_Plan_Y.objects.using(pj.db_bezeichnung()).create(
            ticket_plan=ti_pl,
            y_koordinate=y_koordinate_neu,
            zeitstempel=timezone.now())

    def _y_koordinate(self, pj, plan):
        ti_pl = Ticket_Plan.objects.using(pj.db_bezeichnung()).get(ticket=self,
                                                                   plan=plan)
        return Ticket_Plan_Y.objects.using(pj.db_bezeichnung()).filter(
            ticket_plan=ti_pl).latest('zeitstempel').y_koordinate

    # TICKET EMPFÄNGERGIRMA
    def _empfängerfirma_ändern(self, pj, empfängerfirma_neu_id):
        ti_empf = Ticket_Empfängerfirma.objects.using(
            pj.db_bezeichnung()).create(ticket=self,
                                        firma_id=empfängerfirma_neu_id,
                                        zeitstempel=timezone.now())
        return ti_empf

    def _empfängerfirma(self, pj):
        ti_empf_id = Ticket_Empfängerfirma.objects.using(
            pj.db_bezeichnung()).filter(
                ticket=self).latest('zeitstempel').firma_id
        return Firma.objects.using(DB_SUPER).get(pk=ti_empf_id)

    def _empfängerfirma_gelesen_markieren(self, pj):
        ti_empf = Ticket_Empfängerfirma.objects.using(
            pj.db_bezeichnung()).filter(ticket=self).latest('zeitstempel')
        Ticket_Empfängerfirma_Gelesen.objects.using(
            pj.db_bezeichnung()).create(ticket_empfängerfirma=ti_empf,
                                        zeitstempel=timezone.now())

    def _empfängerfirma_gelesen(self, pj):
        ticket_empfängerfirma = Ticket_Empfängerfirma.objects.using(
            pj.db_bezeichnung()).filter(ticket=self).latest('zeitstempel')
        return ticket_empfängerfirma._gelesen(pj)

    def _empfängerstatus(self, pj):
        ticket_empfängerfirma = Ticket_Empfängerfirma.objects.using(
            pj.db_bezeichnung()).filter(ticket=self).latest('zeitstempel')
        return ticket_empfängerfirma._status(pj)

    # TICKET FÄLLIGKEITSDATUM
    def _fälligkeitsdatum_ändern(self, pj, fälligkeitsdatum_neu):
        Ticket_Fälligkeitsdatum.objects.using(pj.db_bezeichnung()).create(
            ticket=self,
            zeitstempel=timezone.now(),
            fälligkeitsdatum=fälligkeitsdatum_neu)

    def _fälligkeitsdatum(self, pj):
        qs_ticket_fälligkeitsdatum = Ticket_Fälligkeitsdatum.objects.using(
            pj.db_bezeichnung()).filter(ticket=self)
        return qs_ticket_fälligkeitsdatum.latest(
            'zeitstempel').fälligkeitsdatum

    # TICKET PLAN
    def _plan(self, pj):
        qs_ti_pl = Ticket_Plan.objects.using(
            pj.db_bezeichnung()).filter(ticket=self)
        return qs_ti_pl.latest('zeitstempel').plan

    # TICKET HISTORIE
    def _historie(self, pj):

        User = get_user_model()
        li_historie = []

        # Erstellt
        dict_eintrag_erstellt = {}
        dict_eintrag_erstellt['ereignis'] = 'Ticket erstellt'
        ma = User.objects.using(DB_SUPER).get(pk=self.aussteller_id)
        dict_eintrag_erstellt[
            'mitarbeiter_firma'] = f'{ma.first_name} {ma.last_name}'
        dict_eintrag_erstellt['zeitstempel'] = self.zeitstempel
        dict_eintrag_erstellt['text'] = 'Ticket erstellt'

        li_historie.append(dict_eintrag_erstellt)

        # Kommentare
        for k in Ticket_Kommentar.objects.using(
                pj.db_bezeichnung()).filter(ticket=self):
            dict_eintrag_kommentar = {}
            dict_eintrag_kommentar['ereignis'] = 'Kommentar'
            ma = User.objects.using(DB_SUPER).get(pk=k.mitarbeiter_id)
            dict_eintrag_kommentar[
                'mitarbeiter_firma'] = f'{ma.first_name} {ma.last_name}'
            dict_eintrag_kommentar['zeitstempel'] = k.zeitstempel
            dict_eintrag_kommentar['text'] = k.text

            # Kommentar-Anhänge
            pfad_projekt = Pfad_Projekt.objects.using(
                pj.db_bezeichnung()).latest('zeitstempel').pfad
            pfad_anhänge = Pfad_Anhaenge.objects.using(
                pj.db_bezeichnung()).latest('zeitstempel').pfad
            li_anhänge = []
            for a in Ticket_Kommentar_Anhang.objects.using(
                    pj.db_bezeichnung()).filter(ticket_kommentar=k):
                dict_a = a.__dict__
                dict_a['dateiname'] = a.datei.dateiname
                dict_a['dateipfad'] = path.join(
                    pfad_projekt, pfad_anhänge,
                    f'{a.datei.id}_{a.datei.dateiname}')
                li_anhänge.append(dict_a)
            dict_eintrag_kommentar['liste_anhänge'] = li_anhänge

            # Kommentar-Fotos
            pfad_fotos = Pfad_Fotos.objects.using(
                pj.db_bezeichnung()).latest('zeitstempel').pfad
            li_fotos = []
            for fo in Ticket_Kommentar_Foto.objects.using(
                    pj.db_bezeichnung()).filter(ticket_kommentar=k):
                dict_fo = fo.__dict__
                dict_fo['dateiname'] = fo.foto.dateiname
                dict_fo['dateipfad'] = path.join(
                    pfad_projekt, pfad_fotos,
                    f'{fo.foto.id}_{fo.foto.dateiname}')
                li_fotos.append(dict_fo)
            dict_eintrag_kommentar['liste_fotos'] = li_fotos

            li_historie.append(dict_eintrag_kommentar)

        # Ausstellerstati
        for ast in Ticket_Ausstellerstatus.objects.using(
                pj.db_bezeichnung()).filter(ticket=self):
            dict_eintrag_ausstellerstatus = {}
            dict_eintrag_ausstellerstatus['ereignis'] = 'Status Aussteller'
            ma = User.objects.using(DB_SUPER).get(pk=self.aussteller_id)
            dict_eintrag_ausstellerstatus[
                'mitarbeiter_firma'] = f'{ma.first_name} {ma.last_name}'
            dict_eintrag_ausstellerstatus['zeitstempel'] = ast.zeitstempel
            dict_eintrag_ausstellerstatus[
                'text'] = f'Ausstellerstatus geändert auf: {ast.status.bezeichnung}'

            li_historie.append(dict_eintrag_ausstellerstatus)

        # Empfängerstatus
        ti_empf = Ticket_Empfängerfirma.objects.using(
            pj.db_bezeichnung()).filter(ticket=self).latest('zeitstempel')
        for es in Ticket_Empfängerfirma_Status.objects.using(
                pj.db_bezeichnung()).filter(ticket_empfängerfirma=ti_empf):
            dict_eintrag_empfängerstatus = {}
            dict_eintrag_empfängerstatus['ereignis'] = 'Status Empfängerfirma'
            fa = Firma.objects.using(DB_SUPER).get(pk=ti_empf.firma_id)
            dict_eintrag_empfängerstatus[
                'mitarbeiter_firma'] = fa._bezeichnung()
            dict_eintrag_empfängerstatus['zeitstempel'] = es.zeitstempel
            dict_eintrag_empfängerstatus[
                'text'] = f'Empfängerstatus geändert auf: {es.status.bezeichnung}'

            li_historie.append(dict_eintrag_empfängerstatus)

        return sorted(li_historie, key=lambda i: i['zeitstempel'])

    # TICKET DICT
    def _dict_für_übersicht(self, pj):
        dict_ticket = self.__dict__
        dict_ticket['bezeichnung'] = self._bezeichnung(pj)
        User = get_user_model()
        ma = User.objects.using(DB_SUPER).get(pk=self.aussteller_id)
        dict_ticket['aussteller'] = ma.first_name + ' ' + ma.last_name
        dict_ticket['ausstellerstatus'] = self._ausstellerstatus(
            pj).bezeichnung
        # Empfängerfirma
        dict_empfängerfirma = self._empfängerfirma(pj).__dict__
        dict_empfängerfirma['bezeichnung'] = self._empfängerfirma(
            pj)._bezeichnung()
        dict_ticket['empfängerfirma'] = dict_empfängerfirma
        dict_ticket['empfängerstatus'] = self._empfängerstatus(pj).bezeichnung
        dict_ticket['gelesen'] = self._empfängerfirma_gelesen(pj)
        dict_ticket['fälligkeitsdatum'] = self._fälligkeitsdatum(pj)
        dict_ticket['plan'] = self._plan(pj)._bezeichnung(pj)

        return dict_ticket
Ejemplo n.º 17
0
class ItemView(Model):
    item = ForeignKey(Item)
    date = DateTimeField(default=datetime_now)
Ejemplo n.º 18
0
class Ticket_Fälligkeitsdatum(models.Model):
    ticket = models.ForeignKey(Ticket, on_delete=models.CASCADE)
    zeitstempel = DateTimeField()
    fälligkeitsdatum = DateTimeField()
Ejemplo n.º 19
0
class CourseOverview(TimeStampedModel):
    """
    Model for storing and caching basic information about a course.

    This model contains basic course metadata such as an ID, display name,
    image URL, and any other information that would be necessary to display
    a course as part of a user dashboard or enrollment API.
    """

    # IMPORTANT: Bump this whenever you modify this model and/or add a migration.
    VERSION = 1

    # Cache entry versioning.
    version = IntegerField()

    # Course identification
    id = CourseKeyField(db_index=True, primary_key=True, max_length=255)  # pylint: disable=invalid-name
    _location = UsageKeyField(max_length=255)
    display_name = TextField(null=True)
    display_number_with_default = TextField()
    display_org_with_default = TextField()

    # Start/end dates
    start = DateTimeField(null=True)
    end = DateTimeField(null=True)
    advertised_start = TextField(null=True)

    # URLs
    course_image_url = TextField()
    facebook_url = TextField(null=True)
    social_sharing_url = TextField(null=True)
    end_of_course_survey_url = TextField(null=True)

    # Certification data
    certificates_display_behavior = TextField(null=True)
    certificates_show_before_end = BooleanField()
    cert_html_view_enabled = BooleanField()
    has_any_active_web_certificate = BooleanField()
    cert_name_short = TextField()
    cert_name_long = TextField()

    # Grading
    lowest_passing_grade = DecimalField(max_digits=5,
                                        decimal_places=2,
                                        null=True)

    # Access parameters
    days_early_for_beta = FloatField(null=True)
    mobile_available = BooleanField()
    visible_to_staff_only = BooleanField()
    _pre_requisite_courses_json = TextField(
    )  # JSON representation of list of CourseKey strings

    # Enrollment details
    enrollment_start = DateTimeField(null=True)
    enrollment_end = DateTimeField(null=True)
    enrollment_domain = TextField(null=True)
    invitation_only = BooleanField(default=False)
    max_student_enrollments_allowed = IntegerField(null=True)

    @classmethod
    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 lms.djangoapps.courseware.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
        if isinstance(course.id, CCXLocator):
            from ccx.utils import get_ccx_from_ccx_locator  # pylint: disable=import-error
            ccx = get_ccx_from_ccx_locator(course.id)
            display_name = ccx.display_name
            start = ccx.start
            end = ccx.due

        return cls(
            version=cls.VERSION,
            id=course.id,
            _location=course.location,
            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,
            course_image_url=course_image_url(course),
            facebook_url=course.facebook_url,
            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=course.
            max_student_enrollments_allowed,
        )

    @classmethod
    def _load_from_module_store(cls, course_id):
        """
        Load a CourseDescriptor, create a new CourseOverview from it, cache the
        overview, and return it.

        Arguments:
            course_id (CourseKey): the ID of the course overview to be loaded.

        Returns:
            CourseOverview: overview of the requested course.

        Raises:
            - CourseOverview.DoesNotExist if the course specified by course_id
                was not found.
            - IOError if some other error occurs while trying to load the
                course from the module store.
        """
        store = modulestore()
        with store.bulk_operations(course_id):
            course = store.get_course(course_id)
            if isinstance(course, CourseDescriptor):
                course_overview = cls._create_from_course(course)
                course_overview.save()
                return course_overview
            elif course is not None:
                raise IOError(
                    "Error while loading course {} from the module store: {}",
                    unicode(course_id), course.error_msg if isinstance(
                        course, ErrorDescriptor) else unicode(course))
            else:
                raise cls.DoesNotExist()

    @classmethod
    def get_from_id(cls, course_id):
        """
        Load a CourseOverview object for a given course ID.

        First, we try to load the CourseOverview from the database. If it
        doesn't exist, we load the entire course from the modulestore, create a
        CourseOverview object from it, and then cache it in the database for
        future use.

        Arguments:
            course_id (CourseKey): the ID of the course overview to be loaded.

        Returns:
            CourseOverview: overview of the requested course.

        Raises:
            - CourseOverview.DoesNotExist if the course specified by course_id
                was not found.
            - IOError if some other error occurs while trying to load the
                course from the module store.
        """
        try:
            course_overview = cls.objects.get(id=course_id)
            if course_overview.version != cls.VERSION:
                # Throw away old versions of CourseOverview, as they might contain stale data.
                course_overview.delete()
                course_overview = None
        except cls.DoesNotExist:
            course_overview = None
        return course_overview or cls._load_from_module_store(course_id)

    def clean_id(self, padding_char='='):
        """
        Returns a unique deterministic base32-encoded ID for the course.

        Arguments:
            padding_char (str): Character used for padding at end of base-32
                                -encoded string, defaulting to '='
        """
        return course_metadata_utils.clean_course_key(self.location.course_key,
                                                      padding_char)

    @property
    def location(self):
        """
        Returns the UsageKey of this course.

        UsageKeyField has a strange behavior where it fails to parse the "run"
        of a course out of the serialized form of a Mongo Draft UsageKey. This
        method is a wrapper around _location attribute that fixes the problem
        by calling map_into_course, which restores the run attribute.
        """
        if self._location.run is None:
            self._location = self._location.map_into_course(self.id)
        return self._location

    @property
    def number(self):
        """
        Returns this course's number.

        This is a "number" in the sense of the "course numbers" that you see at
        lots of universities. For example, given a course
        "Intro to Computer Science" with the course key "edX/CS-101/2014", the
        course number would be "CS-101"
        """
        return course_metadata_utils.number_for_course_location(self.location)

    @property
    def url_name(self):
        """
        Returns this course's URL name.
        """
        return course_metadata_utils.url_name_for_course_location(
            self.location)

    @property
    def display_name_with_default(self):
        """
        Return reasonable display name for the course.
        """
        return course_metadata_utils.display_name_with_default(self)

    def has_started(self):
        """
        Returns whether the the course has started.
        """
        return course_metadata_utils.has_course_started(self.start)

    def has_ended(self):
        """
        Returns whether the course has ended.
        """
        return course_metadata_utils.has_course_ended(self.end)

    def start_datetime_text(self, format_string="SHORT_DATE"):
        """
        Returns the desired text corresponding the course's start date and
        time in UTC.  Prefers .advertised_start, then falls back to .start.
        """
        return course_metadata_utils.course_start_datetime_text(
            self.start, self.advertised_start, format_string, ugettext,
            strftime_localized)

    @property
    def start_date_is_still_default(self):
        """
        Checks if the start date set for the course is still default, i.e.
        .start has not been modified, and .advertised_start has not been set.
        """
        return course_metadata_utils.course_start_date_is_default(
            self.start,
            self.advertised_start,
        )

    def end_datetime_text(self, format_string="SHORT_DATE"):
        """
        Returns the end date or datetime for the course formatted as a string.
        """
        return course_metadata_utils.course_end_datetime_text(
            self.end, format_string, strftime_localized)

    def may_certify(self):
        """
        Returns whether it is acceptable to show the student a certificate
        download link.
        """
        return course_metadata_utils.may_certify_for_course(
            self.certificates_display_behavior,
            self.certificates_show_before_end, self.has_ended())

    @property
    def pre_requisite_courses(self):
        """
        Returns a list of ID strings for this course's prerequisite courses.
        """
        return json.loads(self._pre_requisite_courses_json)
Ejemplo n.º 20
0
class BusinessAccount(QuicksellModel):
	"""Business account of user."""

	user = OneToOneField(User, related_name='business_account', on_delete=CASCADE)
	is_active = BooleanField(default=False)
	expires = DateTimeField(null=True, blank=True)
Ejemplo n.º 21
0
class AutomatedTask(BaseAuditModel):
    agent = models.ForeignKey(
        "agents.Agent",
        related_name="autotasks",
        on_delete=models.CASCADE,
        null=True,
        blank=True,
    )
    policy = models.ForeignKey(
        "automation.Policy",
        related_name="autotasks",
        null=True,
        blank=True,
        on_delete=models.CASCADE,
    )
    script = models.ForeignKey(
        "scripts.Script",
        null=True,
        blank=True,
        related_name="autoscript",
        on_delete=models.CASCADE,
    )
    script_args = ArrayField(
        models.CharField(max_length=255, null=True, blank=True),
        null=True,
        blank=True,
        default=list,
    )
    assigned_check = models.ForeignKey(
        "checks.Check",
        null=True,
        blank=True,
        related_name="assignedtask",
        on_delete=models.SET_NULL,
    )
    name = models.CharField(max_length=255)
    run_time_bit_weekdays = models.IntegerField(null=True, blank=True)
    # run_time_days is deprecated, use bit weekdays
    run_time_days = ArrayField(
        models.IntegerField(choices=RUN_TIME_DAY_CHOICES,
                            null=True,
                            blank=True),
        null=True,
        blank=True,
        default=list,
    )
    run_time_minute = models.CharField(max_length=5, null=True, blank=True)
    task_type = models.CharField(max_length=100,
                                 choices=TASK_TYPE_CHOICES,
                                 default="manual")
    run_time_date = DateTimeField(null=True, blank=True)
    remove_if_not_scheduled = models.BooleanField(default=False)
    run_asap_after_missed = models.BooleanField(
        default=False)  # added in agent v1.4.7
    managed_by_policy = models.BooleanField(default=False)
    parent_task = models.PositiveIntegerField(null=True, blank=True)
    win_task_name = models.CharField(max_length=255, null=True, blank=True)
    timeout = models.PositiveIntegerField(default=120)
    retcode = models.IntegerField(null=True, blank=True)
    stdout = models.TextField(null=True, blank=True)
    stderr = models.TextField(null=True, blank=True)
    execution_time = models.CharField(max_length=100, default="0.0000")
    last_run = models.DateTimeField(null=True, blank=True)
    enabled = models.BooleanField(default=True)
    status = models.CharField(max_length=30,
                              choices=TASK_STATUS_CHOICES,
                              default="pending")
    sync_status = models.CharField(max_length=100,
                                   choices=SYNC_STATUS_CHOICES,
                                   default="notsynced")
    alert_severity = models.CharField(max_length=30,
                                      choices=SEVERITY_CHOICES,
                                      default="info")
    email_alert = models.BooleanField(default=False)
    text_alert = models.BooleanField(default=False)
    dashboard_alert = models.BooleanField(default=False)

    def __str__(self):
        return self.name

    @property
    def schedule(self):
        if self.task_type == "manual":
            return "Manual"
        elif self.task_type == "checkfailure":
            return "Every time check fails"
        elif self.task_type == "runonce":
            return f'Run once on {self.run_time_date.strftime("%m/%d/%Y %I:%M%p")}'
        elif self.task_type == "scheduled":
            run_time_nice = dt.datetime.strptime(self.run_time_minute,
                                                 "%H:%M").strftime("%I:%M %p")

            days = bitdays_to_string(self.run_time_bit_weekdays)
            return f"{days} at {run_time_nice}"

    @property
    def last_run_as_timezone(self):
        if self.last_run is not None and self.agent is not None:
            return self.last_run.astimezone(pytz.timezone(
                self.agent.timezone)).strftime("%b-%d-%Y - %H:%M")

        return self.last_run

    @staticmethod
    def generate_task_name():
        chars = string.ascii_letters
        return "TacticalRMM_" + "".join(
            random.choice(chars) for i in range(35))

    @staticmethod
    def serialize(task):
        # serializes the task and returns json
        from .serializers import TaskSerializer

        return TaskSerializer(task).data

    def create_policy_task(self, agent=None, policy=None):
        from .tasks import create_win_task_schedule

        # if policy is present, then this task is being copied to another policy
        # if agent is present, then this task is being created on an agent from a policy
        # exit if neither are set or if both are set
        if not agent and not policy or agent and policy:
            return

        assigned_check = None

        # get correct assigned check to task if set
        if agent and self.assigned_check:
            # check if there is a matching check on the agent
            if agent.agentchecks.filter(
                    parent_check=self.assigned_check.pk).exists():
                assigned_check = agent.agentchecks.filter(
                    parent_check=self.assigned_check.pk).first()
            # check was overriden by agent and we need to use that agents check
            else:
                if agent.agentchecks.filter(
                        check_type=self.assigned_check.check_type,
                        overriden_by_policy=True).exists():
                    assigned_check = agent.agentchecks.filter(
                        check_type=self.assigned_check.check_type,
                        overriden_by_policy=True,
                    ).first()
        elif policy and self.assigned_check:
            if policy.policychecks.filter(
                    name=self.assigned_check.name).exists():
                assigned_check = policy.policychecks.filter(
                    name=self.assigned_check.name).first()
            else:
                assigned_check = policy.policychecks.filter(
                    check_type=self.assigned_check.check_type).first()

        task = AutomatedTask.objects.create(
            agent=agent,
            policy=policy,
            managed_by_policy=bool(agent),
            parent_task=(self.pk if agent else None),
            alert_severity=self.alert_severity,
            email_alert=self.email_alert,
            text_alert=self.text_alert,
            dashboard_alert=self.dashboard_alert,
            script=self.script,
            script_args=self.script_args,
            assigned_check=assigned_check,
            name=self.name,
            run_time_days=self.run_time_days,
            run_time_minute=self.run_time_minute,
            run_time_bit_weekdays=self.run_time_bit_weekdays,
            run_time_date=self.run_time_date,
            task_type=self.task_type,
            win_task_name=self.win_task_name,
            timeout=self.timeout,
            enabled=self.enabled,
            remove_if_not_scheduled=self.remove_if_not_scheduled,
            run_asap_after_missed=self.run_asap_after_missed,
        )

        create_win_task_schedule.delay(task.pk)

    def should_create_alert(self, alert_template):
        return (self.dashboard_alert or self.email_alert or self.text_alert
                or (alert_template and (alert_template.task_always_alert
                                        or alert_template.task_always_email
                                        or alert_template.task_always_text)))

    def send_email(self):
        from core.models import CoreSettings

        CORE = CoreSettings.objects.first()
        alert_template = self.agent.get_alert_template()

        if self.agent:
            subject = f"{self.agent.client.name}, {self.agent.site.name}, {self} Failed"
        else:
            subject = f"{self} Failed"

        body = (
            subject +
            f" - Return code: {self.retcode}\nStdout:{self.stdout}\nStderr: {self.stderr}"
        )

        CORE.send_mail(subject, body, alert_template)

    def send_sms(self):

        from core.models import CoreSettings

        CORE = CoreSettings.objects.first()
        alert_template = self.agent.get_alert_template()

        if self.agent:
            subject = f"{self.agent.client.name}, {self.agent.site.name}, {self} Failed"
        else:
            subject = f"{self} Failed"

        body = (
            subject +
            f" - Return code: {self.retcode}\nStdout:{self.stdout}\nStderr: {self.stderr}"
        )

        CORE.send_sms(body, alert_template=alert_template)

    def send_resolved_email(self):
        from core.models import CoreSettings

        alert_template = self.agent.get_alert_template()

        CORE = CoreSettings.objects.first()
        subject = f"{self.agent.client.name}, {self.agent.site.name}, {self} Resolved"
        body = (
            subject +
            f" - Return code: {self.retcode}\nStdout:{self.stdout}\nStderr: {self.stderr}"
        )

        CORE.send_mail(subject, body, alert_template=alert_template)

    def send_resolved_sms(self):
        from core.models import CoreSettings

        alert_template = self.agent.get_alert_template()
        CORE = CoreSettings.objects.first()
        subject = f"{self.agent.client.name}, {self.agent.site.name}, {self} Resolved"
        body = (
            subject +
            f" - Return code: {self.retcode}\nStdout:{self.stdout}\nStderr: {self.stderr}"
        )
        CORE.send_sms(body, alert_template=alert_template)
Ejemplo n.º 22
0
 def output_field(self) -> Field:
     return DateTimeField()
Ejemplo n.º 23
0
class MovEncabezado(models.Model):
    area = models.ForeignKey(Area,
                             related_name="movs_asociados",
                             on_delete=models.PROTECT)
    tipo_mov = models.ForeignKey(TipoMov,
                                 related_name="movs_asociados",
                                 on_delete=models.PROTECT)
    folio = IntegerField()
    descripcion = CharField(max_length=200, default='')
    created_at = DateTimeField(auto_now_add=True)
    updated_at = DateTimeField(auto_now=True)
    #mov_items - MovItem
    #mov_estados - MovEstado

    objects = MovManager()

    def __str__(self):
        return f"Tipo:{self.tipo_mov.name} folio:{self.folio}"

    @property
    def mov_items_sorted_updated(self):
        return self.mov_items.order_by('-updated_at')

    @property
    def estado(self):
        estados = self.mov_estados.all()
        if len(estados.filter(estado__name='EJECUTADO')) > 0:
            return 'EJECUTADO'
        elif len(estados.filter(estado__name='CANCELADO')) > 0:
            return 'CANCELADO'
        elif len(estados.filter(estado__name='NO AUTORIZADO')) > 0:
            return 'NO AUTORIZADO'
        elif len(estados.filter(estado__name='AUTORIZADO')) > 0:
            return 'AUTORIZADO'
        elif len(estados.filter(estado__name='SOLICITADO')) > 0:
            return 'SOLICITADO'
        else:
            return 'CREADO'

    @property
    def user_crea(self):
        return self.mov_estados.filter(estado__name="CREADO")[0].user

    @property
    def num_items_solicitado(self):
        n = 0
        for fila_det in self.mov_items.all():
            try:
                if abs(fila_det.cant_solicitada) > 0:
                    n += 1
            except:
                pass

        return n

    @property
    def num_items_autorizado(self):
        n = 0
        for fila_det in self.mov_items.all():
            try:
                if abs(fila_det.cant_autorizada) > 0:
                    n += 1
            except:
                pass
        return n

    @property
    def num_items_ejecutado(self):
        n = 0
        for fila_det in self.mov_items.all():
            try:
                if abs(fila_det.cant_ejecutada) > 0:
                    n += 1
            except:
                pass
        return n

    @property
    def monto_solicitado(self):
        monto = 0
        for fila_det in self.mov_items.all():
            try:
                monto += fila_det.monto_solicitado
            except:
                pass
        return monto

    @property
    def monto_autorizado(self):
        monto = 0
        for fila_det in self.mov_items.all():
            try:
                monto += fila_det.monto_autorizado
            except:
                pass
        return monto

    @property
    def monto_ejecutado(self):
        monto = 0
        for fila_det in self.mov_items.all():
            try:
                monto += fila_det.monto_ejecutado
            except:
                pass
        return monto

    @property
    def abierto(self):
        return self.estado not in ["CANCELADO", "NO AUTORIZADO", "EJECUTADO"]
Ejemplo n.º 24
0
class User(AbstractUser):
    height = IntegerField(null=True)
    weight = IntegerField(null=True)
    sex = BooleanField(null=True)
    birth = DateTimeField(null=True)
    pass
Ejemplo n.º 25
0
class CourseOverview(TimeStampedModel):
    """
    Model for storing and caching basic information about a course.

    This model contains basic course metadata such as an ID, display name,
    image URL, and any other information that would be necessary to display
    a course as part of:
        user dashboard (enrolled courses)
        course catalog (courses to enroll in)
        course about (meta data about the course)
    """
    class Meta(object):
        app_label = 'course_overviews'

    # IMPORTANT: Bump this whenever you modify this model and/or add a migration.
    VERSION = 6

    # Cache entry versioning.
    version = IntegerField()

    # Course identification
    id = CourseKeyField(db_index=True, primary_key=True, max_length=255)
    _location = UsageKeyField(max_length=255)
    org = TextField(max_length=255, default='outdated_entry')
    display_name = TextField(null=True)
    display_number_with_default = TextField()
    display_org_with_default = TextField()

    # Start/end dates
    start = DateTimeField(null=True)
    end = DateTimeField(null=True)
    advertised_start = TextField(null=True)
    announcement = DateTimeField(null=True)

    # URLs
    course_image_url = TextField()
    social_sharing_url = TextField(null=True)
    end_of_course_survey_url = TextField(null=True)

    # Certification data
    certificates_display_behavior = TextField(null=True)
    certificates_show_before_end = BooleanField(default=False)
    cert_html_view_enabled = BooleanField(default=False)
    has_any_active_web_certificate = BooleanField(default=False)
    cert_name_short = TextField()
    cert_name_long = TextField()
    certificate_available_date = DateTimeField(default=None, null=True)

    # Grading
    lowest_passing_grade = DecimalField(max_digits=5,
                                        decimal_places=2,
                                        null=True)

    # Access parameters
    days_early_for_beta = FloatField(null=True)
    mobile_available = BooleanField(default=False)
    visible_to_staff_only = BooleanField(default=False)
    _pre_requisite_courses_json = TextField(
    )  # JSON representation of list of CourseKey strings

    # Enrollment details
    enrollment_start = DateTimeField(null=True)
    enrollment_end = DateTimeField(null=True)
    enrollment_domain = TextField(null=True)
    invitation_only = BooleanField(default=False)
    max_student_enrollments_allowed = IntegerField(null=True)

    # Catalog information
    catalog_visibility = TextField(null=True)
    short_description = TextField(null=True)
    course_video_url = TextField(null=True)
    effort = TextField(null=True)
    self_paced = BooleanField(default=False)
    marketing_url = TextField(null=True)
    eligible_for_financial_aid = BooleanField(default=True)

    language = TextField(null=True)

    @classmethod
    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('Updating course overview for %s.', unicode(course.id))
            course_overview = course_overview.first()
        else:
            log.info('Creating course overview for %s.', unicode(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

    @classmethod
    def load_from_module_store(cls, course_id):
        """
        Load a CourseDescriptor, create or update a CourseOverview from it, cache the
        overview, and return it.

        Arguments:
            course_id (CourseKey): the ID of the course overview to be loaded.

        Returns:
            CourseOverview: overview of the requested course.

        Raises:
            - CourseOverview.DoesNotExist if the course specified by course_id
                was not found.
            - IOError if some other error occurs while trying to load the
                course from the module store.
        """
        store = modulestore()
        with store.bulk_operations(course_id):
            course = store.get_course(course_id)
            if isinstance(course, CourseDescriptor):
                course_overview = cls._create_or_update(course)
                try:
                    with transaction.atomic():
                        course_overview.save()
                        # Remove and recreate all the course tabs
                        CourseOverviewTab.objects.filter(
                            course_overview=course_overview).delete()
                        CourseOverviewTab.objects.bulk_create([
                            CourseOverviewTab(tab_id=tab.tab_id,
                                              course_overview=course_overview)
                            for tab in course.tabs
                        ])
                        # Remove and recreate course images
                        CourseOverviewImageSet.objects.filter(
                            course_overview=course_overview).delete()
                        CourseOverviewImageSet.create(course_overview, course)

                except IntegrityError:
                    # There is a rare race condition that will occur if
                    # CourseOverview.get_from_id is called while a
                    # another identical overview is already in the process
                    # of being created.
                    # One of the overviews will be saved normally, while the
                    # other one will cause an IntegrityError because it tries
                    # to save a duplicate.
                    # (see: https://openedx.atlassian.net/browse/TNL-2854).
                    pass
                except Exception:  # pylint: disable=broad-except
                    log.exception(
                        "CourseOverview for course %s failed!",
                        course_id,
                    )
                    raise

                return course_overview
            elif course is not None:
                raise IOError(
                    "Error while loading course {} from the module store: {}",
                    unicode(course_id), course.error_msg if isinstance(
                        course, ErrorDescriptor) else unicode(course))
            else:
                raise cls.DoesNotExist()

    @classmethod
    def get_from_id(cls, course_id):
        """
        Load a CourseOverview object for a given course ID.

        First, we try to load the CourseOverview from the database. If it
        doesn't exist, we load the entire course from the modulestore, create a
        CourseOverview object from it, and then cache it in the database for
        future use.

        Arguments:
            course_id (CourseKey): the ID of the course overview to be loaded.

        Returns:
            CourseOverview: overview of the requested course.

        Raises:
            - CourseOverview.DoesNotExist if the course specified by course_id
                was not found.
            - IOError if some other error occurs while trying to load the
                course from the module store.
        """
        try:
            course_overview = cls.objects.select_related('image_set').get(
                id=course_id)
            if course_overview.version < cls.VERSION:
                # Throw away old versions of CourseOverview, as they might contain stale data.
                course_overview.delete()
                course_overview = None
        except cls.DoesNotExist:
            course_overview = None

        # Regenerate the thumbnail images if they're missing (either because
        # they were never generated, or because they were flushed out after
        # a change to CourseOverviewImageConfig.
        if course_overview and not hasattr(course_overview, 'image_set'):
            CourseOverviewImageSet.create(course_overview)

        return course_overview or cls.load_from_module_store(course_id)

    @classmethod
    def get_from_ids_if_exists(cls, course_ids):
        """
        Return a dict mapping course_ids to CourseOverviews, if they exist.

        This method will *not* generate new CourseOverviews or delete outdated
        ones. It exists only as a small optimization used when CourseOverviews
        are known to exist, for common situations like the student dashboard.

        Callers should assume that this list is incomplete and fall back to
        get_from_id if they need to guarantee CourseOverview generation.
        """
        return {
            overview.id: overview
            for overview in cls.objects.select_related('image_set').filter(
                id__in=course_ids, version__gte=cls.VERSION)
        }

    @classmethod
    def get_from_id_if_exists(cls, course_id):
        """
        Return a CourseOverview for the provided course_id if it exists.
        Returns None if no CourseOverview exists with the provided course_id

        This method will *not* generate new CourseOverviews or delete outdated
        ones. It exists only as a small optimization used when CourseOverviews
        are known to exist, for common situations like the student dashboard.

        Callers should assume that this list is incomplete and fall back to
        get_from_id if they need to guarantee CourseOverview generation.
        """
        try:
            course_overview = cls.objects.select_related('image_set').get(
                id=course_id, version__gte=cls.VERSION)
        except cls.DoesNotExist:
            course_overview = None

        return course_overview

    def clean_id(self, padding_char='='):
        """
        Returns a unique deterministic base32-encoded ID for the course.

        Arguments:
            padding_char (str): Character used for padding at end of base-32
                                -encoded string, defaulting to '='
        """
        return course_metadata_utils.clean_course_key(self.location.course_key,
                                                      padding_char)

    @property
    def location(self):
        """
        Returns the UsageKey of this course.

        UsageKeyField has a strange behavior where it fails to parse the "run"
        of a course out of the serialized form of a Mongo Draft UsageKey. This
        method is a wrapper around _location attribute that fixes the problem
        by calling map_into_course, which restores the run attribute.
        """
        if self._location.run is None:
            self._location = self._location.map_into_course(self.id)
        return self._location

    @property
    def number(self):
        """
        Returns this course's number.

        This is a "number" in the sense of the "course numbers" that you see at
        lots of universities. For example, given a course
        "Intro to Computer Science" with the course key "edX/CS-101/2014", the
        course number would be "CS-101"
        """
        return course_metadata_utils.number_for_course_location(self.location)

    @property
    def url_name(self):
        """
        Returns this course's URL name.
        """
        return block_metadata_utils.url_name_for_block(self)

    @property
    def display_name_with_default(self):
        """
        Return reasonable display name for the course.
        """
        return block_metadata_utils.display_name_with_default(self)

    @property
    def display_name_with_default_escaped(self):
        """
        DEPRECATED: use display_name_with_default

        Return html escaped reasonable display name for the course.

        Note: This newly introduced method should not be used.  It was only
        introduced to enable a quick search/replace and the ability to slowly
        migrate and test switching to display_name_with_default, which is no
        longer escaped.
        """
        return block_metadata_utils.display_name_with_default_escaped(self)

    @property
    def dashboard_start_display(self):
        """
         Return start date to diplay on learner's dashboard, preferably `Course Advertised Start`
        """
        return self.advertised_start or self.start

    def has_started(self):
        """
        Returns whether the the course has started.
        """
        return course_metadata_utils.has_course_started(self.start)

    def has_ended(self):
        """
        Returns whether the course has ended.
        """
        return course_metadata_utils.has_course_ended(self.end)

    def has_marketing_url(self):
        """
        Returns whether the course has marketing url.
        """
        return settings.FEATURES.get('ENABLE_MKTG_SITE') and bool(
            self.marketing_url)

    def has_social_sharing_url(self):
        """
        Returns whether the course has social sharing url.
        """
        is_social_sharing_enabled = getattr(settings,
                                            'SOCIAL_SHARING_SETTINGS',
                                            {}).get('CUSTOM_COURSE_URLS')
        return is_social_sharing_enabled and bool(self.social_sharing_url)

    def starts_within(self, days):
        """
        Returns True if the course starts with-in given number of days otherwise returns False.
        """
        return course_metadata_utils.course_starts_within(self.start, days)

    @property
    def start_date_is_still_default(self):
        """
        Checks if the start date set for the course is still default, i.e.
        .start has not been modified, and .advertised_start has not been set.
        """
        return course_metadata_utils.course_start_date_is_default(
            self.start,
            self.advertised_start,
        )

    @property
    def sorting_score(self):
        """
        Returns a tuple that can be used to sort the courses according
        the how "new" they are. The "newness" score is computed using a
        heuristic that takes into account the announcement and
        (advertised) start dates of the course if available.

        The lower the number the "newer" the course.
        """
        return course_metadata_utils.sorting_score(self.start,
                                                   self.advertised_start,
                                                   self.announcement)

    @property
    def start_type(self):
        """
        Returns the type of the course's 'start' field.
        """
        if self.advertised_start:
            return u'string'
        elif self.start != DEFAULT_START_DATE:
            return u'timestamp'
        else:
            return u'empty'

    @property
    def start_display(self):
        """
        Returns the display value for the course's start date.
        """
        if self.advertised_start:
            return self.advertised_start
        elif self.start != DEFAULT_START_DATE:
            return defaultfilters.date(self.start, "DATE_FORMAT")
        else:
            return None

    def may_certify(self):
        """
        Returns whether it is acceptable to show the student a certificate
        download link.
        """
        return course_metadata_utils.may_certify_for_course(
            self.certificates_display_behavior,
            self.certificates_show_before_end, self.has_ended(),
            self.certificate_available_date, self.self_paced)

    @property
    def pre_requisite_courses(self):
        """
        Returns a list of ID strings for this course's prerequisite courses.
        """
        return json.loads(self._pre_requisite_courses_json)

    @pre_requisite_courses.setter
    def pre_requisite_courses(self, value):
        """
        Django requires there be a setter for this, but it is not
        necessary for the way we currently use it. Due to the way
        CourseOverviews are constructed raising errors here will
        cause a lot of issues. These should not be mutable after
        construction, so for now we just eat this.
        """
        pass

    @classmethod
    def update_select_courses(cls, course_keys, force_update=False):
        """
        A side-effecting method that updates CourseOverview objects for
        the given course_keys.

        Arguments:
            course_keys (list[CourseKey]): Identifies for which courses to
                return CourseOverview objects.
            force_update (boolean): Optional parameter that indicates
                whether the requested CourseOverview objects should be
                forcefully updated (i.e., re-synched with the modulestore).
        """
        log.info('Generating course overview for %d courses.',
                 len(course_keys))
        log.debug(
            'Generating course overview(s) for the following courses: %s',
            course_keys)

        action = CourseOverview.load_from_module_store if force_update else CourseOverview.get_from_id

        for course_key in course_keys:
            try:
                action(course_key)
            except Exception as ex:  # pylint: disable=broad-except
                log.exception(
                    'An error occurred while generating course overview for %s: %s',
                    unicode(course_key),
                    text_type(ex),
                )

        log.info('Finished generating course overviews.')

    @classmethod
    def get_all_courses(cls, orgs=None, filter_=None):
        """
        Returns all CourseOverview objects in the database.

        Arguments:
            orgs (list[string]): Optional parameter that allows case-insensitive
                filtering by organization.
            filter_ (dict): Optional parameter that allows custom filtering.
        """
        # Note: If a newly created course is not returned in this QueryList,
        # make sure the "publish" signal was emitted when the course was
        # created. For tests using CourseFactory, use emit_signals=True.
        course_overviews = CourseOverview.objects.all()

        if orgs:
            # In rare cases, courses belonging to the same org may be accidentally assigned
            # an org code with a different casing (e.g., Harvardx as opposed to HarvardX).
            # Case-insensitive matching allows us to deal with this kind of dirty data.
            course_overviews = course_overviews.filter(org__iregex=r'(' +
                                                       '|'.join(orgs) + ')')

        if filter_:
            course_overviews = course_overviews.filter(**filter_)

        return course_overviews

    @classmethod
    def get_all_course_keys(cls):
        """
        Returns all course keys from course overviews.
        """
        return CourseOverview.objects.values_list('id', flat=True)

    def is_discussion_tab_enabled(self):
        """
        Returns True if course has discussion tab and is enabled
        """
        tabs = self.tabs.all()
        # creates circular import; hence explicitly referenced is_discussion_enabled
        for tab in tabs:
            if tab.tab_id == "discussion" and django_comment_client.utils.is_discussion_enabled(
                    self.id):
                return True
        return False

    @property
    def image_urls(self):
        """
        Return a dict with all known URLs for this course image.

        Current resolutions are:
          raw = original upload from the user
          small = thumbnail with dimensions CourseOverviewImageConfig.current().small
          large = thumbnail with dimensions CourseOverviewImageConfig.current().large

        If no thumbnails exist, the raw (originally uploaded) image will be
        returned for all resolutions.
        """
        # This is either the raw image that the course team uploaded, or the
        # settings.DEFAULT_COURSE_ABOUT_IMAGE_URL if they didn't specify one.
        raw_image_url = self.course_image_url

        # Default all sizes to return the raw image if there is no
        # CourseOverviewImageSet associated with this CourseOverview. This can
        # happen because we're disabled via CourseOverviewImageConfig.
        urls = {
            'raw': raw_image_url,
            'small': raw_image_url,
            'large': raw_image_url,
        }

        # If we do have a CourseOverviewImageSet, we still default to the raw
        # images if our thumbnails are blank (might indicate that there was a
        # processing error of some sort while trying to generate thumbnails).
        if hasattr(
                self,
                'image_set') and CourseOverviewImageConfig.current().enabled:
            urls['small'] = self.image_set.small_url or raw_image_url
            urls['large'] = self.image_set.large_url or raw_image_url

        return self.apply_cdn_to_urls(urls)

    @property
    def pacing(self):
        """ Returns the pacing for the course.

        Potential values:
            self: Self-paced courses
            instructor: Instructor-led courses
        """
        return 'self' if self.self_paced else 'instructor'

    @property
    def closest_released_language(self):
        """
        Returns the language code that most closely matches this course' language and is fully
        supported by the LMS, or None if there are no fully supported languages that
        match the target.
        """
        return get_closest_released_language(
            self.language) if self.language else None

    def apply_cdn_to_urls(self, image_urls):
        """
        Given a dict of resolutions -> urls, return a copy with CDN applied.

        If CDN does not exist or is disabled, just returns the original. The
        URLs that we store in CourseOverviewImageSet are all already top level
        paths, so we don't need to go through the /static remapping magic that
        happens with other course assets. We just need to add the CDN server if
        appropriate.
        """
        cdn_config = AssetBaseUrlConfig.current()
        if not cdn_config.enabled:
            return image_urls

        base_url = cdn_config.base_url

        return {
            resolution: self._apply_cdn_to_url(url, base_url)
            for resolution, url in image_urls.items()
        }

    def _apply_cdn_to_url(self, url, base_url):
        """
        Applies a new CDN/base URL to the given URL.

        If a URL is absolute, we skip switching the host since it could
        be a hostname that isn't behind our CDN, and we could unintentionally
        break the URL overall.
        """

        # The URL can't be empty.
        if not url:
            return url

        _, netloc, path, params, query, fragment = urlparse(url)

        # If this is an absolute URL, just return it as is.  It could be a domain
        # that isn't ours, and thus CDNing it would actually break it.
        if netloc:
            return url

        return urlunparse((None, base_url, path, params, query, fragment))

    def __unicode__(self):
        """Represent ourselves with the course key."""
        return unicode(self.id)
Ejemplo n.º 26
0
class Exercise(models.Model):
    step = IntegerField()
    start_time = DateTimeField()
    end_time = DateTimeField()
    type = IntegerField()
    pass
Ejemplo n.º 27
0
class Customer(StripeCustomer):
    doc = """

.. note:: Sources and Subscriptions are attached via a ForeignKey on StripeSource and Subscription, respectively. \
Use ``Customer.sources`` and ``Customer.subscriptions`` to access them.
    """
    __doc__ = getattr(StripeCustomer, "__doc__") + doc

    # account = ForeignKey(Account, related_name="customers")

    default_source = ForeignKey(StripeSource, null=True, related_name="customers", on_delete=SET_NULL)

    subscriber = ForeignKey(
        djstripe_settings.get_subscriber_model_string(), null=True,
        on_delete=SET_NULL, related_name="djstripe_customers"
    )
    date_purged = DateTimeField(null=True, editable=False)

    djstripe_subscriber_key = "djstripe_subscriber"

    class Meta:
        unique_together = ("subscriber", "livemode")

    @property
    def email(self):
        return self.subscriber.email

    def str_parts(self):
        parts = []

        if self.subscriber:
            parts.append(smart_str(self.subscriber))
            parts.append("email={email}".format(email=self.subscriber.email))
        else:
            parts.append("(deleted)")

        parts.extend(super(Customer, self).str_parts())

        return parts

    @classmethod
    def get_or_create(cls, subscriber, livemode=djstripe_settings.STRIPE_LIVE_MODE):
        """
        Get or create a dj-stripe customer.

        :param subscriber: The subscriber model instance for which to get or create a customer.
        :type subscriber: User

        :param livemode: Whether to get the subscriber in live or test mode.
        :type livemode: bool
        """

        try:
            return Customer.objects.get(subscriber=subscriber, livemode=livemode), False
        except Customer.DoesNotExist:
            action = "create:{}".format(subscriber.pk)
            idempotency_key = djstripe_settings.get_idempotency_key("customer", action, livemode)
            return cls.create(subscriber, idempotency_key=idempotency_key), True

    @classmethod
    def create(cls, subscriber, idempotency_key=None):
        trial_days = None
        if djstripe_settings.trial_period_for_subscriber_callback:
            trial_days = djstripe_settings.trial_period_for_subscriber_callback(subscriber)

        stripe_customer = cls._api_create(
            email=subscriber.email,
            idempotency_key=idempotency_key,
            metadata={cls.djstripe_subscriber_key: subscriber.pk}
        )
        customer, created = Customer.objects.get_or_create(
            stripe_id=stripe_customer["id"],
            defaults={"subscriber": subscriber, "livemode": stripe_customer["livemode"]}
        )

        if djstripe_settings.DEFAULT_PLAN and trial_days:
            customer.subscribe(
                plan=djstripe_settings.DEFAULT_PLAN,
                trial_end=timezone.now() + timezone.timedelta(days=trial_days)
            )

        return customer

    def purge(self):
        try:
            self._api_delete()
        except InvalidRequestError as exc:
            if "No such customer:" in str(exc):
                # The exception was thrown because the stripe customer was already
                # deleted on the stripe side, ignore the exception
                pass
            else:
                # The exception was raised for another reason, re-raise it
                six.reraise(*sys.exc_info())

        self.subscriber = None

        # Remove sources
        self.default_source = None
        for source in self.sources.all():
            source.remove()

        self.date_purged = timezone.now()
        self.save()

    # TODO: Override Queryset.delete() with a custom manager, since this doesn't get called in bulk deletes
    #       (or cascades, but that's another matter)
    def delete(self, using=None, keep_parents=False):
        """
        Overriding the delete method to keep the customer in the records. All identifying information is removed
        via the purge() method.

        The only way to delete a customer is to use SQL.

        """

        self.purge()

    def _get_valid_subscriptions(self):
        """ Get a list of this customer's valid subscriptions."""

        return [subscription for subscription in self.subscriptions.all() if subscription.is_valid()]

    def has_active_subscription(self, plan=None):
        """
        Checks to see if this customer has an active subscription to the given plan.

        :param plan: The plan for which to check for an active subscription. If plan is None and
                     there exists only one active subscription, this method will check if that subscription
                     is valid. Calling this method with no plan and multiple valid subscriptions for this customer will
                     throw an exception.
        :type plan: Plan or string (plan ID)

        :returns: True if there exists an active subscription, False otherwise.
        :throws: TypeError if ``plan`` is None and more than one active subscription exists for this customer.
        """

        if plan is None:
            valid_subscriptions = self._get_valid_subscriptions()

            if len(valid_subscriptions) == 0:
                return False
            elif len(valid_subscriptions) == 1:
                return True
            else:
                raise TypeError("plan cannot be None if more than one valid subscription exists for this customer.")

        else:
            # Convert Plan to stripe_id
            if isinstance(plan, Plan):
                plan = plan.stripe_id

            return any([subscription.is_valid() for subscription in self.subscriptions.filter(plan__stripe_id=plan)])

    def has_any_active_subscription(self):
        """
        Checks to see if this customer has an active subscription to any plan.

        :returns: True if there exists an active subscription, False otherwise.
        :throws: TypeError if ``plan`` is None and more than one active subscription exists for this customer.
        """

        return len(self._get_valid_subscriptions()) != 0

    @property
    def active_subscriptions(self):
        """Returns active subscriptions (subscriptions with an active status that end in the future)."""
        return self.subscriptions.filter(
            status=StripeSubscription.STATUS_ACTIVE, current_period_end__gt=timezone.now()
        )

    @property
    def valid_subscriptions(self):
        """Returns this cusotmer's valid subscriptions (subscriptions that aren't cancelled."""
        return self.subscriptions.exclude(status=StripeSubscription.STATUS_CANCELED)

    @property
    def subscription(self):
        """
        Shortcut to get this customer's subscription.

        :returns: None if the customer has no subscriptions, the subscription if
                  the customer has a subscription.
        :raises MultipleSubscriptionException: Raised if the customer has multiple subscriptions.
                In this case, use ``Customer.subscriptions`` instead.
        """

        subscriptions = self.valid_subscriptions

        if subscriptions.count() > 1:
            raise MultipleSubscriptionException("This customer has multiple subscriptions. Use Customer.subscriptions "
                                                "to access them.")
        else:
            return subscriptions.first()

    # TODO: Accept a coupon object when coupons are implemented
    def subscribe(self, plan, charge_immediately=True, **kwargs):
        # Convert Plan to stripe_id
        if isinstance(plan, Plan):
            plan = plan.stripe_id

        stripe_subscription = super(Customer, self).subscribe(plan=plan, **kwargs)

        if charge_immediately:
            self.send_invoice()

        return Subscription.sync_from_stripe_data(stripe_subscription)

    def can_charge(self):
        """Determines if this customer is able to be charged."""

        return self.has_valid_source() and self.date_purged is None

    def charge(self, amount, currency="usd", **kwargs):
        stripe_charge = super(Customer, self).charge(amount=amount, currency=currency, **kwargs)
        charge = Charge.sync_from_stripe_data(stripe_charge)

        return charge

    def add_invoice_item(self, amount, currency, **kwargs):
        # Convert Invoice to stripe_id
        if "invoice" in kwargs and isinstance(kwargs["invoice"], Invoice):
            kwargs.update({"invoice": kwargs["invoice"].stripe_id})

        # Convert Subscription to stripe_id
        if "subscription" in kwargs and isinstance(kwargs["subscription"], Subscription):
            kwargs.update({"subscription": kwargs["subscription"].stripe_id})

        stripe_invoiceitem = super(Customer, self).add_invoice_item(amount=amount, currency=currency, **kwargs)

        return InvoiceItem.sync_from_stripe_data(stripe_invoiceitem)

    def send_invoice(self):
        """
        Pay and send the customer's latest invoice.

        :returns: True if an invoice was able to be created and paid, False otherwise
                  (typically if there was nothing to invoice).
        """
        try:
            invoice = Invoice._api_create(customer=self.stripe_id)
            invoice.pay()
            return True
        except InvalidRequestError:  # TODO: Check this for a more specific error message.
            return False  # There was nothing to invoice

    def retry_unpaid_invoices(self):
        """ Attempt to retry collecting payment on the customer's unpaid invoices."""

        self._sync_invoices()
        for invoice in self.invoices.filter(paid=False, closed=False):
            try:
                invoice.retry()  # Always retry unpaid invoices
            except InvalidRequestError as exc:
                if str(exc) != "Invoice is already paid":
                    six.reraise(*sys.exc_info())

    def has_valid_source(self):
        """ Check whether the customer has a valid payment source."""
        return self.default_source is not None

    def add_card(self, source, set_default=True, three_d_secure_info=None):
        new_stripe_card = super(Customer, self).add_card(source, set_default, three_d_secure_info=three_d_secure_info)
        new_card = Card.sync_from_stripe_data(new_stripe_card)
        self.sync_from_stripe()

        # Change the default source
        if set_default:
            self.default_source = new_card
            self.save()

        return new_card

    def upcoming_invoice(self, **kwargs):
        """ Gets the upcoming preview invoice (singular) for this customer.

        See `Invoice.upcoming() <#djstripe.Invoice.upcoming>`__.

        The ``customer`` argument to the ``upcoming()`` call is automatically set by this method.
        """

        kwargs['customer'] = self
        return Invoice.upcoming(**kwargs)

    def _attach_objects_post_save_hook(self, cls, data):
        default_source = data.get("default_source")

        if default_source:
            # TODO: other sources
            if not isinstance(default_source, dict) or default_source.get("object") == "card":
                source, created = Card._get_or_create_from_stripe_object(data, "default_source", refetch=False)
            else:
                logger.warn("Unsupported source type on %r: %r", self, default_source)
                source = None

            if source and source != self.default_source:
                self.default_source = source
                self.save()

    def _attach_objects_hook(self, cls, data):
        # When we save a customer to Stripe, we add a reference to its Django PK
        # in the `django_account` key. If we find that, we re-attach that PK.
        subscriber_id = data.get("metadata", {}).get(self.djstripe_subscriber_key)
        if subscriber_id:
            cls = djstripe_settings.get_subscriber_model()
            try:
                # We have to perform a get(), instead of just attaching the PK
                # blindly as the object may have been deleted or not exist.
                # Attempting to save that would cause an IntegrityError.
                self.subscriber = cls.objects.get(pk=subscriber_id)
            except (cls.DoesNotExist, ValueError):
                logger.warn("Could not find subscriber %r matching customer %r" % (subscriber_id, self.stripe_id))
                self.subscriber = None

    # SYNC methods should be dropped in favor of the master sync infrastructure proposed
    def _sync_invoices(self, **kwargs):
        for stripe_invoice in Invoice.api_list(customer=self.stripe_id, **kwargs):
            Invoice.sync_from_stripe_data(stripe_invoice)

    def _sync_charges(self, **kwargs):
        for stripe_charge in Charge.api_list(customer=self.stripe_id, **kwargs):
            Charge.sync_from_stripe_data(stripe_charge)

    def _sync_cards(self, **kwargs):
        for stripe_card in Card.api_list(customer=self, **kwargs):
            Card.sync_from_stripe_data(stripe_card)

    def _sync_subscriptions(self, **kwargs):
        for stripe_subscription in Subscription.api_list(customer=self.stripe_id, status="all", **kwargs):
            Subscription.sync_from_stripe_data(stripe_subscription)
Ejemplo n.º 28
0
class LocalDateTime(Func):
    template = '%(expressions)s'
    arg_joiner = ' AT TIME ZONE '
    arity = 2

    output_field = DateTimeField()
Ejemplo n.º 29
0
class Exam(models.Model):
    user = ForeignKey(User , on_delete=models.CASCADE)
    questions = ManyToManyField(Questions)
    answers = ManyToManyField(Answer)
    result = FloatField(null=True)
    answered_at = DateTimeField(auto_now_add=True)
Ejemplo n.º 30
0
class Course(models.Model):
    course_name = models.CharField(max_length=255)
    description = models.TextField()
    created_at = DateTimeField(auto_now_add=True)
    updated_at = DateTimeField(auto_now_add=True)
    objects = CourseManager()