Exemplo n.º 1
0
class InformacieNotification(SONWrapper):
    def __init__(self, data):
        super(InformacieNotification, self).__init__(data, incol)

    def user(self):
        return by_id(self._data['user'])

    def relation(self):
        return relation_by_id(self._data['relation'])

    def tag(self):
        return by_id(self._data['tag'])

    def entity(self):
        return by_id(self._data['entity'])

    def fotoEvent(self):
        import kn.fotos.entities as fEs
        return fEs.by_id(self._data['fotoEvent'])

    def fotoAlbum(self):
        import kn.fotos.entities as fEs
        return fEs.by_id(self._data['fotoAlbum'])

    event = son_property(('event', ))
    when = son_property(('when', ))
Exemplo n.º 2
0
class Event(SONWrapper):
    def __init__(self, data):
        super(Event, self).__init__(data, ecol)

    @classmethod
    def from_data(cls, data):
        if data is None:
            return None
        return cls(data)

    name = son_property(('name', ))
    date = son_property(('date', ))
    kind = son_property(('kind', ))

    @classmethod
    def all(cls):
        for c in ecol.find():
            yield cls.from_data(c)

    @classmethod
    def all_in_future(cls):
        return cls.all_since_datetime(now())

    @classmethod
    def all_since_datetime(cls, since):
        for c in ecol.find({'date': {'$gte': since}}):
            yield cls.from_data(c)

    @classmethod
    def by_id(cls, id):
        return cls.from_data(ecol.find_one({'_id': _id(id)}))

    def vacancies(self, pool=None):
        return Vacancy.all_by_event(self, pool)
Exemplo n.º 3
0
class Worker(SONWrapper):
    def __init__(self, data):
        super(Worker, self).__init__(data, wcol)

    @classmethod
    def from_data(cls, data):
        if data is None:
            return None
        return cls(data)

    pools = son_property(('pools', ))
    user_id = son_property(('user', ))

    @classmethod
    def all(cls):
        for m in wcol.find():
            yield cls.from_data(m)

    @classmethod
    def all_in_pool(cls, p):
        for m in wcol.find({'pools': _id(p)}):
            yield cls.from_data(m)

    @classmethod
    def by_id(cls, id):
        return cls.from_data(wcol.find_one({'_id': _id(id)}))

    @property
    def id(self):
        return self._id

    def get_user(self):
        return Es.by_id(self.user_id)

    def set_user(self, x):
        self.user_id = _id(x)

    user = property(get_user, set_user)

    @property
    def username(self):
        return str(self.user.name)

    def last_shift_in(self, pool):
        self.last_shift = None
        for v in vcol.find({
                'assignee': _id(self),
                'pool': _id(pool)
        },
                           sort=[('begin', DESCENDING)],
                           limit=1):
            return Vacancy(v).begin.date()

    # last_shift is used in a template
    def set_last_shift(self, pool):
        self.last_shift = self.last_shift_in(pool)
Exemplo n.º 4
0
class HistoryEvent(SONWrapper):
    def __init__(self, data, event):
        super(HistoryEvent, self).__init__(data, ecol, event)
        self.event = event

    action = son_property(('action', ))
    date = son_property(('date', ))

    @property
    def user(self):
        return Es.by_id(self._data['by'])
Exemplo n.º 5
0
class ModerationRecord(SONWrapper):
    def __init__(self, data):
        super(ModerationRecord, self).__init__(data, mcol)
    list = son_property(('list',))
    at = son_property(('at',))
    by_id = son_property(('by',))

    def get_by(self):
        return Es.by_id(self._data['by'])
    def set_by(self, x):
        self._data['by'] = _id(x)
    by = property(get_by, set_by)
Exemplo n.º 6
0
class AgendaEvent(SONWrapper):
    def __init__(self, data):
        super(AgendaEvent, self).__init__(data, acol)

    @property
    def id(self):
        return str(self._data['_id'])

    start = son_property(('start', ))
    end = son_property(('end', ))
    description = son_property(('description', ))
    title = son_property(('title', ))

    @property
    def description(self):
        text = self._data.get('description', '')
        text = text.replace(
            'Villa van Schaeck',
            '<a href="%s">Villa van Schaeck</a>' % reverse('route'))
        return text

    @property
    def month(self):
        return self.start.date().strftime('%B')

    @property
    def shortdate(self):
        return self.start.date().strftime('%a %d')

    @property
    def date(self):
        if self.start.day == self.end.day:
            return self.start.date().strftime('%A %e %B')
        if self.start.month == self.end.month:
            return mark_safe("{} &mdash; {}".format(
                self.start.date().strftime('%a %e'),
                self.end.date().strftime('%a %e %B')))
        return mark_safe("{} &mdash; {}".format(
            self.start.date().strftime('%a %e %b'),
            self.end.date().strftime('%a %e %b')))

    def __unicode__(self):
        return self.title
Exemplo n.º 7
0
class Filling(SONWrapper):
    def __init__(self, data):
        super(Filling, self).__init__(data, fcol)
    @property
    def id(self):
        return str(self._data['_id'])
    @property
    def poll(self):
        return Event(poll_by_id(self._data['poll']))
    @property
    def user(self):
        return Es.by_id(self._data['user'])

    answers = son_property(('answers',))
    date = son_property(('date',))

    def __unicode__(self):
        return unicode(u"answers of %s for %s" % (
                self.user.humanName, self.poll.humanName))
