예제 #1
0
파일: models.py 프로젝트: peg5/txrx.org
class EventOccurrence(PhotosMixin,OccurrenceModel):
  event = models.ForeignKey(Event)
  publish_dt = models.DateTimeField(default=datetime.datetime.now) # for rss feed
  get_admin_url = lambda self: "/admin/event/event/%s/"%self.event.id
  name_override = models.CharField(null=True,blank=True,max_length=128)
  name = property(lambda self: self.name_override or self.event.name)
  short_name = property(lambda self: self.name_override or self.event.get_short_name())
  url = property(lambda self: self.url_override or self.event.url)
  description_override = wmd_models.MarkDownField(blank=True,null=True)
  description = property(lambda self: self.description_override or self.event.description)
  get_room = lambda self: self.event.room #! depracate me
  room = cached_property(lambda self: self.event.room,name="room")
  no_conflict = property(lambda self: self.event.no_conflict)

  url_override = models.CharField(max_length=256,null=True,blank=True)
  _get_absolute_url = lambda self: reverse('event:occurrence_detail',args=(self.id,slugify(self.name)))
  get_absolute_url = lambda self: self.url_override or self.event.url or self._get_absolute_url()
  get_absolute_url = cached_method(get_absolute_url,name="get_absolute_url")

  rsvp_cutoff = property(lambda self: self.start - datetime.timedelta(self.event.rsvp_cutoff))
  total_rsvp = property(lambda self: sum([r.quantity for r in self.get_rsvps()]))
  full = property(lambda self: self.total_rsvp >= self.event.max_rsvp)
  icon = property(lambda self: self.event.icon)
  _cid = ContentType.objects.get(model="eventoccurrence").id
  @cached_method
  def get_rsvps(self):
    return RSVP.objects.filter(object_id=self.id,content_type_id=self._cid)
  def save(self,*args,**kwargs):
    # set the publish_dt to a week before the event
    self.publish_dt = self.start - datetime.timedelta(7)
    super(EventOccurrence,self).save(*args,**kwargs)
  @property
  def past(self):
    now = datetime.datetime.now()
    return (self.end < now) or (self.rsvp_cutoff < now and not self.get_rsvps().count())
  @property
  def as_json(self):
    return {
      'room_id': self.event.room_id,
      'name': self.name,
      'start': str(self.start),
      'end': str(self.end),
    }
  class Meta:
    ordering = ('start',)
