Exemplo n.º 1
0
def admin_userpermission_change_v1(token, u_id, permission_id):
    """Summary
        Enables a Dreams owner to change the permissions of another user between Dreams owner (1) and
        standard user (2).
    Args:
        token (string): User session token
        u_id (integer): User id number
        permission_id (integer): Either 1, indicating Dreams owner, or 2, indicating standard user
    
    Returns:
        Empty dictionary
    
    Raises:
        AccessError: When an invalid token value is given, or when the user associated with the token
                     is not a Dreams owner
        InputError: When permission_id does not refer to a valid permission, or 
                    u_id does not refer to a valid user
    """
    check_token(token)  # Check for invalid token

    if user_from_token(token)['permission'] != 1:
        raise AccessError("Authorised user is not an owner.")

    if not 1 <= permission_id <= 2:  # Check for invalid permission_id
        raise InputError("permission_id does not refer to a valid permission.")

    # Search for user with user id u_id and change their permission if found
    for user in users:
        if user['u_id'] == u_id:
            user['permission'] = permission_id
            return {}
    raise InputError("u_id does not refer to a valid user.")
Exemplo n.º 2
0
def notifications_get_v1(token):
    """Summary
        Return the user's most recent 20 notifications
    Args:
        token (string): User session token
    
    Returns:
        { notifications } ({channel_id,dm_id,notification_message}) dictionary of notifications
    
    Raises:
        AccessError: the token entered is not a valid token
    """
    check_token(token)
    u_id = user_from_token(token)['u_id']
    output = []

    # search all teh notifications, and find the notifications which were sent by user(u_id)
    for noti_list in notifications:
        if noti_list['u_id'] == u_id:
            notis = noti_list['notifications']
            # record all the user's most recent 20 notifications
            if len(notis) <= 20:
                output = list(reversed(notis))
            else:
                output = list(reversed(notis))[:20]
    return { 'notifications' : output }
Exemplo n.º 3
0
def dm_leave_v1(token, dm_id):
    '''
    Summary:
        Given a DM ID, the user is removed as a member of this DM
    Args:
        token (string): A user session token 
        dm_id (int): A dm_id number
    Returns: 
        a empty dictionary
    Raises:
        InputError when:
            dm_id is not a valid DM
        AccessError when:
            Authorised user is not a member of DM with dm_id
    '''
    global users, channels, dms
    assert check_token(token)

    auth_user = user_from_token(token)
    if valid_dm(dm_id) == False:
        raise InputError(f"dm_id is not a valid DM")

    current_dm = find_dm(dm_id)  #find the current dm

    if auth_user['u_id'] not in current_dm['members']:
        raise AccessError(f"Authorised user is not a member of DM with dm_id")

    # Remove dm from user's list of dms
    auth_user['dms'].remove(dm_id)
    update_user_dm_stats(auth_user['u_id'])

    # Remove user from dm's members list
    current_dm['members'].remove(auth_user['u_id'])

    return {}
Exemplo n.º 4
0
def channels_list_v2(token):
    '''
    <Provide a list of all channels (and their associated details) that the authorised user is part of>

    Arguments:
        <token>        (<string>)     - <User session token>

    Exceptions:
        AccessError - Occurs when the token is not a vaild token

    Return Value:
        Returns <{ channels }>      on <return the list of these channels that user is apart of>

    '''

    global users, channels
    check_token(token)
    auth_user_id = user_from_token(token)['u_id']

    channelList = []

    # search all the channel
    for channel in channels:
        # if the auth user is a menber of this channel, add this channel to the channellist
        if auth_user_id in channel['all_members']:
            channelList.append({
                'channel_id': channel['channel_id'],
                'name': channel['name']
            })

    # if this user is not in any channel, just return the empty channellist list
    return {'channels': channelList}
Exemplo n.º 5
0
def channels_create_v2(token, name, is_public):
    '''
    <this function will create a channel with the auth_user_id being the creater of the channel, it will give the name of the channel and then set it to public or private>

    Arguments:
        <token>        (<string>)     - <User session token>
        <name>         (<string>)     - <this is the name of the new channel which will be created in this function>
        <is_public>    (<boolean>)    - <this parameter will discrible if this channel is a public channel or a private channel>

    Exceptions:
        InputError  - Occurs when name is more than 20 characters long
        AccessError - Occurs when the token is not a vaild token
    Return Value:
        Returns <{ channel_id }>       on <when channel is successfully created, return the id of this new channel>
    
    '''

    global users, channels, next_channel_id

    check_token(token)
    auth_user = user_from_token(token)
    auth_user_id = auth_user['u_id']

    # Name is more than 20 characters long
    if len(name) > 20:
        raise InputError(
            f"The name entered: {name} is more than 20 characters long")

    channel_id = next_channel_id['id']

    next_channel_id['id'] += 1

    # create a new channel
    new_channel = {
        'channel_id': channel_id,
        'name': name,
        'owner_members': [auth_user_id],
        'all_members': [auth_user_id],
        'is_public': is_public,
        'messages': [],
        'standup': {
            'is_active': False,
            'creator': 0,
            'messages': [],
            'time_finish': 0
        }
    }

    # add the new channel to the channels list
    channels.append(new_channel)

    update_channel_stats(
    )  # Record newly increased number of channels in Dreams stats

    auth_user['channels'].append(
        channel_id)  # Add the channel's id to the user's list of channels
    update_user_channel_stats(auth_user_id)

    return {'channel_id': new_channel['channel_id']}
Exemplo n.º 6
0
def message_edit_v2(token, message_id, message):
    """Summary
        Given a message, update its text with new text. If the new message is an empty string, the message 
        is deleted.
    Args:
        token (string): A user session token
        message_id (int): A message id number
        message (string): The text with which the user wishes to replace the current message
    
    Returns:
        Empty dictionary
    
    Raises:
        AccessError: When an invalid token is given, or the user attempts to delete a message that they did
                     not write, or one in a channel that they do not own, and they are not a dreams owner
        InputError: If the message is not a string, is longer than 1000 characters, or message_id does not
                    refer to a valid message
    """
    global messages
    check_token(token)
    auth_user = user_from_token(token)

    if type(message) != str:
        raise InputError(f"Message {message} is not of type string")

    if len(message) > 1000:
        raise InputError(
            f"Length of message is over 1000 characters (length is {len(message)})"
        )

    for msg in messages:
        if msg['message_id'] == message_id:
            can_edit = False
            if auth_user['u_id'] == msg['author_id'] or is_dreams_owner(
                    auth_user['u_id']):
                # If the user is the author of the message or a dreams owner, they can always edit it
                can_edit = True
            elif msg['channel_id'] != -1 and is_channel_owner(
                    auth_user['u_id'], msg['channel_id']):
                # If the message was sent to a channel and the user is the channel owner
                can_edit = True

            if can_edit:
                if not len(
                        message
                ):  # If the new message text is blank, delete the message
                    message_remove_v1(token, message_id)
                else:  # Replace the current message text with the new text
                    msg['message'] = message
                return {}
            raise AccessError(
                f"User {auth_user['handle_str']} does not have permission to edit message with id {message_id}"
            )

    raise InputError(
        f"Message with id {message_id} does not exist (it may have been deleted)"
    )
