Example #1
0
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 {}
Example #3
0
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}
Example #6
0
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 {}
Example #8
0
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 {}
Example #19
0
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}
Example #24
0
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,
    }
Example #25
0
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")