def get_message_info(message_id): ''' This is a helper function. It will return a message with given message_id Args: param1: target message_id Returns: it will return message_info with given message_id if it exists, else return None to represent no such a message. { 'message' : msg, 'u_id' : msg['u_id'], 'channel_id' : channel_id, 'msg_list' : channel['messages'], } ''' channel_id = int(str(message_id)[:-4]) channel = get_channel_from_id(channel_id) if channel is None: return None for msg in channel['messages']: if msg['message_id'] == message_id: return { 'message': msg, 'u_id': msg['u_id'], 'channel_id': channel_id, 'msg_list': channel['messages'], 'channel': channel, 'reacts': msg['reacts'], 'is_pinned': msg['is_pinned'], } return None
def search(token, query_str): """ Given a query string, return a collection of messages in all of the channels that the user has joined that match that query. :param token: The token of an authorised Flockr user :type token: str :param u_id: The user ID of the user whose permissions we want to change :type u_id: int :return: A dictionary with nested list of messages containing the query string :rtype: dict with nested list """ # check token validity if get_user_from_token(token) is None: raise AccessError(description="Unauthorised access") result = [] user = get_user_from_token(token) # search for messages with query string for channel_id in user['channels']: channel = get_channel_from_id(channel_id) for message in channel['messages']: if query_str in message['message']: if user['u_id'] in message['reacts'][0]['u_ids']: message['reacts'][0]['is_this_user_reacted'] = True else: message['reacts'][0]['is_this_user_reacted'] = False result.append(message) return {'messages': result}
def message_send_later(token, channel_id, message, time_sent): ''' This function will send a message from an authorised user to the channel specified by channel_id automatically at a specified time in the future. Args: param1(str): authorised uesr's token param2(int): id of target channel param3(str): sent message param4(int): unix_timestamp, a future time Returns: It will return a dict with message_id Raises: InputError if: - Channel_id is invalid - Message is more than 1000 characters - Time sent is a time in the past AccessError if: - when the authorised use hasn't joined the channel - when given token is invalid ''' ## Errors auth_user = get_user_from_token(token) channel = get_channel_from_id(channel_id) # access error when given token does not refer to a valid user if auth_user is None: raise AccessError(description='Invalid token') # input error when given channel_id is invalid if channel is None: raise InputError(description='Invalid channel.') # access error when the authorised use hasn't joined the channel if auth_user['u_id'] not in channel['all_members']: raise AccessError(description='User is not a member of channel.') # input error when message is more than 1000 characters if len(message) > 1000: raise InputError(description='Message exceeds 1000 characters.') ### InputError for time in past countdown = time_sent - int(time.time()) if countdown < 0: raise InputError(description='past time given') ### Initiate timer for message_send function new_msg = create_new_msg(message, channel, auth_user['u_id']) channel['latest_msg_id'] += 1 timer = threading.Timer(countdown, append_msg_to_channel, args=[new_msg, channel]) timer.start() return {'message_id': new_msg['message_id']}
def channel_addowner(token, channel_id, u_id): ''' This will set the user with u_id as the owner of target channel. Token refers to one of the owner of target channel. It will return an empty dictionaty. Args: param1: authorised user's token. param2: target channel. param3: new owner's u_id Returns: This will return an empty dictionary. Raises: InputError: 1. Channel ID is not a valid channel 2. When user with user id u_id is already an owner of the channel AccessError: 1. when the authorised user is not an owner of the flockr, or an owner of this channel 2. given token does not refer to a valid token ''' auth_user = get_user_from_token(token) channel = get_channel_from_id(channel_id) invited_user = get_user_from_id(u_id) # access error when the token does not refer to a valid token if auth_user is None: raise AccessError(description='Invalid token') # input error when Channel ID is not a valid channel if channel is None: raise InputError(description='Invalid channel_id') # input error when u_id does not refer to a valid user if invited_user is None: raise InputError(description='Invalid u_id') # input error when When user with user id u_id # is already an owner of the channel if invited_user['u_id'] in channel['owner_members']: raise InputError(description='Already an owner') # access error when the authorised user is not # an owner of the flockr, or an owner of this channel if is_user_an_owner(token, channel_id) is False: raise AccessError(description='Not permitted to add') channel['owner_members'].append(u_id) return {}
def standup_send(token, channel_id, message): ''' This function is for sending a message to get buffered in the standup queue, assuming a standup is currently active. Args: param1(str): request user's token param2(int): the id of target channel param3(str): sent message Returns: It would return an empty dict Raises: InputError: 1. Channel ID is not a valid channel 2. Message is more than 1000 characters 3. An active standup is not currently running in this channel AccessError: 1. given token is invalid 2. The authorised user is not a member of the channel that the message is within ''' user = get_user_from_token(token) channel = get_channel_from_id(channel_id) # access error when given token is invalid if user is None: raise AccessError(description='Invalid token') # input error when given channel_id is invalid if channel is None: raise InputError(description='Invalid channel_id') # input error when An active standup is not currently running in this channel if standup_active(token, channel_id)['is_active'] is False: raise InputError(description='No active standup') # input error when msg is too long if len(message) > 1000: raise InputError(description='Message is too long') # access error when The authorised user is not a member of # the channel that the message is within if channel_id not in user['channels']: raise AccessError(description='Not a member') channel['standup_msg'] += '\n' + user['handle'] + ': ' + message return {}
def channel_detail(channel_id): """ A helper function to get a channel's details from its id. :param channel_id: channel_id of channel whose details we want :type token: int :return: A dictionary containing the new channel's details (id & name) as key value pairs :rtype: dict """ channel = get_channel_from_id(channel_id) return { 'channel_id' : channel['channel_id'], 'name' : channel['name'], }
def channel_invite(token, channel_id, u_id): ''' This will invite a user (with user id u_id) to join a channel with channel_id. Once invited the user is added to the channel immediately. Args: param1: invitor's token. param2: target channel. param3: invited user's u_id Returns: This will return an empty dictionary. Raises: InputError: 1. channel_id does not refer to a valid channel. 2. u_id does not refer to a valid user. AccessError: 1. the authorised user is not already a member of the channel. 2. given token does not refer to a valid token ''' auth_user = get_user_from_token(token) invited_user = get_user_from_id(u_id) channel = get_channel_from_id(channel_id) # access error when given token does not refer to a valid user if auth_user is None: raise AccessError(description='Invalid Token') # input error when u_id does not refer to a valid user if invited_user is None: raise InputError(description='Invalid u_id') # input error when channel_id does not refer to a valid channel. if channel is None: raise InputError(description='Invalid channel_id') # accesss error when the authorised user is not a member of the channel if auth_user['u_id'] not in channel['all_members']: raise AccessError(description='Not a member') # invited_user is already in channel if invited_user['u_id'] in channel['all_members']: return {} channel['all_members'].append(u_id) invited_user['channels'].append(channel_id) return {}
def channel_removeowner(token, channel_id, u_id): ''' This will remove the user with u_id from the owners of target channel. If u_id refers to the owner of flockr, it will ignore the request. Token refers to one of the owner of target channel. It will return an empty dictionaty. Args: param1: authorised user's token. param2: target channel. param3: the user's u_id who is removed from owners Returns: This will return an empty dictionary. Raises: InputError: 1. Channel ID is not a valid channel 2. When user with user id u_id is not an owner of the channel AccessError: 1. when the authorised user is not an owner of the flockr, or an owner of this channel 2. given token does not refer to a valid token ''' auth_user = get_user_from_token(token) channel = get_channel_from_id(channel_id) removed_user = get_user_from_id(u_id) # access error when given token does not refer to a valid user if auth_user is None: raise AccessError(description='Invalid token') # input error when Channel ID is not a valid channel if channel is None: raise InputError(description='Invalid channel_id') # input error when u_id does not refer to a valid user if removed_user is None: raise InputError(description='Invalid u_id') # input error when user with user id u_id is not an owner of the channel if removed_user['u_id'] not in channel['owner_members']: raise InputError(description='Not a owner of channel') # accesss error when the authorised user is not # an owner of the flockr, or an owner of this channel if is_user_an_owner(token, channel_id) is False: raise AccessError(description='Not permitted to remove') channel['owner_members'].remove(u_id) return {}
def channel_details(token, channel_id): ''' This will provide basic details about a channel whose Channel Id is channel_id. Also, the authorised user is part of that channel. Args: param1: authorised user's token. param2: target channel. Returns: This will return a dictionary with channel details. { 'name': channel['name'], 'owner_members': owner_details, 'all_members': all_details, } Raises: InputError: 1. channel_id does not refer to a valid channel. 2. u_id does not refer to a valid user. AccessError: 1. the authorised user is not already a member of the channel. 2. given token does not refer to a valid token ''' auth_user = get_user_from_token(token) channel = get_channel_from_id(channel_id) # access error when given token does not refer to a valid user if auth_user is None: raise AccessError(description='Invalid token') # inputerror when Channel ID is not a valid channel if channel is None: raise InputError(description='Invalid channel_id') # access error when Authorised user is not a member of channel with channel_id if auth_user['u_id'] not in channel['all_members']: raise AccessError(description='Not a member') return { 'name': channel['name'], 'owner_members': list(map(member_initial, channel['owner_members'])), 'all_members': list(map(member_initial, channel['all_members'])), }
def message_send(token, channel_id, message): ''' This function will send a message from authorised_user to the channel specified by channel_id. It will create a unique msg_id for new message. msg_id = channel_id * 10000 + the order in that channel. For example, the third message in channel 6 would have a msg_id with 600003. Args: param1: authorised user's token param2: id of target channel param3: new message Returns: it will return a dictionary of new message id. Raises: InputError: Message is more than 1000 characters AccessError: 1. given token does not refer to a valid user 2. the authorised user has not joined the channel with channel_id ''' auth_user = get_user_from_token(token) channel = get_channel_from_id(channel_id) # AccessError when given token does not refer to a valid user if auth_user is None: raise AccessError(description='Invalid token.') #InputError when message > 1000 characters if len(message) > 1000: raise InputError(description='Message exceeds 1000 characters.') #AccessError when user hasn't joined the channel if channel is None: raise AccessError(description='Invalid channel.') if auth_user['u_id'] not in channel['all_members']: raise AccessError(description='User is not a member of channel.') #Send message new_msg = create_new_msg(message, channel, auth_user['u_id']) channel['latest_msg_id'] += 1 channel['messages'].append(new_msg) return {'message_id': new_msg['message_id']}
def standup_start(token, channel_id, length): ''' This function would start a standup in given channel. Standup would last X second and X is equal to length. After time is up, what is send during standup would be buffered in one message and be sent to given channel. It would return the finish_time. Args: param1(str): request user's token param2(int): the id of target channel param3(int): the time would standup last (in second) Returns: It would return a dict with one tuple 'time_finish' and its value is an integer (unix timestamp) Raises: InputError: 1. Channel ID is not a valid channel 2. An active standup is currently running in this channel AccessError: given token is invalid ''' user = get_user_from_token(token) channel = get_channel_from_id(channel_id) # access error when given token is invalid if user is None: raise AccessError(description='Invalid token') # input error when given channel_id is invalid if channel is None: raise InputError(description='Invalid channel_id') # input error when an active standup is currently runing in this channel if standup_active(token, channel_id)['is_active'] is True: raise InputError(description='Standup has started') # reset data for standup channel['time_standupend'] = int(time.time()) + length channel['standup_msg'] = '' # set standup_end timer = threading.Timer(length, standup_end, args=[user, channel]) timer.start() return {'time_finish': int(time.time()) + length}
def channel_join(token, channel_id): ''' This will add authorised user to given channel. If user is the owner of flockr, it will set user as onwer of that channel. Args: param1: authorised user's token. param2: target channel. Returns: This will return an empty dictionary. Raises: InputError: Channel ID is not a valid channel AccessError: 1. channel_id refers to a channel that is private (when the authorised user is not a global owner) 2. given token does not refer to a valid token ''' auth_user = get_user_from_token(token) channel = get_channel_from_id(channel_id) # access error when the token does not refer to a valid token if auth_user is None: raise AccessError(description='Invalid token') # input error when Channel ID is not a valid channel if channel is None: raise InputError(description='Invalid channel_id') # access error when channel_id refers to a channel that is private # the authorised user is not a global owner if channel['public'] is False and auth_user['permission_id'] != 1: raise AccessError(description='Not permitted to join') # already in the channel if channel_id in auth_user['channels']: return {} channel['all_members'].append(auth_user['u_id']) auth_user['channels'].append(channel_id) return {}
def standup_active(token, channel_id): ''' This funciton is for getting standup active infomation. For a given channel, return whether a standup is active in it, and what time the standup finishes. If no standup is active, then time_finish returns None. Args: param1(str): request user's token param2(int): the id of target channel Returns: It would return a dict containing relative info 'is_active' (boolean) true if standup is active, else false 'time_finish' (int unix timestamp) the time when the standup is finished Raises: InputError: 1. Channel ID is not a valid channel AccessError: 1. given token is invalid ''' user = get_user_from_token(token) channel = get_channel_from_id(channel_id) # access error when given token is invalid if user is None: raise AccessError(description='Invalid token') # input error when given channel_id is invalid if channel is None: raise InputError(description='Invalid channel_id') if channel['time_standupend'] == 0: return { 'is_active': False, 'time_finish': None, } return { 'is_active': True, 'time_finish': channel['time_standupend'], }
def channel_leave(token, channel_id): ''' This will remove authorised user from given channel. If the last user of that channel leaves, we will keep that channel in data. Args: param1: authorised user's token. param2: target channel. Returns: This will return an empty dictionary. Raises: InputError: Channel ID is not a valid channel AccessError: 1. Authorised user is not a member of channel with channel_id 2. given token does not refer to a valid token ''' auth_user = get_user_from_token(token) channel = get_channel_from_id(channel_id) # access error when the token does not refer to a valid token if auth_user is None: raise AccessError(description='Invalid token') # input error when Channel ID is not a valid channel if channel is None: raise InputError(description='Invalid channel_id') # access error when Authorised user is not a member of channel with channel_id if auth_user['u_id'] not in channel['all_members']: raise AccessError(description='Not a member') auth_user['channels'].remove(channel_id) channel['all_members'].remove(auth_user['u_id']) if auth_user['u_id'] in channel['owner_members']: channel['owner_members'].remove(auth_user['u_id']) return {}
def channel_messages(token, channel_id, start): ''' This will return a list of messages from [start] of channel with channel_id. It contains 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: param1: authorised user's token. param2: target channel. param3: start index of messages Returns: This will return a dictionary. { 'messages' : (a list of messages), 'start' : (start index), 'end' : (end index), } Raises: InputError: 1. channel_id does not refer to a valid channel. 2. start is greater than the total number of messages in the channel. AccessError: 1. Authorised user is not a member of channel with channel_id. 2. given token does not refer to a valid token ''' auth_user = get_user_from_token(token) channel = get_channel_from_id(channel_id) # access error when given token does not refer to a valid user if auth_user is None: raise AccessError(description='Invalid token') # input error when Channel ID is not a valid channel if channel is None: raise InputError(description='Invalid channel_id') all_msgs = list(reversed(channel['messages'])) # input error when start is greater than the total number # of messages in the channel if start > len(all_msgs): raise InputError(description='Invalid start index') # access error when Authorised user is not a member of channel with channel_id if auth_user['u_id'] not in channel['all_members']: raise AccessError(description='Not a member') return_messages = [] end = start + 50 if end >= len(all_msgs): end = -1 for msg in all_msgs[start:]: if auth_user['u_id'] in msg['reacts'][0]['u_ids']: msg['reacts'][0]['is_this_user_reacted'] = True else: msg['reacts'][0]['is_this_user_reacted'] = False return_messages.append(msg) else: for msg in all_msgs[start:end]: if auth_user['u_id'] in msg['reacts'][0]['u_ids']: msg['reacts'][0]['is_this_user_reacted'] = True else: msg['reacts'][0]['is_this_user_reacted'] = False return_messages.append(msg) return { 'messages': return_messages, 'start': start, 'end': end, }