Exemplo n.º 7
0
def search_v2(token, query_str):
    """Summary
        Given a query string, return a collection of messages in all of the channels/DMs that the user has joined that match the query
    Args:
        token (string): A user session token
        query_str (string): a string for search message
    
    Returns:
        Dictionary: { messages } ({ message_id, u_id, message, time_created })  Contains the imformation of messages
    
    Raises:
        InputError: query_str is above 1000 characters
    """
    query_str = query_str.lower()

    # InputError: query_str is above 1000 characters
    if len(query_str) > 1000:
        raise InputError("query_str is above 1000 characters")

    check_token(token)
    auth_user_id = user_from_token(token)['u_id']

    output = []
    # search all the messages
    for message in messages:
        user_is_member = False

        # if this message is send to the channel, find the channel
        if message['channel_id'] != -1:
            channel = find_channel(message['channel_id'])
            user_is_member = (auth_user_id in channel['all_members']
                              and query_str in message['message'].lower())
        # if this message is send to the dm, find the dm
        else:
            dm = find_dm(message['dm_id'])
            user_is_member = (auth_user_id in dm['members']
                              and query_str in message['message'].lower())

        # list all the detail of this messagen, and append it to the putput
        if user_is_member:
            react_dict = {
                'react_id': 1,
                'u_ids': message['reacts'],
                'is_this_user_reacted': auth_user_id in message['reacts']
            }

            message_detail = {
                'message_id': message['message_id'],
                'u_id': message['author_id'],
                'message': message['message'],
                'time_created': message['time_created'],
                'reacts': [react_dict],
                'is_pinned': message['is_pinned']
            }
            output.append(message_detail)
    return {'messages': output}
Exemplo n.º 8
0
def channel_details_v2(token, channel_id):
    '''
    Summary:
        Given a Channel with ID channel_id that the authorised user is part of, 
        provide basic details about the channel
    Args:
        token (string): A user session token 
        channel_id (int): A channel_id number
    Returns: 
        a dictionary which contains:
            name of the channel 
            the is_public status of the channel (True for public, False for private)
            a list of owner_member for the channel 
            a list of members for a channel
    Raises:
        InputError when:
            Channel ID is not a valid channel
        AccessError when:
            Authorised user is not a member of channel with channel_id
    '''
    global users, channels
    assert check_token(token)
    auth_user = user_from_token(token)

    if valid_channel(channel_id) == False:
        raise InputError(f"Channel ID {channel_id} is not a valid channel")

    current_channel = find_channel(
        channel_id)  #current channel with the given channel id

    if auth_user['u_id'] not in current_channel['all_members']:
        raise AccessError(
            f"Authorised user {auth_user['u_id']} is not a member of channel with channel_id {channel_id}"
        )

    owner_members = []
    all_members = []
    for u_id in current_channel['all_members']:
        for user in users:
            if user['u_id'] == u_id:
                user_details = {}
                user_details['u_id'] = user['u_id']
                user_details['email'] = user['email']
                user_details['name_first'] = user['name_first']
                user_details['name_last'] = user['name_last']
                user_details['handle_str'] = user['handle_str']
                user_details['profile_img_url'] = user['profile_img_url']
                all_members.append(user_details)
                if u_id in current_channel['owner_members']:
                    owner_members.append(user_details)
    return {  #give the name of the dictonary then the values
        'name': current_channel['name'],
        'is_public': current_channel['is_public'],
        'owner_members': owner_members,
        'all_members': all_members
    }
Exemplo n.º 9
0
def standup_start_v1(token, channel_id, length):
    '''
    Summary:
       For a given channel, 
       start the standup period whereby for the next "length" seconds if someone calls "standup_send" with a message, 
       it is buffered during the X second window then at the end of the X second window a message will be added to the message queue 
       in the channel from the user who started the standup. X is an integer that denotes the number of seconds that the standup occurs for
    Args:
        token (string): A user session token 
        channel_id (int): A channel_id number
        length (int): A length of how long the standup runs
    Returns: 
        dictionary which contains the time_finished 
    Raises:
        InputError when:
            Channel ID is not a valid channel
            An active standup is currently running in this channel
        AccessError when:
            Authorised user is not in the channel
    '''
    global channels
    check_token(token)

    if valid_channel(channel_id) == False:
        raise InputError(f'Channel ID {channel_id} is not a valid channel')

    auth_user_id = user_from_token(token)['u_id']

    if is_channel_member(auth_user_id, channel_id) == False:
        raise AccessError(f'Authorised user is not in the channel')

    current_channel = find_channel(channel_id)

    if current_channel['standup']['is_active'] == True:
        raise InputError(
            f'An active standup is currently running in this channel')

    standup_period_finish = datetime.now(
        timezone.utc) + timedelta(seconds=length)
    timestamp = standup_period_finish.replace(tzinfo=timezone.utc).timestamp()

    # what will i add to the message here
    #dummy = ''
    #message_id = message_sendlater_v1(token, channel_id, dummy, timestamp)
    #message id here or standup send
    #standup_info = {}
    #create the standup dicitonary in channel create
    current_channel['standup']['is_active'] = True
    current_channel['standup']['creator'] = auth_user_id
    current_channel['standup']['messages'] = []
    current_channel['standup']['time_finish'] = timestamp

    #current_channel['standup'] = standup_info

    return {'time_finish': timestamp}
