def admin_userpermission_change(token, u_id, permission_id): """Given a User by their user ID, set their permissions to new permissions described by permission_id Args: token (string) u_id (int) permission_id (int) """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) confirm_u_id(data, u_id) if permission_id not in (MEMBER, OWNER): raise InputError(description="InputError: permission_id does not refer to a value permission") # Error check: The authorised user is not an owner user_id = convert_token_to_u_id(data, token) if not validate_flockr_owner(data, user_id): raise AccessError(description="AccessError: User is not a flockr owner") # Error check (Assumption): First flockr owner cannot have member permissions if u_id == data.get_first_owner_u_id() and permission_id == MEMBER: raise InputError(description="InputError: First flockr owner cannot be a member") data.set_user_permission_id(u_id, permission_id) with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {}
def user_profile_sethandle(token, handle_str): """Update authorised users handle Args: token (string) handle_str (string) Returns: (dict): {} """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) # Error check: handle_str must be between 3 and 20 characters if not validate_handle_str(handle_str): raise InputError( description= "InputError: Handle string must be between 3 and 20 characters (inclusive)" ) # Error check: handle is already used by another user if not validate_handle_unique(data, handle_str): raise InputError( description="InputError: Handle is already used by another user") # updating in users list. u_id = convert_token_to_u_id(data, token) data.set_user_handle(u_id, handle_str) with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {}
def auth_login(email, password): """Given a registered users' email and password and generates a valid token for the user to remain authenticated Args: email (string): [description] password (string): [description] Returns: (dict): { u_id, token } """ data = pickle.load(open(DATA_FILE, "rb")) # Error check: Email validation email = email.lower() if not validate_create_email(email): raise InputError(description="InputError: Invalid email address") # Error check: Password validation if not validate_password_length(password): raise InputError( description= "InputError: Password must be between 6 to 128 characters (inclusive)" ) if not validate_password_chars(password): raise InputError(description="InputError: Invalid password characters") password = hashlib.sha256(password.encode()).hexdigest() if not validate_password(data, password): raise InputError(description="InputError: Password is not correct") u_id = convert_email_to_u_id(data, email) if u_id == NON_EXIST: raise InputError( description="InputError: User with email '{email}' does not exist") # if user has requested a password reset, they should not be able to login. for user in data.get_reset_users(): if user['u_id'] == u_id: raise AccessError( description="Please reset password before trying to login") token = generate_token(data, u_id) # if user is already logged in if validate_token_by_u_id(data, u_id): return { 'u_id': u_id, 'token': token, } # if user is not logged in, add to data base data.create_active_user(u_id, token) with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return { 'u_id': u_id, 'token': token, }
def message_sendlater(token, channel_id, message, time_sent): """Send a message from authorised_user to the channel specified by channel_id automatically at a specified time in the future Args: token (string) channel_id (int) message (string) time_sent (int) Returns: (dict): { message_id } """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) confirm_channel_id(data, channel_id) # Error check: Message is more than 1000 characters or 0 characters if len(message) > 1000: raise InputError( description="InputError: Message has more than 1000 characters") if len(message) == 0: raise InputError(description="InputError: Message is empty") # Error check: Time sent is a time in the past curr_time = int(datetime.now(tz=timezone.utc).timestamp()) if curr_time > time_sent: raise InputError( description="InputError: Time sent is a time in the past") # Error check: the authorised user has not joined the channel they are trying to post to if not validate_token_as_channel_member(data, token, channel_id): raise AccessError( description= "AccessError: Authorised user is not a member of the channel") # Send the message at the time_sent if curr_time == time_sent: send_message = message_send(token, channel_id, message) message_id = send_message['message_id'] else: time_delay = int(time_sent - curr_time) message_id = data.generate_message_id() with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) Thread(target=delay_message_send, args=(token, channel_id, message, time_delay), daemon=True).start() return {'message_id': message_id}
def standup_start(token, channel_id, length): """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) channel_id (int) length (int) Returns: (dict): { time_finish } """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) confirm_channel_id(data, channel_id) # Error check: An active standup is currently running in this channel if data.specify_standup_status(channel_id)['is_active']: raise InputError( description="Standup is already running in the channel") # Error check (Assumption): User must be in the channel to start a standup if not validate_token_as_channel_member(data, token, channel_id): raise AccessError( description="User must be in the channel to start a standup") # Error check (Assumption): Length specified is less than or equal to 0 if length <= 0: raise InputError( description="Length of standup must be greater than 0 seconds") # set standup as active and calculate time_finish completion_time = int(datetime.now(tz=timezone.utc).timestamp()) + length data.set_standup_active_in_channel(channel_id, completion_time) # when completion time is met, set standup as inactive and send messages with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) Thread(target=set_standup_inactive, args=(token, channel_id, length), daemon=True).start() return {'time_finish': completion_time}
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 the query Args: token (string) query_str (string) Returns: (dict): { messages } """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) # Error check (Assumption): query_str must be atleast 1 character if len(query_str) == 0: raise InputError(description="InputError: query_str must be atleast 1 character long") all_messages = [] for channel in data.get_channels(): if validate_token_as_channel_member(data, token, channel['channel_id']): messages = get_messages_list(data, token, channel['channel_id']) for msg in messages: all_messages.append(msg) # Get the u_id matched_msg = [] for message in all_messages: if message['message'].find(query_str) != INVALID_QUERY: matched_msg.insert(0, message) return { 'messages': matched_msg }
def standup_send(token, channel_id, message): """Sending a message to get buffered in the standup queue, assuming a standup is currently active Args: token (string) channel_id (int) message (string) Returns: (dict): {} """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) confirm_channel_id(data, channel_id) # Error check: Message is more than 1000 characters or 0 characters if len(message) > 1000: raise InputError( description="InputError: Message has more than 1000 characters") if len(message) == 0: raise InputError(description="InputError: Message is empty") # Error check (Assumption): User must be in the channel to start a standup if not validate_token_as_channel_member(data, token, channel_id): raise AccessError( description="User must be in the channel to start a standup") # if an active standup is not currently running in this channel standup_information = data.specify_standup_status(channel_id) if not standup_information['is_active']: raise InputError( description="Standup is not currently running in this channel") # append message to 'standup_messages' string handle_name = token_to_handle_name(data, token) if data.show_standup_messages(channel_id) == "": new_message = f'{handle_name}: {message}' else: new_message = f'\n{handle_name}: {message}' data.append_standup_message(channel_id, new_message) with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {}
def auth_passwordreset_reset(reset_code, new_password): """Given a reset code for a user, set that user's new password to the password provided Args: reset_code (string) new_password (string) Returns: (dict): {} """ data = pickle.load(open(DATA_FILE, "rb")) # Error check: Password validation if not validate_password_length(new_password): raise InputError( description= "InputError: Password must be between 6 to 128 characters (inclusive)" ) if not validate_password_chars(new_password): raise InputError(description="InputError: Invalid password characters") # getting the user with a reset code u_id = 0 found = False for user in data.get_reset_users(): if user['secret'] == reset_code: u_id = user['u_id'] found = True if not found: raise InputError("InputError: Incorrect reset code.") # hashing password password = hashlib.sha256(new_password.encode()).hexdigest() for user in data.get_users(): if user['u_id'] == u_id: # changing password data.set_user_password(u_id, password) # removing user from reset_users data.remove_request(u_id) with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {}
def channel_removeowner(token, channel_id, u_id): """Remove user with user id u_id an owner of this channel Args: token (string) channel_id (int) u_id (int) Returns: (dict): {} """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) confirm_channel_id(data, channel_id) confirm_u_id(data, u_id) # Error check: When user with user id u_id is not an owner of the channel if not validate_u_id_as_channel_owner(data, u_id, channel_id): raise InputError( description= f"InputError: User with u_id {u_id} is not an owner of channel") # Error check: User is not an owner of the flockr, or an owner of this channel if not validate_token_as_channel_member(data, token, channel_id): raise AccessError( description= "AccessError: Authorised user is not an owner of the flockr, or an owner of the channel" ) # Error check (Assumption): There must be at least one owner in the channel channel_data = data.get_channel_details(channel_id) if len(channel_data['owner_members']) == 1: raise InputError( description= "InputError: There must be at least one owner in the channel") data.remove_owner_from_channel(u_id, channel_id) with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {}
def user_profile_setname(token, name_first, name_last): """Update the authorised user's first and last name Args: token (string) name_first (string) name_last (string) Returns: (dict): {} """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) # Error check: Name validation if not validate_names(name_first): raise InputError( description= "First name must be between 1 to 50 characters long (inclusive)") if not validate_names(name_last): raise InputError( description= "Last name must be between 1 to 50 characters long (inclusive)") if not validate_names_characters(name_first): raise InputError( description= "First name can only include uppercase and lowercase alphabetical characters, hyphens or whitespaces" ) if not validate_names_characters(name_last): raise InputError( description= "Last name can only include uppercase and lowercase alphabetical characters, hyphens or whitespaces" ) # changing name in the users field u_id = convert_token_to_u_id(data, token) data.set_user_name(u_id, name_first, name_last) data.set_user_name_in_channels(u_id, name_first, name_last) with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {}
def message_pin(token, message_id): """Given a message within a channel, mark it as "pinned" to be given special display treatment by the frontend Args: token (string) message_id (int) Returns: (dict) """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) confirm_message_id(data, message_id) # Error check: Message with ID message_id is already pinned channel_id = data.get_channel_id_with_message_id(message_id) channel_messages = data.get_channel_details(channel_id)['messages'] for curr_message in channel_messages: if curr_message['message_id'] == message_id: if curr_message['is_pinned']: raise InputError( description="InputError: Message is already pinned") # Check if user is a flockr owner. u_id = convert_token_to_u_id(data, token) flockr_owner = validate_u_id_as_flockr_owner(data, u_id) channel_member = validate_token_as_channel_member(data, token, channel_id) channel_owner = validate_token_as_channel_owner(data, token, channel_id) # Error check: The authorised user is not a member of the channel that the message is within if not flockr_owner and not channel_member: raise AccessError( description= "AccessError: Authorised user is not a member of the channel \ that contains the message") # Error check: The authorised user is not an owner if not flockr_owner and not channel_owner: raise AccessError( description= "AccessError: The authorised user is not an owner of the channel") # Pin message (If user is a flockr owner or channel owner). for curr_channel in data.get_channels(): for curr_message in curr_channel['messages']: if curr_message['message_id'] == message_id: curr_message['is_pinned'] = True with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {}
def message_react(token, message_id, react_id): """Given a message within a channel the authorised user is part of, add a "react" to that particular message Args: token (string) message_id (int) react_id (int) Returns: (dict): {} """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) confirm_message_id(data, message_id) confirm_react_id(data, message_id, react_id) # Error check: Message with ID message_id already contains an active React # with ID react_id from the authorised user u_id = convert_token_to_u_id(data, token) if validate_active_react_id(data, u_id, message_id, react_id): raise InputError( description=f"InputError: Message already contains an active react" ) # Error check (Assumption): Flockr member not in channel with message_id channel_id = data.get_channel_id_with_message_id(message_id) is_member = validate_u_id_as_channel_member(data, u_id, channel_id) is_flock_owner = validate_u_id_as_flockr_owner(data, u_id) if not is_member and not is_flock_owner: raise AccessError( description= f"AccessError: User is not in the channel that has the message_id {message_id}" ) # unreact all active reacts (based on assumption) active_react_ids = data.get_active_react_ids(u_id, message_id) if active_react_ids != []: for active_react_id in active_react_ids: message_unreact(token, message_id, active_react_id) # reload to get updated data from message_unreact data = pickle.load(open(DATA_FILE, "rb")) message = data.get_message_details(channel_id, message_id) message['reacts'][react_id - 1]['u_ids'].append(u_id) with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {}
def message_send(token, channel_id, message): """Send a message from authorised_user to the channel specified by channel_id Args: token (string) channel_id (int) message (string) Returns: (dict): { message_id } """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) confirm_channel_id(data, channel_id) # Error check: Message is more than 1000 characters or 0 characters if len(message) > 1000: raise InputError( description="InputError: Message has more than 1000 characters") if len(message) == 0: raise InputError(description="InputError: Message is empty") # Error check: the authorised user has not joined the channel they are trying to post to if not validate_token_as_channel_member(data, token, channel_id): raise AccessError( description= "AccessError: Authorised user is not a member of the channel") # Add message to the channel message_id = data.generate_message_id() u_id = convert_token_to_u_id(data, token) data.create_message(u_id, channel_id, message_id, message) with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {'message_id': message_id}
def user_profile_setemail(token, email): """Update the authorised user's email. Args: token (string): unique identifier of user. email (string): what the email will be set to. Returns: (dict): Contains no key types. """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) # Make the input email lowercase. email = email.lower() # Error check: Email validation if not validate_create_email(email): raise InputError(description="InputError: Invalid email address") # Check for whether email is already in use. for curr_user in data.get_users(): if curr_user['email'] == email: raise InputError( description= f"InputError: Email address is already being used by another user" ) u_id = convert_token_to_u_id(data, token) data.set_user_email(u_id, email) with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {}
def message_edit(token, message_id, message): """Given a message, update it's text with new text. If the new message is an empty string, the message is deleted. Args: token (string) message_id (int) message (string) Returns: (dict): {} """ data = pickle.load(open(DATA_FILE, "rb")) # remove message if new message is an empty string if message == '': return message_remove(token, message_id) # Error checks: Basic validation confirm_token(data, token) confirm_message_id(data, message_id) # Error check: Message is more than 1000 characters or 0 characters if len(message) > 1000: raise InputError( description="InputError: Message has more than 1000 characters") # edit the message if user is flockr owner or channel owner or sent by authorized user # (Assumption) flockr owner does not need to be a part of the channel to edit message u_id = convert_token_to_u_id(data, token) channel_id = data.get_channel_id_with_message_id(message_id) valid_permission = validate_universal_permission(data, token, channel_id) userAuthorized = False for channel in data.get_channels(): for curr_message in channel['messages']: if curr_message['message_id'] == message_id: if curr_message['u_id'] == u_id or valid_permission: userAuthorized = True data.edit_message(channel_id, message_id, message) # Error check: User was not authorised to edit the message if not userAuthorized: raise AccessError("AccessError: User not authorized to edit message") with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {}
def message_unreact(token, message_id, react_id): """Given a message within a channel the authorised user is part of, remove a "react" to that particular message Args: token (string) message_id (int) react_id (int) Returns: (dict): {} """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) confirm_message_id(data, message_id) confirm_react_id(data, message_id, react_id) # Error check: Message with ID message_id does not contain an active React with ID react_id u_id = convert_token_to_u_id(data, token) if not validate_active_react_id(data, u_id, message_id, react_id): raise InputError( description= f"InputError: Message already contains a non-active react") # Error check (Assumption): Flockr member not in channel with message_id channel_id = data.get_channel_id_with_message_id(message_id) is_member = validate_u_id_as_channel_member(data, u_id, channel_id) is_flock_owner = validate_u_id_as_flockr_owner(data, u_id) if not is_member and not is_flock_owner: raise AccessError( description= f"AccessError: User is not in the channel that has the message_id {message_id}" ) # Otherwise unreact the message with react_id. message = data.get_message_details(channel_id, message_id) message['reacts'][react_id - 1]['u_ids'].remove(u_id) with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {}
def channel_invite(token, channel_id, u_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 Args: token (string) channel_id (int) u_id (int): Returns: (dict): {} """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) confirm_channel_id(data, channel_id) confirm_u_id(data, u_id) # Error check: the authorised user is not already a member of the channel # (i.e. not in channel when calling this function) if not validate_token_as_channel_member(data, token, channel_id): raise AccessError( description= "AccessError: User not authorized to invite, please join channel") # Error check (Assumption): User with u_id is already in the channel but is # invited again if validate_u_id_as_channel_member(data, u_id, channel_id): raise InputError( description="InputError: User is already part of the channel") user = data.get_user_details(u_id) data.add_member_to_channel(u_id, channel_id) data.add_channel_to_user_list(u_id, channel_id) # if user is flockr owner: make him the group owner too if user['permission_id'] == OWNER: data.add_owner_to_channel(u_id, channel_id) with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {}
def channel_addowner(token, channel_id, u_id): """Make user with user id u_id an owner of this channel Args: token (string) channel_id (int) u_id (int) Returns: (dict): {} """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) confirm_channel_id(data, channel_id) confirm_u_id(data, u_id) # Error check: User id u_id is already an owner of the channel if validate_u_id_as_channel_owner(data, u_id, channel_id): raise InputError( description= f"InputError: User with u_id {u_id} is not an owner of channel") # Error check: User is not an owner of the flockr, or an owner of this channel if not validate_token_as_channel_member(data, token, channel_id): raise AccessError( description= "AccessError: Authorised user is not an owner of the flockr, or an owner of the channel" ) # Add user as member if not already. if not validate_u_id_as_channel_member(data, u_id, channel_id): data.add_member_to_channel(u_id, channel_id) data.add_channel_to_user_list(u_id, channel_id) data.add_owner_to_channel(u_id, channel_id) with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {}
def channels_create(token, name, is_public): """Creates a new channel with that name that is either a public or private channel Args: token (string) name (string) is_public (bool) Returns: (dict): { channel_id } """ data = pickle.load(open(DATA_FILE, "rb")) confirm_token(data, token) # Error check: Channel name validation if len(name) > 20 or len(name) < 1: raise InputError( description="Channel name must be between 1 to 20 characters") # Generate channel_id. channel_id = 1 if len(data.get_channels()) != 0: channel_list = data.get_channels() channel_id = channel_list[-1]['channel_id'] + 1 # Create new channel and store it into data structure. data.create_channel(name, is_public, channel_id) u_id = convert_token_to_u_id(data, token) data.add_channel_to_user_list(u_id, channel_id) # Add user to created channel as well as making them owner. data.add_member_to_channel(u_id, channel_id) data.add_owner_to_channel(u_id, channel_id) with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {'channel_id': channel_id}
def confirm_channel_id(data, channel_id): if not validate_channel_id(data, channel_id): raise InputError(description="InputError: Invalid channel id")
def confirm_message_id(data, message_id): if not validate_message_id(data, message_id): raise InputError(description="InputError: Invalid message id")
def confirm_react_id(data, message_id, react_id): if not validate_react_id(data, react_id, message_id): raise InputError(description="InputError: Invalid react id")
def channel_messages(token, channel_id, start): """Given a Channel with ID channel_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) channel_id (int) start (int) Returns: (dict): { messages, start, end } """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) confirm_channel_id(data, channel_id) # Error check: start is greater than the total number of messages in the channel channel_details = data.get_channel_details(channel_id) if start >= len(channel_details['messages']) and start != 0: raise InputError( description=f"InputError: start value ({start}) is greater than the \ total number of messages in the channel ({len(channel_details['messages'])} messages)" ) if start < 0: raise InputError( description= f"InputError: start value ({start}) must be greater than or equal to 0" ) # Error check: Authorised user is not a member of channel with channel_id if not validate_token_as_channel_member(data, token, channel_id): raise AccessError( description= "AccessError: Authorised user is not a member of the channel") # (Assumption) Case where there are no messages in the channel if len(channel_details['messages']) == 0: return { 'messages': [], 'start': -1, 'end': -1, } # Case where there are messages in the channel end = start + 50 if end >= len(channel_details['messages']): end = -1 # Create the messages list. messages_list = get_messages_list(data, token, channel_id) if end == -1: messages = messages_list[start:] else: messages = messages_list[start:end] return {'messages': messages, 'start': start, 'end': end}
def auth_register(email, password, name_first, name_last): """Given a user's first and last name, email address, and password, create a new account for them and return a new token for authentication in their session. A handle is generated that is the concatentation of a lowercase-only first name and last name. If the concatenation is longer than 20 characters, it is cutoff at 20 characters. If the handle is already taken, you may modify the handle in any way you see fit to make it unique. Args: email (string) password (string) name_first (string) name_last (string) Returns: (dict): { u_id, token } """ data = pickle.load(open(DATA_FILE, "rb")) # Error check: Name validation if not validate_names(name_first): raise InputError( description= "First name must be between 1 to 50 characters long (inclusive)") if not validate_names(name_last): raise InputError( description= "Last name must be between 1 to 50 characters long (inclusive)") if not validate_names_characters(name_first): raise InputError( description= "First name can only include uppercase and lowercase alphabetical characters, hyphens or whitespaces" ) if not validate_names_characters(name_last): raise InputError( description= "Last name can only include uppercase and lowercase alphabetical characters, hyphens or whitespaces" ) # Error check: Email validation email = email.lower() if not validate_create_email(email): raise InputError(description="InputError: Invalid email address") u_id = convert_email_to_u_id(data, email) if u_id != NON_EXIST: raise InputError( description= f"InputError: User with email '{email}' has already been registered" ) # Error check: Password validation if not validate_password_length(password): raise InputError( description= "InputError: Password must be between 6 to 128 characters (inclusive)" ) if not validate_password_chars(password): raise InputError(description="InputError: Invalid password characters") # Creating user hstring = generate_handle_str(data, name_first, name_last) u_id = len(data.get_users()) + 1 data.create_user(email, password, name_first, name_last, u_id, hstring) user = data.get_user_details(u_id) assert len(user['handle_str']) <= 20 # assigning flockr owner if user['u_id'] == FIRST_FLOCKR_OWNER_ID: data.set_user_permission_id(u_id, OWNER) data.set_first_owner_u_id(u_id) # logging in user token = generate_token(data, u_id) data.create_active_user(u_id, token) with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return { 'u_id': u_id, 'token': token, }
def auth_passwordreset_request(email): """Given an email address, if the user is a registered user, send's them a an email containing a specific secret code, that when entered in auth_passwordreset_reset, shows that the user trying to reset the password is the one who got sent this email. Args: email (string) Returns: (dict): {} """ email = email.lower() data = pickle.load(open(DATA_FILE, "rb")) # Error check: Checking that user is registered u_id = convert_email_to_u_id(data, email) if u_id == NON_EXIST: raise InputError( description=f"InputError: User with email '{email}' does not exist" ) secret = secrets.token_urlsafe(8) # adding user to reset users field found = False for user in data.get_reset_users(): if user['email'] == email: # update only the secret data.update_secret(email, secret) found = True if not found: # add user to reset_user structure data.create_password_request(email, u_id, secret) # sending an email to the user message_template = read_template('message.txt') s = smtplib.SMTP(host='smtp.gmail.com', port=587) s.starttls() s.login(MY_ADDRESS, PASSWORD) msg = MIMEMultipart() # creating a message full_name = '' for user in data.get_users(): if user['email'] == email: full_name = user['name_first'] + ' ' + user['name_last'] message = message_template.substitute(PERSON_NAME=full_name.title(), SECRET_CODE=secret) # setup parameters of message msg['From'] = MY_ADDRESS msg['To'] = email msg['Subject'] = "flockr - Password Reset" msg.attach(MIMEText(message, 'plain')) s.send_message(msg) del msg s.quit() with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {}
def user_profile_uploadphoto(token, img_url, x_start, y_start, x_end, y_end): """Given a URL of an image on the internet, crops the image within bounds (x_start, y_start) and (x_end, y_end). Position (0,0) is the top left. Args: token (string) img_url (string) x_start (int) y_start (int) x_end (int) y_end (int) Returns: (dict): {} """ data = pickle.load(open(DATA_FILE, "rb")) # Error checks: Basic validation confirm_token(data, token) # Error check: img_url returns an HTTP status other than 200. try: response = requests.get(img_url) except: raise InputError( description="InputError: Image URL cannot be requested") if response.status_code != 200: raise InputError( description= "InputError: Image URL returns an HTTP status other than 200") # Generate file url path img_file_local_path = generate_img_file_path() # Error check: check if the image can be download. If can, download it. try: urllib.request.urlretrieve(img_url, 'src/' + img_file_local_path) except: raise InputError( description="InputError: Image URL cannot be retrieved") # Error check: Image uploaded is not a JPG if imghdr.what('src/' + img_file_local_path) != "jpeg": os.remove('src/' + img_file_local_path) raise InputError(description="InputError: Image uploaded is not a JPG") # Error check: Check if the x and y dimensions are within bounds img_object = Image.open('src/' + img_file_local_path) width, height = img_object.size if x_start not in range(0, width): os.remove('src/' + img_file_local_path) raise InputError(description="x_start not in boundary of the image") if x_end not in range(0, width + 1): os.remove('src/' + img_file_local_path) raise InputError(description="x_end not in boundary of the image") if y_start not in range(0, height): os.remove('src/' + img_file_local_path) raise InputError(description="y_start not in boundary of the image") if y_end not in range(0, height + 1): os.remove('src/' + img_file_local_path) raise InputError(description="y_end not in boundary of the image") if x_end <= x_start: os.remove('src/' + img_file_local_path) raise InputError(description="x_end must be greater than x_start") if y_end <= y_start: os.remove('src/' + img_file_local_path) raise InputError(description="y_end must be greater than y_start") # Crop the images img_object.crop( (x_start, y_start, x_end, y_end)).save('src/' + img_file_local_path) # Assign image to the user and save it on the server u_id = convert_token_to_u_id(data, token) try: server_img_url = f"{request.url_root}{img_file_local_path}" except: os.remove('src/' + img_file_local_path) raise AccessError(description="Server must be running to upload photo") data.set_user_photo(u_id, server_img_url) data.set_user_photo_in_channels(u_id, server_img_url) with open(DATA_FILE, 'wb') as FILE: pickle.dump(data, FILE) return {}
def confirm_u_id(data, u_id): if not validate_u_id(data, u_id): raise InputError(description="InputError: Invalid user id")