from django.db import models from django.utils.translation import ugettext as _ from django.contrib.auth.models import User, Permission from django.db.models import Q from datetime import datetime from location_field.models import PlainLocationField class NoNextEventException(Exception): def __str__(self): return "No event scheduled for the future" class Event(models.Model): EVENT_TYPES = ( ('Reh', _('Rehearsal')), ('Conc', _('Concert')), ('Party', _('Party')), ('Travel', _('Travel')), ('Option', _('Option')), ) type = models.CharField(max_length=6, choices=EVENT_TYPES, default='Reh', verbose_name=_("type")) short_desc = models.CharField(null=True, max_length=100, blank=True, verbose_name=_("Short Description")) location = models.TextField(blank=True, verbose_name=_("location")) map_location = PlainLocationField(blank=True, based_field=location, zoom=7, verbose_name=_("Location on map")) desc = models.TextField(blank=True, verbose_name=_("description")) date = models.DateField(verbose_name=_("date")) time = models.TimeField(null=True, blank=True, verbose_name=_("time")) meeting_time = models.TimeField(null=True, blank=True, verbose_name=_("meeting_time")) end_date = models.DateField(null=True, blank=True, verbose_name=_("End Date")) participants = models.ManyToManyField(User, through='EventParticipation', verbose_name=_("participants")) def __unicode__(self): return self.title def save(self, *args, **kwargs): # Call the "real" save() method super(Event, self).save(*args, **kwargs) # Create a "Don't Know" participation for each Musician for u in User.objects.all(): if not u in self.participants.all(): EventParticipation.objects.create(event=self, user=u, status='-', comment='') @property def title(self): res = self.get_type_display() if self.short_desc: res += " (" + self.short_desc + ") " return res @property def displaytime(self): if self.meeting_time is None or self.meeting_time == "": return self.time else: return self.meeting_time @property def displaydatetime(self): if not self.displaytime == None: return datetime.combine(self.date, self.displaytime) else: return datetime.combine(self.date, datetime.min.time()) @staticmethod def getNextEvent(eventType="", includePreviousFromToday=True): """Return the next event, of the given type. If type is the empty string the next event is returned regardless of its type. if includePreviousFromToday the nextEvent returned could also have been today with a startime < now """ if includePreviousFromToday: if eventType == "": nextEvents = Event.objects.filter(date__gte=datetime.now()).order_by('date')[:1] else: nextEvents = Event.objects.filter(date__gte=datetime.now(), type=eventType).order_by('date')[:1] if len(nextEvents) == 0: raise NoNextEventException() return nextEvents[0] else: maximalNumberOfEventsOnSameDay = 4 nextEvents = [] if eventType == "": nextEvents = Event.objects.filter(date__gte=datetime.now()).order_by('date')[ :maximalNumberOfEventsOnSameDay] else: nextEvents = Event.objects.filter(date__gte=datetime.now(), type=eventType).order_by('date')[ :maximalNumberOfEventsOnSameDay] if len(nextEvents) == 0: raise NoNextEventException() i = 0 nextEvent = nextEvents[0] # nextEvent is not necessarily events[0] since events[0] may have been previously today while nextEvent.displaydatetime < datetime.now(): if len(nextEvents) <= i: raise NoNextEventException() else: i += 1 nextEvent = nextEvents[i] return nextEvent class EventParticipation(models.Model): OPTIONS = (('?', _('?')), ('Yes', _('Yes')), ('No', _('No')), ('-', _('-')) ) event = models.ForeignKey(Event, verbose_name=_("event"), on_delete=models.PROTECT) user = models.ForeignKey(User, verbose_name=_("user"), on_delete=models.PROTECT) status = models.CharField(max_length=3, choices=OPTIONS, default='?', verbose_name=_("status")) comment = models.CharField(max_length=64, blank=True, verbose_name=_("comment")) def get_username(self): return self.user.username def save(self, *args, **kwargs): prev = EventParticipation.objects.filter(event=self.event, user=self.user) if len(prev) == 0: super(EventParticipation, self).save(*args, **kwargs) else: prev = prev[0] if prev.status != self.status or prev.comment != self.comment: super(EventParticipation, self).save(*args, **kwargs) @staticmethod def hasUserSetParticipationForAllEvents(user): if not EventParticipation.isMember(user): return True futurePart = EventParticipation.objects.filter(event__date__gte=datetime.now()) notYetEntered = futurePart.filter(user=user).filter(status='-') if len(notYetEntered) > 0: return False else: return True @staticmethod def isMember(user): return user.has_perm('eventplanner.member') @staticmethod def isAdmin(user): return user.has_perm('eventplanner.admin') @staticmethod def members(): perm = Permission.objects.get(codename='member') f = User.objects.filter(Q(groups__permissions=perm) | Q(user_permissions=perm)).distinct() return f.order_by('musician__position') @staticmethod def get_or_create(user, event): try: result = EventParticipation.objects.get(event=event, user=user) except EventParticipation.DoesNotExist: result = EventParticipation.objects.create(event=event, user=user, status='-', comment='') return result class Meta: unique_together = ("event", "user") permissions = ( ("admin", _("Admin")), ("member", _("Member")), )