Exemplo n.º 10
0
def dm_remove_v1(token, dm_id):
    """
    Summary
        Delete an existing DM. This can only be done by the original creator of the DM.
    Args:
        token (string): A user session token
        dm_id (int): A dm id number

        AccessError: When an invalid token is given, or the authorised user is not already a member of the DM
        InputError: When dm_id does not refer to a valid dm, 
        InputError: When u_id does not refer to a valid user.
    """
    global messages
    check_token(token)
    auth_user = user_from_token(token)

    # Check that auth user is the creator of the dm
    dm_found = False
    dm_members = []
    for dm in dms:
        if dm['dm_id'] == dm_id:
            dm_found = True
            dm_members = dm['members']
            if dm['creator'] != auth_user['u_id']:
                raise AccessError(
                    f"User {auth_user['handle_str']} is not the creator of dm with id {dm_id}"
                )
    if not dm_found:
        raise InputError(f"id {dm_id} does not refer to a valid dm")

    # Remove dm from all members' dm list
    for user in users:
        if user['u_id'] in dm_members:
            user['dms'].remove(dm_id)
            update_user_dm_stats(user['u_id'])

    # Delete messages sent in this dm
    for message in list(messages):
        if message['dm_id'] == dm_id:
            messages.remove(message)

    # Remove desired dm from dms list
    # Must be done this way to ensure that dms list is updated across all modules
    cleared_dms = [dm for dm in dms if dm['dm_id'] != dm_id]
    dms.clear()
    for dm in cleared_dms:
        dms.append(dm)

    update_dm_stats()

    return {}
Exemplo n.º 11
0
def channel_invite_v2(token, channel_id, u_id):
    '''
    Summary:
        Invites a user (with user id u_id) to join a channel with ID channel_id. 
        Once invited the user is added to the channel immediately.
    Args:
        token (string): A user session token 
        channel_id (int): A channel_id number
        u_id (int): A user id 
    Returns: 
        empty dictionary

    Raises:
        InputError when:
            channel_id does not refer to a valid channel
            u_id does not refer to a valid user
        AccessError when:
            the authorised user is not already a member of the channel
    '''
    global users, channels
    assert check_token(token)
    auth_user = user_from_token(token)

    if valid_channel(channel_id) == False:
        raise InputError(f"Channel ID {channel_id} is not a valid channel")

    if valid_user(u_id) == False:
        raise InputError(f"u_id {u_id} does not refer to a valid user")

    current_channel = find_channel(
        channel_id)  #current channel with the given channel id
    invitee = user_from_id(u_id)

    if auth_user['u_id'] not in current_channel['all_members']:
        raise AccessError(
            f"Authorised user {auth_user['u_id']} is not a member of channel with channel_id {channel_id}"
        )

    if u_id in current_channel['all_members']:
        raise AccessError(
            f"u_id {u_id} you are inviting is already inside the channel")

    current_channel['all_members'].append(u_id)
    if invitee[
            'permission'] == 1:  # Dreams owner is automatically channel owner
        current_channel['owner_members'].append(u_id)
    invitee['channels'].append(channel_id)
    update_user_channel_stats(invitee['u_id'])
    send_channel_added_notification(auth_user['handle_str'], u_id,
                                    current_channel['channel_id'])
    return {}
Exemplo n.º 12
0
def message_pin_v1(token, message_id):
    '''Summary
        Given a message within a channel or DM, mark it as "pinned" to be given special display treatment by the frontend
    Args:
        token (string): A user session token
        message_id (int): A message_id of the message
    
    Returns:
        A empty dictionary
    
    Raises:
       Raises:
        InputError when:
            message_id is not a valid message
            Message with ID message_id is already pinned
        AccessError when:
            The authorised user is not a member of the channel
            The authorised user is not a member of the DM that the message is within
            The authorised user is not an owner of the channel or DM
    '''
    check_token(token)
    auth_user = user_from_token(token)
    if valid_message(message_id) == False:
        raise InputError("message_id is not a valid message")

    message = get_message_from_message_id(message_id)

    if message['is_pinned'] == True:
        raise InputError("Message with ID message_id is already pinned")

    if message['channel_id'] == -1:  #this means this is a dm message
        current_dm = find_dm(message['dm_id'])
        if auth_user['u_id'] not in current_dm['members']:
            raise AccessError("The authorised user is not a member of the DM")
        if auth_user['u_id'] != current_dm[
                'creator']:  # this error will get raised twice is this ok? / this is kinda redundent because if u have to be the owner to pin whats the point of checking for members?
            raise AccessError("The authorised user is not an owner of the DM")
        message['is_pinned'] = True

    if message['dm_id'] == -1:  # this means this a channel message
        current_channel = find_channel(message['channel_id'])
        if auth_user['u_id'] not in current_channel['all_members']:
            raise AccessError(
                "The authorised user is not a member of the channel")
        if auth_user['u_id'] not in current_channel['owner_members']:
            raise AccessError(
                "The authorised user is not an owner of the channel")
        message['is_pinned'] = True

    return {}
Exemplo n.º 13
0
def message_share_v1(token, og_message_id, message, channel_id, dm_id):
    '''
    Summary:
        og_message_id is the original message. 
        
        channel_id is the channel that the message is being shared to, 
        and is -1 if it is being sent to a DM. 
        
        dm_id is the DM that the message is being shared to, 
        and is -1 if it is being sent to a channel.
        
        message is the optional message in addition to the shared message, 
        and will be an empty string '' if no message is given   
    Args:
        token (string): A user session token 
        og_message_id (int): the message id of the original message
        message (string): a message string added to the shared message
        channel_id (int): A channel_id number -1 if we are sharing to dms
        dm_id (int): A message_id number -1 if send to we are sharing to channels
    Returns: 
        dictionary which contains the shared_message_id
    Raises:
        AccessError when:
            the authorised user has not joined the channel or DM they are trying to share the message to
    '''
    global users, channels, next_message_id, dms, messages
    assert check_token(token)
    auth_user_id = user_from_token(token)['u_id']
    og_message_text = get_message_from_message_id(og_message_id)['message']

    shared_message = message + '\n\n' + og_message_text
    is_channel_message = (channel_id != -1)
    shared_message_id = -1
    if is_channel_message:
        if is_channel_member(auth_user_id, channel_id):
            shared_message_id = message_send_v2(token, channel_id,
                                                shared_message)['message_id']
        else:
            raise AccessError(
                f"Authorised user with id {auth_user_id} has not joined the channel they are trying to share the message to"
            )
    else:
        if is_dm_member(dm_id, auth_user_id):
            shared_message_id = message_senddm_v1(token, dm_id,
                                                  shared_message)['message_id']
        else:
            raise AccessError(
                f"Authorised user with id {auth_user_id} has not joined the DM they are trying to share the message to"
            )
    return {'shared_message_id': shared_message_id}
