コード例 #1
0
async def get_user_statistics_in_group(
    group_id: str, user_id: int, db: Session = Depends(get_db)) -> UserGroup:
    """
    Get a user's statistic in a group (last read, hidden, etc.), including the group information.

    **Potential error codes in response:** 
    * `600`: if the user is not in the group,
    * `601`: if the group does not exist,
    * `250`: if an unknown error occurred.
    """
    try:
        message_amount = await environ.env.rest.group.count_messages_in_group(
            group_id)
        user_group_stats = await environ.env.rest.group.get_user_group_stats(
            group_id, user_id, db)

        query = GroupInfoQuery(count_messages=False)
        group_info = await environ.env.rest.group.get_group(
            group_id, query, db, message_amount=message_amount)

        return UserGroup(group=group_info, stats=user_group_stats)

    except NoSuchGroupException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_GROUP, sys.exc_info(), e)
    except UserNotInGroupException as e:
        log_error_and_raise_known(ErrorCodes.USER_NOT_IN_GROUP, sys.exc_info(),
                                  e)
    except Exception as e:
        log_error_and_raise_unknown(sys.exc_info(), e)
コード例 #2
0
ファイル: post.py プロジェクト: thenetcircle/dino-service
async def send_message_to_user(
    user_id: int, query: SendMessageQuery, db: Session = Depends(get_db)
) -> Message:
    """
    User sends a message in a **1-to-1** conversation. It is not always known on client side if a
    **1-to-1** group exists between two users, so this API can then be used; Dino will do a group
    lookup and see if a group with `group_type=1` exists for them, send a message to it and return
    the group_id.

    If no group exists, Dino will create a __new__ **1-to-1** group, send the message and return the
    `group_id`.

    This API should NOT be used for EVERY **1-to-1** message. It should only be used if the client
    doesn't know if a group exists for them or not. After this API has been called once, the client
    should use the `POST /v1/groups/{group_id}/users/{user_id}/send` API for future messages as
    much as possible.

    When listing recent history, the client will know the group_id for recent **1-to-1** conversations
    (since the groups that are **1-to-1** have `group_type=1`), and should thus use the other send API.

    **Potential error codes in response:**
    * `604`: if the user does not exist,
    * `250`: if an unknown error occurred.
    """
    try:
        return await environ.env.rest.message.send_message_to_user(user_id, query, db)
    except NoSuchUserException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_USER, sys.exc_info(), e)
    except Exception as e:
        log_error_and_raise_unknown(sys.exc_info(), e)
コード例 #3
0
ファイル: post.py プロジェクト: thenetcircle/dino-service
async def get_one_to_one_information(
    user_id: int, query: OneToOneQuery, db: Session = Depends(get_db)
) -> OneToOneStats:
    """
    Get details about a 1v1 group.

    **Potential error codes in response:**
    * `601`: if the group does not exist,
    * `250`: if an unknown error occurred.
    """
    try:
        return await environ.env.rest.group.get_1v1_info(user_id, query.receiver_id, db)
    except NoSuchGroupException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_GROUP, sys.exc_info(), e)
    except Exception as e:
        log_error_and_raise_unknown(sys.exc_info(), e)
コード例 #4
0
ファイル: put.py プロジェクト: thenetcircle/dino-service
async def join_group(
    group_id: str, query: JoinGroupQuery,
    db: Session = Depends(get_db)) -> None:
    """
    Join a group.

    **Potential error codes in response:**
    * `601`: if the group does not exist,
    * `250`: if an unknown error occurred.
    """
    try:
        return await environ.env.rest.group.join_group(group_id, query, db)
    except NoSuchGroupException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_GROUP, sys.exc_info(), e)
    except Exception as e:
        log_error_and_raise_unknown(sys.exc_info(), e)
コード例 #5
0
ファイル: put.py プロジェクト: thenetcircle/dino-service
async def edit_group_information(
    group_id, query: UpdateGroupQuery, db: Session = Depends(get_db)) -> None:
    """
    Update group details.

    **Potential error codes in response:**
    * `601`: if the group does not exist,
    * `250`: if an unknown error occurred.
    """
    try:
        await environ.env.rest.group.update_group_information(
            group_id, query, db)
    except NoSuchGroupException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_GROUP, sys.exc_info(), e)
    except Exception as e:
        log_error_and_raise_unknown(sys.exc_info(), e)
