예제 #1
0
class KegSessionChunk(_AbstractChunk):
  """A specific keg's contribution to a session (spans all users)."""
  class Meta:
    unique_together = ('session', 'keg')
    get_latest_by = 'starttime'
    ordering = ('-starttime',)

  objects = managers.SessionManager()
  site = models.ForeignKey(KegbotSite, related_name='keg_chunks')
  session = models.ForeignKey(DrinkingSession, related_name='keg_chunks')
  keg = models.ForeignKey(Keg, related_name='keg_session_chunks', blank=True,
      null=True)

  def GetTitle(self):
    return self.session.GetTitle()
예제 #2
0
class DrinkingSession(_AbstractChunk):
    """A collection of contiguous drinks. """
    class Meta:
        unique_together = ('site', 'seqn')
        get_latest_by = 'start_time'
        ordering = ('-start_time', )

    objects = managers.SessionManager()
    site = models.ForeignKey(KegbotSite, related_name='sessions')
    seqn = models.PositiveIntegerField(editable=False)
    name = models.CharField(max_length=256, blank=True, null=True)
    slug = AutoSlugField(populate_from='name',
                         unique_with='site',
                         blank=True,
                         null=True)

    def __str__(self):
        return "Session #%s: %s" % (self.seqn, self.start_time)

    def RecomputeStats(self):
        self.stats.all().delete()
        try:
            last_d = self.drinks.valid().latest()
            last_d._UpdateSessionStats()
        except Drink.DoesNotExist:
            pass

    @models.permalink
    def get_absolute_url(self):
        if self.slug:
            slug = self.slug
        else:
            slug = 'session-%i' % self.seqn
        return ('kb-session', (), {
            'kbsite_name': self.site.url(),
            'year': self.start_time.year,
            'month': '%02i' % self.start_time.month,
            'day': '%02i' % self.start_time.day,
            'seqn': self.seqn,
            'slug': slug
        })

    def GetStatsRecord(self):
        try:
            return SessionStats.objects.get(session=self)
        except SessionStats.DoesNotExist:
            return None

    def GetStats(self):
        record = self.GetStatsRecord()
        if record:
            return record.stats
        return {}

    def summarize_drinkers(self):
        def fmt(user):
            url = '/drinker/%s/' % (user.username, )
            return '<a href="%s">%s</a>' % (url, user.username)

        chunks = self.user_chunks.all().order_by('-volume_ml')
        users = tuple(c.user for c in chunks)
        names = tuple(fmt(u) for u in users if u)

        if None in users:
            guest_trailer = ' (and possibly others)'
        else:
            guest_trailer = ''

        num = len(names)
        if num == 0:
            return 'no known drinkers'
        elif num == 1:
            ret = names[0]
        elif num == 2:
            ret = '%s and %s' % names
        elif num == 3:
            ret = '%s, %s and %s' % names
        else:
            if guest_trailer:
                return '%s, %s and at least %i others' % (names[0], names[1],
                                                          num - 2)
            else:
                return '%s, %s and %i others' % (names[0], names[1], num - 2)

        return '%s%s' % (ret, guest_trailer)

    def GetTitle(self):
        if self.name:
            return self.name
        else:
            return 'Session %i' % (self.seqn, )

    def AddDrink(self, drink):
        super(DrinkingSession, self).AddDrink(drink)
        session_delta = drink.site.settings.GetSessionTimeoutDelta()

        defaults = {
            'start_time': drink.time,
            'end_time': drink.time + session_delta,
        }

        # Update or create a SessionChunk.
        chunk, created = SessionChunk.objects.get_or_create(session=self,
                                                            user=drink.user,
                                                            keg=drink.keg,
                                                            defaults=defaults)
        chunk.AddDrink(drink)

        # Update or create a UserSessionChunk.
        chunk, created = UserSessionChunk.objects.get_or_create(
            session=self, site=drink.site, user=drink.user, defaults=defaults)
        chunk.AddDrink(drink)

        # Update or create a KegSessionChunk.
        chunk, created = KegSessionChunk.objects.get_or_create(
            session=self, site=drink.site, keg=drink.keg, defaults=defaults)
        chunk.AddDrink(drink)

    def UserChunksByVolume(self):
        chunks = self.user_chunks.all().order_by('-volume_ml')
        return chunks

    def IsActiveNow(self):
        return self.IsActive(datetime.datetime.now())

    def IsActive(self, now):
        return self.end_time > now

    def Rebuild(self):
        self.volume_ml = 0
        self.chunks.all().delete()
        self.user_chunks.all().delete()
        self.keg_chunks.all().delete()

        drinks = self.drinks.valid()
        if not drinks:
            # TODO(mikey): cancel/delete the session entirely.  As it is, session will
            # remain a placeholder.
            return

        session_delta = self.site.settings.GetSessionTimeoutDelta()
        min_time = None
        max_time = None
        for d in drinks:
            self.AddDrink(d)
            if min_time is None or d.time < min_time:
                min_time = d.time
            if max_time is None or d.time > max_time:
                max_time = d.time
        self.start_time = min_time
        self.end_time = max_time + session_delta
        self.save()

    @classmethod
    def AssignSessionForDrink(cls, drink):
        # Return existing session if already assigned.
        if drink.session:
            return drink.session

        # Return last session if one already exists
        q = drink.site.sessions.all().order_by('-end_time')[:1]
        if q and q[0].IsActive(drink.time):
            session = q[0]
            session.AddDrink(drink)
            drink.session = session
            drink.save()
            return session

        # Create a new session
        session = cls(start_time=drink.time,
                      end_time=drink.time,
                      site=drink.site)
        session.save()
        session.AddDrink(drink)
        drink.session = session
        drink.save()
        return session