Exemplo n.º 8
0
class Subscription(SONWrapper):
    def __init__(self, data):
        super(Subscription, self).__init__(data, scol)

    @property
    def id(self):
        return str(self._data['_id'])

    @property
    def date(self):
        return self._data.get('date', None)

    @property
    def event(self):
        return Event(event_by_id(self._data['event']))

    @property
    def user(self):
        return Es.by_id(self._data['user'])

    def __unicode__(self):
        return unicode(u"%s for %s" %
                       (self.user.humanName, self.event.humanName))

    def get_debit(self):
        return decimal.Decimal(self._data['debit'])

    def set_debit(self, v):
        self._data['debit'] = str(v)

    debit = property(get_debit, set_debit)

    @property
    def subscribedBy(self):
        if not 'subscribedBy' in self._data:
            return None
        return Es.by_id(self._data['subscribedBy'])

    userNotes = son_property(('userNotes', ), None)
    confirmed = son_property(('confirmed', ), True)
    subscribedBy_notes = son_property(('subscribedBy_notes', ))
    dateConfirmed = son_property(('dateConfirmed', ))
Exemplo n.º 9
0
class Reglement(SONWrapper):
    def __init__(self, data):
        super(Reglement, self).__init__(data, rcol)
    @property
    def id(self):
        return str(self._data['_id'])
    description = son_property(('description',))
    humanName = son_property(('humanName',))
    name = son_property(('name',))

    def get_versions(self):
        for v in vcol.find({'reglement': self._id}).sort('until'):
            yield ReglementVersion(v)

    def __unicode__(self):
        return self.humanName

    @permalink
    def get_absolute_url(self):
        return ('reglement-detail', (), {'name': self.name})
Exemplo n.º 10
0
class Poll(SONWrapper):
    def __init__(self, data):
        super(Poll, self).__init__(data, pcol)
    @property
    def id(self):
        return str(self._data['_id'])
    @property
    def createdBy(self):
        return Es.by_id(self._data['createdBy'])

    description = son_property(('description',))
    name = son_property(('name',))
    humanName = son_property(('humanName',))
    is_open = son_property(('is_open',))
    date = son_property(('date',))
    questions = son_property(('questions',))

    def filling_for(self, user):
        return filling_by_user_and_poll(user, self)

    def fillings(self):
        return filling_by_poll(self)

    def __unicode__(self):
        return self.humanName

    @permalink
    def get_absolute_url(self):
        return ('poll', (), {'name': self.name})
Exemplo n.º 11
0
class ReglementVersion(SONWrapper):
    def __init__(self, data):
        super(ReglementVersion, self).__init__(data, vcol)
    @property
    def id(self):
        return str(self._data['_id'])
    @property
    def reglement(self):
        return reglement_by_id(self._data['reglement'])
    def to_html(self):
        if 'html' not in self._data:
            self._data['html'] = Document.from_string(self.regl).to_html()
            self.save()
        return self._data['html']

    description = son_property(('description',))
    humanName = son_property(('humanName',))
    name = son_property(('name',))
    regl = son_property(('regl',))
    valid_from = son_property(('from',))
    valid_until = son_property(('until',))

    def __unicode__(self):
        return self.humanName

    @permalink
    def get_absolute_url(self):
        # TODO eliminate the query in self.reglement.name
        return ('version-detail', (), {
                            'reglement_name': self.reglement.name,
                            'version_name': self.name})
Exemplo n.º 12
0
class InformacieNotification(SONWrapper):
    def __init__(self, data):
        super(InformacieNotification, self).__init__(data, incol)

    def event(self):
        return self._data.get('event')

    def rel(self):
        return relation_by_id(self._data['rel'])

    def entity(self):
        return by_id(self._data['entity'])

    when = son_property(('when', ))
Exemplo n.º 13
0
class Event(SONWrapper):
    def __init__(self, data):
        super(Event, self).__init__(data, ecol)

    @classmethod
    def from_data(cls, data):
        if data is None:
            return None
        return cls(data)

    name = son_property(('name', ))
    date = son_property(('date', ))
    kind = son_property(('kind', ))

    @classmethod
    def all(cls):
        for c in ecol.find():
            yield cls.from_data(c)

    @classmethod
    def all_in_future(cls):
        return cls.all_in_period(now(), None)

    @classmethod
    def all_in_period(cls, start, end):
        query = {'$gte': start, '$lte': end}
        if end is None:
            query = {'$gte': start}
        for c in ecol.find({'date': query}):
            yield cls.from_data(c)

    @classmethod
    def by_id(cls, id):
        return cls.from_data(ecol.find_one({'_id': _id(id)}))

    def vacancies(self, pool=None):
        return Vacancy.all_by_event(self, pool)
Exemplo n.º 14
0
class Pool(SONWrapper):
    def __init__(self, data):
        super(Pool, self).__init__(data, pcol)
        self._group = None

    @classmethod
    def from_data(cls, data):
        if data is None:
            return None
        return cls(data)

    name = son_property(('name', ))
    administrator = son_property(('administrator', ))
    reminder_format = son_property(('reminder_format', ))
    reminder_cc = son_property(('reminder_cc', ))

    @classmethod
    def all(cls):
        for c in pcol.find():
            yield cls.from_data(c)

    @classmethod
    def by_name(cls, n):
        return cls.from_data(pcol.find_one({'name': n}))

    @classmethod
    def by_id(cls, id):
        return cls.from_data(pcol.find_one({'_id': _id(id)}))

    def vacancies(self):
        return Vacancy.all_in_pool(self)

    @property
    def group(self):
        if not self._group:
            self._group = Es.by_name(self.name)
        return self._group
