Ejemplo n.º 1
0
    def vote_insert(self, request):
        """
        Exposes an API endpoint to insert a vote for the current user.
        """
        user = auth_user(self.request_state.headers)

        anno = Anno.get_by_id(request.anno_id)
        if anno is None:
            raise endpoints.NotFoundException('No anno entity with the id "%s" exists.' % request.id)

        vote = Vote()
        vote.anno_key = anno.key
        vote.creator = user.key
        if request.created is not None:
            vote.created = request.created
        vote.put()

        anno.vote_count += 1
        anno.last_update_time = datetime.datetime.now()
        anno.last_activity = 'vote'
        anno.last_update_type = 'create'
        anno.put()

        # update user anno state
        UserAnnoState.insert(user=user, anno=anno, type=AnnoActionType.UPVOTED)

        # update vote in search document
        put_search_document(anno.generate_search_document(), SearchIndexName.ANNO)

        return vote.to_message()
Ejemplo n.º 2
0
    def flag_insert(self, request):
        """
        Exposes an API endpoint to insert a flag for the current user.
        """
        user = auth_user(self.request_state.headers)

        anno = Anno.get_by_id(request.anno_id)
        if anno is None:
            raise endpoints.NotFoundException('No anno entity with the id "%s" exists.')

        flag = Flag()
        flag.anno_key = anno.key
        flag.creator = user.key
        if request.created is not None:
            flag.created = request.created
        flag.put()

        anno.flag_count += 1
        anno.last_update_time = datetime.datetime.now()
        anno.last_activity = 'flag'
        anno.last_update_type = 'create'
        anno.put()

        # update user anno state
        UserAnnoState.insert(user=user, anno=anno, type=AnnoActionType.FLAGGED)

        # update flag in search document
        put_search_document(anno.generate_search_document(), SearchIndexName.ANNO)

        return flag.to_message()
Ejemplo n.º 3
0
    def anno_merge(self, request):
        """
        Exposes an API endpoint to merge(update only the specified properties) an anno.
        """
        user = auth_user(self.request_state.headers)

        if request.id is None:
            raise endpoints.BadRequestException('id field is required.')

        anno = Anno.get_by_id(request.id)

        if anno is None:
            raise endpoints.NotFoundException('No anno entity with the id "%s" exists.' % request.id)

        anno.merge_from_message(request, user)
        # set last update time & activity
        anno.last_update_time = datetime.datetime.now()
        anno.last_activity = 'anno'
        anno.put()

        # update search document.
        put_search_document(anno.generate_search_document(), SearchIndexName.ANNO)

        # send notifications
        ActivityPushNotifications.send_push_notification(first_user=user, anno=anno, action_type=AnnoActionType.EDITED)

        # update last_read of UserAnnoState
        from model.userannostate import UserAnnoState
        UserAnnoState.update_last_read(user=user, anno=anno)

        return anno.to_response_message(user)
Ejemplo n.º 4
0
    def anno_get(self, request):
        """
        Exposes an API endpoint to get an anno detail by the specified id.
        """
        try:
            user = auth_user(self.request_state.headers)
        except Exception:
            user = None

        if request.id is None:
            raise endpoints.BadRequestException('id field is required.')

        anno = Anno.get_by_id(request.id)

        if anno is None:
            raise endpoints.NotFoundException('No anno entity with the id "%s" exists.' % request.id)

        # set anno basic properties
        anno_resp_message = anno.to_response_message(user, list_message=False)

        # set anno association with followups
        followups = FollowUp.find_by_anno(anno)
        followup_messages = [ entity.to_message(team_key=request.team_key) for entity in followups ]
        anno_resp_message.followup_list = followup_messages

        # set anno association with votes/flags
        # if current user exists, then fetch vote/flag.
        if user is not None:
            anno_resp_message.is_my_vote = Vote.is_belongs_user(anno, user)
            anno_resp_message.is_my_flag = Flag.is_belongs_user(anno, user)

            # update last_read of UserAnnoState
            UserAnnoState.update_last_read(user=user, anno=anno)

        return anno_resp_message
