def message_remove(token, message_id): ''' Deletes a valid message based on message id ''' check_token(token) channel_specific = get_channel_by_msg_id(message_id) message_specific = get_message_by_msg_id(message_id) if not is_channel_owner(token, channel_specific) and not is_message_owner( token, message_id) and not is_slackr_owner(token): raise AccessError(description='Not qualified to edit') channel_specific['messages'].remove(message_specific) return {}
def user_profile(token, user_id): '''finds and returns a user profile :param token: jwt token :type token: str :param user_id: id corresponding to the target user :type user_id: int :return: contains u_id, email, name_first, name_last, handle_str :rtype: dict ''' check_token(token) return {'user': get_user_information(user_id)}
def channels_listall(token): ''' loops through CHANNELS and generates a list of all channel_ids and their associated names. ''' check_token(token) glob_channels = get_channels() return { 'channels': [{ 'channel_id': channel_id, 'name': glob_channels[channel_id]['name'] } for channel_id in glob_channels] }
def message_edit(token, message_id, message): ''' Changes a valid message. deletes message if the message is changed to be empty ''' check_token(token) channel_specific = get_channel_by_msg_id(message_id) message_specific = get_message_by_msg_id(message_id) if not is_channel_owner(token, channel_specific): if not is_message_owner(token, message_id): if not is_slackr_owner(token): raise AccessError(description='Not qualified to edit') if len(message) == 0: channel_specific['messages'].remove(message_specific) else: message_specific['message'] = message return {}
def message_sendlater(token, channel_id, message, time_sent): ''' sends a message at a given time_sent, where time_sent is a unix timestamp greater than the current time. ''' u_id = check_token(token) if not is_valid_channel(channel_id): raise InputError(description="No channel exists with that ID") if not is_user_a_member(channel_id, u_id): raise AccessError(description='You are not a member of this channel') if len(message) > 1000 or len(message) < 1: raise InputError( description= 'Your message should be less than 1000 characters and at least 1 character' ) curr_time = get_current_timestamp() if curr_time >= time_sent: raise InputError(description="You can not send a message back in time") delay = time_sent - curr_time message_id = get_num_messages() set_num_messages(message_id + 1) message_template = create_message(u_id, message_id, time_sent, message) timer = Timer(delay, sendlater_end, args=[channel_id, message_template]) timer.start() return {'message_id': message_id}
def is_message_owner(token, message_id): """ Determine whether the user is the owner of the message """ message = get_message_by_msg_id(message_id) u_id = check_token(token) return u_id == message['u_id']
def users_all(token): '''Returns a list of all users :param token: jwt token :type token: str :return: contains u_id, email, name_first, name_last, handle_str for each user :rtype: dict ''' check_token(token) users = get_users() return { 'users': [ get_user_information(user_id) for user_id in users if not is_user_disabled(user_id) ], }
def is_slackr_owner(token): """ Determine whether the user owns the slackr """ owners = get_slackr_owners() u_id = check_token(token) return u_id in owners
def message_send(token, channel_id, message): ''' adds message to a channels list of messages expects parameter types: token: str channel_id: int message: str returns dictionary ''' user_id = check_token(token) if len(message) > 1000 or len(message) < 1: raise InputError( description= 'Your message should be less than 1000 characters and at least 1 character' ) if not is_valid_channel(channel_id): raise InputError if not is_user_a_member(channel_id, user_id): raise AccessError message_id = get_num_messages() glob_channels = get_channels() channel = glob_channels[channel_id] time_created = get_current_timestamp() if message.startswith('/hangman'): start_hangman(channel_id, user_id, time_created, message_id) elif message.startswith('/guess'): guess(message, channel_id, user_id, time_created, message_id) else: channel['messages'].insert( 0, create_message(user_id, message_id, time_created, message)) set_num_messages(message_id + 1) return {'message_id': message_id}
def permission_change(token, u_id, permission_id): '''change a user's permissions on the server :param token: jwt token :type token: str :param u_id: User id corresponding to the target user :type u_id: int :param permission_id: ID of user new permissions :type permission_id: int :raises InputError: u_id does not correspond to a user :raises InputError: Invalid Permission ID :raises AccessError: User is not a slackr owner :return: empty dictionary :rtype: dict ''' user_id = check_token(token) if not user_id in get_slackr_owners(): raise AccessError( description='You are not permitted to perform this action') if not is_valid_user(u_id): raise InputError(description='User does not exist') if permission_id not in (1, 2): raise InputError(description='Invalid permission ID') # all possible errors raised. if permission_id == 1: get_users()[u_id]['is_owner'] = True elif permission_id == 2: get_users()[u_id]['is_owner'] = False return {}
def channel_details(token, channel_id): ''' returns a dictionary of information about the channel and it's users ''' user_id = check_token(token) if not is_valid_channel(channel_id): raise InputError(description="Invalid channel id") if not is_user_a_member(channel_id, user_id): raise AccessError( description="User does not have access to this channel") owner_members = [] all_members = [] for user_id in get_channel_owners(channel_id): member_info = get_member_information(user_id) owner_members.append(member_info) all_members.append(member_info) for user_id in get_channel_members(channel_id): member_info = get_member_information(user_id) all_members.append(member_info) return { 'name': get_channels()[channel_id]['name'], 'owner_members': owner_members, 'all_members': all_members }
def message_pin(token, message_id): ''' Pins a message in a channel ''' u_id = check_token(token) channel_specific = get_channel_by_msg_id(message_id) message_specific = get_message_by_msg_id(message_id) if u_id not in channel_specific['members'] and not is_channel_owner( token, channel_specific): raise AccessError( description= 'The authorised user is not a member of the channel that the message is within' ) if not is_channel_owner(token, channel_specific): raise InputError(description='The authorised user is not an owner') if message_specific['is_pinned']: raise InputError( description='Message with ID message_id is already pinned') if is_channel_owner(token, channel_specific ) is True and message_specific['is_pinned'] is False: message_specific['is_pinned'] = True return {}
def channel_messages(token, channel_id, start): ''' returns a dictionary containing: messages: a list of messages starting with the most recent at index 0 start: the index of the starting message end: the index of the last message ''' user_id = check_token(token) if not is_valid_channel(channel_id): raise InputError if not is_user_a_member(channel_id, user_id): raise AccessError channel = get_channels()[channel_id] if start > len(channel['messages']): raise InputError end = start + 50 if end > len(channel['messages']): end = -1 set_reacted_messages(user_id, channel['messages'][start:start + 50]) return { 'messages': channel['messages'][start:start + 50], 'start': start, 'end': end, }
def user_in_channel_by_msg_id(message_id, token): """ Determine whether or not the user is in that channel which contains message_id """ u_id = check_token(token) channels = get_channel_by_msg_id(message_id) return u_id in channels['members'] or u_id in channels['owners']
def is_channel_owner(token, channel): """ Determine whether the user is the owner of the channel """ u_id = check_token(token) if u_id in channel['owners']: return True else: return False
def test_invalidation(): ''' A token that has been invalidated should raise an error ''' for user_id in range(100): new_token = generate_token(user_id) invalidate_token(new_token) with pytest.raises(AccessError): assert check_token(new_token) assert len(get_users()) == 0
def standup_active(token, channel_id): ''' if there is an active standup in the channel, returns unix timestamp of when standup will finish otherwise, returns None ''' u_id = check_token(token) check_standup_inputs(channel_id, u_id) is_active = is_standup_active(channel_id) try: time_finish = get_standups()[channel_id]['time_created'] except KeyError: time_finish = None return {'is_active': is_active, 'time_finish': time_finish}
def channel_join(token, channel_id): ''' Adds a user to a channel if they are authorised to join it ''' user_id = check_token(token) if not is_valid_channel(channel_id): raise InputError(description="No channel found with that ID") if not is_channel_public( channel_id) and not user_id in get_slackr_owners(): raise AccessError(description="This channel is private") get_channel_members(channel_id).append(user_id) return {}
def channels_list(token): ''' Loops through CHANNELS and generates a list of only the channels which contain the user as a member or as an owner ''' u_id = check_token(token) glob_channels = get_channels() return { 'channels': [{ 'channel_id': channel_id, 'name': glob_channels[channel_id]['name'] } for channel_id in glob_channels if is_user_a_member(channel_id, u_id)] }
def channel_leave(token, channel_id): ''' Removes a user from a channel ''' user_id = check_token(token) if not is_valid_channel(channel_id): raise InputError if is_user_a_owner(channel_id, user_id): get_channel_owners(channel_id).remove(user_id) elif is_user_a_member(channel_id, user_id): get_channel_members(channel_id).remove(user_id) else: raise AccessError return {}
def search(token, query_str): ''' finds all messages containing the query str ''' user_id = check_token(token) search_results = [] channels = get_channels() for channel_id in channels: if not is_user_a_member(channel_id, user_id): continue for message in channels[channel_id]['messages']: if query_str in message['message']: search_results.append(message) sorted(search_results, key=lambda message: message['time_created'], reverse=True) set_reacted_messages(user_id, search_results) return {'messages': search_results}
def standup_send(token, channel_id, message): ''' adds a given message to the buffer of messages to be sent when the standup ends. message is saved as 'handle_str: message', to be ready to be printed ''' u_id = check_token(token) check_standup_inputs(channel_id, u_id) if len(message) > 1000: raise InputError( description='Message must be less than 1000 characters') if not is_standup_active(channel_id): raise InputError( description='There is no standup active in this channel') get_standups()[channel_id]['message'].append( f'{find_handle(u_id)}: {message}') return {}
def user_profile_setemail(token, email): '''Given a valid token and new email, updates a user's email address :param token: jwt token :type token: str :param email: new email :type email: str :raises InputError: If email is invalid according to is_new_email() :return: empty dictionary :rtype: dict ''' user_id = check_token(token) if not is_new_email(user_id, email): raise InputError(description='Email invalid or already being used') user = get_users()[user_id] user['email'] = email return {}
def user_profile_sethandle(token, handle_str): '''Given a valid new handle_str and token, updates a user's handle_str :param token: jwt token :type token: str :param handle_str: new handle :type handle_str: str :raises InputError: If handle_str is invalid according to is_valid_handle() :return: empty dictionary :rtype: dict ''' user_id = check_token(token) if not is_valid_handle(user_id, handle_str): raise InputError(description='Handle invalid or already being used') user = get_users()[user_id] user['handle_str'] = handle_str return {}
def channel_invite(token, channel_id, user_id): ''' 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 An input error is thrown when the user_id/channel_id is invalid Access error when the user is not a member of the channel ''' host_user_id = check_token(token) if not is_valid_user(user_id): raise InputError if not is_valid_channel(channel_id): raise InputError if not is_user_a_member(channel_id, host_user_id): raise AccessError get_channels()[channel_id]['members'].append(user_id) return {}
def user_remove(token, u_id): ''' Removes a user from a channel, only a slackr Owner can use this function ''' host_user_id = check_token(token) if not is_valid_user(u_id): raise InputError if not host_user_id in get_slackr_owners(): raise AccessError for channel_id in get_channels(): if is_user_a_owner(channel_id, u_id): get_channel_owners(channel_id).remove(u_id) elif is_user_a_member(channel_id, u_id): get_channel_members(channel_id).remove(u_id) glob_users = get_users() glob_users[u_id]['disabled'] = True return {}
def channel_removeowner(token, channel_id, user_id): ''' Makes a channel owner a regular channel member the token must be one of the channel owners or the slackr owner ''' owner_id = check_token(token) if not is_valid_channel(channel_id): raise InputError if not is_user_a_owner(channel_id, owner_id) and not owner_id in get_slackr_owners(): raise AccessError if not is_user_a_owner(channel_id, user_id): raise InputError if is_user_a_owner(channel_id, user_id): get_channel_owners(channel_id).remove(user_id) get_channel_members(channel_id).append(user_id) return {}
def standup_start(token, channel_id, length): ''' starts a standup in a given channel for length amount of time creates blank message with time_finish timestamp, placeholder message_id, and stores it in glob_standups ''' u_id = check_token(token) check_standup_inputs(channel_id, u_id) if is_standup_active(channel_id): raise InputError( description='A standup is already active in this channel') glob_standups = get_standups() time_finish = get_current_timestamp(length) message_template = create_message(u_id, -1, time_finish, []) glob_standups[channel_id] = message_template standup = Timer(length, standup_end, args=[channel_id]) standup.start() return {'time_finish': time_finish}
def message_react(token, message_id, react_id): ''' adds a reaction to a messages list of reactions expects parameter types: token: str message_id: int react_id: int returns empty dictionary ''' u_id = check_token(token) message = get_message_by_msg_id(message_id) if react_id not in VALID_REACTS: raise InputError(description='Invalid react id') if not user_in_channel_by_msg_id(message_id, token): raise InputError(description='User is not in channel') for react in message['reacts']: if react['react_id'] == react_id: if u_id in react['u_ids']: raise InputError(description='Already reacted') react['u_ids'].append(u_id) return {}
def user_profile_setname(token, name_first, name_last): '''Given a valid token, name_first, name_last, updates a users name_first, name_last :param token: jwt token :type token: str :param name_first: new first name :type name_first: str :param name_last: new last name :type name_last: str :raises InputError: if either name_first or name_last is invalid :return: empty dictionary :rtype: dict ''' user_id = check_token(token) if not (is_name_valid(name_first) and is_name_valid(name_last)): raise InputError( description='Names must be between 1 and 50 characters') user = get_users()[user_id] user['name_first'] = name_first user['name_last'] = name_last return {}