Exemplo n.º 14
0
def channel_join_v2(token, channel_id):
    '''
    Summary:
        Given a channel_id of a channel that the authorised user can join, 
        add them to that channel members
    Args:
        token (string): A user session token 
        channel_id (int): A channel_id number
    Returns: 
        a empty dictionary
    Raises:
        InputError when:
            Channel ID is not a valid channel
        AccessError when:
            channel_id refers to a channel that is private 
            (when the authorised user is not a global owner)
    '''
    global users, channels
    assert check_token(token)
    auth_user = user_from_token(token)

    if valid_channel(channel_id) == False:
        raise InputError(f"Channel ID {channel_id} is not a valid channel")
    current_channel = find_channel(
        channel_id)  #current channel with the given channel id

    is_dreams_owner = auth_user['permission'] == 1

    not_in_current_channel = auth_user['u_id'] not in current_channel[
        'all_members']

    if current_channel['is_public'] == True:
        if not_in_current_channel:
            if is_dreams_owner:
                current_channel['owner_members'].append(auth_user['u_id'])
            current_channel['all_members'].append(auth_user['u_id'])
            auth_user['channels'].append(channel_id)
            update_user_channel_stats(auth_user['u_id'])
    else:
        if is_dreams_owner and not_in_current_channel:
            current_channel['owner_members'].append(auth_user['u_id'])
            current_channel['all_members'].append(auth_user['u_id'])
            auth_user['channels'].append(channel_id)
            update_user_channel_stats(auth_user['u_id'])
        else:
            raise AccessError(
                f"channel_id {channel_id} refers to a channel that is private ( authorised user is not a global owner)"
            )

    return {}
Exemplo n.º 15
0
def channel_removeowner_v1(token, channel_id, u_id):
    """Summary
        Remove user with user id u_id from the owner members list of channel with channel id channel_id
    Args:
        token (string): A user session token
        channel_id (int): A channel id number
        u_id (int): A user id number

    Returns:
        Empty dictionary
    
    Raises:
        AccessError: When an invalid token is given, or the user referred to by token is not a Dreams owner
                     or an owner of the channel with channel id channel_id
        InputError: When channel_id does not refer to a valid channel, when the user with user id u_id is
                    not an owner of the channel, or the user with user id u_id is currently the only owner
    """
    check_token(token)

    auth_user = user_from_token(token)
    # User is a Dreams owner if their permission code is 1
    auth_user_is_dreams_owner = auth_user['permission'] == 1

    for channel in channels:
        if channel['channel_id'] == channel_id:
            owners = channel['owner_members']
            # Verify that auth user is a Dreams owner or an owner of the channel
            if auth_user_is_dreams_owner or auth_user['u_id'] in owners:
                # Verify that user to be removed is an owner
                if u_id in owners:
                    # Verify that there is more than one channel owner
                    if len(owners) > 1:
                        channel['owner_members'].remove(u_id)
                        return {}
                    else:
                        raise InputError(
                            f"User with user id {u_id} is currently the only owner"
                        )
                else:
                    raise InputError(
                        f"User with user id {u_id} is not an owner of the channel"
                    )
            else:
                raise AccessError(
                    f"Authorised user {auth_user['handle_str']} is not an owner of the **Dreams**, or an owner of this channel"
                )

    raise InputError(
        f"Channel ID {channel_id} does not refer to a valid channel")
Exemplo n.º 16
0
def message_unpin_v1(token, message_id):
    '''
    Summary:
        Given a message within a channel or DM, remove it's mark as unpinned
    Args:
        token (string): A user session token 
        message_id (int): A message_id number
    Returns: 
        empty dictionary 
    Raises:
        InputError when:
            message_id is not a valid message
            Message with ID message_id is already unpinned
        AccessError when:
            The authorised user is not a member of the channel or DM that the message is within
            The authorised user is not an owner of the channel or DM
    '''
    check_token(token)
    auth_user = user_from_token(token)
    if valid_message(message_id) == False:
        raise InputError("message_id is not a valid message")

    message = get_message_from_message_id(message_id)

    if message['is_pinned'] == False:
        raise InputError("Message with ID message_id is already unpinned")

    if message['channel_id'] == -1:  #this means this is a dm message
        current_dm = find_dm(message['dm_id'])
        if auth_user['u_id'] not in current_dm['members']:
            raise AccessError("The authorised user is not a member of the DM")
        if auth_user['u_id'] != current_dm['creator']:
            raise AccessError("The authorised user is not an owner of the DM")
        message['is_pinned'] = False

    if message['dm_id'] == -1:  # this means this a channel message
        current_channel = find_channel(message['channel_id'])
        if auth_user['u_id'] not in current_channel['all_members']:
            raise AccessError(
                "The authorised user is not a member of the channel")
        if auth_user['u_id'] not in current_channel['owner_members']:
            raise AccessError(
                "The authorised user is not an owner of the channel")
        message['is_pinned'] = False

    return {}
Exemplo n.º 17
0
def channel_addowner_v1(token, channel_id, u_id):
    '''
    Summary:
        Make user with user id u_id an owner of this channel
    Args:
        token (string): A user session token 
        channel_id (int): A channel_id number
        u_id (int): A user id number
    Returns: 
        a empty dictionary
    Raises:
        InputError when:
            Channel ID is not a valid channel
            When user with user id u_id is already an owner of the channel
        AccessError when:
           the authorised user is not an owner of the **Dreams**, 
           or an owner of this channel
    '''
    global users, channels
    assert check_token(token)
    assert valid_user(u_id)
    if valid_channel(channel_id) == False:
        raise InputError(f"Channel ID is not a valid channel")
    auth_user = user_from_token(token)
    current_channel = find_channel(
        channel_id)  #current channel with the given channel id

    if not is_channel_owner(auth_user['u_id'],
                            channel_id) and not is_dreams_owner(
                                auth_user['u_id']):
        raise AccessError(
            f"the authorised user is not an owner of the channel or Dreams")
    if is_channel_owner(u_id, channel_id) == True:
        raise InputError(
            f"User with user id {u_id} is already an owner of the channel")

    target_user = user_from_id(u_id)

    current_channel['owner_members'].append(u_id)
    if u_id not in current_channel['all_members']:
        current_channel['all_members'].append(u_id)
        target_user['channels'].append(channel_id)
        update_user_channel_stats(u_id)
        send_channel_added_notification(auth_user['handle_str'], u_id,
                                        current_channel['channel_id'])
    return {}