예제 #2
0
파일: models.py 프로젝트: peg5/txrx.org
class Course(PhotosMixin, ToolsMixin, FilesMixin, models.Model):
    name = models.CharField(max_length=64)
    slug = property(lambda self: slugify(self.name))
    active = models.BooleanField(
        default=True)  # only used with the reshedule view
    _ht = "Used for the events page."
    short_name = models.CharField(max_length=64,
                                  null=True,
                                  blank=True,
                                  help_text=_ht)
    get_short_name = lambda self: self.short_name or self.name
    subjects = models.ManyToManyField(Subject)
    no_discount = models.BooleanField(default=False)

    @cached_property
    def first_room(self):
        return (self.courseroomtime_set.all() or [self])[0].room

    presentation = models.BooleanField("Evaluate Presentation", default=True)
    visuals = models.BooleanField("Evaluate Visuals", default=True)
    content = models.BooleanField("Evaluate Content", default=True)

    _ht = "The dashboard (/admin/) won't bug you to reschedule until after this date"
    reschedule_on = models.DateField(default=datetime.date.today,
                                     help_text=_ht)
    first_date = property(lambda self: self.active_sessions[0].first_date)
    last_date = property(lambda self: self.active_sessions[-1].last_date)

    @property
    def as_json(self):
        image = get_thumbnail(get_override(self.first_photo, 'landscape_crop'),
                              "298x199",
                              crop="center")
        out = {
            'id':
            self.pk,
            'name':
            self.name,
            'subject_names': [s.name for s in self.subjects.all()],
            'subject_ids': [s.pk for s in self.subjects.all()],
            'url':
            self.get_absolute_url(),
            'im': {
                'width': image.width,
                'height': image.height,
                'url': image.url
            },
            'next_time':
            time.mktime(self.first_date.timetuple())
            if self.active_sessions else 0,
            'fee':
            self.fee,
            'active_sessions': [s.as_json for s in self.active_sessions],
            'past_session_count':
            len(self.archived_sessions),
            'short_description':
            self.get_short_description(),
            'requirements':
            self.requirements,
            'no_discount':
            self.no_discount,
        }
        out['enrolled_status'] = "Enroll" if out[
            'active_sessions'] else "Details"
        return out

    fee = models.IntegerField(null=True, blank=True, default=0)
    fee_notes = models.CharField(max_length=256, null=True, blank=True)
    requirements = models.CharField(max_length=256, null=True, blank=True)
    prerequisites = models.CharField(max_length=256, null=True, blank=True)
    description = models.TextField(null=True, blank=True)
    short_description = models.TextField(null=True, blank=True)
    get_short_description = lambda self: self.short_description or truncatewords(
        striptags(self.description), 40)
    safety = models.BooleanField(default=False)
    room = models.ForeignKey(Room)

    def get_location_string(self):
        if self.first_room != self.room:
            s = "This class meets in the %s and then moves to the %s after a half hour lecture."
            return s % (self.first_room.name.lower(), self.room.name.lower())
        return "This class meets in the %s." % (self.room.name.lower())

    _ht = "If true, this class will not raise conflict warnings for events in the same room."
    no_conflict = models.BooleanField(default=False, help_text=_ht)
    max_students = models.IntegerField(default=16)

    objects = CourseManager()
    __unicode__ = lambda self: self.name
    get_absolute_url = lambda self: reverse("course:detail",
                                            args=[self.pk, self.slug])
    get_admin_url = lambda self: "/admin/course/course/%s/" % self.id

    @cached_method
    def get_tools(self):
        criterion_ids = Criterion.objects.filter(courses=self).values_list(
            "id", flat=True)
        return Tool.objects.filter(
            permission__criteria__id__in=criterion_ids).distinct()

    @cached_property
    def active_sessions(self):
        # sessions haven't ended yet (and maybe haven't started)
        first_date = datetime.datetime.now() - datetime.timedelta(0.5)
        return list(self.sessions.filter(last_date__gte=first_date))

    @property
    def archived_sessions(self):
        # opposite of active_sessions
        first_date = datetime.datetime.now() - datetime.timedelta(0.5)
        last_year = first_date - datetime.timedelta(365)
        sessions = self.session_set.filter(last_date__lt=first_date,
                                           last_date__gte=last_year)
        return list(sessions.order_by("-first_date"))

    sessions = lambda self: Session.objects.filter(course=self, active=True)
    sessions = cached_property(sessions, name="sessions")
    last_session = lambda self: (list(self.sessions) or [None])[-1]

    def save(self, *args, **kwargs):
        super(Course, self).save(*args, **kwargs)
        #this has to be repeated in the admin because of how that works
        subjects = self.subjects.all()
        for subject in subjects:
            if subject.parent and not (subject.parent in subjects):
                self.subjects.add(subject.parent)

        reset_classes_json("Classes reset during course save")

    #! inherited from section, may not be necessary
    def get_notes(self):
        notes = []
        if self.requirements:
            notes.append(('Requirements', self.requirements))
        if self.fee_notes:
            notes.append(('Fee Notes', self.fee_notes))
        if self.safety:
            notes.append((
                'Safety',
                "This class has a 20 minute safety session before the first session."
            ))
        if self.prerequisites:
            notes.append(('Prerequisites', self.prerequisites))
        return notes

    @property
    def list_users(self):
        return list(set([s.user for s in self.active_sessions]))

    class Meta:
        ordering = ("name", )