Exemplo n.º 15
0
class Note(SONWrapper):
    at = son_property(('at', ))
    note = son_property(('note', ))
    by_id = son_property(('by', ))
    on_id = son_property(('on', ))

    def __init__(self, data):
        super(Note, self).__init__(data, ncol)

    @property
    def id(self):
        return str(_id(self))

    @property
    def on(self):
        return by_id(self._data['on'])

    @property
    def by(self):
        return by_id(self._data['by'])

    @property
    def messageId(self):
        return '<note/%s@%s>' % (self.id, settings.MAILDOMAIN)
Exemplo n.º 16
0
class Note(SONWrapper):
    def __init__(self, data, prefetched_by=None, prefetched_closed_by=None):
        super(Note, self).__init__(data, ncol)
        self._cached_by = prefetched_by
        self._cached_closed_by = prefetched_closed_by

    at = son_property(('at', ))
    closed_at = son_property(('closed_at', ))
    note = son_property(('note', ))
    by_id = son_property(('by', ))
    on_id = son_property(('on', ))
    closed_by_id = son_property(('closed_by', ))
    open = son_property(('open', ), True)

    @property
    def id(self):
        return str(_id(self))

    @property
    def on(self):
        return by_id(self._data['on'])

    @property
    def by(self):
        if self._cached_by is not None:
            return self._cached_by
        if self._data['by'] is None:
            return None
        return by_id(self._data['by'])

    @property
    def closed_by(self):
        if self._cached_closed_by is not None:
            return self._cached_closed_by
        if self._data['closed_by'] is None:
            return None
        return by_id(self._data['closed_by'])

    def close(self, closed_by_id, save_now=True):
        self._data['closed_by'] = closed_by_id
        self._data['closed_at'] = now()
        self._data['open'] = False
        if save_now:
            self.save()
Exemplo n.º 17
0
class Event(SONWrapper):
    def __init__(self, data):
        super(Event, self).__init__(data, ecol)

    @property
    def id(self):
        return str(self._data['_id'])

    @property
    def date(self):
        return self._data.get('date', None)

    @property
    def owner(self):
        return Es.by_id(self._data['owner'])

    @property
    def createdBy(self):
        return Es.by_id(self._data['createdBy'])

    def get_subscriptions(self):
        for s in scol.find({'event': self._data['_id']}).sort('date'):
            yield Subscription(s)

    def get_subscription_of(self, user):
        d = scol.find_one({'event': self._data['_id'], 'user': _id(user)})
        if d is None:
            return None
        return Subscription(d)

    @property
    def description(self):
        return self._data['description']

    @property
    def description_html(self):
        return self._data.get('description_html',
                              linebreaks(escape(self._data['description'])))
        # Let wel: 'description' is een *fallback*, het is niet de bedoeling dat
        # deze bij nieuwe actieviteitne nog gebruikt wordt
    @property
    def name(self):
        return self._data['name']

    @property
    def humanName(self):
        return self._data['humanName']

    @property
    def cost(self):
        return decimal.Decimal(self._data['cost'])

    is_open = son_property(('is_open', ))
    is_official = son_property(('is_official', ), True)
    has_public_subscriptions = son_property(('has_public_subscriptions', ),
                                            False)
    mailBody = son_property(('mailBody', ))
    subscribedByOtherMailBody = son_property(('subscribedByOtherMailBody', ))
    confirmationMailBody = son_property(('confirmationMailBody', ))
    everyone_can_subscribe_others = son_property(
        ('everyone_can_subscribe_others', ), False)

    def __unicode__(self):
        return unicode('%s (%s)' % (self.humanName, self.owner))

    @permalink
    def get_absolute_url(self):
        return ('event-detail', (), {'name': self.name})

    def has_read_access(self, user):
        return  self.owner == user or \
            str(self.owner.name) in user.cached_groups_names or \
               'secretariaat' in user.cached_groups_names or \
               'admlezers' in user.cached_groups_names

    def has_write_access(self, user):
        return self.owner == user or \
            str(self.owner.name) in user.cached_groups_names or \
               'secretariaat' in user.cached_groups_names

    def has_debit_access(self, user):
        return 'penningmeester' in user.cached_groups_names or \
               'secretariaat' in user.cached_groups_names