Exemplo n.º 18
0
def dm_details_v1(token, dm_id):
    """Summary
        Allows users that are members of a direct message to view basic information about the DM
        
        Dictionary: Contains the name of the dm and details about each of its members
    
    Raises:
        AccessError: When an invalid token is given, or the authorised user referred to by the token is not
                     a member of the dm
    
        InputError: When dm_id does not refer to a valid dm
    """
    check_token(token)
    auth_user = user_from_token(token)

    # Find the desired dm, if it exists, and retrieve its name and list of member u_ids
    output = None
    for dm in dms:
        if dm['dm_id'] == dm_id:
            if auth_user['u_id'] in dm['members']:
                output = {'name': dm['name'], 'members': []}
                member_ids = dm['members']
            else:
                raise AccessError(
                    f"Authorised user {auth_user['handle_str']} is not a member of DM with id {dm_id}"
                )

    if output == None:  # If output is still None, DM with id dm_id was not found
        raise InputError(f"DM id {dm_id} does not refer to a valid DM")

    # Find all dm members, and append their details to output
    for user in users:
        if user['u_id'] in member_ids:
            member_details = {
                'u_id': user['u_id'],
                'email': user['email'],
                'name_first': user['name_first'],
                'name_last': user['name_last'],
                'handle_str': user['handle_str'],
                'profile_img_url': user['profile_img_url']
            }
            output['members'].append(member_details)

    return output
Exemplo n.º 19
0
def dm_invite_v1(token, dm_id, u_id):
    """Summary
        Inviting a user to an existing dm
    Args:
        token (string): A user session token
        dm_id (int): A dm id number
        u_id (int): An user's id, who want to add this dm
        
    Returns:
        Empty dictionary
    
    Raises:
        AccessError: When an invalid token is given, or the user that token refers to is not the creator of the dm
                     with id dm_id
    """
    check_token(token)
    auth_user = user_from_token(token)

    invitee = user_from_id(u_id)

    # InputError: When u_id does not refer to a valid user.
    if invitee == {}:
        raise InputError(f"id {u_id} does not refer to a valid user")

    # search all the dm in dms, and search the current dm by dm_id
    for dm in dms:
        if dm['dm_id'] == dm_id:
            # if auth user is a member of the dm, add the u_id to this dm
            if auth_user['u_id'] in dm['members']:
                dm['members'].append(u_id)
                invitee['dms'].append(dm_id)
                update_user_dm_stats(invitee['u_id'])
                send_dm_added_notification(auth_user['handle_str'], u_id,
                                           dm['dm_id'])
                return {}
            else:
                raise AccessError(
                    f"The authorised user {auth_user['handle_str']} is not already a member of the DM with id {dm_id}"
                )

    # InputError: When dm_id does not refer to a valid dm
    raise InputError(f"id {dm_id} does not refer to a valid dm")
Exemplo n.º 20
0
def dm_list_v1(token):
    """Summary
        Returns the list of DMs that the user is a member of
    Args:
        token (string): A user session token
    
    Returns:
        Dictionary: { dms } ({dm_id,name})  Contains the id and name of the dm
    
    Raises:
        AccessError: invaild token

    """
    check_token(token)
    auth_user = user_from_token(token)

    # Find the desired dm, if it exists, and return all dm's name and id
    output = []
    for dm in dms:
        if auth_user['u_id'] in dm['members']:
            id_name = {'dm_id': dm['dm_id'], 'name': dm['name']}
            output.append(id_name)

    return {'dms': output}
Exemplo n.º 21
0
def standup_send_v1(token, channel_id, message):

    check_token(token)

    sender = user_from_token(token)
    u_id = sender['u_id']

    # InputError when Channel ID is not a valid channel
    if valid_channel(channel_id) == False:
        raise InputError(f"Channel ID {channel_id} is not a valid channel")

    # InputError when Message is more than 1000 characters (not including the username and colon)
    if len(message) > 1000:
        raise InputError(f"Message more than 1000 characters")

    # AccessError when The authorised user is not a member of the channel that the message is within
    if is_channel_member(u_id, channel_id) == False:
        raise AccessError(
            f"The authorised user {u_id} is not a member of the channel that the message is within"
        )

    for channel in channels:
        if channel['channel_id'] == channel_id:
            # InputError when An active standup is not currently running in this channel
            if channel['standup']['is_active'] == False:
                raise InputError(
                    "An active standup is not currently running in this channel"
                )
            else:
                message_dict = {
                    'author_handle': sender['handle_str'],
                    'message': message
                }
                channel['standup']['messages'].append(message_dict)

    return {}
Exemplo n.º 22
0
def dm_messages_v1(token, dm_id, start):
    """Summary
        Given a DM with ID dm_id that the authorised user is part of, return up to 50 messages between index 
        "start" and "start + 50". Message with index 0 is the most recent message in the channel. This function 
        returns a new index "end" which is the value of "start + 50", or, if this function has returned the least 
        recent messages in the channel, returns -1 in "end" to indicate there are no more messages to load after 
        this return.
    Args:
        token (string): A user session token
        dm_id (int): A dm id number
        start (int): The index in the dm's list of messages at which to begin collecting them
    
    Returns:
        TYPE: Contains the start index, the end index (-1 if the final message in the list was collected,
              or start + 50 if 50 messages were collected without reaching the end of the list) and the
              list of collected messages.
    
    Raises:
        AccessError: When an invalid token is given, or authorised user is not a member of channel with channel_id
        InputError: When dm_id does not refer to a valid dm or start is negative or greater than the 
        total number of messages in the channel 
    """
    check_token(token)
    auth_user_id = user_from_token(token)['u_id']

    # Retrieve messages from channel with given channel_id
    message_ids = None
    for dm in dms:
        if dm['dm_id'] == dm_id:
            if auth_user_id in dm['members']:
                message_ids = dm['messages']
            else:
                raise AccessError(
                    f"Authorised user is not a member of dm with id {dm_id}")
    if message_ids == None:
        raise InputError(f"dm id {dm_id} does not refer to a valid dm")

    messageList = []
    for message in messages:
        if message['message_id'] in message_ids:
            messageList.append(message)

    # If the channel has no messages, return an empty list
    if start == 0 and not len(messageList):
        return {'messages': messageList, 'start': start, 'end': -1}

    # Check whether start index is negative
    if start < 0:
        raise InputError(f"start cannot be negative (given {start})")

    messageList.reverse()  # Most recent message should have index 0

    # Check whether start index is within bounds of message list
    if start < len(messageList):
        output = []
        index = start
        while len(output) < 50:
            if index >= len(messageList):
                return {'messages': output, 'start': start, 'end': -1}
            message = messageList[index]

            # { react_id, u_ids, is_this_user_reacted }

            react_dict = {
                'react_id': 1,
                'u_ids': message['reacts'],
                'is_this_user_reacted': auth_user_id in message['reacts']
            }

            message_dict = {}
            message_dict['message_id'] = message['message_id']
            message_dict['u_id'] = message['author_id']
            message_dict['message'] = message['message']
            message_dict['time_created'] = message['time_created']
            message_dict['reacts'] = [react_dict]
            message_dict['is_pinned'] = message['is_pinned']

            output.append(message_dict)
            index += 1

        return {
            'messages': output,
            'start': start,
            'end': start + 50 if len(messageList) > 50 else -1
        }
    else:
        raise InputError(
            f"start index {start} is greater than the total number of messages in the channel {len(messages)}"
        )