예제 #3
0
class DrinkingSession(_AbstractChunk):
    """A collection of contiguous drinks. """
    class Meta:
        get_latest_by = 'start_time'
        ordering = ('-start_time', )

    objects = managers.SessionManager()
    name = models.CharField(max_length=256, blank=True, null=True)

    def __str__(self):
        return "Session #%s: %s" % (self.id, self.start_time)

    def ShortUrl(self):
        return '%s%s' % (SiteSettings.get().base_url(),
                         reverse('kb-session-short', args=(str(self.id), )))

    def HighlightPicture(self):
        pictures = self.pictures.all().order_by('-time')
        if pictures:
            return pictures[0]
        chunks = self.user_chunks.filter(user__ne=None).order_by('-volume_ml')
        if chunks:
            mugshot = chunks[0].user.get_profile().mugshot
            return mugshot

    def OtherPictures(self):
        pictures = self.pictures.all().order_by('-time')
        if pictures:
            return pictures[1:]
        return []

    def get_absolute_url(self):
        dt = timezone.localtime(self.start_time)
        return reverse('kb-session-detail',
                       args=(),
                       kwargs={
                           'year': dt.year,
                           'month': dt.month,
                           'day': dt.day,
                           'pk': self.pk
                       })

    def GetStatsRecord(self):
        qs = SessionStats.objects.filter(session=self).order_by('-id')
        if len(qs):
            return qs[0]
        return None

    def GetStats(self):
        ret = {}
        record = self.GetStatsRecord()
        if record:
            ret = record.stats
        return util.AttrDict(ret)

    def summarize_drinkers(self):
        def fmt(user):
            url = '/drinkers/%s/' % (user.username, )
            return '<a href="%s">%s</a>' % (url, user.username)

        chunks = self.user_chunks.all().order_by('-volume_ml')
        users = tuple(c.user for c in chunks)
        names = tuple(fmt(u) for u in users if u)

        if None in users:
            guest_trailer = ' (and possibly others)'
        else:
            guest_trailer = ''

        num = len(names)
        if num == 0:
            return 'no known drinkers'
        elif num == 1:
            ret = names[0]
        elif num == 2:
            ret = '%s and %s' % names
        elif num == 3:
            ret = '%s, %s and %s' % names
        else:
            if guest_trailer:
                return '%s, %s and at least %i others' % (names[0], names[1],
                                                          num - 2)
            else:
                return '%s, %s and %i others' % (names[0], names[1], num - 2)

        return '%s%s' % (ret, guest_trailer)

    def GetTitle(self):
        if self.name:
            return self.name
        else:
            if self.id:
                return 'Session %s' % (self.id, )
            else:
                # Not yet saved.
                return 'New Session'

    def AddDrink(self, drink):
        super(DrinkingSession, self).AddDrink(drink)
        session_delta = SiteSettings.get().GetSessionTimeoutDelta()

        defaults = {
            'start_time': drink.time,
            'end_time': drink.time + session_delta,
        }

        # Update or create a SessionChunk.
        chunk, created = SessionChunk.objects.get_or_create(session=self,
                                                            user=drink.user,
                                                            keg=drink.keg,
                                                            defaults=defaults)
        chunk.AddDrink(drink)

        # Update or create a UserSessionChunk.
        chunk, created = UserSessionChunk.objects.get_or_create(
            session=self, user=drink.user, defaults=defaults)
        chunk.AddDrink(drink)

        # Update or create a KegSessionChunk.
        chunk, created = KegSessionChunk.objects.get_or_create(
            session=self, keg=drink.keg, defaults=defaults)
        chunk.AddDrink(drink)

    def UserChunksByVolume(self):
        chunks = self.user_chunks.all().order_by('-volume_ml')
        return chunks

    def IsActiveNow(self):
        return self.IsActive(timezone.now())

    def IsActive(self, now):
        return self.end_time > now

    def Rebuild(self):
        """Recomputes start and end time, and chunks, based on current drinks.

        This method should be called after changing the set of drinks
        belonging to this session.

        This method has no effect on statistics; see stats module.
        """
        self.volume_ml = 0
        self.chunks.all().delete()
        self.user_chunks.all().delete()
        self.keg_chunks.all().delete()

        drinks = self.drinks.all()
        if not drinks:
            self.delete()
            return

        session_delta = SiteSettings.get().GetSessionTimeoutDelta()
        min_time = None
        max_time = None
        for d in drinks:
            self.AddDrink(d)
            if min_time is None or d.time < min_time:
                min_time = d.time
            if max_time is None or d.time > max_time:
                max_time = d.time
        self.start_time = min_time
        self.end_time = max_time + session_delta
        self.save()

    @classmethod
    def AssignSessionForDrink(cls, drink):
        # Return existing session if already assigned.
        if drink.session:
            return drink.session

        # Return last session if one already exists
        q = DrinkingSession.objects.all().order_by('-end_time')[:1]
        if q and q[0].IsActive(drink.time):
            session = q[0]
            session.AddDrink(drink)
            drink.session = session
            drink.save()
            return session

        # Create a new session
        session = cls(start_time=drink.time, end_time=drink.time)
        session.save()
        session.AddDrink(drink)
        drink.session = session
        drink.save()
        return session