Ejemplo n.º 5
0
    def to_response_message(self, user, list_message=True):
        """
        Convert anno model to AnnoResponseMessage.
        """
        user_message = None
        if self.creator is not None:
            user_info = self.creator.get()
            user_message = UserMessage(display_name=user_info.display_name,
                                       image_url=user_info.image_url)

        app = self.app.get() if self.app else None
        app_name = app.name if app else self.app_name
        app_icon_url = app.icon_url if app else None
        app_version = app.version if app else self.app_version

        if list_message:
            anno_read_status = False
            if user:
                from model.userannostate import UserAnnoState
                anno_read_status = UserAnnoState.is_read(user, self)

            last_activity_user = UserAnnoState.last_activity_user(self)

            circle_level_value = None
            if (self.community and self.circle_level > 0):
                circle_level_value = Community.getCircleLevelValue(self.community, self.circle_level)

            anno_message = AnnoResponseMessage(id=self.key.id(), anno_text=self.anno_text,
                                               anno_type=self.anno_type, app_name=app_name,
                                               app_icon_url=app_icon_url, created=self.created,
                                               creator=user_message, last_update_time=self.last_update_time,
                                               last_activity=self.last_activity, last_update_type=self.last_update_type,
                                               anno_read_status=anno_read_status, last_activity_user=last_activity_user,
                                               circle_level_value=circle_level_value
                                            )
        else:
            anno_message = AnnoResponseMessage(id=self.key.id(),
                                   anno_text=self.anno_text,
                                   anno_type=self.anno_type,
                                   level=self.level,
                                   device_model=self.device_model,
                                   app_name=app_name,
                                   app_version=app_version,
                                   app_icon_url=app_icon_url,
                                   os_name=self.os_name,
                                   os_version=self.os_version,
                                   created=self.created,
                                   creator=user_message,
                                   draw_elements=self.draw_elements,
                                   screenshot_is_anonymized=self.screenshot_is_anonymized,
                                   vote_count=self.vote_count,
                                   flag_count=self.flag_count,
                                   followup_count=self.followup_count,
                                   last_update_time=self.last_update_time,
                                   last_activity=self.last_activity,
                                   last_update_type=self.last_update_type)

        return anno_message
Ejemplo n.º 6
0
    def insert_anno(cls, message, user):
        """
        create a new anno model from request message.
        """
        itemCount = 0
        appinfo, community = getAppAndCommunity(message, user)

        circle_level = 0
        if community:
            itemCount = cls.countItemsForTeam(community.key)
            circle_level = UserRole.getCircleLevel(user, community)
            if message.circle_level and (message.circle_level <= circle_level):
                circle_level = message.circle_level

        entity = cls(anno_text=message.anno_text, anno_type=message.anno_type,
                     level=message.level, device_model=message.device_model,
                     os_name=message.os_name, os_version=message.os_version,
                     creator=user.key, draw_elements=message.draw_elements,
                     image=message.image, screenshot_is_anonymized=message.screenshot_is_anonymized,
                     geo_position=message.geo_position, flag_count=0, vote_count=0,
                     followup_count=0, latitude=message.latitude, longitude=message.longitude,
                     screen_info=message.screen_info)

        # set appinfo and community
        entity.app = appinfo.key
        entity.community = community.key if community else None
        entity.circle_level = circle_level

        # set created time if provided in the message.
        if message.created is not None:
            entity.created = message.created

        # use google map api to retrieve country information and save into datastore.
        if message.latitude is not None and message.longitude is not None:
            entity.country = get_country_by_coordinate(message.latitude, message.longitude)

        # set last update time & activity
        entity.last_update_time = datetime.datetime.now()
        entity.last_activity = 'UserSource'
        entity.last_update_type = 'create'
        anno_key = entity.put()

        entity.anno_id = anno_key.id()
        entity.put()

        # update user anno state
        from model.userannostate import UserAnnoState
        UserAnnoState.insert(user=user, anno=entity, type=AnnoActionType.CREATED)

        if community:
            itemCount = cls.query_count_by_community(community_key=community.key)
            if itemCount == 0:
                send_first_anno_email(community.name, user.display_name)

        return entity
