def test_generate_handle(): ''' Ensures handles that are generated are unique ''' # Initialisation global_var.initialise_all() # First instance of handle in server user1 = auth.auth_register("*****@*****.**", "pass123", "Ashley", "Huang") user1 = helpers.get_user_by_token(user1["token"]) assert user1.handle == "ashleyhuang" # Non-first instance of handle in server - substitute found user2 = auth.auth_register("*****@*****.**", "pass123", "Ashley", "Huang") user2 = helpers.get_user_by_token(user2["token"]) assert user2.handle == "1ashleyhuang" # Non-first instance of handle in server - first no substitute found auth.auth_register("*****@*****.**", "pass123", "3Ashley", "Huang") user4 = auth.auth_register("*****@*****.**", "pass123", "Ashley", "Huang") user4 = helpers.get_user_by_token(user4["token"]) assert user4.handle == "0" # Non-first instance of handle in server - second no substitute found auth.auth_register("*****@*****.**", "pass123", "5Ashley", "Huang") user6 = auth.auth_register("*****@*****.**", "pass123", "Ashley", "Huang") user6 = helpers.get_user_by_token(user6["token"]) assert user6.handle == "1"
def test_get_user_token_by_u_id(): ''' Ensures that the correct token is obtained by get_user_token_by_u_id ''' # Initialisation global_var.initialise_all() # Creating a user user = auth.auth_register("*****@*****.**", "pass123", "Raydon", "Smith") assert helpers.get_user_token_by_u_id(user["u_id"]) == user["token"] with pytest.raises(AccessError, match="Invalid Token"): helpers.get_user_by_token(-1)
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. ''' channel = get_channel_by_message_id(message_id) message_obj = get_message_by_message_id(message_id) user = get_user_by_token(token) # message_id does not refer to an existing message if not valid_message_id(message_id): raise ValueError("Message does not exist") # message is not of appropriate length if valid_message(message): raise ValueError("Message length too long") # User does not have permission to edit message if not message_obj.user_sent_message(user.u_id) and \ not token_is_admin(token) and \ not token_is_owner(token) and \ not channel.is_owner(user.u_id): raise AccessError("User does not have permission") # Edit channel message if not message.strip(): # If empty message, delete channel = get_channel_by_message_id(message_id) channel.remove_message(message_id) else: # Otherwise, edit message message_obj.edit_message(message) 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 ''' channel = get_channel_by_message_id(message_id) message_obj = get_message_by_message_id(message_id) user = get_user_by_token(token) # Message_id does not refer to an existing message if not valid_message_id(message_id): raise ValueError("Message does not exist") # User is not a member of the channel if not channel.is_member(user.u_id): raise AccessError("Authorised user is not a member of the channel") # React_id does not refer to a valid react if not valid_react_id(react_id): raise ValueError("Invalid React ID") # Message already has an react id by the given user if not message_obj.user_has_reacted(user.u_id, react_id): raise ValueError("Message does not contain an active react") # Removing react from message message_obj.remove_react(user.u_id, react_id) return {}
def message_sendlater(token, channel_id, message, time_sent): ''' Sends a message from authorised_user to the channel specified by channel_id automatically at a specified time in the future ''' channel = get_channel_by_channel_id(channel_id) user = get_user_by_token(token) # Channel_id does not refer to a valid channel if channel is None: raise ValueError("Invalid Channel ID") # Message is not of appropriate length if valid_message(message): raise ValueError("Message length too long") # Time to be sent is in the past if time_sent < datetime.datetime.now().timestamp(): raise ValueError("Time sent was in the past") # User has not joined the channel if not channel.is_member(user.u_id): raise AccessError("Authorised user is not a member of the channel") # create new message object and update send time message_object = global_var.Message(user.u_id, message, channel_id) message_object.time_created = time_sent time_diff = time_sent - datetime.datetime.now().timestamp() Timer(time_diff, channel.add_message, args=[message_object]).start() return { "message_id": message_object.id }
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 ''' channel = get_channel_by_message_id(message_id) message_obj = get_message_by_message_id(message_id) user = get_user_by_token(token) # Message_id does not refer to an existing message if not valid_message_id(message_id): raise ValueError("Message does not exist") # Message_id is already pinned if message_obj.is_pinned: raise ValueError("Message is currently pinned") # User is not a member of the channel if not channel.is_member(user.u_id): raise AccessError("Authorised user is not a member of the channel") # User is not an owner of the channel if not channel.is_owner(user.u_id) and \ not token_is_admin(token) and \ not token_is_owner(token): raise ValueError("User is not an admin") # Pin message message_obj.pin_message() return {}
def message_unpin(token, message_id): ''' Given a message within a channel, remove it's mark as unpinned ''' channel = get_channel_by_message_id(message_id) message_obj = get_message_by_message_id(message_id) user = get_user_by_token(token) # Message_id does not refer to an existing message if not valid_message_id(message_id): raise ValueError("Message does not exist") # Message_id is already unpinned if not message_obj.is_pinned: raise ValueError("Message is currently unpinned") # User is not a member of the channel if not channel.is_member(user.u_id): raise AccessError("Authorised user is not a member of the channel") # User is not an owner of the channel if not channel.is_owner(user.u_id) and \ not token_is_admin(token) and \ not token_is_owner(token): raise ValueError("User is not an admin") # Unpinning message message_obj.unpin_message() return {}
def message_send(token, channel_id, message): ''' Send a message from authorised_user to the channel specified by channel_id ''' channel = get_channel_by_channel_id(channel_id) user = get_user_by_token(token) # Channel_id does not refer to a valid channel if channel is None: raise ValueError("Invalid Channel ID") # Message is not of appropriate length if valid_message(message): raise ValueError("Message length too long") # User has not joined the channel if not channel.is_member(user.u_id): raise AccessError("Authorised user is not a member of the channel") message_object = global_var.Message(user.u_id, message, channel_id) # Append message to channel list channel.add_message(message_object) return { "message_id": message_object.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 ''' channel = get_channel_by_channel_id(channel_id) user = get_user_by_token(token) if channel is None: raise ValueError("Channel Does Not Exist") if channel.standup_running() is not False: raise ValueError("Standup Already Running") if not channel.is_member(user.u_id): raise AccessError("Cannot Access Channel") # Start standup and after length seconds end the standup time = datetime.datetime.now() + datetime.timedelta(seconds=length) channel.start_standup(time.timestamp()) Timer(length, channel.end_standup, args=[token]).start() return {"time_finish" : time.timestamp()}
def test_auth_register(): ''' Test functions for auth_register ''' data.initialise_all() #A user is registered user = auth.auth_register("*****@*****.**", "valid_password", "a", "b") # Check database for id and token user_id = get_user_by_email("*****@*****.**").u_id user_token = get_user_token_by_u_id(user_id) # confirm that register returned the correct ID and token assert user == {"u_id": user_id, "token": user_token} # A invalid email is given with pytest.raises(ValueError, match="Invalid Email"): auth.auth_register("invalid_email", "valid_password", "a", "b") # Email given is already in use with pytest.raises(ValueError, match="Email Already Registered"): auth.auth_register("*****@*****.**", "valid_password", "a", "b") # Password provided is not strong enough with pytest.raises(ValueError, match="Password Not Strong"): auth.auth_register("*****@*****.**", "bpas", "a", "b") # First name is invalid with pytest.raises(ValueError, match="Invalid First Name"): invalid = "a" * 51 auth.auth_register("*****@*****.**", "valid_password", invalid, "b") # Last name is invalid with pytest.raises(ValueError, match="Invalid Last Name"): auth.auth_register("*****@*****.**", "valid_password", "a", invalid) # Testing unique handle # Creating user: first_name="asd", last_name="dsa" user1 = auth.auth_register("*****@*****.**", "valid_password", "asd", "dsa") user1 = get_user_by_token(user1["token"]) assert user1.handle == "asddsa" # Creating user: first_name="asd", last_name="dsa" user2 = auth.auth_register("*****@*****.**", "valid_password", "asd", "dsa") user2 = get_user_by_token(user2["token"]) assert user2.handle == "2asddsa"
def test_get_reset_code_from_email(): ''' Returns a reset_code according to a user email ''' # Register a user user = auth.auth_register("*****@*****.**", "passsword", "a", "b") user = helpers.get_user_by_token(user["token"]) user2 = auth.auth_register("*****@*****.**", "passsword", "a", "b") user2 = helpers.get_user_by_token(user2["token"]) auth.auth_passwordreset_request(user2.email) # No such email request assert helpers.get_reset_code_from_email("*****@*****.**") is None # Reset email request auth.auth_passwordreset_request(user.email) assert helpers.get_reset_code_from_email(user.email) ==\ global_var.data["reset_code"][1]["reset_code"]
def user_profiles_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 x and y co-oridinates ValueError: - img_url returns an HTTP status other than 200 (2xx indicates success) - xy points are outside the dimensions of the image at the url ''' req = Request(img_url, headers={"User-Agent": "Mozilla/5.0"}) # Checking if the img_url is an accessable URL try: response = urlopen(req) except URLError as error: raise ValueError(f"The server cannot be reached: {error.reason}") # Obtaining image image_object = Image.open(response) # Checks if image is a jpg if image_object.format != "JPEG": raise ValueError("Image uploaded is not a JPG") # Check that the crop co-ordinates are valid # Getting the width and height of image width, height = image_object.size # Checking if the crop coordinates are within the bounds of the image valid_crop(x_start, x_end, y_start, y_end, width, height) # Obtaining user_id (user_id will be the unique filename) user = get_user_by_token(token) # Creating file path if it doesn't already exist if not os.path.exists("server/assets/images/"): os.makedirs("server/assets/images/") # File path img_file_path = f"server/assets/images/{create_photo_path(user)}.jpg" # Gets image from url and saves it in images folder urllib.request.urlretrieve(img_url, img_file_path) # Cropping image img_file = open(img_file_path, "wb") cropped = image_object.crop((x_start, y_start, x_end, y_end)) cropped.save(img_file) # Use request in running server context and give default url for unit tests try: url = request.host_url except: url = "http://localhost:5001/" user.upload_photo(f"{url}imgurl/{img_file_path}") return {}
def test_unique_handle(): ''' Ensure that handles are unique ''' # Initialisation global_var.initialise_all() # Testing unique handle assert helpers.unique_handle("AshleyHuang") is True # Testing not unique handle user = auth.auth_register("*****@*****.**", "pass123", "Ashley", "Huang") get_user = helpers.get_user_by_token(user["token"]) assert helpers.unique_handle(get_user.handle) is False
def channels_list(token): ''' Provides a list of all channels and details that the auth user is part of ''' user = get_user_by_token(token) channels_user_is_member = [] # Create a list of channels that the user is apart of for channel in global_var.data["channels"]: if channel.is_member(user.u_id): channels_user_is_member.append({"channel_id": channel.id, \ "name": channel.name}) return {"channels": channels_user_is_member}
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 ''' messages = [] # Searching for messages with query string for channel in data.data["channels"]: # Checking all channels which the user has joined if channel.user_in_channel(get_user_by_token(token).u_id): # Returning all messages in channel with substring messages = messages + channel.search_message(token, query_str) return {"messages": messages}
def channel_leave(token, channel_id): ''' Given a channel ID, the user is removed as a member of the channel ''' channel = get_channel_by_channel_id(channel_id) user = get_user_by_token(token) # channel_id does not refer to a valid channel if channel is None: raise ValueError("Channel does not exist") # User is removed as a member of the channel channel.remove_user(user.u_id) channel.remove_owner(user.u_id) return {}
def channels_create(token, name, is_public): ''' Create a channel with the name that is either public or private ''' # Exception raised if len(name) > MAX_CHANNEL_LENGTH: raise ValueError("Name is longer than 20 characters") user = get_user_by_token(token) # A channel object is created new_channel = global_var.Channel(name, user.u_id, is_public) # channel is added to channels list global_var.data["channels"].append(new_channel) return {"channel_id": new_channel.id}
def user_profile_sethandle(token, handle_str): ''' Update the authorised user's handle ''' if len(handle_str) > MAX_HANDLE_LENGTH or len(handle_str) < \ MIN_HANDLE_LENGTH: raise ValueError("Invalid Handle") if not unique_handle(handle_str): raise ValueError("Handle Taken") # Changes user's handle in database user = get_user_by_token(token) # Update user's handle user.update_handle(handle_str) return {}
def test_token_is_owner(): ''' Test if a token is in an owner ''' # Initialisation global_var.initialise_all() # Creating a user user = auth.auth_register("*****@*****.**", "pass123", "Raydon", "Smith") with pytest.raises(AccessError, match="Invalid Token"): helpers.token_is_owner("-1") token = user["token"] user = helpers.get_user_by_token(token) user.permission = 1 assert helpers.token_is_owner(token) is True user.permission = 0 assert helpers.token_is_owner(token) is False
def standup_send(token, channel_id, message): ''' Sending a message to get buffered in the standup queue, assuming a standup is currently active ''' channel = get_channel_by_channel_id(channel_id) user = get_user_by_token(token) if channel is None: raise ValueError("Channel Does Not Exist") if len(message) > MAX_MESSAGE_LENGTH: raise ValueError("Message Too Long") if not channel.is_member(user.u_id): raise AccessError("Cannot Access Channel") if channel.standup_running() is False: raise ValueError("Not Currently In Standup") channel.add_standup_message(token, message) return {}
def message_remove(token, message_id): ''' Given a message ID, the message is removed ''' channel = get_channel_by_message_id(message_id) message = get_message_by_message_id(message_id) user = get_user_by_token(token) # Message_id does not refer to an existing message if not valid_message_id(message_id): raise ValueError("Message does not exist") # User does not have permission to remove message if not message.user_sent_message(user.u_id) and \ not token_is_admin(token) and \ not token_is_owner(token) and \ not channel.is_owner(user.u_id): raise AccessError("User does not have permission") # Removing message channel.remove_message(message_id) return {}
def user_profile_setname(token, name_first, name_last): ''' Update the authorised user's first and last name ValueError: - name_first is more than 50 characters - name_last is more than 50 characters ''' if len(name_first) > MAX_NAME_LENGTH: raise ValueError("Name too long") if len(name_last) > MAX_NAME_LENGTH: raise ValueError("Name too long") user = get_user_by_token(token) # Update user's first name user.update_name_first(name_first) # Update user's last name user.update_name_last(name_last) return {}
def user_profile_setemail(token, email): ''' Updates the authorised user's email address ValueError: - Email entered is not a valid email - Email address is already being used by another user ''' user = get_user_by_email(email) if valid_email(email) is False: raise ValueError("Invalid email") if user: raise ValueError("Email already in use") # Changes user's email in database user = get_user_by_token(token) # Update user's email user.update_email(email) return {}
def channel_join(token, channel_id): ''' Given a channel_id of a channel that the authorised user can join adds them to that channel ''' channel = get_channel_by_channel_id(channel_id) user = get_user_by_token(token) # channel_id does not refer to a valid channel if channel is None: raise ValueError("Channel does not exist") # User does not have permission to join channel without invite if not channel.is_public and \ not token_is_admin(token) and \ not token_is_owner(token): raise AccessError("Channel is private and user is not admin") # User is added to channel channel.add_user(user.u_id) return {}
def add_standup_message(self, token, message): self.standup_messages.append({ 'user': helpers.get_user_by_token(token).handle, 'message': message })