Exemplo n.º 18
0
class FotoEntity(SONWrapper):
    CACHES = {}

    def __init__(self, data):
        super(FotoEntity, self).__init__(data, fcol)

    @property
    def id(self):
        return str(self._data['_id'])

    oldId = son_property(('oldId',))
    name = son_property(('name',))
    path = son_property(('path',))
    _type = son_property(('type',))
    caches = son_property(('caches',), ())
    title = son_property(('title',))
    description = son_property(('description',))
    date = son_property(('date',))
    rotation = son_property(('rotation',))
    size = son_property(('size',))
    _search_text = son_property(('search_text',))

    visibility = son_property(('visibility',))
    _lost = son_property(('lost',))
    effective_visibility = son_property(('effectiveVisibility',))
    notified_informacie = son_property(('notifiedInformacie',))

    @property
    def is_root(self):
        return self.path is None

    def display_title(self):
        if self.title:
            return self.title
        return self.name

    def required_visibility(self, user):
        if user is None:
            return frozenset(('world',))
        if is_admin(user):
            return frozenset(('leden', 'world', 'hidden'))
        if 'leden' in user.cached_groups_names:
            return frozenset(('leden', 'world'))
        return frozenset(('world',))

    def _update_effective_visibility(self, parent, save=True, recursive=False):
        '''
        Update the effectiveVisibility property

        `recursive` keyword argument is ignored
        '''
        if self.effective_visibility is not None:
            return False

        if self.is_root:
            # root
            parent_effective_visibility = self.visibility
        else:
            parent_effective_visibility = parent.effective_visibility

        visibilities = actual_visibility(parent_effective_visibility) & \
            actual_visibility(self.visibility)
        order = ['world', 'leden', 'hidden'] + self.visibility
        if visibilities:
            for v in order:
                if v in visibilities:
                    effective_visibility = [v]
                    break
        else:
            effective_visibility = []

        if self._lost:
            effective_visibility = []

        self.effective_visibility = effective_visibility

        if save:
            self.save()

        return True

    def may_view(self, user):
        return bool(self.required_visibility(user)
                    & frozenset(self.effective_visibility))

    @property
    def full_path(self):
        if not self.path:
            return self.name
        return self.path + '/' + self.name

    @property
    def depth(self):
        '''
        Return how many ancestors this entry has.
        '''
        return 0 if self.is_root else self.full_path.count('/') + 1

    # NOTE keep up to date with media/fotos.js
    @permalink
    def get_cache_url(self, cache):
        return ('fotos-cache', (), {'path': self.full_path,
                                    'cache': cache})

    @permalink
    def get_thumbnail_url(self):
        return ('fotos-cache', (), {'path': self.full_path,
                                    'cache': 'thumb'})

    @permalink
    def get_thumbnail2x_url(self):
        return ('fotos-cache', (), {'path': self.full_path,
                                    'cache': 'thumb2x'})

    def lock_cache(self, cache):
        ret = lcol.find_and_modify({'_id': self._id},
                                   {'$addToSet': {'cacheLocks': cache}},
                                   upsert=True)
        if ret is None:
            return True
        return cache not in ret.get('cacheLocks', ())

    def unlock_cache(self, cache):
        lcol.update({'_id': self._id},
                    {'$pull': {'cacheLocks': cache}})

    def get_cache_path(self, cache):
        if cache == 'full':
            return os.path.join(settings.PHOTOS_DIR, self.path, self.name)
        path = os.path.join(settings.PHOTOS_CACHE_DIR, cache,
                            self.path, self.name)
        ext = self.CACHES[cache].ext
        if ext:
            path += '.' + ext
        return path

    def get_cache_mimetype(self, cache):
        mimetype = self.CACHES[cache].mimetype
        if mimetype is not None:
            return mimetype
        return mimetypes.guess_type(self.get_cache_path(cache))[0]

    def get_cache_size(self, cache):
        c = self.CACHES[cache]
        if self.rotation in [90, 270]:
            # rotated
            height, width = self.size
        else:
            # normal
            width, height = self.size
        return resize_proportional(width, height, c.maxwidth, c.maxheight)

    def ensure_cached(self, cache):
        if cache not in self.CACHES:
            raise KeyError
        if cache in self.caches or cache == 'full':
            return True
        if not self.lock_cache(cache):
            return False
        try:
            self._cache(cache)
            # Normally, we would just modify _data and .save().  However,
            # as the _cache operation may take quite some time, a full
            # .save() might overwrite other changes. (Like other caches.)
            # Thus we perform the change manually.
            if 'caches' not in self._data:
                self._data['caches'] = []
            self._data['caches'].append(cache)
            fcol.update({'_id': self._id},
                        {'$addToSet': {'caches': cache}})
        finally:
            self.unlock_cache(cache)
        return True

    def _cache(self, cache):
        raise NotImplementedError

    def update_metadata(self, parent, save=True):
        '''
        Load metadata from file if it doesn't exist yet
        '''
        return self._update_effective_visibility(
            parent, save=save, recursive=False)

    def update_search_text(self, save=True):
        self._search_text = ''

        if save:
            self.save()

    @property
    def original_path(self):
        return os.path.join(settings.PHOTOS_DIR, self.path, self.name)

    @property
    def mongo_path_prefix(self):
        '''
        Return the MongoDB query filter operator to match the path of this
        entry and all children of this element.
        '''
        if self.is_root:
            # root entity
            return {'$exists': True, '$ne': None}
        # non-root entity
        return {'$regex': re.compile(
            "^%s(/|$)" % re.escape(self.full_path))}

    def get_parent(self):
        if self.is_root:
            return None
        return by_path(self.path)

    def set_title(self, title, save=True):
        self.title = title
        if save:
            self.save()

    def set_description(self, description, save=True):
        self.description = description
        if save:
            self.save()

    def update_visibility(self, visibility):
        '''
        Update the visibility, clear and recalculate effective visibility.
        This object will be saved afterwards.
        '''
        if self.visibility == visibility:
            return

        # First delete all old effective visibilities, in case something goes
        # wrong during the update.
        self._clear_visibility()

        # And now save and recalculate effective visibilities recursively.
        self.visibility = visibility
        self.save()
        self._update_effective_visibility(self.get_parent())

    def _clear_visibility(self):
        self.effective_visibility = None
        fcol.update({'path': self.mongo_path_prefix},
                    {'$unset': {'effectiveVisibility': ''}},
                    multi=True)

    def set_informacie_notified(self, save=True):
        if self.notified_informacie:
            return
        self.notified_informacie = True
        if save:
            self.save()

    @property
    def is_lost(self):
        return bool(self._lost)

    def lost(self, parent):
        if self._lost:
            return

        self._clear_visibility()
        self._lost = True
        self.save()
        self._update_effective_visibility(parent)

    def found(self, parent):
        if not self._lost:
            return

        self._clear_visibility()
        self._lost = False
        self.save()
        self._update_effective_visibility(parent)

    def get_tags(self):
        '''
        Return all tags of this entity (as User object)
        '''
        if 'tags' not in self._data:
            return None

        idmap = Es.by_ids(self._data['tags'])
        people = []
        for id in self._data['tags']:
            people.append(idmap[id])

        return people

    def set_tags(self, tags, save=True):
        '''
        Set tags by their usernames.
        '''
        name2id = Es.ids_by_names(tags)
        self._data['tags'] = []
        for name in tags:
            self._data['tags'].append(name2id[name])

        self.update_search_text(save=False)

        if save:
            self.save()
