def get_next_message_id(): ''' Helper function to get next message id to be assigned''' try: message_id = store.get("next_id", "type", "message_id")[0]["value"] store.update("next_id", "value", message_id + 1, "type", "message_id") except ValueError: message_id = 0 store.insert("next_id", {"type": "message_id", "value": 1}) return message_id
def standup_send(token, channel_id, message): ''' Sends a standup message and a normal message''' message_send(token, channel_id, message) standup_data = store.get("standup", "channel_id", channel_id)[0] if not standup_data["is_active"]: raise AccessError summaries = standup_data["summaries"] summaries[standup_data["standup_id"]] += get_name_from_token(token) + ' - ' + message + '\n' store.update("standup", "summaries", summaries, "channel_id", channel_id) return {}
def channels_create(token, name, is_public): ''' Create a new channel -------- token: string token of the requester name: string name of the channel is_public: bool boolean indicating if the channel will be public or private \u207b------- ValueError when: name is more than 20 characters long -------- return: channel_id ''' type_check_token(token) if not isinstance(name, str): raise ValueError('Name is not a string') if not isinstance(is_public, bool): raise ValueError('is_public is not a boolean') if not isinstance(name, str): raise ValueError('Name is not a string') if len(name) > 20: raise ValueError('Name is more than 20 characters long') if len(name) <= 0: raise ValueError('Name is invalid') channel_id = store.n_elems('channel_data') + 1 u_id = auth_check_token(token) member = create_member_from_u_id(u_id) store.insert('channel_data', { 'channel_id': channel_id, 'name': name, 'messages': [], 'members': [member], 'owners': [member], 'is_public': is_public }) store.insert('channels', { 'channel_id': channel_id, 'name' : name }) channels = store.get('users', 'u_id', u_id)[0]['channels'] channels.append({ 'channel_id': channel_id, 'name' : name }) store.update('users', 'channels', channels, 'u_id', u_id) return {'channel_id': channel_id}
def user_profiles_uploadphoto(img_url, x_start, y_start, x_end, y_end, caller_u_id=None): # Ideally, we'd have some kind of configuration system to provide us with a way to access # the absolute path we need, and our server's URL. # However, for the purposes of this project, I think it's good enough to use a relative # path and hardcode our URL - especially since the frontend has the loopback address # hardcoded too. # Check paramater validity if x_start >= x_end or y_start >= y_end or min(x_start, x_end, y_start, y_end) < 0: raise ValueError("Invalid crop coordinates") # Get response object for image, and check validity of response try: resp = urlrequest.urlopen(img_url) except HTTPError: # non-200 response raise ValueError("Image URL did not open successfully") if resp.getheader( "Content-Type") == None or "image/jpeg" not in resp.getheader( "Content-Type"): raise ValueError("URL did not point to a JPEG image") # Get PIL.Image object for the image img = Image.open(resp) if x_start > img.width or x_end > img.width or y_start > img.height or y_end > img.height: raise ValueError("Invalid crop coordinates") # Crop & save the image img_cropped = img.crop((x_start, y_start, x_end, y_end)) file_path = f"../static/img/{str(caller_u_id)}.jpg" # shady relative path but it's fine img_cropped.save(os.path.abspath(file_path)) # Close images to release memory img_cropped.close() img.close() # Update user dict with URL to profile photo photo_URL = f"http://127.0.0.1:5001/img/{str(caller_u_id)}.jpg" store.update("users", "profile_img_url", photo_URL, "u_id", caller_u_id) return {}
def user_profile_setemail(email, caller_u_id=None): # check email validity if not is_valid_email(email): raise ValueError(f"{email} is not a valid email") # check if user with email exists results = store.get("users", "email", email) if len(results) > 0: raise ValueError(f"User with email {email} already exists") # update email in store store.update("users", "email", email, "u_id", caller_u_id) # != 1: # raise Exception("Error updating email") return {}
def user_profile_setname(name_first, name_last, caller_u_id=None): # check name length requirements if len(name_first) < 1 or len(name_first) > 50: raise ValueError("Names must be between 1 and 50 characters long") if len(name_last) < 1 or len(name_last) > 50: raise ValueError("Names must be between 1 and 50 characters long") # update names in store store.update("users", "name_first", name_first, "u_id", caller_u_id) # != 1: # raise Exception("Error updating first name") store.update("users", "name_last", name_last, "u_id", caller_u_id) # != 1: # raise Exception("Error updating last name") return {}
def admin_userpermission_change(token, u_id, permission_id): """ Given a user ID, set their permissions to new permissions described by permission_id. """ if not isinstance(u_id, int): raise ValueError("u_id is not an int") if not isinstance(permission_id, int): raise ValueError("permission_id is not an int") if permission_id < 1 or permission_id > 3: raise ValueError("permission_id is not valid") # Check requesting user's permissions req_u_id = auth_check_token(token) req_user = store.get("users", "u_id", req_u_id)[0] req_perm = req_user.get("permission_id") if req_perm == 3: raise AccessError("requesting user is not an owner or admin") if req_perm == 2 and permission_id == 1: raise AccessError("admins cannot make users owners") # Check target user results = store.get("users", "u_id", u_id) if len(results) != 1: raise ValueError(f"user with u_id {u_id} does not exist") target = results[0] target_perm = target.get("permission_id") if req_perm == 2 and target_perm == 1: raise AccessError("admins cannot change owners' permissions") # Execute permission change index = store.update("users", "permission_id", permission_id, "u_id", u_id) if index == 0: raise ValueError("Invalid user ID") return {}
def user_profile_sethandle(handle_str, caller_u_id=None): # check handle length requirements if len(handle_str) < 3 or len(handle_str) > 20: raise ValueError("handle must be between 3 and 20 characters long") # check if user with handle exists results = store.get("users", "handle_str", handle_str) if len(results) > 0: raise ValueError(f"user with handle {handle_str} already exists") # update handle in store store.update("users", "handle_str", handle_str, "u_id", caller_u_id) # != 1: # raise Exception("error updating handle") return {}
def channel_removeowner(token, channel_id, u_id): ''' Change an owner into an user in the channel ------- token: string Changer token channel_id: int id of the channel u_id: int id of the owner who will become user -------- ValueError when: channel_id does not refer to a valid channel that the authorised user is part of. u_id does not refer to a valid user which is part of the channel u_id is already an owner of the channel token does not refer to a valid user AccessError when: the authorised user is not an owner of the slackr, or an owner of this channel -------- Returns {} ''' type_check_token(token) type_check_channel_id(channel_id) type_check_u_id(u_id) check_channel_exists(channel_id) if not owner_in_channel(u_id, channel_id): raise ValueError('The user with ID u_id is not an owner of the channel') requester_u_id = auth_check_token(token) req_perm = store.get('users', 'u_id', requester_u_id)[0]['permission_id'] if req_perm == 3 and not user_in_channel(requester_u_id, channel_id): raise ValueError('The requester is not part of the channel and is also not an admin/owner') if req_perm == 3 and not owner_in_channel(requester_u_id, channel_id): raise AccessError('Requester has not the right to add an owner') if nb_of_channel_owners(channel_id) == 1: raise ValueError('The requested u_id is the only owner of the channel') channel_owners = store.get('channel_data', 'channel_id', channel_id)[0]['owners'] remove_member_from_list(u_id, channel_owners) store.update('channel_data', 'owners', channel_owners, 'channel_id', channel_id) return {}
def channel_addowner(token, channel_id, u_id): ''' Change a user into an owner in the channel ------- token: string Changer token channel_id: int id of the channel u_id: int id of the user who will become owner -------- ValueError when: channel_id does not refer to a valid channel that the authorised user is part of. u_id does not refer to a valid user which is part of the channel u_id is already an owner of the channel token does not refer to a valid user AccessError when the authorised user is not already a member of the channel -------- Returns {} ''' type_check_token(token) type_check_channel_id(channel_id) type_check_u_id(u_id) check_channel_exists(channel_id) if owner_in_channel(u_id, channel_id): raise ValueError('The user with ID u_id is already an owner of the channel') requester_u_id = auth_check_token(token) req_perm = store.get('users', 'u_id', requester_u_id)[0]['permission_id'] if req_perm == 3 and not user_in_channel(requester_u_id, channel_id): ValueError('Requester is not part of the channel, and is a normal user in the slackr') if req_perm == 3 and not owner_in_channel(requester_u_id, channel_id): raise AccessError('Requester has not the right to add an owner') channel_owners = store.get('channel_data', 'channel_id', channel_id)[0]['owners'] channel_owners.append(create_member_from_u_id(u_id)) store.update('channel_data', 'owners', channel_owners, 'channel_id', channel_id) return {}
def channel_invite(token, channel_id, u_id): ''' Invite a user in the channel ------- token: string Inviter token channel_id: int id of the channel u_id: int id of the user invited -------- ValueError when: channel_id does not refer to a valid channel that the authorised user is part of. u_id does not refer to a valid user which is part of the channel token does not refer to a valid user AccessError when the authorised user is not already a member of the channel -------- Returns {} ''' type_check_token(token) type_check_channel_id(channel_id) type_check_u_id(u_id) check_channel_exists(channel_id) check_user_not_in_channel_value_error(u_id, channel_id, 'u_id is already part of the channel') check_user_in_channel_access_error(auth_check_token(token), channel_id, 'The token is not a member of channel') channel_members = store.get('channel_data', 'channel_id', channel_id)[0]['members'] new_member = create_member_from_u_id(u_id) channel_members.append(new_member) store.update('channel_data', 'members', channel_members, 'channel_id', channel_id) user_channels = store.get('users', 'u_id', u_id)[0]['channels'] user_channels.append(get_channel(channel_id)) store.update('users', 'channels', user_channels, 'u_id', u_id) return {}
def channel_join(token, channel_id): ''' Join a channel ------- token: string joiner token channel_id: int id of the channel -------- ValueError when: channel_id does not refer to a valid channel that the authorised user is part of. token does not refer to a valid user which is not part of the channel AccessError whenchannel_id refers to a channel that is private - when the authorised user is not an admins -------- Returns {} ''' type_check_token(token) type_check_channel_id(channel_id) check_channel_exists(channel_id) req_u_id = auth_check_token(token) check_user_not_in_channel_value_error(req_u_id, channel_id, 'token is already in channel') req_permission = store.get('users', 'u_id', req_u_id)[0]['permission_id'] channel_is_public = store.get('channel_data', 'channel_id', channel_id)[0]['is_public'] if (not channel_is_public) and (req_permission == 3): raise AccessError('The user is not an admin and he tries to access a private channel') member = create_member_from_u_id(req_u_id) new_list_members = store.get('channel_data', 'channel_id', channel_id)[0]['members'] new_list_members.append(member) store.update('channel_data', 'members', new_list_members, 'channel_id', channel_id) user_channels = store.get('users', 'u_id', req_u_id)[0]['channels'] user_channels.append(get_channel(channel_id)) store.update('users', 'channels', user_channels, 'u_id', req_u_id) 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 TODO stub """ # Check if reset code is valid res = store.get("resets", "reset_code", reset_code) if not res: raise ValueError("invalid reset code") reset = res[0] # Change password if len(new_password) < 6: raise ValueError("new password must be at least 6 characters") pwhash = hashlib.sha256(new_password.encode("utf-8")).hexdigest() store.update("users", "password", pwhash, "u_id", reset.get("u_id")) # Remove reset obj from store (after successful reset, just in case user screws up) store.remove("resets", "reset_code", reset_code) return {}
def standup_start(token, channel_id, standup_length=15*60): ''' Begin standup in channel, calls end standup after the time has expired''' validate_user(token, channel_id, "channel") except_message = "Already currently active standup" try: standup_data = store.get("standup", "channel_id", channel_id)[0] if standup_data["is_active"]: raise ValueError(except_message) store.update("standup", "is_active", True, "channel_id", channel_id) new_message_index = standup_data["standup_id"] store.update("standup", "standup_id", new_message_index+1, "channel_id", channel_id) summaries = standup_data["summaries"] summaries.append("Standup summary:\n") store.update("standup", "summaries", summaries, "channel_id", channel_id) except (ValueError) as ex: if ex.args[0] == except_message: raise ValueError(ex) store.insert("standup", {"channel_id": channel_id, "is_active": True,\ "standup_id": 0, "summaries": ["Standup summary:\n"]}) end = datetime.now()+timedelta(seconds=standup_length) my_timer(end, standup_end, (token, channel_id)) store.update("standup", "end", end, "channel_id", channel_id) return {"time_finish" : convert_time(end)}
def channel_leave(token, channel_id): ''' Leaves a channel ------- token: string leaver token channel_id: int id of the channel -------- ValueError when: channel_id does not refer to a valid channel that the authorised user is part of. token does not refer to a valid user which is part of the channel -------- Returns {} ''' type_check_token(token) type_check_channel_id(channel_id) check_channel_exists(channel_id) req_u_id = auth_check_token(token) check_user_in_channel_value_error(req_u_id, channel_id, 'User is not in channel') if nb_of_channel_members(channel_id) == 1: raise ValueError('You can\'t quit a channel with 1 member') if nb_of_channel_owners(channel_id) == 1 and owner_in_channel(req_u_id, channel_id): raise ValueError('You are the only owner of the channel') members_before = store.get("channel_data", "channel_id", channel_id)[0].get("members") remove_member_from_list(req_u_id, members_before) store.update("channel_data", "members", members_before, "channel_id", channel_id) owners_before = store.get("channel_data", "channel_id", channel_id)[0].get("owners") try: remove_member_from_list(req_u_id, owners_before) store.update("channel_data", "owners", owners_before, "channel_id", channel_id) except ValueError: pass channels_before = store.get("users", "u_id", req_u_id)[0].get("channels") remove_channel_from_list(channel_id, channels_before) store.update("users", "channels", channels_before, "u_id", req_u_id) return {}
def update_channel_messages(channel_id, messages): ''' Helper function to store updated messages back in channel''' store.update("channel_data", "messages", messages, "channel_id", channel_id)