Beispiel #1
0
    def __init__(self, id, trashed, app, authors, title, time, location, description):
        super().__init__(id=id, trashed=trashed, app=app)
        Editable.__init__(self, authors=authors)
        self.title = title
        self.time = time
        self.location = location
        self.description = description

        self._items_key = self.id + '.items'
        self._trashed_items_key = self.id + '.trashed_items'
        self.items = JSONRedisMapping(self.app.r, self._items_key)
        self.trashed_items = JSONRedisMapping(self.app.r, self._trashed_items_key)
Beispiel #2
0
    def __init__(self, id, trashed, app, authors, title, time, location,
                 description):
        super().__init__(id=id, trashed=trashed, app=app)
        Editable.__init__(self, authors=authors)
        self.title = title
        self.time = parse_isotime(time) if time else None
        self.location = location
        self.description = description

        self._items_key = self.id + '.items'
        self._trashed_items_key = self.id + '.trashed_items'
        self.items = JSONRedisMapping(self.app.r, self._items_key)
        self.trashed_items = JSONRedisMapping(self.app.r,
                                              self._trashed_items_key)
Beispiel #3
0
 def setUp(self):
     super().setUp()
     self.objects = OrderedDict([('cat:0', Cat('cat:0', 'Happy')),
                                 ('cat:1', Cat('cat:1', 'Grumpy')),
                                 ('cat:2', Cat('cat:2', 'Long')),
                                 ('cat:3', Cat('cat:3', 'Monorail')),
                                 ('cat:4', Cat('cat:4', 'Ceiling'))])
     self.r.omset(self.objects)
     self.r.rpush('cats', *self.objects.keys())
     self.cats = JSONRedisMapping(self.r, 'cats')
Beispiel #4
0
 def __init__(self,
              redis_url='',
              email='bot@localhost',
              smtp_url='',
              render_email_auth_message=None):
     super().__init__(redis_url=redis_url,
                      email=email,
                      smtp_url=smtp_url,
                      render_email_auth_message=render_email_auth_message)
     self.types.update({'Meeting': Meeting, 'AgendaItem': AgendaItem})
     self.meetings = JSONRedisMapping(self.r, 'meetings')
Beispiel #5
0
class Meeting(Object, Editable):
    """See :ref:`Meeting`.

    .. attribute:: items

       Ordered map of :class:`AgendaItem` s on the meeting's agenda.

    .. attribute:: trashed_items

       Ordered map of trashed (deleted) :class:`AgendaItem` s.
    """
    def __init__(self, id, trashed, app, authors, title, time, location,
                 description):
        super().__init__(id=id, trashed=trashed, app=app)
        Editable.__init__(self, authors=authors)
        self.title = title
        self.time = parse_isotime(time) if time else None
        self.location = location
        self.description = description

        self._items_key = self.id + '.items'
        self._trashed_items_key = self.id + '.trashed_items'
        self.items = JSONRedisMapping(self.app.r, self._items_key)
        self.trashed_items = JSONRedisMapping(self.app.r,
                                              self._trashed_items_key)

    def do_edit(self, **attrs):
        e = InputError()
        if 'title' in attrs and not str_or_none(attrs['title']):
            e.errors['title'] = 'empty'
        e.trigger()

        if 'title' in attrs:
            self.title = attrs['title']
        if 'time' in attrs:
            self.time = attrs['time']
        if 'location' in attrs:
            self.location = str_or_none(attrs['location'])
        if 'description' in attrs:
            self.description = str_or_none(attrs['description'])

    def create_agenda_item(self, title, duration=None, description=None):
        """See :http:post:`/api/meetings/(id)/items`."""
        if not self.app.user:
            raise PermissionError()

        e = InputError()
        if str_or_none(title) is None:
            e.errors['title'] = 'empty'
        if duration is not None and duration <= 0:
            e.errors['duration'] = 'not_positive'
        description = str_or_none(description)
        e.trigger()

        item = AgendaItem(id='AgendaItem:' + randstr(),
                          trashed=False,
                          app=self.app,
                          authors=[self.app.user.id],
                          title=title,
                          duration=duration,
                          description=description)
        self.app.r.oset(item.id, item)
        self.app.r.rpush(self._items_key, item.id)
        return item

    def trash_agenda_item(self, item):
        """See :http:post:`/api/meetings/(id)/trash-agenda-item`."""
        if not self.app.r.lrem(self._items_key, 1, item.id):
            raise ValueError('item_not_found')
        self.app.r.rpush(self._trashed_items_key, item.id)
        item.trashed = True
        self.app.r.oset(item.id, item)

    def restore_agenda_item(self, item):
        """See :http:post:`/api/meetings/(id)/restore-agenda-item`."""
        if not self.app.r.lrem(self._trashed_items_key, 1, item.id):
            raise ValueError('item_not_found')
        self.app.r.rpush(self._items_key, item.id)
        item.trashed = False
        self.app.r.oset(item.id, item)

    def move_agenda_item(self, item, to):
        """See :http:post:`/api/meetings/(id)/move-agenda-item`."""
        if to:
            if to.id not in self.items:
                raise ValueError('to_not_found')
            if to == item:
                # No op
                return
        if not self.app.r.lrem(self._items_key, 1, item.id):
            raise ValueError('item_not_found')
        if to:
            self.app.r.linsert(self._items_key, 'after', to.id, item.id)
        else:
            self.app.r.lpush(self._items_key, item.id)

    def json(self, restricted=False, include=False):
        """See :meth:`Object.json`.

        If *include_items* is ``True``, *items* and *trashed_items* are included.
        """
        json = super().json(restricted=restricted, include=include)
        json.update(Editable.json(self, restricted=restricted,
                                  include=include))
        json.update({
            'title': self.title,
            'time': self.time.isoformat() + 'Z' if self.time else None,
            'location': self.location,
            'description': self.description
        })
        if include:
            json['items'] = [
                i.json(restricted=restricted, include=include)
                for i in self.items.values()
            ]
            json['trashed_items'] = [
                i.json(restricted=restricted, include=include)
                for i in self.trashed_items.values()
            ]
        return json