Exemplo n.º 23
0
def dm_create_v1(token, u_id):
    '''
    Summary:
        u_ids is the user(s) that this DM is directed to, and will not include the creator. 
        The creator is the owner of the DM. 
        
        name should be automatically generated based on the user(s) that is in this dm. 
        The name should be an alphabetically-sorted, comma-separated list of user handles, e.g. 
        'handle1, handle2, handle3'.
    Args:
        token (string): A user session token 
        u_ids (list): A list of user ids 
    Returns: 
        a dictionary which contains the id of the dm (dm_id) 
        and the name of the dm which is the concatenated handles

    Raises:
        InputError when:
            u_id does not refer to a valid user
    '''
    global users, channels, next_dm_id, dms
    assert check_token(token)

    auth_user = user_from_token(token)
    user_list_handles = [auth_user['handle_str']]

    for i in range(len(u_id)):
        if valid_user(u_id[i]) == False:
            raise InputError(f"u_id {u_id[i]} does not refer to a valid user")
        else:
            member = user_from_id(u_id[i])
            user_list_handles.append(member['handle_str'])
    name = join_handle(user_list_handles)
    dm_id = next_dm_id['id']  #give the current global id number to this dm
    next_dm_id['id'] += 1  #after add one so the the dm id is always unique
    dm_members = [auth_user['u_id']]
    for user_id in u_id:
        dm_members.append(user_id)

    # Add dm to each member's list of dms
    for user in users:
        if user['u_id'] in dm_members:
            user['dms'].append(dm_id)
            update_user_dm_stats(user['u_id'])

    new_dm = {
        'dm_id': dm_id,
        'name': name,
        'creator': auth_user['u_id'],
        'messages': [],
        'members': dm_members
    }

    dms.append(new_dm)

    update_dm_stats()

    for user_id in new_dm['members']:
        send_dm_added_notification(auth_user['handle_str'], user_id, dm_id)

    return {'dm_id': dm_id, 'dm_name': new_dm['name']}
Exemplo n.º 24
0
def message_senddm_v1(token, dm_id, message):
    """Summary
        Send a message from authorised_user to the DM specified by dm_id. Note: Each message should have it's own unique ID. I.E. 
        No messages should share an ID with another message, even if that other message is in a different channel or DM.
    Args:
        token (string): A user session token
        dm_id (int): A dream id number which the message will be sented to
        message (string): The text with which the user wishes to sent to dream
    
    Returns:
        Dictionary: { message_id } the new message
    
    Raises:
        AccessError: when:  the authorised user is not a member of the DM they are trying to post to
        InputError: Message is more than 1000 characters
    """
    global next_message_id
    check_token(token)
    auth_user = user_from_token(token)

    # InputError: Message is more than 1000 characters
    if len(message) > 1000:
        raise InputError(f"Message {message} is more than 1000 characters")

    for dm in dms:
        if dm['dm_id'] == dm_id:
            # AccessError: when:  the authorised user is not a member of the DM they are trying to post to
            if auth_user['u_id'] not in dm['members']:
                raise AccessError(
                    f"the authorised user is not a member of the DM {dm_id}")
            else:
                current_time = current_unix_timestamp()
                message_id = next_message_id['id']
                next_message_id['id'] += 1

                # create a new message which will be sent to the dm
                current_message = {}
                current_message['message_id'] = message_id
                current_message['channel_id'] = -1
                current_message['dm_id'] = dm_id
                current_message['author_id'] = auth_user['u_id']
                current_message['message'] = message
                current_message['reacts'] = []
                current_message['time_created'] = current_time
                current_message['is_pinned'] = False

                contains_tag = False
                tag_strings = []

                if '@' in message:
                    for word in message.split(' '):
                        if word.startswith('@'):
                            tag_strings.append(word[1:])
                            contains_tag = True

                # the massage is already in the taget dm, send a notification
                if contains_tag:
                    for user_id in dm['members']:
                        user = user_from_id(user_id)
                        if user['handle_str'] in tag_strings:
                            send_dm_tag_notification(auth_user['handle_str'],
                                                     user_id, dm_id, message)

                # add the new massage to the messages list in the data
                dm['messages'].append(message_id)
                messages.append(current_message)

                update_user_message_stats(auth_user['u_id'])

                update_message_stats()

                return {'message_id': message_id}
    raise InputError(f"DM id {dm_id} does not refer to a valid dm")
