Exemplo n.º 1
0
    async def test_publish_stream(self) -> None:
        activity = self.make_activity()
        stream = activity.stream()

        observed = []
        closed = False
        async def observe() -> None:
            nonlocal closed
            async for event in stream:
                observed.append(event)
            closed = True
        self.io_loop.add_callback(observe)
        # Scheduled coroutines are run in the next IO loop iteration but one
        await sleep(0)
        await sleep(0)

        events = [
            Event.create('meow', None, app=self.app), # type:ignore
            Event.create('woof', None, app=self.app) # type:ignore
        ] # type: List[Event]
        activity.publish(events[0]) # type:ignore
        activity.publish(events[1]) # type:ignore
        await sleep(0)
        await stream.aclose()
        await sleep(0)

        self.assertEqual(observed, events)
        self.assertTrue(closed)
Exemplo n.º 2
0
    def create_meeting(self,
                       title,
                       time=None,
                       location=None,
                       description=None):
        """See :http:post:`/api/meetings`."""
        if not self.user:
            raise PermissionError()

        e = InputError()
        if not str_or_none(title):
            e.errors['title'] = 'empty'
        e.trigger()

        meeting = Meeting(id='Meeting:' + randstr(),
                          trashed=False,
                          app=self,
                          authors=[self.user.id],
                          title=title,
                          time=time.isoformat() + 'Z' if time else None,
                          location=str_or_none(location),
                          description=str_or_none(description))
        self.r.oset(meeting.id, meeting)
        self.r.rpush('meetings', meeting.id)

        self.activity.publish(
            Event.create('create-meeting',
                         None, {'meeting': meeting},
                         app=self))
        return meeting
Exemplo n.º 3
0
 def uncheck(self):
     """See :http:post:`/api/lists/(list-id)/items/(id)/uncheck`."""
     _check_feature(self.app.user, 'check', self)
     self._check_permission(self.app.user, 'item-modify')
     self.checked = False
     self.app.r.oset(self.id, self)
     self.list.activity.publish(Event.create('item-uncheck', self, app=self.app))
Exemplo n.º 4
0
 async def test_send_device_notification_invalid_push_subscription(self) -> None:
     push_subscription = cast(Dict[str, str], json.loads(self.push_subscription))
     push_subscription['endpoint'] += 'foo'
     push_subscription = json.dumps(push_subscription)
     with self.assertRaisesRegex(ValueError, 'push_subscription_invalid'):
         await self.app.send_device_notification(push_subscription,
                                                 Event.create('meow', None, app=self.app))
Exemplo n.º 5
0
        async def _create(self,
                          title,
                          *,
                          text=None,
                          resource=None,
                          location=None):
            # pylint: disable=protected-access; List is a friend
            self.host[0]._check_permission(self.app.user, 'list-modify')
            attrs = await WithContent.process_attrs(
                {
                    'text': text,
                    'resource': resource
                }, app=self.app)
            if str_or_none(title) is None:
                raise micro.ValueError('title_empty')

            item = Item(id='Item:{}'.format(randstr()),
                        app=self.app,
                        authors=[self.app.user.id],
                        trashed=False,
                        text=attrs['text'],
                        resource=attrs['resource'],
                        list_id=self.host[0].id,
                        title=title,
                        location=location.json() if location else None,
                        checked=False)
            self.app.r.oset(item.id, item)
            self.app.r.rpush(self.map_key, item.id)
            self.host[0].activity.publish(
                Event.create('list-create-item', self.host[0], {'item': item},
                             self.app))
            return item
Exemplo n.º 6
0
 async def test_send_device_notification_invalid_push_subscription_host(self) -> None:
     push_subscription = json.dumps({ # type: ignore[misc]
         **cast(Dict[str, str], json.loads(self.push_subscription)),
         'endpoint': 'http://example.invalid'
     })
     with self.assertRaises(CommunicationError):
         await self.app.send_device_notification(push_subscription,
                                                 Event.create('meow', None, app=self.app))
Exemplo n.º 7
0
 def unvote(self, *, user):
     """See :http:delete:`/api/lists/(list-id)/items/(id)/votes/user`."""
     if not user:
         raise PermissionError()
     if 'vote' not in self.item.list.features:
         raise error.ValueError('Disabled item list features vote')
     if self.app.r.zrem(self.ids.key, user.id.encode()):
         self.item.list.activity.publish(
             Event.create('item-votes-unvote', self.item, app=self.app))
Exemplo n.º 8
0
 async def test_notify_invalid_push_subscription(self):
     await self.user.enable_device_notifications(self.push_subscription)
     self.user.push_subscription = 'foo'
     self.app.login()
     self.user.notify(Event.create('test', None, app=self.app))
     # Scheduled coroutines are run in the next IO loop iteration but one
     await sleep(0)
     await sleep(0)
     self.assertEqual(self.user.device_notification_status, 'off.expired')
Exemplo n.º 9
0
    def test_publish(self, notify):
        activity = self.make_activity()
        activity.subscribe()
        self.app.login()
        activity.subscribe()

        event = Event.create('meow', None, app=self.app)
        activity.publish(event)
        self.assertIn(event, activity)
        notify.assert_called_once_with(self.user, event)