Beispiel #6
0
class Meeting(Object, Editable):
    """See :ref:`Meeting`.

    .. attribute:: items

       Ordered map of :class:`AgendaItem` s on the meeting's agenda.

    .. attribute:: trashed_items

       Ordered map of trashed (deleted) :class:`AgendaItem` s.
    """

    def __init__(self, id, trashed, app, authors, title, time, location, description):
        super().__init__(id=id, trashed=trashed, app=app)
        Editable.__init__(self, authors=authors)
        self.title = title
        self.time = time
        self.location = location
        self.description = description

        self._items_key = self.id + '.items'
        self._trashed_items_key = self.id + '.trashed_items'
        self.items = JSONRedisMapping(self.app.r, self._items_key)
        self.trashed_items = JSONRedisMapping(self.app.r, self._trashed_items_key)

    def do_edit(self, **attrs):
        e = InputError()
        if 'title' in attrs and not str_or_none(attrs['title']):
            e.errors['title'] = 'empty'
        e.trigger()

        if 'title' in attrs:
            self.title = attrs['title']
        if 'time' in attrs:
            self.time = attrs['time']
        if 'location' in attrs:
            self.location = str_or_none(attrs['location'])
        if 'description' in attrs:
            self.description = str_or_none(attrs['description'])

    def create_agenda_item(self, title, duration=None, description=None):
        """See :http:post:`/api/meetings/(id)/items`."""
        if not self.app.user:
            raise PermissionError()

        e = InputError()
        if str_or_none(title) is None:
            e.errors['title'] = 'empty'
        if duration is not None and duration <= 0:
            e.errors['duration'] = 'not_positive'
        description = str_or_none(description)
        e.trigger()

        item = AgendaItem(
            id='AgendaItem:' + randstr(), trashed=False, app=self.app, authors=[self.app.user.id],
            title=title, duration=duration, description=description)
        self.app.r.oset(item.id, item)
        self.app.r.rpush(self._items_key, item.id)
        return item

    def trash_agenda_item(self, item):
        """See :http:post:`/api/meetings/(id)/trash-agenda-item`."""
        if not self.app.r.lrem(self._items_key, 1, item.id):
            raise ValueError('item_not_found')
        self.app.r.rpush(self._trashed_items_key, item.id)
        item.trashed = True
        self.app.r.oset(item.id, item)

    def restore_agenda_item(self, item):
        """See :http:post:`/api/meetings/(id)/restore-agenda-item`."""
        if not self.app.r.lrem(self._trashed_items_key, 1, item.id):
            raise ValueError('item_not_found')
        self.app.r.rpush(self._items_key, item.id)
        item.trashed = False
        self.app.r.oset(item.id, item)

    def move_agenda_item(self, item, to):
        """See :http:post:`/api/meetings/(id)/move-agenda-item`."""
        if to:
            if to.id not in self.items:
                raise ValueError('to_not_found')
            if to == item:
                # No op
                return
        if not self.app.r.lrem(self._items_key, 1, item.id):
            raise ValueError('item_not_found')
        if to:
            self.app.r.linsert(self._items_key, 'after', to.id, item.id)
        else:
            self.app.r.lpush(self._items_key, item.id)

    def json(self, restricted=False, include_users=False, include_items=False):
        """See :meth:`Object.json`.

        If *include_items* is ``True``, *items* and *trashed_items* are included.
        """
        # pylint: disable=arguments-differ; extended signature
        json = super().json(attrs={
            'title': self.title,
            'time': self.time.isoformat() + 'Z' if self.time else None,
            'location': self.location,
            'description': self.description
        })
        json.update(Editable.json(self, restricted=restricted, include_users=include_users))
        if include_items:
            json['items'] = [i.json(restricted=restricted, include_users=include_users)
                             for i in self.items.values()]
            json['trashed_items'] = [i.json(restricted=restricted, include_users=include_users)
                                     for i in self.trashed_items.values()]
        return json