Exemplo n.º 25
0
def message_sendlaterdm_v1(token, dm_id, message, time_sent):
    """Summary
        Send a message from authorised_user to the dm specified by dm_id automatically at a specified time in the future
    Args:
        token (string): A user session token
        dm_id (int): A dm id number which the message will be sented to
        message (string): The text with which the user wishes to sent to dm
        time_sent (int): the time of when this message will be sent
    
    Returns:
        Dictionary: { message_id } the new message
    
    Raises:
        AccessError: the authorised user has not joined the dm they are trying to post to
        InputError:  dm ID is not a valid dm
                     Message is more than 1000 characters
                     Time sent is a time in the past
    """

    # current_time = current_unix_timestamp()
    # time_intervel = time_sent - current_time

    # # InputError: Time sent is a time in the past
    # if time_intervel < 0:
    #     raise InputError("Time sent is a time in the past")

    # time.sleep(time_intervel)
    # message_id = message_senddm_v1(token, dm_id, message)

    # return { 'message_id': message_id }

    global users, dms, next_message_id, messages
    assert check_token(token)

    # InputError:  dm ID is not a valid dm
    if valid_dm(dm_id) == False:
        raise InputError(f"DM ID {dm_id} is not a valid dm")

    # InputError: Message is more than 1000 characters
    if len(message) > 1000:
        raise InputError(f"Message {message} is more than 1000 characters")

    current_time = current_unix_timestamp()
    time_intervel = time_sent - current_time

    # InputError: Time sent is a time in the past
    if time_intervel < 0:
        raise InputError("Time sent is a time in the past")

    auth_user = user_from_token(token)
    current_dm = find_dm(dm_id)  #current dm with the given dm id

    if auth_user['u_id'] not in current_dm['members']:
        raise AccessError(
            f"the authorised user has not joined the dm they are trying to post to"
        )

    message_id = next_message_id['id']
    next_message_id['id'] += 1

    future_message = {}
    future_message['message_id'] = message_id  #message_id
    future_message['dm_id'] = dm_id
    future_message[
        'channel_id'] = -1  #this is a dm message not dm so for all dm's give -1
    future_message['author_id'] = auth_user['u_id']
    future_message['message'] = message
    future_message['reacts'] = []
    future_message['time_created'] = time_sent
    future_message['is_pinned'] = False

    future_messages.append(future_message)

    return {
        'message_id': future_message['message_id']  #message_id
    }
Exemplo n.º 26
0
def message_react_v1(token, message_id, react_id):
    """Summary
        Given a message, update its text with new text. If the new message is an empty string, the message 
        is deleted.
    Args:
        token (string): A user session token
        message_id (int): A message id number
        react_id (int): the react type of this react, (only the 1 for now)
    
    Returns:
        Empty dictionary
    
    Raises:
        AccessError: The authorised user is not a member of the channel or DM that the message is within
        InputError: message_id is not a valid message within a channel or DM that the authorised user has joined
                    react_id is not a valid React ID. The only valid react ID the frontend has is 1
                    Message with ID message_id already contains an active React with ID react_id from the authorised user
    """
    global messages

    check_token(token)
    auth_user = user_from_token(token)
    user_id = auth_user['u_id']

    # react_id is not a valid React ID. The only valid react ID the frontend has is 1
    if react_id != 1:
        raise InputError(
            f"react_id {react_id} is not a valid React ID. The only valid react ID the frontend has is 1"
        )

    message_found = False
    for msg in messages:
        if msg['message_id'] == message_id:
            message_found = True
            if msg['channel_id'] != -1:
                if is_channel_member(user_id, msg['channel_id']) == False:
                    raise AccessError(
                        f"The authorised user {user_id} is not a member of the channel that the message is within"
                    )
                send_channel_message_react_notification(
                    user_id, msg['author_id'], msg['channel_id'])
            if msg['dm_id'] != -1:
                if is_dm_member(msg['dm_id'], user_id) == False:
                    raise AccessError(
                        f"The authorised user {user_id} is not a member of the dm that the message is within"
                    )
                send_dm_message_react_notification(user_id, msg['author_id'],
                                                   msg['dm_id'])
            # if 'reacts' in msg.keys():
            react_peoples = msg['reacts']
            check_react = False
            # check if this user has already reacted this message
            for react_people in react_peoples:
                if react_people == user_id:
                    check_react = True
                    raise InputError(
                        f"Message {message_id} already contains an active React with ID react_id from the authorised user"
                    )
            if check_react == False:
                msg['reacts'].append(user_id)
            # else:
            #     msg['reacts'] = [user_id]

        # InputError: message_id is not a valid message within a channel or DM that the authorised user has joined
    if not message_found:
        raise InputError(
            f"message_id {message_id} is not a valid message within a channel or DM that the authorised user has joined"
        )

    return {}
Exemplo n.º 27
0
def admin_user_remove_v1(token, u_id):
    '''
    Summary:
        Given a User by their user ID, remove the user from the Dreams. 
        Dreams owners can remove other **Dreams** owners (including the original first owner). 
        Once users are removed from **Dreams**, the contents of the messages they sent will be replaced by 'Removed user'. 
        Their profile must still be retrievable with user/profile/v2, with their name replaced by 'Removed user'.
    Args:
        token (string): A user session token 
        u_id (int): A user id number
    Returns: 
        empty dictionary
    Raises:
        InputError when:
            u_id does not refer to a valid user
            The user is currently the only owner
        AccessError when:
            The authorised user is not an owner
    '''
    global users, channels, tokens, dms
    assert check_token(token)
    auth_user = user_from_token(token)
    if valid_user(u_id) == False:
        raise InputError(f"User with u_id is not a valid user")
    dream_owners = find_all_dream_owners()  #list of all dream owners
    if auth_user['permission'] != 1:
        raise AccessError("The authorised user is not an owner")
    elif auth_user['u_id'] == u_id and len(dream_owners) == 1:
        # Only way that user being removed can be only owner is if they are removing themself
        raise InputError("The user is currently the only owner")

    # Remove all tokens associated with user being removed
    cleared_tokens = [
        tkn for tkn in tokens if user_from_token(tkn)['u_id'] != u_id
    ]
    tokens.clear()
    for tkn in cleared_tokens:
        tokens.append(tkn)

    user = user_from_id(u_id)
    user['name_first'] = 'Removed'
    user['name_last'] = 'user'
    user['permission'] = 0  # User permission id 0 indicates a removed user

    for channel in channels:
        for owner_member in channel['owner_members']:
            if owner_member == u_id:
                channel['owner_members'].remove(u_id)
        for normal_member in channel['all_members']:
            if normal_member == u_id:
                channel['all_members'].remove(u_id)

    for dm in dms:
        for member in dm['members']:
            if member == u_id:
                dm['members'].remove(u_id)

    for message in messages:
        if message['author_id'] == u_id:
            message['message'] = 'Removed user'

    return {}