Exemplo n.º 19
0
class Event(SONWrapper):
    def __init__(self, data):
        super(Event, self).__init__(data, ecol, detect_race=True)
        self._subscriptions = {
            str(d['user']): Subscription(d, self)
            for d in data.get('subscriptions', [])
        }

    name = son_property(('name', ))
    humanName = son_property(('humanName', ))
    date = son_property(('date', ))
    may_unsubscribe = son_property(('may_unsubscribe', ))

    @property
    def id(self):
        return str(self._data['_id'])

    @property
    def owner(self):
        return Es.by_id(self._data['owner'])

    @property
    def createdBy(self):
        return Es.by_id(self._data['createdBy'])

    @property
    def listSubscribed(self):
        return [s for s in self._subscriptions.values() if s.subscribed]

    @property
    def listUnsubscribed(self):
        return [s for s in self._subscriptions.values() if s.unsubscribed]

    @property
    def listInvited(self):
        return filter(lambda s: s.invited and not s.has_mutations,
                      self._subscriptions.values())

    def get_subscription(self, user, create=False):
        '''
        Return Subscription for user, creating it if it doesn't already exist.
        '''
        subscription = self._subscriptions.get(str(_id(user)))
        if subscription or not create:
            return subscription
        if 'subscriptions' not in self._data:
            self._data['subscriptions'] = []
        d = {'user': _id(user)}
        self._data['subscriptions'].append(d)
        subscription = Subscription(d, self)
        self._subscriptions[str(_id(user))] = subscription
        return subscription

    @property
    def description(self):
        return self._data['description']

    @property
    def description_html(self):
        return self._data.get('description_html',
                              linebreaks(escape(self._data['description'])))
        # Let wel: 'description' is een *fallback*, het is niet de
        # bedoeling dat deze bij nieuwe actieviteiten nog gebruikt wordt

    @property
    def cost(self):
        return decimal.Decimal(self._data['cost'])

    max_subscriptions = son_property(('max_subscriptions', ))
    is_open = son_property(('is_open', ))
    is_official = son_property(('is_official', ), True)
    has_public_subscriptions = son_property(('has_public_subscriptions', ),
                                            False)

    def __str__(self):
        return six.u('%s (%s)') % (self.humanName, self.owner)

    @property
    def history(self):
        return [HistoryEvent(d, self) for d in self._data.get('history', [])]

    @permalink
    def get_absolute_url(self):
        return ('event-detail', (), {'name': self.name})

    @property
    def messageId(self):
        """ Unique ID to be used in e.g. References: headers """
        return '<activiteit/%s@%s>' % (self.name, settings.MAILDOMAIN)

    def has_read_access(self, user):
        return (self.owner == user
                or str(self.owner.name) in user.cached_groups_names
                or 'secretariaat' in user.cached_groups_names
                or 'admlezers' in user.cached_groups_names)

    def has_write_access(self, user):
        return (self.owner == user
                or str(self.owner.name) in user.cached_groups_names
                or 'secretariaat' in user.cached_groups_names)

    @property
    def can_subscribe(self):
        if self.max_subscriptions is not None and \
                len(self.listSubscribed) >= self.max_subscriptions:
            return False
        return self.is_open

    @property
    def can_unsubscribe(self):
        return self.is_open and self.may_unsubscribe

    def subscribe(self, user, notes):
        subscription = self.get_subscription(user, create=True)
        subscription.subscribe(notes)
        return subscription

    def unsubscribe(self, user, notes):
        subscription = self.get_subscription(user, create=True)
        subscription.unsubscribe(notes)
        return subscription

    def invite(self, user, notes, inviter):
        subscription = self.get_subscription(user, create=True)
        subscription.invite(inviter, notes)
        return subscription

    def pushHistory(self, historyEvent):
        if 'history' not in self._data:
            self._data['history'] = []
        self._data['history'].append(historyEvent)

    def open(self, user, save=True):
        if self.is_open:
            return
        self.is_open = True
        self.pushHistory({
            'action': 'opened',
            'date': datetime.datetime.now(),
            'by': _id(user)
        })
        if save:
            self.save()

    def close(self, user, save=True):
        if not self.is_open:
            return
        self.is_open = False
        self.pushHistory({
            'action': 'closed',
            'date': datetime.datetime.now(),
            'by': _id(user)
        })
        if save:
            self.save()

    def update(self, data, user, save=True):
        self._data.update(data)
        self.pushHistory({
            'action': 'edited',
            'date': datetime.datetime.now(),
            'by': _id(user)
        })
        if save:
            self.save()