Ejemplo n.º 7
0
def update_userannostate_schema_from_anno_action(cls, cursor=None):
    activity_list, cursor, more = cls.query()\
                                     .order(cls.created)\
                                     .fetch_page(BATCH_SIZE, start_cursor=cursor)

    for activity in activity_list:
        user = activity.creator.get()
        anno = activity.anno_key.get()
        modified = activity.created
        if user and anno:
            UserAnnoState.insert(user=user, anno=anno, modified=modified)

    if more:
        update_userannostate_schema_from_anno_action(cls=cls, cursor=cursor)
Ejemplo n.º 8
0
    def followup_insert(self, request):
        """
        Exposes and API endpoint to insert a follow up for the current user.
        """
        user = auth_user(self.request_state.headers)

        anno = Anno.get_by_id(request.anno_id)
        if anno is None:
            raise endpoints.NotFoundException('No anno entity with the id "%s" exists.' % request.id)

        followup = FollowUp()
        followup.anno_key = anno.key
        followup.creator = user.key
        followup.comment = request.comment
        followup.tagged_users = request.tagged_users
        if request.created is not None:
            followup.created = request.created
        followup.put()

        anno.followup_count += 1
        anno.last_update_time = datetime.datetime.now()
        anno.last_activity = 'follwup'
        anno.last_update_type = 'create'
        anno.put()

        # update user anno state
        UserAnnoState.insert(user=user, anno=anno, type=AnnoActionType.COMMENTED)

        for tagged_user_id in followup.tagged_users:
            tagged_user = User.get_by_id(int(tagged_user_id))
            if tagged_user:
                UserAnnoState.insert(user=tagged_user, anno=anno, type=AnnoActionType.TAGGEDUSER)

        # update search document
        put_search_document(anno.generate_search_document(), SearchIndexName.ANNO)
        put_search_document(followup.generate_search_document(), SearchIndexName.FOLLOWUP)

        # find all hashtags
        tags = extract_tags_from_text(followup.comment.lower())
        for tag, count in tags.iteritems():
            # Write the cumulative amount per tag
            Tag.add_tag_total(tag, total=count)

        # send notifications
        ActivityPushNotifications.send_push_notification(first_user=user, anno=anno, action_type=AnnoActionType.COMMENTED,
                                                         comment=request.comment)

        return followup.to_message(request.team_key)
Ejemplo n.º 9
0
    def getEngagedUsers(cls, anno_id, auth_user, include_auth_user=False):
        from model.userannostate import UserAnnoState
        userannostates = UserAnnoState.list_users_by_anno(anno_id=anno_id, projection=[UserAnnoState.user])

        users = []
        for userannostate in userannostates:
            current_user = userannostate.user.get()
            users.append(UserMessage(id=current_user.key.id(),
                                     user_email=current_user.user_email,
                                     display_name=current_user.display_name,
                                     image_url=current_user.image_url))

        # removing auth_user
        if auth_user:
            if include_auth_user:
                if not any(user_info.user_email == auth_user.user_email for user_info in users):
                    users.append(UserMessage(id=auth_user.key.id(),
                                             user_email=auth_user.user_email,
                                             display_name=auth_user.display_name,
                                             image_url=auth_user.image_url))
            else:
                [ users.remove(user_info) for user_info in users if user_info.user_email == auth_user.user_email ]

        # sorting users alphabetically
        return sorted(users, key=lambda user_info: user_info.display_name.lower())
Ejemplo n.º 10
0
    def list_favorite_apps(cls, user_key):
        # We are using "query" on key for getting anno data instead of "get" or "get_multi"
        # Getting anno using "query" is more memory efficient than using "get" or "get_multi",
        # we don't know why.
        # Getting anno using "query" also create index for this.

        from model.userannostate import UserAnnoState
        from model.anno import Anno

        userannostate_list = UserAnnoState.list_by_user(user_key, 50)
        anno_key_list = [ userannostate.anno for userannostate in userannostate_list if userannostate.anno is not None ]

        if len(anno_key_list):
            anno_list = Anno.query(ndb.AND(Anno.key.IN(anno_key_list),
                                           Anno.app != None)
                                   )\
                            .fetch(projection=[Anno.app])
            app_key_list = [ anno.app for anno in anno_list ]
            app_key_list = sorted(app_key_list, key=app_key_list.count, reverse=True)
            unique_app_key_list = []
            [ unique_app_key_list.append(app_key) for app_key in app_key_list if app_key not in unique_app_key_list ]
            app_list = ndb.get_multi(unique_app_key_list)
        else:
            app_list = []

        favorite_apps_list = []
        for app in app_list:
            if app:
                app_message = UserFavoriteApp(name=app.name, icon_url=(app.icon_url or ""), version=(app.version or ""))
                favorite_apps_list.append(app_message)

        return favorite_apps_list
