def channel_invite(token, channel_id, u_id): ''' Inviting a user to join the channel. ''' #Checked invalid channel if helper_functions.check_channelid_valid(channel_id): raise error.InputError("Channel not valid") # user id is not valid if helper_functions.check_uid_valid(u_id): raise error.InputError("User not valid") # user token is invalid if helper_functions.check_token(token).get('token_status'): raise error.InputError(description="Token invalid") auth_id = helper_functions.check_token(token).get('u_id') #If token is in channel if helper_functions.check_u_id_in_channel(auth_id, channel_id): raise error.AccessError("Authorised user not in channel") #User already in channel if helper_functions.check_u_id_in_channel(u_id, channel_id) == False: raise error.AccessError("Already in channel") # add to user to channel if everything is valid # details_user = {u_id, email, name_first, name_last, handle_str} for user in channels.channel_data: if user.get("channel_id") == channel_id: user["member_ids"].append(u_id) break return {}
def channel_addowner(token, channel_id, u_id): ''' When a user is added as an owner to the channel. ''' #Checked invalid channel if helper_functions.check_channelid_valid(channel_id): raise error.InputError("Channel not valid") # user token is invalid if helper_functions.check_token(token).get('token_status'): raise error.InputError(description="Token invalid") u_id_for_token = helper_functions.check_token(token).get("u_id") #Check if they are an owner if helper_functions.check_uid_owner_in_channel(u_id_for_token, channel_id): raise error.AccessError( "Authorised user not in channel or flockr owner") #If u_id already owner if helper_functions.check_uid_owner_in_channel(u_id, channel_id) == False: raise error.InputError("u_id already owner") #Append u_id to list of owners for user in channels.channel_data: if user.get("channel_id") == channel_id: user.get("owner_ids").append(u_id) break return {}
def standup_start(token, channel_id, length): ''' Begin the standup ''' # Checking is the token exist then getting their u_id if helper_functions.check_token(token).get('token_status'): raise error.AccessError(description="Token invalid") #If channel valid if helper_functions.check_channelid_valid(channel_id): raise error.InputError(description="Channel_id invalid") #If startup is active in channel if standup_active(token, channel_id)['is_active'] == True: raise error.InputError(description="Startup is currently active") #Get the time it will end dt_finish = datetime.now() + timedelta(seconds=length) time_finish = dt_finish.timestamp() #Append startup to STANDUPS STANDUPS.append({ 'channel_id': channel_id, 'time_finish': int(time_finish) }) #Append to CHANNELMSGS CHANNELSMSG[channel_id] = [] t = threading.Timer(int(length), helper_send_message, args=[token, channel_id]) t.start() return {'time_finish': int(time_finish)}
def start_hangman(token, channel_id): #pragma: no cover """ start the hangman game """ # Testing #If token valid if helper_token_valid(token): raise error.InputError(description="Invalid token") #If channel valid if helper_channel_valid(channel_id): raise error.InputError(description="Channel_id invalid") # Checking for a game if check_exsisting_hangman(channel_id): raise error.InputError( description="There is already a hangman game in this channel") word = random.choice(tuple(english_words_lower_set)) # Initialising the game data hangman_game = { 'channel_id': channel_id, 'word': word, 'state': word, 'num_guess': 0, 'char_guess': [] } HANGMAN.append(hangman_game) calling_bot_to_channel(channel_id) message_hangman = r"Hangman has started! *\(^v^)/*" message.message_send(BOT_TOKEN, channel_id, message_hangman) return hangman_state_initialise(hangman_game, channel_id)
def auth_passwordreset_reset(reset_code, new_password): # checking validity of reset code invalid_code = True for user in reset_codes: # check if the code given is an existing code if reset_code == user.get("reset_code"): # grab email of user email = user.get("email") # if reset code is valid, then break out of loop invalid_code = False break # Raise an input error if invalid_token is true if invalid_code == True: raise error.InputError("You have entered an invalid reset code") # checking validity of password, if password is less then length 6 if len(new_password) < 6: raise error.InputError(description="Password length less than 6") #Encrypt password encrypted_password = hashlib.sha256(new_password.encode()).hexdigest() # updating password password_new = {'password': encrypted_password} for users in registered_users: if users['email'] == email: # gets rid of existing value and replaces it with new value users.update(password_new) break return {}
def channel_leave(token, channel_id): ''' When a user leaves the channel. ''' # user token is invalid if helper_functions.check_token(token).get('token_status'): raise error.InputError(description="Token invalid") user_id = helper_functions.check_token(token).get("u_id") #Checked invalid channel if helper_functions.check_channelid_valid(channel_id): raise error.InputError("Channel not valid") #User already in channel if helper_functions.check_u_id_in_channel(user_id, channel_id): raise error.AccessError("Already in channel") for current_channel in channels.channel_data: if current_channel.get("channel_id") == channel_id: for members in current_channel.get("member_ids"): if user_id == members: current_channel["member_ids"].remove(user_id) break break return {}
def user_profile_setname(token, name_first, name_last): caller = check_token(token) # remove trailing and leading whitespaces fname = name_first.strip() lname = name_last.strip() # check name_first is between 1 and 50 characters if len(fname) < 1 or len(fname) > 50: raise error.InputError( 'First name must be between 1 and 50 characters') # check name_last is between 1 and 50 characters if len(lname) < 1 or len(lname) > 50: raise error.InputError('Last name must be between 1 and 50 characters') caller["name_first"] = fname caller["name_last"] = lname # update the user's details in the channels they're part of for channel in data['channels']: for member in channel['all_members']: if member['u_id'] == caller['u_id']: member['name_first'] = fname member['name_last'] = lname for member in channel['owner_members']: if member['u_id'] == caller['u_id']: member['name_first'] = fname member['name_last'] = lname return {}
def standup_send(token, channel_id, message): """ Add a message to standup queue """ # If token is valid, take u_id which is used to look through users u_id = database.get_current_user(token) # Check if user is member of channel that message is within # if not then raise an AccessError channel_data = database.get_channel_data(channel_id) if u_id not in channel_data['member_ids']: raise error.AccessError( description="You are not a member of this channel") # Check if message if more than 1000 characters long and raise InputError if that is the case if len(message) > 1000: raise error.InputError( description="The message entered is more than 1000 characters long" ) # Check if standup is currently active in channel, raise InputError if not if standup_active(token, channel_id)['is_active'] is False: raise error.InputError( description="There are no standups active in this channel") # Format message to "handle_str: message" handle_str = database.get_user_data(u_id)['handle_str'] string = handle_str + ": " + message # Now add string to the appropriate list in queues QUEUES[str(channel_id)].append(string) return {}
def channel_removeowner(token, channel_id, u_id): # Check that token is valied caller = check_token(token) # Check that user is part of flockr removed_person = find_with_uid(u_id) # Find the channel target_channel = find_channel(channel_id) # Check person to remove is part of channel is_member = is_member_check(caller['u_id'], target_channel) if not is_member: raise error.InputError('User to be removed is not in the channel') # Check to see if caller is an owner is_owner = is_owner_check(caller['u_id'], target_channel) # Access Error if the person calling is not an owner if not is_owner: raise error.AccessError( 'You are not an owner of the channel and cannot add owners') # Check to see if caller is a flockr owner if caller['permission_id'] == 1: is_owner = True # Check to see if the admin is removing a flockr owner if removed_person['permission_id'] == 1: raise error.AccessError('You cannot remove rights from Flockr Owner') # Access Error if the caller is not an owner if not is_owner: raise error.AccessError( 'You are not an owner of the channel and cannot remove owners') # Check to see if removed person is an owner is_owner = is_owner_check(removed_person['u_id'], target_channel) # Input Error if the person to be removed is not owner if not is_owner: raise error.InputError('Person to be demoted is not an owner') # Check to see if we are removing ourselves as owner if caller['u_id'] == removed_person['u_id']: # If we are the only person left in the channel then raise error if len(target_channel['all_members']) == 1: raise error.InputError( 'You are the only person in the channel, you cannot remove yourself as owner, please add another member' ) # If we are the only owner in the channel raise error to indicate a new owner must be assigned elif len(target_channel['owner_members']) == 1: raise error.InputError( 'You are the only owner in the channel, please make someone else owner before removing yourself' ) # Otherwise, we can remove self as owner else: remove_helper_func(channel_id, removed_person) return {} # We can remove the person as owner remove_helper_func(channel_id, removed_person) return {}
def user_profile_sethandle(token, handle_str): ''' Update the authorised user's handle. ''' #Check if token valid and get u_id if helper_functions.check_token(token).get('token_status'): raise error.AccessError(description="Token invalid") u_id = helper_functions.check_token(token).get('u_id') #If handle_str valid if len(handle_str) < 3 or len(handle_str) > 20: raise error.InputError(description="Handle_str invalid") #If handle_str already being used for item in auth.registered_users: if item.get("handle") == handle_str: raise error.InputError(description="Handle_str being used") #Update handle_str for item in auth.registered_users: if item.get("u_id") == u_id: item["handle"] = handle_str break return {}
def user_profile_setname(token, name_first, name_last): ''' Updates the authorised user's first and last name. ''' # Checking is the token exist then getting their u_id if helper_functions.check_token(token).get('token_status'): raise error.AccessError(description="Token invalid") user_id = helper_functions.check_token(token).get('u_id') #If first_name is not 1 < first_name < 50 if (len(name_first) < 1) or (len(name_first) > 50): raise error.InputError( "First name invalid, needs to be between 1 and 50 characters") #If last_name is not 1 < last_name < 50 if (len(name_last) < 1) or (len(name_last) > 50): raise error.InputError( "Last name invalid, needs to be between 1 and 50 characters") # new value for keys to update name new_name = {'first_name': name_first, 'last_name': name_last} # loops through users in list for users in auth.registered_users: if users['u_id'] == user_id: # gets rid of existing value and replaces it with new value users.update(new_name) break return {}
def standup_send(token, channel_id, message): ''' Send message in standup ''' # Checking is the token exist if helper_functions.check_token(token).get('token_status'): raise error.AccessError(description="Token invalid") u_id = helper_functions.check_token(token).get('u_id') #If channel valid if helper_functions.check_channelid_valid(channel_id): raise error.InputError(description="Channel_id invalid") #If startup is active in channel if standup_active(token, channel_id)['is_active'] == False: raise error.InputError(description="Startup is not currently active") #If message is more than 1000 characters if len(message) > 1000: raise error.InputError(description="Message length too long") #Make a new message for user in auth.registered_users: if user['u_id'] == u_id: handle_str = user['handle'] break string = str(handle_str) + ": " + str(message) #Append message to CHANNELSMSG CHANNELSMSG[channel_id].append(string) return {}
def auth_login(email, password): """ Login user with given email and password. """ # Check if email entered belongs to a user password_data = database.get_password_data(email) if password_data is None: raise error.InputError( description="The email you entered is incorrect") # Hash the password and see if it matches the hashed passowrd in the database passcode = hashlib.sha256(password.encode()).hexdigest() # Check if password matches email if password_data['password'] != passcode: raise error.InputError( description="The password you entered is incorrect") # find user's u_id from email given u_id = 0 for user in database.get_users(): if user['email'] == email: u_id = user['u_id'] # Check if already logged in. if database.get_token_from_user(u_id) is not None: raise error.AccessError( description="Cannot login when already logged in!") # Generate a token payload = {'u_id': u_id} token = str(jwt.encode(payload, 'jwt_secret', algorithm='HS256')) dictionary = {'u_id': u_id, 'token': token} database.set_current_user(u_id, token) return dictionary
def message_unreact(token, message_id, react_id): # Make sure react_id is valid thumbs_up = 1 if react_id != thumbs_up: raise error.InputError('Invalid react_id') # check for valid user user = check_token(token) # Find the message in the message field of data target_message = {} for message_value in data['messages']: if message_id == message_value['message_id']: target_message = message_value # InputError if message doesnt exist if target_message == {}: raise error.InputError('Message does not exist') # Find the channel the message is in target_channel = find_channel(target_message['channel_id']) # Remove u_id in messages for react type for reacts in target_message['reacts']: if react_id == reacts['react_id']: reacts['u_ids'].remove(user['u_id']) # update channel['messages'] with react data as well for channel_message in target_channel['messages']: if channel_message['message_id'] == target_message['message_id']: for reacts in channel_message['reacts']: if react_id == reacts['react_id']: reacts['u_ids'].remove(user['u_id']) return {}
def message_sendlater(token, channel_id, message, time_sent): # Check that the token is valid caller = check_token(token) # Capture the current time asap current_time = (datetime.datetime.now()).timestamp() # Find the channel target_channel = find_channel(channel_id) # Check to see if caller is part of that channel is_member = is_member_check(caller['u_id'], target_channel) # Access Error if the person inviting is not within the server if not is_member: raise error.AccessError( 'You are not part of the channel you want to send messages to') # Check the message length for issues if len(message) > 1000 or len(message) < 1 or len(message.strip()) < 1: raise error.InputError( 'The message you are sending is over 1000 characters') # Check the time is not from before current if (time_sent - current_time) < 0: raise error.InputError('Trying to send message in the past') delay = time_sent - current_time threading.Timer(delay, send_message, kwargs={ 'caller': caller, 'message': message, 'target_channel': target_channel, 'channel_id': channel_id }).start()
def standup_send(token, channel_id, message): # check for valid token caller = check_token(token) # check valid channel target_channel = find_channel(channel_id) # check if user is in channel is_member = is_member_check(caller['u_id'], target_channel) if not is_member: raise error.AccessError('You are not part of the channel') # check the message length for issues if len(message) > 1000 or len(message) < 1 or len(message.strip()) < 1: raise error.InputError( 'Invalid message. Please shorten to less than 1000 characters.') # check for active standup standup = standup_active(token, channel_id) if standup['is_active'] is False: raise error.InputError("There is already an active standup in channel") # throw error if message is user trying to start standup if message.startswith('/standup'): raise error.InputError("There is already an active standup in channel") # update standup with message and user's details target_channel['standup']['standup_messages'].append(caller['name_first'] + ': ' + message) return {}
def auth_login(email, password): #checking if provided email is invalid hashed_password = hashlib.sha256(password.encode()).hexdigest() if not helper.validate_email(email): raise error.InputError("The provided email is invalid") #If the email inputted, does not belong to a current user user_not_valid = True u_id = 0 token = 0 for user in data.users: if user.get('email') == email: user_not_valid = False u_id = user['u_id'] break if user_not_valid == True: raise error.InputError("The provided email is not registered") #If the password inputted is not correct not_valid_password = True for user in data.users: if user.get("email") == email: if user.get("password") == hashed_password: not_valid_password = False if not_valid_password == True: raise error.InputError("The provided password is not valid") for user in data.users: if user['u_id'] == u_id: user['token'] = user['u_id'] token = jwt.encode({'token' : user['u_id']}, data.secret, algorithm='HS256').decode('utf-8') return {'u_id': u_id, 'token': token}
def auth_passwordreset_reset(reset_code, new_password): ''' This function resets the password for the user based on their new password they have reset it to. This function will firstly check if the reset_code is valid by firstly searching the reset_code in the resets_codes storage structure, secondly checks if the new_password is valid, thirdly hashes the new_password and overwrites it in the user data storage structure. ''' # Need to check if the reset_code is valid first current_user = {} is_reset_code_valid = False for user in data.reset_codes: if user['reset_code'] == reset_code: is_reset_code_valid = True #collect email address current_user['email'] = user['user_email'] ## # Raise error if reset_code is not valid if is_reset_code_valid == False: raise error.InputError("Invalid reset code.") # Need to check if the new_password is valid, otherwise raise error password_result = helper.password_check(new_password) if not password_result: raise error.InputError("Password entered is not a valid password.") # hash it then store accordingly new_password_hashed = hashlib.sha256(new_password.encode()).hexdigest() # Set the new_password_hashed for the particular user. for targeted_user in data.users: if current_user['email'] == targeted_user['email']: targeted_user['password'] = new_password_hashed
def channel_details(token, channel_id): ''' Presenting the details of the channel. ''' #Checked invalid channel if helper_functions.check_channelid_valid(channel_id): raise error.InputError("Channel not valid") # user token is invalid if helper_functions.check_token(token).get('token_status'): raise error.InputError(description="Token invalid") user_id = helper_functions.check_token(token).get('u_id') #User already in channel if helper_functions.check_u_id_in_channel(user_id, channel_id): raise error.AccessError("Not in channel") #return details about channel channel_detail = { 'name': 'name', 'owner_members': [], 'all_members': [], } for curr_channels in channels.list_of_all_channels: if curr_channels.get('channel_id') == channel_id: channel_detail['name'] = curr_channels['name'] break for curr_channels in channels.channel_data: if curr_channels.get('channel_id') == channel_id: user_ids = curr_channels.get("member_ids") for user in user_ids: for user_detail in auth.registered_users: if user_detail['u_id'] == user: member_details = { 'u_id': user, 'name_first': user_detail['first_name'], 'name_last': user_detail['last_name'], 'profile_img_url': user_detail['profile_img_url'], } channel_detail['all_members'].append(member_details) for curr_channels in channels.channel_data: if curr_channels.get('channel_id') == channel_id: user_ids = curr_channels.get("owner_ids") for user in user_ids: for user_detail in auth.registered_users: if user_detail['u_id'] == user: owner_details = { 'u_id': user, 'name_first': user_detail['first_name'], 'name_last': user_detail['last_name'], 'profile_img_url': user_detail['profile_img_url'], } channel_detail['owner_members'].append(owner_details) return channel_detail
def channels_create(token, name, is_public): ''' Creates a new channel that is either public or private. ''' # Checking for a valid token if helper_functions.check_token(token).get('token_status'): raise error.InputError(description="Token invalid") user_id = helper_functions.check_token(token).get('u_id') # Error is the channel is greater than 20 if len(name) > 20: raise error.InputError( "The channel name you have entered is greater than 20 characters.") # Error if theres no channel name if len(name) == 0: raise error.InputError("No channel name entered.") # Assigning the channel id as the number of channels number_of_channels = len(list_of_all_channels) channel_id = number_of_channels + 1 channels_details = {'channel_id': channel_id, 'name': name} channel_data_base = { 'owner_ids': [], 'member_ids': [], 'channel_id': channel_id, 'is_public': True, 'messages': [], 'name': name } # Assigning whether the channels is public or private channel_data_base['is_public'] = is_public # Adding the data of the channel for user in auth.registered_tokens: if token == user.get("token"): user_id = user.get("u_id") channel_data_base['owner_ids'].append(user_id) channel_data_base['member_ids'].append(user_id) # Adding the newly created channel into the list channel_data.append(channel_data_base) list_of_all_channels.append(channels_details) return {'channel_id': channel_id}
def user_profile_sethandle(token, handle_str): """ given input for a handle name set user's handle """ if (len(handle_str) > 20 or len(handle_str) < 2): raise error.InputError( description="Handle is not within 2-20 characters") users = database.get_users() for user in users: if user['handle_str'] is handle_str: raise error.InputError(description="Handle is already taken") u_id = database.get_current_user(token) user = database.get_user_data(u_id) user['handle_str'] = handle_str database.set_user_data(user)
def user_profile_uploadphoto(token, img_url, x_start, y_start, x_end, y_end): """ given url of image on the internet, crops it within bounds. """ # pylint: disable=too-many-arguments # This pylint warning is supressed because the function requires 6 arguments # Get the image from img_url and check if HTTP status of 200 returned try: req = urllib.request.Request(img_url, headers={'User-Agent': 'Mozilla/5.0'}) response = urllib.request.urlopen(req) except: raise error.InputError( description="The image could not be opened from the given url") # Open the image, check if x and y are within dimensions of the image img = Image.open(response) width, height = img.size if x_start < 0 or y_start < 0 or x_end > width or y_end > height: raise error.InputError( description="Bounds given exceed the dimensions of the image") # Check if image type if a JPG if img.format != "JPEG": raise error.InputError(description="Image given is not of JPG type") # Crop the image to the correct dimensions img = img.crop((x_start, y_start, x_end, y_end)) # Get u_id from token u_id = database.get_current_user(token) img_path = os.path.join(os.path.dirname(__file__), f"static/{u_id}.jpg") # Save the image in the static directory # image saved as {u_id}.jpg img.save(img_path) # serve image from file profile_img_url = url_for('static', filename=f"{u_id}.jpg", _external=True) # Add profile_img_url to database user = database.get_user_data(u_id) user['profile_img_url'] = profile_img_url database.set_user_data(user) return {}
def find_message_in_messages(message_id): # Find the message in the message field of data for message in data['messages']: if message_id == message['message_id']: return message # If no target is returned then the message doesnt exist raise error.InputError('Message does not exist')
def channels_create(token, name, is_public): """ Create a channel using the given parameters """ # Check if name is more than 20 characters long and return InputError if this is the case if len(name) > 20: raise error.InputError( description="The name you entered is more than 20 characters long") # Generate a channel_id for the new channel # Simply done in order of time of creation (1..) # Generation of channel_id will be done in this way as long as ability to delete channels # remains unimplemented num_channels = len(database.get_channels()) channel_id = num_channels + 1 # Use database.set_channel to create channel in the database channel = {'channel_id': channel_id, 'name': name} database.set_channel(channel) channel_data = database.get_channel_data(channel_id) channel_data['is_public'] = is_public database.set_channel_data(channel_data) # User who creates the channel joins it automatically channel_join(token, channel_id) return {'channel_id': channel_id}
def channel_join(token, channel_id): channel_id = int(channel_id) decoded_jwt = jwt.decode(token.encode('utf-8'), data.secret, algorithms=['HS256']) decoded_token = decoded_jwt['token'] # checks if the channel exists and is public check = 0 for channel in data.channels: if channel['channel_id'] == channel_id: if not channel['is_public']: raise error.AccessError(description="Channel is not public") check = 1 break if check != 1: raise error.InputError(description="channel id is invalid") # adds user to channel_members user_data = {} permission = 0 for user in data.users: if user['token'] == decoded_token: user_data['u_id'] = user['u_id'] user_data['name_first'] = user['name_first'] user_data['name_last'] = user['name_last'] user_data['profile_img_url'] = user['profile_img_url'] permission = user['permission_id'] channel['all_members'].append(user_data) if permission == 1: channel['owner_members'].append(user_data) return
def standup_start(token, channel_id, length): """ Start a standup in channel given """ # Check if standup is currently active in this channel, if so raise InputError if standup_active(token, channel_id)['is_active'] is True: raise error.InputError( description="There is already a standup active in this channel") # Calculate time_finish to return now = datetime.now() dt_finish = now + timedelta(seconds=length) time_finish = dt_finish.timestamp() # Add details of standup to STANDUPS STANDUPS.append({ 'channel_id': channel_id, 'time_finish': int(time_finish) }) # Add new message queue to QUEUES QUEUES[str(channel_id)] = [] # Schedule when to send dump queue from QUEUES Timer(length, standup_start_helper, args=[channel_id, token]).start() return {'time_finish': int(time_finish)}
def find_with_uid(u_id): #Finds user by u_ID, if the user does not exist then input error is given. for user in data['users']: if u_id == user['u_id']: return user # If we are here then the token was invalid raise error.InputError('The user is not valid')
def find_channel(channel_id): #Finds the channel given channel_id, inputError if not found for channel in data['channels']: if channel_id == channel['id']: return channel # Input Error if the channel doesn't exist raise error.InputError('Channel does not exist')
def check_existing_email(email): # check for existing email for registered_user in data['users']: if registered_user['email'] == email: raise error.InputError( 'Email already taken by another registered user') return False
def auth_passwordreset_request(email): ''' This function will search through the users data structure, check if the user is registered and then send an email to the user with their 16 digit alphanumeric reset code. ''' # Find if the email is valid/ is a registered user current_user = {} is_registered_user = False for user in data.users: if user['email'] == email: is_registered_user = True # picking up the u_id to be used when adding the user to the rest_codes list current_user['u_id'] = user['u_id'] # Send the email if is_registered_user: # generate reset_code reset_code = helper.generate_reset_code(current_user['u_id'], email) # create a dictionary to be appended to reset_codes list reset_dict = {} reset_dict['user_email'] = email reset_dict['u_id'] = current_user['u_id'] reset_dict['reset_code'] = reset_code data.reset_codes.append(reset_dict) #the sending of the reset code is done through an external helper helper.send_reset_code_email(email, reset_code) else: raise error.InputError("given email does not exist")