예제 #1
0
파일: test_entity.py 프로젝트: kbase/feeds
def test_entity_to_dict(e_id, e_type, name):
    e = Entity(e_id, e_type, name=name)
    d = {"id": e_id, "type": e_type}
    d_name = d.copy()
    d_name["name"] = name
    assert e.to_dict() == d
    assert e.to_dict(with_name=True) == d_name
예제 #2
0
 def set_seen(self, act_ids: List[str], user: Entity) -> None:
     """
     Setting seen just means removing the user from the list of unseens.
     The query should find all docs in the list of act_ids, where the user
     is in the list of users, AND the list of unseens.
     The update should remove the user from the list of unseens.
     """
     u = user.to_dict()
     coll = get_feeds_collection()
     coll.update_many({
         'id': {
             '$in': act_ids
         },
         'users': u,
         'unseen': u
     }, {'$pull': {
         'unseen': u
     }})
예제 #3
0
 def set_unseen(self, act_ids: List[str], user: Entity) -> None:
     """
     Setting unseen means adding the user to the list of unseens. But we should only do that for
     docs that the user can't see anyway, so put that in the query.
     """
     u = user.to_dict()
     coll = get_feeds_collection()
     coll.update_many(
         {
             'id': {
                 '$in': act_ids
             },
             'users': u,
             'unseen': {
                 '$nin': [u]
             }
         }, {'$addToSet': {
             'unseen': u
         }})
예제 #4
0
class NotificationFeed(BaseFeed):
    def __init__(self, user_id: str, user_type: str, token: str = None):
        self.user = Entity(user_id, user_type, token=token)
        self.token = token
        self.timeline_storage = MongoTimelineStorage(user_id, user_type)
        self.activity_storage = MongoActivityStorage()
        self.timeline = None
        self.cache = TTLCache(1000, 600)

    def _update_timeline(self) -> None:
        """
        Updates a local user timeline cache. This is a list of activity ids
        that are used for fetching from activity storage (for now). Sorted
        by newest first.

        TODO: add metadata to timeline storage - type and verb, first.
        """
        logging.getLogger(__name__).info('Fetching timeline for '.format(
            self.user))
        self.timeline = self.timeline_storage.get_timeline()

    def get_group_notifications(self,
                                group: Dict[str, str],
                                count: int = 10,
                                include_seen: bool = False,
                                level=None,
                                verb=None,
                                reverse: bool = False) -> dict:
        """
        Returns all notifications (using the get_notifications fn.) for a user, filtered down to
        those that reference an Entity of type group with the given id.
        """
        notes = self.get_notifications(count=count,
                                       include_seen=include_seen,
                                       level=level,
                                       verb=verb,
                                       reverse=reverse)
        # group has id and name keys
        group_notes = {"unseen": 0, "name": group.get("name"), "feed": list()}
        gid = group["id"]

        def is_group(e: Entity) -> bool:
            return e.id == gid and e.type == "group"

        notes_list = list()
        for n in notes["feed"]:
            if is_group(n.actor) or is_group(n.object) or any(
                [is_group(t) for t in n.target]):
                notes_list.append(n)
                if not n.seen:
                    group_notes["unseen"] += 1
        Notification.update_entity_names(notes_list, token=self.token)
        for n in notes_list:
            group_notes["feed"].append(n.user_view())
        return group_notes

    def get_notifications(self,
                          count: int = 10,
                          include_seen: bool = False,
                          level=None,
                          verb=None,
                          reverse: bool = False,
                          user_view: bool = False) -> dict:
        """
        Fetches all activities matching the requested inputs.
        :param count: max number of most recent notifications to return. default=10
        :param include_seen: include notifications that have been seen in the response.
            default = False
        :param level: if not None, will only return notifications of the given level.
            default = None
        :param verb: if not None, will only return notifications made with the given verb.
            default = None
        :param reverse: if True, will reverse the order of the result (default False)
        :param user_view: if True, will return the user_view dict version of each Notification
            object. If False, will return a list of Notification objects instead. default False
        :return: a dict with the requested notifications, and a key with the total number in the
            feed that are marked unseen
        :rtype: dict
        :raises ValueError: if count <= 0
        """
        activities = self.get_activities(count=count,
                                         include_seen=include_seen,
                                         verb=verb,
                                         level=level,
                                         reverse=reverse,
                                         user_view=user_view)
        ret_struct = {
            "unseen": self.get_unseen_count(),
            "name": self.user.name
        }
        if user_view:
            ret_struct["feed"] = list()
            Notification.update_entity_names(activities, token=self.token)
            for act in activities:
                ret_struct["feed"].append(act.user_view())
        else:
            ret_struct["feed"] = activities
        return ret_struct

    def get_notification(self, note_id):
        """
        Returns a single notification.
        If it doesn't exist (either the user can't see it, or it's really not there), raises
        a NotificationNotFoundError.
        """
        note = self.timeline_storage.get_single_activity_from_timeline(note_id)
        if note is None:
            raise NotificationNotFoundError(
                "Cannot find notification with id {}.".format(note_id))
        else:
            return Notification.from_dict(note, self.token)

    def get_activities(self,
                       count=10,
                       include_seen=False,
                       level=None,
                       verb=None,
                       reverse=False,
                       user_view=False) -> List[Notification]:
        """
        Returns a selection of activities.
        :param count: Maximum number of Notifications to return (default 10)
        """
        # steps.
        # 0. If in cache, return them.  <-- later
        # 1. Get storage adapter.
        # 2. Query it for recent activities from this user.
        # 3. Cache them here.
        # 4. Return them.
        if count < 1 or not isinstance(count, int):
            raise ValueError("Count must be an integer > 0")
        serial_notes = self.timeline_storage.get_timeline(
            count=count,
            include_seen=include_seen,
            level=level,
            verb=verb,
            reverse=reverse)
        note_list = list()
        user_dict = self.user.to_dict()
        for note in serial_notes:
            if user_dict in note["unseen"]:
                note["seen"] = False
            else:
                note["seen"] = True
            note_list.append(Notification.from_dict(note, self.token))
        return note_list

    def mark_activities(self, activity_ids: List[str], seen=False) -> None:
        """
        Marks the given list of activities as either seen (True) or unseen (False).
        If the owner of this feed is not on the users list for an activity, nothing is
        changed for that activity.
        """
        if seen:
            self.activity_storage.set_seen(activity_ids, self.user)
        else:
            self.activity_storage.set_unseen(activity_ids, self.user)

    def add_notification(self, note) -> None:
        return self.add_activity(note)

    def add_activity(self, note) -> None:
        """
        Adds an activity to this user's feed
        """
        self.activity_storage.add_to_storage(note, [self.user])

    def get_unseen_count(self) -> int:
        """
        Returns the number of unread / unexpired notifications in this feed.
        """
        return self.timeline_storage.get_unseen_count()