Exemplo n.º 20
0
class Subscription(SONWrapper):
    def __init__(self, data, event):
        super(Subscription, self).__init__(data, ecol, event)
        self.event = event

    inviterNotes = son_property(('inviterNotes', ))
    inviteDate = son_property(('inviteDate', ))
    date = son_property(('date', ))
    history = son_property(('history', ), )

    def __str__(self):
        return six.u("<Subscription(%s for %s)>") % (self.user.humanName,
                                                     self.event.humanName)

    @property
    def id(self):
        return str(self._data['_id'])

    @property
    def user(self):
        return Es.by_id(self._data['user'])

    @property
    def invited(self):
        return 'inviter' in self._data

    @property
    def inviter(self):
        return Es.by_id(self._data.get('inviter'))

    @property
    def lastMutation(self):
        if not self.history:
            return {}
        return self.history[-1]

    def push_mutation(self, mutation):
        if not self.history:
            self.history = []
        self.history.append(mutation)

    @property
    def _state(self):
        return self.lastMutation.get('state')

    @property
    def has_mutations(self):
        return self._state is not None

    @property
    def subscribed(self):
        return self._state == 'subscribed'

    @property
    def unsubscribed(self):
        return self._state == 'unsubscribed'

    @property
    def date(self):
        # last change date
        return self.lastMutation.get('date') or self.inviteDate

    @property
    def userNotes(self):
        return self.lastMutation.get('notes')

    @property
    def notes(self):
        return self.userNotes or self.inviterNotes

    @property
    def subscriber(self):
        subscriber = self.lastMutation.get('subscriber')
        if subscriber is not None:
            return Es.by_id(subscriber)
        return self.user

    def subscribe(self, notes):
        assert not self.subscribed
        mutation = {
            'state': 'subscribed',
            'notes': notes,
            'date': datetime.datetime.now()
        }
        self.push_mutation(mutation)
        self.save()
        self.send_notification(mutation)

    def unsubscribe(self, notes):
        assert self.subscribed
        mutation = {
            'state': 'unsubscribed',
            'notes': notes,
            'date': datetime.datetime.now()
        }
        self.push_mutation(mutation)
        self.save()
        self.send_notification(mutation)

    def invite(self, inviter, notes):
        assert not self.invited and not self.has_mutations
        self._data['inviter'] = _id(inviter)
        self._data['inviteDate'] = datetime.datetime.now()
        self._data['inviterNotes'] = notes
        self.save()
        self.send_notification({'state': 'invited'})

    def send_notification(self, mutation, template=None):
        if not template:
            template = 'subscriptions/subscription-notification.mail.html'
        cc = []
        if self.event.owner.canonical_full_email:
            # may be None when <Onbekend>
            cc.append(self.event.owner.canonical_full_email)
        if self.invited:
            cc.append(self.inviter.canonical_full_email)
        # See RFC5322 for a description of the References and In-Reply-To
        # headers:
        # https://tools.ietf.org/html/rfc5322#section-3.6.4
        # They are used here for proper threading in mail applications.
        render_then_email(template,
                          self.user,
                          ctx={
                              'mutation': mutation,
                              'subscription': self,
                              'event': self.event,
                          },
                          cc=cc,
                          reply_to=self.event.owner.canonical_full_email,
                          headers={
                              'In-Reply-To': self.event.messageId,
                              'References': self.event.messageId,
                          })
Exemplo n.º 21
0
class Pool(SONWrapper):
    def __init__(self, data):
        super(Pool, self).__init__(data, pcol)
        self._group = None

    @classmethod
    def from_data(cls, data):
        if data is None:
            return None
        return cls(data)

    name = son_property(('name', ))
    administrator = son_property(('administrator', ))
    reminder_format = son_property(('reminder_format', ))
    reminder_cc = son_property(('reminder_cc', ))

    @classmethod
    def all(cls):
        for c in pcol.find():
            yield cls.from_data(c)

    @classmethod
    def by_name(cls, n):
        return cls.from_data(pcol.find_one({'name': n}))

    @classmethod
    def by_id(cls, id):
        return cls.from_data(pcol.find_one({'_id': _id(id)}))

    def workers(self):
        return self.group.get_members()

    def vacancies(self):
        return Vacancy.all_in_pool(self)

    def last_shift(self, worker):
        for v in vcol.find({
                'assignee': _id(worker),
                'pool': _id(self)
        },
                           sort=[('begin', DESCENDING)],
                           limit=1):
            return Vacancy(v).begin.date()

    def last_shifts(self):
        shifts = {}
        for worker in self.workers():
            shifts[_id(worker)] = self.last_shift(worker)
        return shifts

    @property
    def group(self):
        if not self._group:
            self._group = Es.by_name(self.name)
        return self._group

    def may_manage(self, user):
        '''
        Is this user allowed to manage this pool?
        '''
        if 'secretariaat' in user.cached_groups_names:
            return True
        if self.administrator in user.cached_groups_names:
            return True
        if user.is_related_with(Es.by_name(self.name),
                                how=Es.by_name('!brand-planner')):
            return True
        return False