Ejemplo n.º 11
0
    def update_notify(self, request):
        user = auth_user(self.request_state.headers)
        anno = Anno.get_by_id(request.anno_id)
        entity = UserAnnoState.get(user=user, anno=anno)

        if entity:
            entity.notify = request.notify
            entity.put()

        return message_types.VoidMessage()
Ejemplo n.º 12
0
    def delete(cls, anno):
        anno_id = "%d" % anno.key.id()

        # deleting UserAnnoState of anno
        from model.userannostate import UserAnnoState
        UserAnnoState.delete_by_anno(anno_key=anno.key)

        # deleting FollowUp of anno
        from model.follow_up import FollowUp
        FollowUp.delete_by_anno(anno_key=anno.key)

        # deleting Vote of anno
        from model.vote import Vote
        Vote.delete_by_anno(anno_key=anno.key)

        # deleting Flag of anno
        from model.flag import Flag
        Flag.delete_by_anno(anno_key=anno.key)

        anno.key.delete()
        index = search.Index(name=SearchIndexName.ANNO)
        index.delete(anno_id)
Ejemplo n.º 13
0
    def anno_teamnotes_insert(self, request):
        anno = Anno.get_by_id(request.id)
        user = auth_user(self.request_state.headers)

        if anno:
            anno.team_notes = request.team_notes
            UserAnnoState.tag_users(anno, anno.tagged_users, request.tagged_users)
            anno.tagged_users = request.tagged_users
            anno.put()

        mentions = []
        for tagged_user in request.tagged_users:
            user_info = User.get_by_id(int(tagged_user))
            is_auth_user = user_info.user_email == user.user_email
            mentions.append(AnnoMentionsResponseMessage(id=user_info.key.id(),
                                                        display_name=user_info.display_name,
                                                        user_email=user_info.user_email,
                                                        image_url=user_info.image_url,
                                                        is_auth_user=is_auth_user))

        return AnnoTeamNotesMetadataMessage(tags=parseTeamNotesForHashtags(request.team_notes),
                                            mentions=mentions)
Ejemplo n.º 14
0
def update_userannostate_schema(cursor=None):
    userannostate_list, cursor, more = UserAnnoState.query().fetch_page(BATCH_SIZE, start_cursor=cursor)

    userannostate_update_list = []
    for userannostate in userannostate_list:
        if not userannostate.tagged:
            userannostate.tagged = False
            userannostate_update_list.append(userannostate)

    if len(userannostate_update_list):
        ndb.put_multi(userannostate_update_list)

    if more:
        update_userannostate_schema(cursor=cursor)
Ejemplo n.º 15
0
    def send_push_notification(cls, first_user, anno, action_type, comment=""):
        """
        Send push notification for anno actions

        :param ndb.Model first_user: "******" datastore of user who did anno action
        :param ndb.Model anno: "anno" datastore
        :param str action_type: one of the :py:class:`.AnnoActionType`
        :param str comment: comment made on an anno
        """
        # get list of device ids to which push notification to be sent
        notf_device = cls.get_noft_devices(first_user, anno, action_type)

        # create push notification message for iOS and Android devices
        notf_msg = cls.create_notf_msg(first_user, anno, action_type, comment)

        # if action is "deleted" then delete all UserAnnoState related to that anno
        if action_type == AnnoActionType.DELETED:
            UserAnnoState.delete_by_anno(anno_key=anno.key)

        for platform, devices in notf_device.iteritems():
            message, data = notf_msg[platform]
            if len(devices):
                PushTaskQueue.add(message=message, ids=devices, typ=platform.lower(), data=data)