예제 #3
0
파일: models.py 프로젝트: peg5/txrx.org
class ClassTime(OccurrenceModel):
    session = models.ForeignKey(Session)
    emailed = models.DateTimeField(null=True, blank=True)

    def short_name(self):
        times = list(self.session.classtime_set.all())
        s = self.session.course.get_short_name()
        if len(times) != 1:
            s = "%s (%s/%s)" % (s, times.index(self) + 1, len(times))
        if self.session.private:
            return "[PRIVATE] " + s
        return s

    get_absolute_url = lambda self: self.session.get_absolute_url()
    get_absolute_url = cached_method(get_absolute_url, name='get_absolute_url')
    get_admin_url = lambda self: "/admin/course/session/%s/" % self.session.id
    get_room = lambda self: self.session.course.room
    no_conflict = lambda self: self.session.course.no_conflict
    description = cached_property(lambda self: self.session.course.description,
                                  name="description")
    name = cached_property(lambda self: self.session.course.name, name="name")
    room = cached_property(lambda self: self.session.course.room, name="room")
    icon = property(lambda self: 'private'
                    if self.session.private else 'course')

    @property
    def as_json(self):
        room = self.session.course.first_room
        return {
            'room_id': self.session.course.room_id,
            'session_id': self.session_id,
            'name': self.short_name(),
            'start': str(self.start),
            'end': str(self.end),
            #! this should just be an id on session or course with a separate lookup
            'first_room': {
                'id': room.id,
                'name': room.name
            }
        }

    @cached_method
    def build_class_times(self):
        course = self.session.course

        # 1-indexed day number
        daynumber = self.session.classtime_set.filter(
            start__gte=self.start).count()
        roomtimes = course.courseroomtime_set.filter(day=daynumber)
        roomtimes = roomtimes or course.courseroomtime_set.filter(day=0)
        if not roomtimes:
            return [self]
        out = []
        current_datetime = self.start
        for roomtime in roomtimes:
            remaining = self.end - current_datetime
            occurrence = SessionRoomTime(
                start=current_datetime,
                end_time=(current_datetime +
                          datetime.timedelta(0, roomtime.seconds_at)
                          or remaining).time(),
                name="%s at %s for %s hours" %
                (course, roomtime.room, roomtime.hours_at),
                room=roomtime.room,
                session=self.session)
            current_datetime = occurrence.end
            out.append(occurrence)
        if occurrence.end != self.end:
            remaining = current_datetime - self.end
            occurrence = SessionRoomTime(
                start=current_datetime,
                end_time=self.end_time,
                room=self.room,
                name="%s at %s until end (%s)" %
                (course, course.room, occurrence.end_time),
                session=self.session,
            )
            out.append(occurrence)
        return out

    class Meta:
        ordering = ("start", )