Exemplo n.º 28
0
def message_unreact_v1(token, message_id, react_id):
    """Summary
        Given a message within a channel or DM the authorised user is part of, remove a "react" to that particular message
    Args:
        token (string): A user session token
        message_id (int): A message id number
        react_id (int): the react type of this react, (only the 1 for now)
    
    Returns:
        Empty dictionary
    
    Raises:
        AccessError: The authorised user is not a member of the channel or DM that the message is within
        InputError: message_id is not a valid message within a channel or DM that the authorised user has joined
                    react_id is not a valid React ID. The only valid react ID the frontend has is 1
                    Message with ID message_id does not contain an active React with ID react_id from the authorised user
    """
    global messages

    check_token(token)
    auth_user = user_from_token(token)
    user_id = auth_user['u_id']

    # react_id is not a valid React ID. The only valid react ID the frontend has is 1
    if react_id != 1:
        raise InputError(
            f"react_id {react_id} is not a valid React ID. The only valid react ID the frontend has is 1"
        )

    message_found = False
    for msg in messages:
        if msg['message_id'] == message_id:
            message_found = True
            if msg['channel_id'] != -1:
                if is_channel_member(user_id, msg['channel_id']) == False:
                    raise AccessError(
                        f"The authorised user {user_id} is not a member of the channel that the message is within"
                    )
            else:
                if is_dm_member(msg['dm_id'], user_id) == False:
                    raise AccessError(
                        f"The authorised user {user_id} is not a member of the dm that the message is within"
                    )

            # if 'reacts' in msg.keys():
            react_peoples = msg['reacts']
            check_react = False
            # check if this user has already reacted this message
            for react_people in react_peoples:
                if react_people == user_id:
                    check_react = True
                    msg['reacts'].remove(user_id)
            if check_react == False:
                raise InputError(
                    f"Message {message_id} does not contain an active React with ID react_id from the authorised user"
                )
            # else:
            #     raise InputError(f"Message {message_id} does not contain an active React with ID react_id from the authorised user")

        # InputError: message_id is not a valid message within a channel or DM that the authorised user has joined
    if not message_found:
        raise InputError(
            f"message_id {message_id} is not a valid message within a channel or DM that the authorised user has joined"
        )

    return {}
Exemplo n.º 29
0
def message_send_v2(token, channel_id, message):
    '''
    Summary:
        Send a message from authorised_user to the channel specified by channel_id. 
        Note: Each message should have it's own unique ID. 
        I.E. No messages should share an ID with another message, 
        even if that other message is in a different channel.
    Args:
        token (string): A user session token 
        channel_id (int): A channel_id number
        message (string): a message string 
    Returns: 
        empty dictionary which contains the message_id
    Raises:
        InputError when:
            Message is more than 1000 characters
        AccessError when:
            the authorised user has not joined the channel they are trying to post to
    '''
    global users, channels, next_message_id, messages
    assert check_token(token)
    assert valid_channel(channel_id)

    auth_user = user_from_token(token)
    current_channel = find_channel(
        channel_id)  #current channel with the given channel id

    if current_channel['standup']['is_active']:
        standup_send_v1(token, channel_id, message)
        return

    if len(message) > 1000:
        raise InputError(f"Message more than 1000 characters")
    if auth_user['u_id'] not in current_channel['all_members']:
        raise AccessError(
            f"the authorised user has not joined the channel they are trying to post to"
        )

    current_time = current_unix_timestamp()  #gives us the current timestamp
    current_message = {}
    current_message['message_id'] = next_message_id['id']  #message_id
    current_message['channel_id'] = channel_id
    current_message[
        'dm_id'] = -1  #this is a channel message not dm so for all dm's give -1
    current_message['author_id'] = auth_user['u_id']
    current_message['message'] = message
    current_message['reacts'] = []
    current_message['time_created'] = current_time
    current_message['is_pinned'] = False
    current_channel['messages'].append(current_message['message_id'])
    next_message_id[
        'id'] += 1  #update the global message id so we get unique ids

    message_words = message.split(' ')

    # Standup start checker
    # Start a standup if message is exactly "/standup X" where X is a number of seconds
    if message.startswith('/standup') and len(
            message_words) == 2 and message_words[1].isdigit():
        duration = int(message_words[1])
        standup_start_v1(token, channel_id, duration)

    #notications checker and handler
    contains_tag = False
    tag_strings = []
    if '@' in message:
        for word in message_words:
            if word.startswith('@'):
                tag_strings.append(word[1:])
                contains_tag = True
    if contains_tag:
        for user_id in current_channel['all_members']:
            user = user_from_id(user_id)
            if user['handle_str'] in tag_strings:
                send_channel_tag_notification(auth_user['handle_str'], user_id,
                                              channel_id, message)

    messages.append(current_message)

    update_user_message_stats(auth_user['u_id'])

    update_message_stats()

    return {
        'message_id': current_message['message_id']  #message_id
    }
Exemplo n.º 30
0
def message_remove_v1(token, message_id):
    """Summary
        Given a message_id for a message, this message is removed from the channel/DM
    Args:
        token (string): A user session token
        message_id (int): A message id number

    Returns:
        Empty dictionary
    
    Raises:
        AccessError: 
            when none of the following are true:
                Message with message_id was sent by the authorised user making this request
                The authorised user is an owner of this channel (if it was sent to a channel) or the **Dreams**
        InputError: Message (based on ID) no longer exists
    """

    check_token(token)
    auth_user = user_from_token(token)

    is_channel_message = False
    for msg in messages:
        if msg['message_id'] == message_id:
            is_channel_message = (msg['channel_id'] != -1
                                  )  # If channel_id is -1, it is a dm message
            can_remove = False
            if auth_user['u_id'] == msg['author_id'] or is_dreams_owner(
                    auth_user['u_id']):
                # If the user is the author of the message or a dreams owner, they can always edit it
                can_remove = True
            elif msg['channel_id'] != -1 and is_channel_owner(
                    auth_user['u_id'], msg['channel_id']):
                # If the message was sent to a channel and the user is the channel owner
                can_remove = True
            if can_remove:
                author_id = msg['author_id']
                # delete from messages
                cleared_messages = [
                    msg for msg in messages if msg['message_id'] != message_id
                ]
                messages.clear()
                for msg in cleared_messages:
                    messages.append(msg)

                update_user_message_stats(author_id)

                update_message_stats()

                # delete from channel
                if is_channel_message:
                    for channel in channels:
                        if msg['message_id'] in channel['messages']:
                            channel['messages'] = [
                                m for m in channel['messages'] if m != msg
                            ]
                else:
                    # delete from dm
                    for dm in dms:
                        if msg['message_id'] in dm['messages']:
                            dm['messages'] = [
                                m for m in dm['messages'] if m != msg
                            ]
                return {}
            else:
                raise AccessError(
                    f"User {auth_user['handle_str']} does not have permission to remove message with id {message_id}"
                )
    raise InputError(f"Message with id {message_id} no longer exists")