Ejemplo n.º 16
0
    def query_my_anno(cls, limit, curs, user):
        if user:
            from model.userannostate import UserAnnoState
            userannostate_list = UserAnnoState.list_by_user(user_key=user.key)
            anno_id_list = [ userannostate.anno.id() for userannostate in userannostate_list ]

            anno_message_list = []
            more = False
            if len(anno_id_list):
                query = cls.query(cls.anno_id.IN(anno_id_list)).order(-cls.last_update_time, cls.key)
                anno_list, next_curs, more = query.fetch_page(limit, start_cursor=curs)
                anno_message_list = [ anno.to_response_message(user) for anno in anno_list if anno is not None ]

            if more:
                return AnnoListMessage(anno_list=anno_message_list, cursor=next_curs.urlsafe(), has_more=more)
            else:
                return AnnoListMessage(anno_list=anno_message_list, has_more=more)
        else:
            return AnnoListMessage(anno_list=[])
Ejemplo n.º 17
0
    def query_by_my_mentions_for_dashboard(cls, limit, curs, user):
        query = cls.query()
        query = query.order(-cls.created)
        query = filter_anno_by_user(query, user, True)

        from model.userannostate import UserAnnoState
        userannostate_list = UserAnnoState.query().filter(ndb.AND(UserAnnoState.user == user.key, UserAnnoState.tagged == True)).fetch()
        anno_list = [ userannostate.anno.id() for userannostate in userannostate_list]
        if len(anno_list):
            query = query.filter(cls.anno_id.IN(anno_list))

            annos, next_curs, more = query.fetch_page(limit, start_cursor=curs)
            items = [entity.to_dashboard_response_message(user) for entity in annos]

            if more:
                return AnnoDashboardListMessage(anno_list=items, cursor=next_curs.urlsafe(), has_more=more)
            else:
                return AnnoDashboardListMessage(anno_list=items, has_more=more)
        else:
            return AnnoDashboardListMessage(anno_list=[])
Ejemplo n.º 18
0
    def get_noft_devices(cls, first_user, anno, action_type):
        """
        Get list of device ids to which notification to be sent

        :param ndb.Model first_user: "******" datastore of user who did anno action
        :param ndb.Model anno: "anno" datastore
        :param str action_type: one of the :py:class:`.AnnoActionType`
        :returns: list of device ids for iOS and Android devices
        :rtype: dict
        """
        interested_user_deviceids = {PlatformType.IOS: [], PlatformType.ANDROID: []}
        community_manager_deviceids = {PlatformType.IOS: [], PlatformType.ANDROID: []}

        # get all interested users for anno if action_type is other than "created"
        if action_type != AnnoActionType.CREATED:
            interested_user_list = UserAnnoState.list_users_by_anno(
                anno_key=anno.key, projection=[UserAnnoState.user, UserAnnoState.last_read]
            )
            interested_user_deviceids = cls.list_deviceid(interested_user_list)

        # anno is in community-scope then send notification to all managers of that community
        if anno.community:
            community_id = anno.community.id()
            community_manager_list = UserRole.community_user_list(community_id=community_id, only_managers=True)
            community_manager_deviceids = cls.list_deviceid(community_manager_list)

        # merging device ids of interested users and community managers
        notf_devices = {
            platform: list(set(interested_user_deviceids[platform] + community_manager_deviceids[platform]))
            for platform in interested_user_deviceids
        }

        # removing first user from push notification task
        if first_user.device_id and first_user.device_type:
            if first_user.device_id in notf_devices[first_user.device_type]:
                notf_devices[first_user.device_type].remove(first_user.device_id)

        return notf_devices
Ejemplo n.º 19
0
 def get_unread_count(self, request):
     return UserUnreadMessage(unread_count=UserAnnoState.get_unread_count(request))
Ejemplo n.º 20
0
def update_userannostate_schema_from_anno(anno):
    user = anno.creator.get()
    modified = anno.last_update_time
    if user:
        UserAnnoState.insert(user=user, anno=anno, modified=modified)