Exemplo n.º 10
0
 async def test_notify_invalid_push_subscription(self) -> None:
     device = self.user.devices[0]
     await device.enable_notifications(self.push_subscription)
     device.push_subscription = 'foo'
     context.user.set(self.app.devices.sign_in().user)
     self.user.notify(Event.create('test', None, app=self.app))
     # Scheduled coroutines are run in the next IO loop iteration but one
     await sleep(0)
     await sleep(0)
     self.assertEqual(device.notification_status, 'off.expired')
Exemplo n.º 11
0
 def unassign(self, assignee, *, user):
     """See :http:delete:`/api/lists/(list-id)/items/(id)/assignees/(assignee-id)`."""
     # pylint: disable=protected-access; Item is a friend
     self.item._check_permission(user, 'list-modify')
     if 'assign' not in self.item.list.features:
         raise error.ValueError('Disabled item list features assign')
     if self.item.trashed:
         raise error.ValueError('Trashed item')
     if not self.app.r.zrem(self.ids.key, assignee.id.encode()):
         raise error.ValueError(
             'No assignee {} in assignees of item {}'.format(assignee.id, self.item.id))
     self.item.list.activity.publish(
         Event.create('item-assignees-unassign', self.item, detail={'assignee': assignee},
                      app=self.app))
Exemplo n.º 12
0
        async def create(self, text: Optional[str], resource: Optional[str]) -> Greeting:
            """Create a :class:`Greeting` and return it."""
            user = context.user.get()
            if not user:
                raise error.PermissionError()
            attrs = await WithContent.process_attrs({'text': text, 'resource': resource},
                                                    app=self.app)
            if not (attrs['text'] or attrs['resource']):
                raise error.ValueError('No text and resource')

            greeting = Greeting(
                id='Greeting:{}'.format(randstr()), app=self.app, authors=[user.id],
                text=attrs['text'], resource=attrs['resource'])
            self.app.r.oset(greeting.id, greeting)
            self.app.r.lpush(self.ids.key, greeting.id)
            self.app.activity.publish(
                Event.create('greetings-create', None, detail={'greeting': greeting}, app=self.app))
            return greeting
Exemplo n.º 13
0
        def create(self, use_case=None, description=None, title=None, v=1):
            """See :http:post:`/api/lists`."""
            if v == 1:
                # create(title, description=None)
                title = title or use_case
                if title is None:
                    raise TypeError()
                lst = self.create('simple', v=2)
                lst.edit(title=title, description=description)
                return lst
            if v == 2:
                # create(use_case='simple')
                use_case = use_case or 'simple'
            else:
                raise NotImplementedError()

            if not self.app.user:
                raise PermissionError()
            if use_case not in _USE_CASES:
                raise micro.ValueError('use_case_unknown')

            data = _USE_CASES[use_case]
            id = 'List:{}'.format(randstr())
            lst = List(id=id,
                       app=self.app,
                       authors=[self.app.user.id],
                       title=data['title'],
                       description=None,
                       features=data['features'],
                       mode='collaborate',
                       activity=Activity('{}.activity'.format(id),
                                         self.app,
                                         subscriber_ids=[]))
            self.app.r.oset(lst.id, lst)
            self.app.r.rpush(self.map_key, lst.id)
            self.app.user.lists.add(lst, user=self.app.user)
            self.app.activity.publish(
                Event.create('create-list', None, {'lst': lst}, app=self.app))
            return lst
Exemplo n.º 14
0
        def create(self, use_case='simple', *, v=2):
            """See :http:post:`/api/lists`."""
            # pylint: disable=unused-argument; former feature toggle
            # Compatibility for endpoint version (deprecated since 0.22.0)
            if not self.app.user:
                raise PermissionError()
            if use_case not in _USE_CASES:
                raise micro.ValueError('use_case_unknown')

            data = _USE_CASES[use_case]
            id = 'List:{}'.format(randstr())
            lst = List(
                id=id, app=self.app, authors=[self.app.user.id], title=data['title'],
                description=None, features=data['features'], mode=data.get('mode', 'collaborate'),
                activity=Activity('{}.activity'.format(id), self.app, subscriber_ids=[]))
            self.app.r.oset(lst.id, lst)
            self.app.r.zadd('{}.users'.format(lst.id), {self.app.user.id.encode(): -time()})
            self.app.r.rpush(self.map_key, lst.id)
            self.app.user.lists.add(lst, user=self.app.user)
            self.app.activity.publish(
                Event.create('create-list', None, {'lst': lst}, app=self.app))
            return lst
Exemplo n.º 15
0
 async def test_send_device_notification(self) -> None:
     await self.app.send_device_notification(self.push_subscription,
                                             Event.create('meow', None, app=self.app))
Exemplo n.º 16
0
 async def test_notify(self) -> None:
     await self.user.devices[0].enable_notifications(self.push_subscription)
     self.user.notify(Event.create('test', None, app=self.app))
Exemplo n.º 17
0
 def make_event(self) -> Tuple[Event, Cat]:
     cat = self.app.cats.create()
     event = Event.create('meow', cat, app=self.app)
     return event, cat