예제 #4
0
class DrinkingSession(models.Model):
    """A collection of contiguous drinks. """
    class Meta:
        get_latest_by = 'start_time'
        ordering = ('-start_time',)
    start_time = models.DateTimeField()
    end_time = models.DateTimeField()
    volume_ml = models.FloatField(default=0)

    objects = managers.SessionManager()
    name = models.CharField(max_length=256, blank=True, null=True)

    def __unicode__(self):
        return 'Session #{}: {}'.format(self.id, self.start_time)

    def Duration(self):
        return self.end_time - self.start_time

    def _AddDrinkNoSave(self, drink):
        session_delta = KegbotSite.get().get_session_timeout_timedelta()
        session_end = drink.time + session_delta

        if self.start_time > drink.time:
            self.start_time = drink.time
        if self.end_time < session_end:
            self.end_time = session_end
        self.volume_ml += drink.volume_ml

    def AddDrink(self, drink):
        self._AddDrinkNoSave(drink)
        self.save()

    def short_url(self):
        return '%s%s' % (KegbotSite.get().base_url(), reverse('kb-session-short',
            args=(str(self.id),)))

    def full_url(self):
        return '%s%s' % (KegbotSite.get().base_url(), self.get_absolute_url())

    def get_highlighted_picture(self):
        pictures = self.pictures.all().order_by('-time')
        if pictures:
            return pictures[0]
        return None

    def get_non_highlighted_pictures(self):
        pictures = self.pictures.all().order_by('-time')
        if pictures:
            return pictures[1:]
        return []

    def get_absolute_url(self):
        dt = timezone.localtime(self.start_time)
        return reverse('kb-session-detail', args=(), kwargs={
          'year' : dt.year,
          'month' : dt.month,
          'day' : dt.day,
          'pk' : self.pk})

    def get_stats(self):
        return Stats.get_latest_for_view(session=self)

    def summarize_drinkers(self):
        stats = self.get_stats()
        volmap = stats.get('volume_by_drinker', {})
        names = [x for x in reversed(sorted(volmap, key=volmap.get))]

        if 'guest' in names:
            guest_trailer = ' (and possibly others)'
        else:
            guest_trailer = ''

        num = len(names)
        if num == 0:
            return 'no known drinkers'
        elif num == 1:
            ret = names[0]
        elif num == 2:
            ret = '{} and {}'.format(*names)
        elif num == 3:
            ret = '{}, {} and {}'.format(*names)
        else:
            if guest_trailer:
                return '%s, %s and at least %i others' % (names[0], names[1], num-2)
            else:
                return '%s, %s and %i others' % (names[0], names[1], num-2)

        return '%s%s' % (ret, guest_trailer)

    def GetTitle(self):
        if self.name:
            return self.name
        else:
            if self.id:
                return 'Session %s' % (self.id,)
            else:
                # Not yet saved.
                return 'New Session'

    def IsActiveNow(self):
        return self.IsActive(timezone.now())

    def IsActive(self, now):
        return self.end_time > now

    def Rebuild(self):
        """Recomputes start time, end time, and volume, based on current drinks.

        This method should be called after changing the set of drinks
        belonging to this session.

        This method has no effect on statistics; see stats module.
        """
        self.volume_ml = 0

        drinks = self.drinks.all()
        if not drinks:
            self.delete()
            return

        session_delta = KegbotSite.get().get_session_timeout_timedelta()
        min_time = None
        max_time = None
        for d in drinks:
            self.AddDrink(d)
            if min_time is None or d.time < min_time:
                min_time = d.time
            if max_time is None or d.time > max_time:
                max_time = d.time
        self.start_time = min_time
        self.end_time = max_time + session_delta
        self.save()

    @classmethod
    def AssignSessionForDrink(cls, drink):
        # Return existing session if already assigned.
        if drink.session:
            return drink.session

        # Return last session if one already exists
        q = DrinkingSession.objects.all().order_by('-end_time')[:1]
        if q and q[0].IsActive(drink.time):
            session = q[0]
            session.AddDrink(drink)
            drink.session = session
            drink.save()
            return session

        # Create a new session
        session = cls(start_time=drink.time, end_time=drink.time)
        session.save()
        session.AddDrink(drink)
        drink.session = session
        drink.save()
        return session