예제 #4
0
파일: models.py 프로젝트: peg5/txrx.org
class Session(UserModel, PhotosMixin, models.Model):
    def __init__(self, *args, **kwargs):
        super(Session, self).__init__(*args, **kwargs)
        if self.pk:
            # this sets self.first_date to the first ClassTime.start if they aren't equal
            # also sets self.last_date to the last ClassTime.end
            # handled in the admin by /static/js/course_admin.js
            _a = self.all_occurrences
            if not _a:
                return
            if not _a[0].start == self.first_date:
                self.first_date = _a[0].start
                self.save()
            if not _a[-1].end == self.last_date:
                self.last_date = _a[-1].end
                self.save()

    get_ics_url = lambda self: reverse_ics(self)
    course = models.ForeignKey(Course)
    cancelled = models.BooleanField(default=False)
    active = models.BooleanField(default=True)
    _ht = "This session will not appear as overbooked if it is less than X seats overbooked."
    overbook = models.IntegerField(default=0, help_text=_ht)
    _ht = "Private classes cannot be signed up for and do not appear on the session page unless " \
          "the user is manually enrolled. It will appear on calendar but it will be marked in red."
    private = models.BooleanField(default=False, help_text=_ht)
    notified = models.DateTimeField(null=True, blank=True)
    publish_dt = models.DateTimeField(null=True, blank=True)
    _ht = "This will be automatically updated when you save the model. Do not change"
    first_date = models.DateTimeField(default=datetime.datetime.now,
                                      help_text=_ht)  # for filtering
    last_date = models.DateTimeField(default=datetime.datetime.now,
                                     help_text=_ht)  # for filtering
    created = models.DateTimeField(
        auto_now_add=True)  # for emailing new classes
    # depracated?
    branding = models.ForeignKey(Branding, null=True, blank=True)

    _ht = "Date the instructor marked students in the class as completed"
    instructor_completed = models.DateField(null=True, blank=True)
    needed = models.TextField("What is needed?", blank=True, default="")
    needed_completed = models.DateField(null=True, blank=True)

    __unicode__ = lambda self: latin1_to_ascii("%s (%s - %s)" %
                                               (self.course, self.user,
                                                self.first_date.date()))
    title = property(lambda self: "%s (%s)" %
                     (self.course.name, self.first_date.date()))

    in_progress = property(lambda self: self.first_date < datetime.datetime.
                           now() < self.last_date)
    past = property(lambda self: datetime.datetime.now() > self.last_date)
    closed = property(lambda self: self.cancelled or
                      (self.past and not self.in_progress))

    @property
    def as_json(self):
        short_dates = self.get_short_dates()
        enrolled_status = "Enrolled: %s" % short_dates
        if datetime.datetime.now() > self.last_date:
            d = self.last_date
            enrolled_status = "Completed: %s/%s/%s" % (d.month, d.day, d.year)
        closed_status = self.closed_string if (self.closed
                                               or self.full) else None
        if self.private:
            closed_status = 'private'
        return {
            'id': self.pk,
            'name': "<b>%s</b> %s" % (self.course, short_dates),
            'course_name': self.course.name,
            'closed_status': closed_status,
            'short_dates': short_dates,
            'instructor_name': self.get_instructor_name(),
            'instructor_pk': self.user_id,
            'course_id': self.course_id,
            'enrolled_status': enrolled_status,
            'classtimes': [c.as_json for c in self.classtime_set.all()],
            'product_id': self.sessionproduct.id,
            'private': True,
        }

    json = property(lambda self: dumps(self.as_json))
    get_room = lambda self: self.course.room

    total_students = property(
        lambda self: sum([e.quantity for e in self.enrollment_set.all()]))
    evaluated_students = property(lambda self: self.get_evaluations().count())
    completed_students = property(lambda self: self.enrollment_set.filter(
        completed__isnull=False).count())
    full = property(
        lambda self: self.total_students >= self.course.max_students)
    list_users = property(lambda self: [self.user])

    #! mucch of this if deprecated after course remodel
    description = property(lambda self: self.course.description)

    @cached_property
    def first_photo(self):
        return (self.get_photos() or [super(Session, self).first_photo])[0]

    @cached_method
    def get_photos(self):
        return self._get_photos() or self.course.get_photos()

    #calendar crap
    name = property(lambda self: self.course.name)
    all_occurrences = cached_property(
        lambda self: list(self.classtime_set.all()), name='all_occurrences')
    get_ics_url = lambda self: reverse_ics(self)

    @cached_method
    def get_week(self):
        sunday = self.first_date.date() - datetime.timedelta(
            self.first_date.weekday())
        return (sunday, sunday + datetime.timedelta(6))

    subjects = cached_property(
        lambda self: self.course.subjects.filter(parent__isnull=True),
        name="subjects")
    all_subjects = cached_property(lambda self: self.course.subjects.all(),
                                   name="all_subjects")

    @cached_property
    def related_sessions(self):
        sessions = Session.objects.filter(
            first_date__gte=datetime.datetime.now(), active=True)
        sessions = sessions.exclude(course=self.course)
        sub_subjects = self.course.subjects.filter(parent__isnull=False)
        sub_sessions = list(
            sessions.filter(course__subjects__in=sub_subjects).distinct())
        if len(sub_sessions) >= 5:
            return sub_sessions
        sessions = sessions.filter(course__subjects__in=self.subjects.all())
        sessions = list(sessions.exclude(course__subjects__in=sub_subjects))
        return sub_sessions + sessions

    @property
    def closed_string(self):  #! may be depracated
        if self.cancelled:
            return "cancelled"
        if self.past:
            return "past"
        return "full"

    def save(self, *args, **kwargs):
        #this may be depracated, basically the site fails hard if instructors don't have membership profiles
        from membership.models import UserMembership
        if not self.pk and self.course:
            c = self.course
            c.active = True
            c.save()
        if self.active and not self.publish_dt:
            publish_dt = datetime.datetime.now()
        profile, _ = UserMembership.objects.get_or_create(user=self.user)
        super(Session, self).save(*args, **kwargs)
        SessionProduct.objects.get_or_create(session=self)[0].update()

    @cached_method
    def get_absolute_url(self):
        return self.course.get_absolute_url()

    get_admin_url = lambda self: "/admin/course/session/%s/" % self.id
    get_rsvp_url = cached_method(
        lambda self: reverse('course:rsvp', args=[self.id]),
        name="get_rsvp_url")

    def get_instructor_name(self):
        if self.user.first_name and self.user.last_name:
            return "%s %s." % (self.user.first_name, self.user.last_name[0])
        return self.user.username

    def get_short_dates(self):
        dates = [ct.start for ct in self.all_occurrences]
        month = None
        out = []
        for d in dates:
            if month != d.month:
                month = d.month
                out.append(d.strftime("%b %e"))
            else:
                out.append(d.strftime("%e"))
        return ', '.join(out)

    def get_evaluations(self):
        return Evaluation.objects.filter(enrollment__session=self)

    def has_completed_permission(self, user):
        return user.is_superuser or user.is_toolmaster or user.id == self.user_id

    class Meta:
        ordering = ('first_date', )