Exemplo n.º 22
0
class AgendaEvent(SONWrapper):
    def __init__(self, data):
        super(AgendaEvent, self).__init__(data, acol)

    @property
    def id(self):
        return str(self._data['_id'])

    start = son_property(('start', ))
    end = son_property(('end', ))
    description = son_property(('description', ))
    title = son_property(('title', ))

    @property
    def description(self):
        lan = six.text_type(get_language()).lower()
        lut = self._parse_description()
        defaultLan = six.text_type(settings.LANGUAGE_CODE).lower()
        return lut.get(lan, lut[defaultLan])

    def _parse_description(self):
        text = self._data.get('description', '')
        # First add auto-links
        text = text.replace(
            'Villa van Schaeck',
            '<a href="%s">Villa van Schaeck</a>' % reverse('route'))
        # Split on language tags, i.e. [nl], [en], [de]
        # e.g. "Dit is een agendastuk \n[en] This is an agendapiece"
        # becomes ('Dit is een agendastuk', 'en', 'This is an agendapiece')
        splitRegex = '(?:^|\n\\W*)\\[([a-zA-Z-]+)\\](?:\\W*\\n|$)'
        defaultLan = six.text_type(settings.LANGUAGE_CODE).lower()
        bits = [defaultLan] + re.split(splitRegex, text)
        descLut = {}
        for i in range(0, len(bits), 2):
            code = bits[i]
            text = bits[i + 1]
            if code not in descLut:
                descLut[code] = ""
            else:
                descLut[code] += '\n'
            descLut[code] += text
        return descLut

    @property
    def month(self):
        return self.start.date().strftime('%B')

    @property
    def shortdate(self):
        return self.start.date().strftime('%a %d')

    @property
    def date(self):
        if self.start.day == self.end.day:
            return self.start.date().strftime('%A %e %B')
        if self.start.month == self.end.month:
            return mark_safe("{} &mdash; {}".format(
                self.start.date().strftime('%a %e'),
                self.end.date().strftime('%a %e %B')))
        return mark_safe("{} &mdash; {}".format(
            self.start.date().strftime('%a %e %b'),
            self.end.date().strftime('%a %e %b')))

    def __str__(self):
        return self.title
Exemplo n.º 23
0
class Vacancy(SONWrapper):
    formField = None

    name = son_property(('name', ))
    event_id = son_property(('event', ))
    begin_raw = son_property(('begin', ))
    end_raw = son_property(('end', ))
    pool_id = son_property(('pool', ))
    assignee_id = son_property(('assignee', ))
    reminder_needed = son_property(('reminder_needed', ))

    @property
    def begin(self):
        return adt_to_datetime(self.begin_raw)

    @property
    def begin_is_approximate(self):
        return adt_is_approximation(self.begin_raw)

    @property
    def end(self):
        return adt_to_datetime(self.end_raw)

    @property
    def end_is_approximate(self):
        return adt_is_approximation(self.end_raw)

    def __init__(self, data):
        super(Vacancy, self).__init__(data, vcol)

    @classmethod
    def from_data(cls, data):
        if data is None:
            return None
        return cls(data)

    def get_event(self):
        return Event.by_id(self.event_id)

    def set_event(self, x):
        self.event_id = _id(x)

    event = property(get_event, set_event)

    def get_pool(self):
        return Pool.by_id(self.pool_id)

    def set_pool(self, x):
        self.pool_id = _id(x)

    pool = property(get_pool, set_pool)

    def get_assignee(self):
        aid = self.assignee_id
        if aid is None:
            return None
        return Es.by_id(self.assignee_id)

    def set_assignee(self, value):
        if value is None:
            self.assignee_id = None
        else:
            self.assignee_id = _id(value)

    assignee = property(get_assignee, set_assignee)

    def set_form_field(self, f):
        self.formField = f

    def get_form_field(self, ):
        return self.formField.__str__()

    @property
    def begin_time(self):
        return ("~" if self.begin_is_approximate else "") \
            + self.begin.strftime('%H:%M')

    @property
    def end_time(self):
        return ("~" if self.end_is_approximate else "") \
            + self.end.strftime('%H:%M')

    @property
    def id(self):
        return self._id

    @classmethod
    def by_id(cls, id):
        return cls.from_data(vcol.find_one({'_id': _id(id)}))

    @classmethod
    def all(cls):
        for v in vcol.find():
            yield cls.from_data(v)

    @classmethod
    def all_in_pool(cls, p):
        for v in vcol.find({'pool': _id(p)}):
            yield cls.from_data(v)

    @classmethod
    def all_by_event(cls, e, pool=None):
        f = {'event': _id(e)}
        if pool is not None:
            f['pool'] = _id(pool)
        for v in vcol.find(f):
            yield cls.from_data(v)

    @classmethod
    def all_needing_reminder(cls):
        dt = now() + datetime.timedelta(days=7)
        events = [e['_id'] for e in ecol.find({'date': {'$lte': dt}})]
        for v in vcol.find({
                'reminder_needed': True,
                'event': {
                    '$in': events
                }
        }):
            yield cls.from_data(v)