コード例 #6
0
ファイル: post.py プロジェクト: thenetcircle/dino-service
async def get_message_info(
        user_id: int, message_id: str, query: MessageInfoQuery
) -> Message:
    """
    Get details about a message. The `created_at` field on the query is
    needed to avoid large table scans when trying to find the message
    in Cassandra.

    **Potential error codes in response:**
    * `602`: if the message doesn't exist for the given group and user,
    * `250`: if an unknown error occurred.
    """
    try:
        return await environ.env.rest.message.get_message_info(user_id, message_id, query)
    except NoSuchMessageException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_MESSAGE, sys.exc_info(), e)
    except Exception as e:
        log_error_and_raise_unknown(sys.exc_info(), e)
コード例 #7
0
ファイル: delete.py プロジェクト: thenetcircle/dino-service
async def leave_group(
    user_id: int,
    group_id: str,
    query: CreateActionLogQuery,
    db: Session = Depends(get_db)) -> None:
    """
    Leave a group.

    **Potential error codes in response:** 
    * `601`: if the group does not exist,
    * `250`: if an unknown error occurred.
    """
    try:
        return environ.env.rest.group.leave_group(group_id, user_id, query, db)
    except NoSuchGroupException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_GROUP, sys.exc_info(), e)
    except Exception as e:
        log_error_and_raise_unknown(sys.exc_info(), e)
コード例 #8
0
ファイル: put.py プロジェクト: thenetcircle/dino-service
async def update_user_statistics_in_group(
        group_id: str,
        user_id: int,
        query: UpdateUserGroupStats,
        db: Session = Depends(get_db),
) -> None:
    """
    Update user statistic in a group. Only values specified in the query
    will be updated (if a field is blank in the query it won't be updated).

    This API should __NOT__ be used to update `last_read_time` when opening
    a conversation. The `last_read_time` is updated automatically when a
    user calls the `/v1/groups/{group_id}/user/{user_id}/histories` API for
    a group.

    **Can be used for updating the following:**

    * `last_read_time`: should be creating time of last received message,
    * `delete_before`: when a user deletes a conversation, set to the creation time of the last received message,
    * `highlight_time`: until when should this conversation be highlighted for this user,
    * `highlight_limit`: max number of highlights to allow (will cancel the oldest highlight time if this call causes the highlights to exceed the limit)
    * `hide`: whether to hide/show a conversation,
    * `bookmark`: whether to bookmark a conversation or not,
    * `pin`: whether to pin a conversation or not,
    * `rating`: a user can rate a conversation (1v1 usually).

    When setting `bookmark` to false, it will set the unread count to 0,
    and `last_read_time` will be `last_message_time`.

    **Potential error codes in response:**
    * `600`: if the user is not in the group,
    * `601`: if the group does not exist,
    * `250`: if an unknown error occurred.
    """
    try:
        return await environ.env.rest.group.update_user_group_stats(
            group_id, user_id, query, db)
    except NoSuchGroupException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_GROUP, sys.exc_info(), e)
    except UserNotInGroupException as e:
        log_error_and_raise_known(ErrorCodes.USER_NOT_IN_GROUP, sys.exc_info(),
                                  e)
    except Exception as e:
        log_error_and_raise_unknown(sys.exc_info(), e)
コード例 #9
0
ファイル: post.py プロジェクト: thenetcircle/dino-service
async def get_attachment_info_from_file_id(
    group_id: str, query: AttachmentQuery, db: Session = Depends(get_db)
) -> Message:
    """
    Get attachment info from `file_id`.

    **Potential error codes in response:**
    * `601`: if the group does not exist,
    * `604`: if the attachment does not exist,
    * `250`: if an unknown error occurred.
    """
    try:
        return await environ.env.rest.message.get_attachment_info(group_id, query, db)
    except NoSuchGroupException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_GROUP, sys.exc_info(), e)
    except NoSuchAttachmentException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_ATTACHMENT, sys.exc_info(), e)
    except Exception as e:
        log_error_and_raise_unknown(sys.exc_info(), e)
コード例 #10
0
ファイル: post.py プロジェクト: thenetcircle/dino-service
async def get_group_information(
    group_id: str, query: GroupInfoQuery, db: Session = Depends(get_db)
) -> Group:
    """
    Get details about one group.

    If `count_messages` is set to `true`, a count of all messages in the group
    will be returned in `message_amount`. If `count_messages` is set to `false`,
    `message_amount` will be `-1`. Default value is `false`.

    **Potential error codes in response:**
    * `601`: if the group does not exist,
    * `250`: if an unknown error occurred.
    """
    try:
        return await environ.env.rest.group.get_group(group_id, query, db)
    except NoSuchGroupException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_GROUP, sys.exc_info(), e)
    except Exception as e:
        log_error_and_raise_unknown(sys.exc_info(), e)