예제 #5
0
class Level(models.Model):
    name = models.CharField(max_length=64)
    order = models.IntegerField("Level")
    products = cached_property(
        lambda self: self.product_set.filter(active=True), name="products")
    monthly_product = property(lambda self: self.products.filter(months=1)[0])
    yearly_product = property(lambda self: self.products.filter(months=12)[0])
    discount_percentage = models.IntegerField(default=0)
    group = models.ForeignKey(Group, null=True, blank=True)
    features = cached_property(
        lambda self: [a.feature for a in self.membershipfeature_set.all()],
        name="features")
    permission_description = models.TextField(blank=True, default="")

    # Corporate membership features
    machine_credits = models.IntegerField(default=0)
    simultaneous_users = models.IntegerField(default=0)
    cost_per_credit = models.DecimalField(max_digits=30,
                                          decimal_places=2,
                                          default=0)
    custom_training_cost = models.DecimalField(max_digits=30,
                                               decimal_places=2,
                                               default=0)
    custom_training_max = models.DecimalField(max_digits=30,
                                              decimal_places=2,
                                              default=0)

    # access schedule defaults
    tool_schedule = models.ForeignKey("tool.Schedule",
                                      null=True,
                                      blank=True,
                                      related_name="+")
    door_schedule = models.ForeignKey("tool.Schedule",
                                      null=True,
                                      blank=True,
                                      related_name="+")
    holiday_access = models.BooleanField(default=False)

    def get_schedule_id(self, obj):
        if obj._meta.model_name == 'permission':
            return self.tool_schedule_id
        elif obj._meta.model_name == 'doorgroup':
            try:
                return self.leveldoorgroupschedule_set.get(
                    doorgroup=obj).schedule_id
            except LevelDoorGroupSchedule.DoesNotExist:
                return self.door_schedule_id

    def get_features(self):
        if not self.cost_per_credit:
            return self.features
        credits = '%s Machine credits.' % self.machine_credits
        if self.machine_credits:
            credits = "%s Monthly machine credits." % self.machine_credits
        discount = "%s%% Discount on all training classes" % self.discount_percentage
        if self.custom_training_cost:
            d2 = " and custom training sessions @ $%s/hr (max %s hrs per month)"
            d2 = d2 % (int(
                self.custom_training_cost), int(self.custom_training_max))
            discount = discount + d2
        features = [
            credits,
            "Max %s simultaneous users." % self.simultaneous_users,
            discount + ".",
            "Machine credits can be purchased @ $%s per credit." %
            self.cost_per_credit,
        ]
        return [{'text': f} for f in features] + self.features

    @cached_property
    def all_users(self):
        return get_user_model().objects.filter(subscrition__level=self)

    def count_all_users(self):
        return self.all_users.count()

    def count_active_users(self):
        return self.all_users.filter(
            subscription__canceled__isnull=True).distinct().count()

    def profiles(self):
        return self.profile_set.all()

    class Meta:
        verbose_name = "Membership Level"
        ordering = ("order", )

    __unicode__ = lambda self: self.name