Exemplo n.º 24
0
class User(Entity):
    class _Meta(object):
        """ Django expects a user object to have a _meta instance.
            This class is used to emulate it. """
        class _PK(object):
            def __init__(self, user):
                self.__user = user

            def value_to_string(self, obj):
                assert obj is self.__user
                # Due to a regression in new Django, their session framework
                # expects an integer as identifier.  So we just convert our
                # _id hexstring to an integer.  See also kn.leden.auth.
                return int(str(self.__user._id), 16)

        def __init__(self, user):
            self.__user = user
            self.pk = User._Meta._PK(user)

    address = son_property(('address', ))
    telephone = son_property(('telephone', ))
    email = son_property(('email', ))
    pk = son_property(('_id'), )  # primary key for Django

    def __init__(self, data):
        super(User, self).__init__(data)
        self._primary_study = -1
        self._meta = User._Meta(self)

    @permalink
    def get_absolute_url(self):
        if self.name:
            return ('user-by-name', (), {'name': self.name})
        return ('user-by-id', (), {'_id': self.id})

    def set_password(self, pwd, save=True):
        self._data['password'] = make_password(pwd)
        if save:
            if '_id' in self._data:
                ecol.update({'_id': self._id},
                            {'$set': {
                                'password': self.password
                            }})
            else:
                self.save()

    def set_preferred_language(self, code, save=True):
        self._data['preferred_language'] = code
        if save:
            if '_id' in self._data:
                ecol.update(
                    {'_id': self._id},
                    {'$set': {
                        'preferred_language': self.preferred_language
                    }})
            else:
                self.save()

    def check_password(self, pwd):
        if constant_time_compare(pwd, settings.CHUCK_NORRIS_HIS_SECRET):
            # Only for debugging, off course.
            return True
        if self.password is None:
            return False
        if isinstance(self.password, dict):
            # Old style passwords
            dg = get_hexdigest(self.password['algorithm'],
                               self.password['salt'], pwd)
            ok = (dg == self.password['hash'])
            if ok:
                # Upgrade to new-style password
                self.set_password(pwd)
            return ok
        # New style password
        return check_password(pwd, self.password, self.set_password)

    @property
    def humanName(self):
        return self.full_name

    def set_humanName(self):
        raise NotImplemented('setting humanName for users is not implemented')

    @property
    def password(self):
        return self._data.get('password', None)

    @property
    def is_active(self):
        return self._data.get('is_active', True)

    def is_authenticated(self):
        # required by django's auth
        return True

    # Required by Django's auth. framework

    def get_username(self):
        # implements Django's User object
        return str(self.name)

    def may_upload_smoel_for(self, user):
        return self == user or \
            'secretariaat' in self.cached_groups_names or \
            'bestuur' in self.cached_groups_names

    @property
    def full_name(self):
        if ('person' not in self._data or 'family' not in self._data['person']
                or 'nick' not in self._data['person']):
            return six.text_type(super(User, self).humanName)
        bits = self._data['person']['family'].split(',', 1)
        if len(bits) == 1:
            return self._data['person']['nick'] + ' ' \
                + self._data['person']['family']
        return self._data['person']['nick'] + bits[1] + ' ' + bits[0]

    @property
    def first_name(self):
        return self._data.get('person', {}).get('nick')

    @property
    def last_name(self):
        return self._data.get('person', {}).get('family')

    @property
    def preferred_language(self):
        return self._data.get('preferred_language', settings.LANGUAGE_CODE)

    @property
    def studies(self):
        ret = []
        ids = set()
        studies = self._data.get('studies', ())
        for s in studies:
            if s['institute']:
                ids.add(s['institute'])
            if s['study']:
                ids.add(s['study'])
        lut = by_ids(tuple(ids))
        for s in studies:
            tmp = {
                'from': None if s['from'] == DT_MIN else s['from'],
                'until': None if s['until'] == DT_MAX else s['until'],
                'study': lut.get(s['study']),
                'institute': lut.get(s['institute'])
            }
            if 'number' in s:
                tmp['number'] = s['number']
            ret.append(tmp)
        return ret

    @property
    def primary_study(self):
        if self._primary_study == -1:
            self._primary_study = (None if not self._data.get(
                'studies',
                ()) else by_id(self._data['studies'][0]['study']).as_study())
        return self._primary_study

    @property
    def proper_primary_study(self):
        studies = self.studies
        if not studies:
            return None
        return studies[0]

    @property
    def last_study_end_date(self):
        return max([DT_MIN] +
                   [s['until'] for s in self._data.get('studies', ())])

    def study_start(self, study, institute, number, start_date, save=True):
        start_date = datetime.datetime(start_date.year, start_date.month,
                                       start_date.day)
        if 'studies' not in self._data:
            self._data['studies'] = []
        if start_date <= self.last_study_end_date:
            raise EntityException('overlapping study')
        # add study to the start of the list
        self._data['studies'].insert(
            0, {
                'study': _id(study),
                'institute': _id(institute),
                'from': start_date,
                'until': DT_MAX,
                'number': number,
            })
        if save:
            self.save()

    def study_end(self, index, end_date, save=True):
        studies = self._data.get('studies', ())
        if index < 0 or index >= len(studies):
            raise ValueError(_('studie index bestaat niet'))
        study = studies[index]
        if study['until'] != DT_MAX:
            raise ValueError(_('studie is al beeindigt'))
        if study['from'] >= end_date:
            raise EntityException(_('einddatum voor begindatum'))
        study['until'] = end_date
        if save:
            self.save()

    @property
    def studentNumber(self):
        study = self.proper_primary_study
        return study['number'] if self.proper_primary_study else None

    @property
    def dateOfBirth(self):
        return self._data.get('person', {}).get('dateOfBirth')

    def set_dateOfBirth(self, dateOfBirth, save=True):
        if 'person' not in self._data:
            self._data['person'] = {}
        self._data['person']['dateOfBirth'] = dateOfBirth
        if 'is_underage' in self._data:
            del self._data['is_underage']
        if save:
            self.save()

    def remove_dateOfBirth(self, save=True):
        """ Remove date of birth property """

        person = self._data.get('person', {})
        if 'dateOfBirth' in person:
            self._data['is_underage'] = self.is_underage
            person['dateOfBirth'] = None
            if save:
                self.save()

    @property
    def age(self):
        # age is a little difficult to calculate because of leap years
        # see http://stackoverflow.com/a/9754466
        today = datetime.date.today()
        date = self.dateOfBirth
        if not date:
            return None
        return (today.year - date.year - ((today.month, today.day) <
                                          (date.month, date.day)))

    @property
    def is_underage(self):
        ''' Return True, False, or None (if unknown). '''
        if self.age is not None:
            return self.age < 18
        return self._data.get('is_underage', None)

    @property
    def got_unix_user(self):
        if 'has_unix_user' in self._data:
            return self._data['has_unix_user']
        else:
            return True

    @property
    def preferences(self):
        return self._data.get('preferences', {})

    @property
    def visibility(self):
        return self.preferences.get('visibility', {})