コード例 #11
0
ファイル: put.py プロジェクト: thenetcircle/dino-service
async def edit_message(
    user_id: int,
    message_id: str,
    query: EditMessageQuery,
    db: Session = Depends(get_db)) -> Message:
    """
    Edit the context of a message. Returns the ActionLog for the edit.

    **Potential error codes in response:**
    * `602`: if the message doesn't exist for the given group and user,
    * `250`: if an unknown error occurred.
    """
    try:
        return await environ.env.rest.message.edit(user_id, message_id, query,
                                                   db)
    except NoSuchMessageException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_MESSAGE, sys.exc_info(),
                                  e)
    except Exception as e:
        log_error_and_raise_unknown(sys.exc_info(), e)
コード例 #12
0
ファイル: post.py プロジェクト: thenetcircle/dino-service
async def send_message_to_group(
    group_id: str, user_id: int, query: SendMessageQuery, db: Session = Depends(get_db)
) -> Message:
    """
    User sends a message in a group. This API should also be used for **1-to-1** conversations
    if the client knows the `group_id` for the **1-to-1** conversations. Otherwise the
    `POST /v1/users/{user_id}/send` API can be used to send a message and get the `group_id`.

    **Potential error codes in response:**
    * `600`: if the user is not in the group,
    * `601`: if the group does not exist,
    * `250`: if an unknown error occurred.
    """
    try:
        return await environ.env.rest.message.send_message_to_group(
            group_id, user_id, query, db
        )
    except NoSuchGroupException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_GROUP, sys.exc_info(), e)
    except UserNotInGroupException as e:
        log_error_and_raise_known(ErrorCodes.USER_NOT_IN_GROUP, sys.exc_info(), e)
    except Exception as e:
        log_error_and_raise_unknown(sys.exc_info(), e)
コード例 #13
0
ファイル: post.py プロジェクト: thenetcircle/dino-service
async def get_attachments_in_group_for_user(
    group_id: str, user_id: int, query: MessageQuery, db: Session = Depends(get_db)
) -> List[Message]:
    """
    Get all attachments in this group for this user.

    Only one of `since` and `until` can be used at the same time. At least one needs to be
    specified.

    **Potential error codes in response:**
    * `600`: if the user is not in the group,
    * `601`: if the group does not exist,
    * `250`: if an unknown error occurred.
    """
    try:
        return await environ.env.rest.group.get_attachments_in_group_for_user(
            group_id, user_id, query, db
        )
    except NoSuchGroupException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_GROUP, sys.exc_info(), e)
    except UserNotInGroupException as e:
        log_error_and_raise_known(ErrorCodes.USER_NOT_IN_GROUP, sys.exc_info(), e)
    except Exception as e:
        log_error_and_raise_unknown(sys.exc_info(), e)
コード例 #14
0
ファイル: post.py プロジェクト: thenetcircle/dino-service
async def get_group_history_for_user(
    group_id: str, user_id: int, query: MessageQuery, db: Session = Depends(get_db)
) -> Histories:
    """
    Get user visible history in a group for a user. Sorted by creation time in descendent.
    Response contains a list of messages sent in the group, a list of action logs, and a list
    the last read time for each user in the group.

    Calling this API will update `last_read_time` in this group for this user, and
    broadcast the new read time to every one else in the group that is online.

    History can be filtered by `message_type` to e.g. only list images sent in the group.

    Only one of `since` and `until` can be used at the same time. At least one needs to be
    specified.

    If `only_sender=true` (default is `false`), the API will only return messages history in
    this group that were sent by `user_id`. This can be combined with `until` and `per_page`,
    to paginate through all the messages for a user, but setting the next query's `until` to
    the `created_at` time of the last message returned from the previous query.

    If `admin_id` is set, and is greater than `0`, the read status will not be updated. Useful
    for getting history in admin UI without updating `last_read_time` of the user.

    **Potential error codes in response:**
    * `600`: if the user is not in the group,
    * `601`: if the group does not exist,
    * `605`: if the since/until parameters are not valid,
    * `250`: if an unknown error occurred.
    """
    try:
        return await environ.env.rest.group.histories(group_id, user_id, query, db)
    except NoSuchGroupException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_GROUP, sys.exc_info(), e)
    except UserNotInGroupException as e:
        log_error_and_raise_known(ErrorCodes.USER_NOT_IN_GROUP, sys.exc_info(), e)
    except InvalidRangeException as e:
        log_error_and_raise_known(ErrorCodes.WRONG_PARAMETERS, sys.exc_info(), e)
    except Exception as e:
        log_error_and_raise_unknown(sys.exc_info(), e)
コード例 #15
0
ファイル: post.py プロジェクト: thenetcircle/dino-service
async def create_an_attachment(
    user_id: int,
    message_id: str,
    query: CreateAttachmentQuery,
    db: Session = Depends(get_db),
) -> Message:
    """
    Create an attachment.

    When a user sends an image or video, first call the "send message API" with the
    `message_type` set to `image` (or similar). When the image has finished processing
    in the backend, call this API to create the actual attachment meta data for it.

    First we create the "empty" message so indicate to all relevant users that someone
    has sent something, usually the client application will show a loading icon for this
    "empty" message. When this API is called after the image processing is done, Dino
    will broadcast an update to the clients with a reference to the ID of the "empty"
    message, so the real image can replace the loading icon.

    **Potential error codes in response:**
    * `601`: if the group does not exist,
    * `602`: if the message does not exist,
    * `250`: if an unknown error occurred.
    """
    try:
        return await environ.env.rest.message.create_attachment(
            user_id, message_id, query, db
        )
    except QueryValidationError as e:
        log_error_and_raise_known(ErrorCodes.WRONG_PARAMETERS, sys.exc_info(), e)
    except NoSuchGroupException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_GROUP, sys.exc_info(), e)
    except NoSuchMessageException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_MESSAGE, sys.exc_info(), e)
    except Exception as e:
        log_error_and_raise_unknown(sys.exc_info(), e)
コード例 #16
0
ファイル: post.py プロジェクト: thenetcircle/dino-service
async def get_message_count_for_user_in_group(
    group_id: str, user_id: int, query: Optional[OnlySenderQuery] = None, db: Session = Depends(get_db)
) -> MessageCount:
    """
    Count the number of messages in a group since a user's `delete_before`.

    If `only_sender` is set to False (default value), the messages for all
    users in the groups will be counted. If set to True, only messages sent
    by the specified `user_id` will be counted. When set to True, only
    messages send by this user _after_ his/her `delete_before` and _before_
    his/her `last_sent_time` will be counted.

    Note: setting `only_sender=true` is slow. Around 2 seconds for a group
    of 6k messages. This is because we can not filter by `user_id` in
    Cassandra, and have to instead batch query for all messages in the group
    and filter out and count afterwards.

    **Potential error codes in response:**
    * `600`: if the user is not in the group,
    * `601`: if the group does not exist,
    * `250`: if an unknown error occurred.
    """
    try:
        group_info: UserGroupStatsBase = environ.env.db.get_user_stats_in_group(group_id, user_id, db)

        # can't filter by user id in cassandra without restricting 'created_at', so
        # use the cached value from the rdbms
        if query and query.only_sender:
            # can return both None and -1; -1 means we've checked the db before, but it has not
            # yet been counted, to avoid checking the db every time a new message is sent
            message_count = environ.env.db.get_sent_message_count(group_id, user_id, db)

            # if it hasn't been counted before, count from cassandra in batches (could be slow)
            if message_count is None or message_count == -1:
                # until isn't inclusive, so the last message sent won't be counted otherwise;
                until = group_info.last_sent
                until += timedelta(milliseconds=1)

                message_count = environ.env.storage.count_messages_in_group_from_user_since(
                    group_id,
                    user_id,
                    until=until,
                    since=group_info.delete_before
                )
                environ.env.db.set_sent_message_count(group_id, user_id, message_count, db)

        else:
            message_count = environ.env.storage.count_messages_in_group_since(
                group_id, group_info.delete_before
            )

        return MessageCount(
            group_id=group_id,
            user_id=user_id,
            delete_before=to_ts(group_info.delete_before),
            message_count=message_count
        )

    except NoSuchGroupException as e:
        log_error_and_raise_known(ErrorCodes.NO_SUCH_GROUP, sys.exc_info(), e)
    except UserNotInGroupException as e:
        log_error_and_raise_known(ErrorCodes.USER_NOT_IN_GROUP, sys.exc_info(), e)
    except Exception as e:
        log_error_and_raise_unknown(sys.exc_info(), e)