Ejemplo n.º 1
0
def standup_start(token, channel_id, length):
    """
    standup_start

    Args:
        token: authorises user
        channel_id: the target channel to initiate the standup in
        length: how long the standup will last (in seconds)

    Returns:
        time_finish: the time the startup will end and consequently send the start up messages into the message queue of the channel
    """
    token_validator(token)
    channel_validator(channel_id)  

    # Check if there is a standup currently running in the channel
    if standup_active(token, channel_id)['is_active']:
        raise InputError("There is already a standup currently active")

    # Start the standup period, for length (seconds) where messages using standup 
    # will be sent to a standup_queue, then all added to the channel_messages by a 
    # packed message sent by the creator of the standup when the standup finishes
    time_finish = get_timestamp(length)
    standup_start = threading.Thread(target=thread_standup, args=(token, channel_id, length))
    standup_start.start()

    for channel in data['channels']:
        if channel['channel_id'] == channel_id:
            channel['time_finish'] = time_finish
    
    return {
        'time_finish': time_finish
    }
Ejemplo n.º 2
0
def users_all(token):
    '''
    users_all

    Args:
        token: authorises user
    
    Returns:
        users: information about all users in the data
    
    Raises:
        AccessError when token is not valid
    '''
    # Verify that token is valid
    token_validator(token)

    # Find and return all users in the data
    all_users = []
    for users in data['users']:
        user = {
            'u_id': users['u_id'],
            'email': users['email'],
            'name_first': users['name_first'],
            'name_last': users['name_last'],
            'handle_str': users['handle_str'],
            'profile_img_url': users['profile_img_url']
        }
        all_users.append(user)

    return {'users': all_users}
Ejemplo n.º 3
0
def standup_active(token, channel_id):
    """
    standup_active

    Args:
        token: authorises user
        channel_id: the target channel to get startup details from

    Returns:
        is_active: if there is currently an active standup True, otherwise False
        time_finish: the time the startup will end, or None if no active standup
    """
    token_validator(token)
    channel_validator(channel_id)  

    time_finish = None
    for channel in data['channels']:
        if channel['channel_id'] == channel_id:
            time_finish = channel['time_finish']

    # There is currently a standup running in the channel
    if time_finish != None:
        return {
            'is_active': True,
            'time_finish': time_finish
        }
    # There is not currently a standup running in the channel
    else:
        return {
            'is_active': False,
            'time_finish': None
        }
Ejemplo n.º 4
0
def message_unpin(token, message_id):
    # pinner = the user who is requesting the message to be pinned
    unpinner = token_validator(token)['u_id']

    # Locate the given message_id and verify it
    valid_message = False
    for channel in data['channels']:
        for message in channel['messages']:
            if message_id == message['message_id']:
                valid_message = True
                break

    if valid_message:
        if message['is_pinned']:
            if unpinner in channel['all_members'] or is_flockr_owner(
                    token, unpinner):
                if unpinner in channel['owner_members'] or is_flockr_owner(
                        token, unpinner):
                    message['is_pinned'] = False
                else:
                    raise AccessError("Authorised user is not an owner")
            else:
                raise AccessError(
                    "Authorised user is not a member of the channel \
                                   that the message is within")
        else:
            raise InputError("Message with ID message_id is already unpinned")
    else:
        raise InputError("message_id is not a valid message")

    return {}
Ejemplo n.º 5
0
def standup_send(token, channel_id, message):
    """
    standup_send
    
    Args:
        token: authorises user
        channel_id: the target channel to buffer a message to the active standup
        message: the message to buffer into the active standup
    """
    print(token)
    print(channel_id)
    print(message)

    u_id = token_validator(token)['u_id']
    channel_validator(channel_id)
    
    # Verify that the standup is currently active
    if not standup_active(token, channel_id)['is_active']:
        raise InputError("There is already a standup currently active")
    
    # Verify that the is under 1000 characters
    if len(message) > 1000:
        raise InputError("Message is more than 1000 characters")
    
    # Verifies that the user is a member of the channel
    channel_details(token, channel_id)

    handle_str = user_profile(token, u_id)['user']['handle_str']
    standup.add_standup_queue(message, handle_str)

    return {}
Ejemplo n.º 6
0
def message_remove(token, message_id):
    '''
    Either an authorised user (i.e. channel owner) or the sender of a message removes a message. Specified by message_id
    '''
    # Verify that the remover has a valid token
    remover = token_validator(token)

    # Locate the relevant message by looping through the channels and messages
    for channel in data['channels']:
        # Find the message to be removed
        for message_find in channel['messages']:
            if message_find['message_id'] == message_id:
                # If message has been found, check authorisation to remove
                # Remover is authorised if they are either the sender of the message or they are the owner of the channel
                if remover['u_id'] == message_find['u_id'] or remover[
                        'u_id'] in channel['owner_members'] or is_flockr_owner(
                            token, remover['u_id']):
                    del channel['messages'][message_id]
                    return {}
                else:
                    raise AccessError(
                        "Sorry, you are neither the owner of the channel or creator of the message"
                    )

    # If the message was not found, raise Input Error
    raise InputError("The message you are trying to remove was not found")
Ejemplo n.º 7
0
def user_profile_setemail(token, email):
    '''
    user_profile_setemail

    Args:
        token: authorises user
        email: the new email address
    
    Returns: 
        returns {}

    Raises:
        InputError when email is not valid
        InputError when email is already being used
        AccessError when token is not valid
    '''
    # Validating the token of the user
    user = token_validator(token)

    # Check that the new email is valid using the method provided
    regex = r'^[a-z0-9]+[\._]?[a-z0-9]+[@]\w+[.]\w{2,3}$'
    if (re.search(regex, email)):
        for users in data['users']:
            if users['email'] == email:
                raise InputError(
                    "The new email you are updating is currently being used")
    else:
        raise InputError("The new email you are updating to is invalid")

    for users in data['users']:
        if users['u_id'] == user['u_id']:
            users['email'] = email

    return {}
Ejemplo n.º 8
0
def message_unreact(token, message_id, react_id):
    user = token_validator(token)

    # Check is message exists
    valid_message_id = False
    for channel in data['channels']:
        # Check if the user who is reacting to the message in the channel, is actually in the channel
        for current_message in channel['messages']:
            if current_message['message_id'] == message_id:
                valid_message_id = True
                break

    if user['u_id'] not in channel['all_members']:
        raise InputError("The user is not part of the channel")

    if react_id != 1:
        raise InputError('The react_id for this message is invalid')

    if valid_message_id:
        for react in current_message['reacts']:
            if user['u_id'] in react['u_ids']:
                react['u_ids'].remove(user['u_id'])
                react['is_this_user_reacted'] = False
            else:
                raise InputError("You have not reacted this message yet")
    else:
        raise InputError("The message you are trying to unreact was not found")

    return {}
Ejemplo n.º 9
0
def user_profile_setname(token, name_first, name_last):
    """
        user_profile_setname

        Args:
            token: authorises user
            name_first: new first name for user
            name_last: new last name for user

        Returns:
            empty dictionary but changes user's name

        Raises:
            InputError when name_first is not within 1 to 50 characters inclusive
            InputError when name_last is not within 1 to 50 characters inclusive
            AccessError when token is not valid
    """

    # Validating the token
    user = token_validator(token)

    valid_first_name = 1 <= len(name_first) <= 50
    if not valid_first_name:
        raise InputError("Invalid first name length")

    valid_last_name = 1 <= len(name_last) <= 50
    if not valid_last_name:
        raise InputError("Invalid last name length")

    for users in data['users']:
        if users['u_id'] == user['u_id']:
            users['name_first'] = name_first
            users['name_last'] = name_last

    return {}
Ejemplo n.º 10
0
def channels_listall(token):
    """
    channels_listall

    Args:
        token: authorises user

    Returns:
        a dictionary of all channels that exist and their information
    """

    token_validator(token)

    all_channels = []
    for channels in data['channels']:
        list_channel = channels
        list_channel_copy = list_channel.copy()
        all_channels.append(list_channel_copy)

    return {'channels': all_channels}
Ejemplo n.º 11
0
def auth_logout(token):
    '''
    auth_logout

    Args: 
        token: user token for the session 

    Returns:
        a dictionary containing 'is_success': their token  
    
    Raises:
        AccessError when token is invalid
    '''

    # since token_validator may raise error, need to catch it and return false when hapens
    try:
        token_validator(token)
    except AccessError:
        return {'is_success': False}

    return {'is_success': True}
Ejemplo n.º 12
0
def thread_standup(token, channel_id, length):
    # Creates a class which will buffer all messages
    standup.reset_standup_queue()

    # Pauses this thread until standup finishes executing
    time.sleep(length)

    # When standup time finishes, send all standup messages into a message
    packed_message = standup.get_packed_message()

    # Get target channel
    channel = None
    for channels in data['channels']:
        if channels['channel_id'] == channel_id:
            channel = channels

    # If standup is empty then don't send a standup message
    if not packed_message:
        # time_finish is reset after the channel standup is done
        channel['time_finish'] = None

        return
    
    # message_send is not used as the check for the message length needs to be ignored
    # since the packed message contains 'unecessary characters' such as the handle_str
    sender = token_validator(token)
    message_id = data['message_counter']

    # time_finish is reset after the channel standup is done
    channel['time_finish'] = None

    # Append standup message into the data
    data['message_counter'] += 1
    channel['messages'].append({
        'message_id': message_id, 
        'u_id': sender['u_id'], 
        'message': packed_message, 
        'time_created': get_timestamp(),
        'reacts': [
            {
                'react_id': 0,
                'u_ids': [],
                'is_this_user_reacted': False
            }
        ],
        'is_pinned': False,
    })

    return {
        'message_id': message_id,
    }
Ejemplo n.º 13
0
def message_send(token, channel_id, message):
    '''
    Send a message from authorised_user to the channel specified by channel_id
    '''
    sender = token_validator(token)
    channel_validator(channel_id)

    # Verify that the is under 1000 characters
    if len(message) > 1000:
        raise InputError("Message is more than 1000 characters")
    # Verify that the message is not empty or contains just whitespace
    elif message == "" or message.isspace():
        raise InputError("Message is empty or contains only whitespace")

    # Verify that the sender (token) is in the right channel
    message_id = data['message_counter']
    for channel in data['channels']:
        if channel_id == channel['channel_id']:
            current_time = datetime.utcnow()
            timestamp = int(
                current_time.replace(tzinfo=timezone.utc).timestamp())

            if sender['u_id'] in channel['all_members']:
                # Append message information into the data
                data['message_counter'] += 1
                channel['messages'].append({
                    'message_id':
                    message_id,
                    'u_id':
                    sender['u_id'],
                    'message':
                    message,
                    'time_created':
                    timestamp,
                    'reacts': [{
                        'react_id': 0,
                        'u_ids': [],
                        'is_this_user_reacted': False
                    }],
                    'is_pinned':
                    False,
                })
            else:
                raise AccessError(
                    "The authorised user has not joined the channel \
                                   that they are are trying to post to.")
    return {
        'message_id': message_id,
    }
Ejemplo n.º 14
0
def user_profile(token, u_id):
    '''
    user_profile

    Args:
        token: authorises user
        u_id: identifies user in the flockr
    
    Returns:
        user: information about the user

    Raises:
        InputError when user_id does not refer to a valid user
        AccessError when token is not valid
    '''
    # Validates u_id and token
    u_id_validator(u_id)
    token_validator(token)

    user = {}
    # Finds the corresponding user based of u_id
    for users in data['users']:
        if u_id == users['u_id']:
            user = users

    return {
        'user': {
            'u_id': user['u_id'],
            'email': user['email'],
            'name_first': user['name_first'],
            'name_last': user['name_last'],
            'handle_str': user['handle_str'],
            'permission_id': user['permission_id'],
            'profile_img_url': user['profile_img_url'],
        },
    }
Ejemplo n.º 15
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

    Search Method: locates substrings inside messages using regex function search()
    '''
    owner = token_validator(token)

    if query_str == "" or query_str.isspace():
        raise InputError("Query string is empty or contains whitespace")

    # Assumption: Uppercase and lowercase letters are treated as the same
    query_str = query_str.lower()

    user_messages = []

    for channel in data['channels']:
        # Verify that the user is part of a channel
        if owner['u_id'] in channel['all_members']:
            # Loop through all messages in the channel
            for current in channel['messages']:
                if re.search(query_str, current['message'].lower()):
                    current_message = {
                        'message_id':
                        current['message_id'],
                        'u_id':
                        current['u_id'],
                        'message':
                        current['message'],
                        'time_created':
                        current['time_created'],
                        'reacts': [{
                            'react_id': 0,
                            'u_ids': [],
                            'is_this_user_reacted': False,
                        }],
                        'is_pinned':
                        current['is_pinned'],
                    }
                    user_messages.append(current_message)
        else:
            raise AccessError("The user is not part of any channels")

    if user_messages == []:
        raise InputError("There were no messages found")

    return {'messages': user_messages}
Ejemplo n.º 16
0
def channels_create(token, name, is_public):
    """
    channels_create

    Args:
        token: authorises user
        name: name for new channel
        is_public: determines if new channel will be public or private

    Returns:
        the channel_id of created channel

    Raises:
        InputError when channel length is not within 1 to 20 characters
        InputError when is_public is not equal to True or False
    """

    user = token_validator(token)

    # Check if name is valid
    name_valid = 1 <= len(name) <= 20
    if not name_valid:
        raise InputError("Channel name is not within 1 to 20 characters")

    # Check if is_public is a true or false boolean
    # For example: rejects is_public = 'djaspo' which would normally be True
    if is_public not in (True, False):
        raise InputError("Undefined channel privacy to be public or private")

    # Determine channel_id for this channel
    channel_id = new_channel_id()

    # Input created channel into data
    data['channels'].append({
        'channel_id': channel_id,
        'name': name,
        'owner_members': [user['u_id']],
        'all_members': [user['u_id']],
        'is_public': is_public,
        'time_finish': None,
        'messages': []
    })

    return {'channel_id': channel_id}
Ejemplo n.º 17
0
def channels_list(token):
    """
    channels_list

    Args:
        token: authorises user

    Returns:
        a dictionary of all channels the user is in
    """

    user = token_validator(token)

    users_channels = []
    for channel in data['channels']:
        for users in channel['all_members']:
            if users == user['u_id']:
                users_channels.append(channel)

    return {'channels': users_channels}
Ejemplo n.º 18
0
def user_profile_sethandle(token, handle_str):
    '''
    user_profile_sethandle 

    Args:
        token: authorises user
        handle_str: new handle to be updated 

    Returns: 
        returns {}

    Raises: 
        InputError when handle_str not between 3 and 20 characters
        InputError when handle is already in use by any registered user.
        AccessError when token is not valid
    '''
    # Validating the token of the user and finds corresponding user.
    user = token_validator(token)

    # Checks to see if handle is between 3 and 20 characters.
    if len(handle_str) <= 3:
        raise InputError(
            "The new handle you are updating must be greater than 3 characters."
        )
    if len(handle_str) >= 20:
        raise InputError(
            "The new handle you are updating must be less than than 20 characters."
        )

    # Checks to see if handle is already in use.
    for users in data['users']:
        if handle_str == users['handle_str']:
            raise InputError("The handle you entered is already in use.")

    # Updates the handle to the new handle specified.
    for users in data['users']:
        if users['u_id'] == user['u_id']:
            users['handle_str'] = handle_str

    return {}
Ejemplo n.º 19
0
def message_edit(token, message_id, message):
    # Validate the authorised user
    editor = token_validator(token)
    new_message = message

    # Locate the message to edit by looping through channels then messages
    # If we fix channel_messages and call it, we won't have to loop through.
    message_found = False
    for channel in data["channels"]:
        for curr_message in channel["messages"]:
            # Find the message the user wants to edit
            if curr_message['message_id'] == message_id:
                # Check if user is flockr owner
                # Verify that the user is authorised to edit
                if editor['u_id'] == curr_message['u_id'] or editor[
                        "u_id"] in channel["owner_members"] or is_flockr_owner(
                            token, editor["u_id"]):
                    # Safe to edit the message
                    message_found = True
                    break
                else:
                    raise AccessError(
                        "Sorry, you are neither the owner of the channel or \
                                       creator of the message, you cannot edit the message"
                    )

    if message_found:
        if len(new_message) == 0:
            # The entire message including its details is deleted
            del channel['messages'][message_id]
        else:
            # The message in data is replaced with the new message
            curr_message['message'] = new_message
    else:
        raise AccessError(
            "The message_id does not match the message you are trying to edit."
        )

    return {}
Ejemplo n.º 20
0
def admin_userpermission_change(token, u_id, permission_id):
    """
    admin_userpermission_change

    Helper Modules:
        user_validator: validates if user exists

    Args:
        token: authorises user
        u_id: the targeted user to change permission_id
        permission_id: can only be 1 (owner) and 2 (member)

    Returns:
        Empty dictionary but changes a user's permissions

    Raises:
        InputError when u_id does not refer to a valid user within the channel
        InputError when permission_id is not valid (1 or 2)
        AccessError when the authorised user (token) is not an owner
    """

    # Check if the token is valid
    user = token_validator(token)

    # Check if the u_id is valid
    u_id_validator(u_id)

    # Checks if permission_id is valid
    if permission_id not in (1, 2):
        raise InputError("Permission value has to be 1 or 2")

    # Checks if authorised user is a Flockr owner
    if not is_flockr_owner(token, user['u_id']):
        raise AccessError("The authorised user is not a Flockr owner")

    # Change target u_id's permission_id
    for user in data['users']:
        if user['u_id'] == u_id:
            user['permission_id'] = permission_id
Ejemplo n.º 21
0
def message_react(token, message_id, react_id):
    user = token_validator(token)

    # Locate the message to edit by looping through channels then messages
    # If we fix channel_messages and call it, we won't have to loop through
    valid_message_id = False
    for channel in data['channels']:
        # Check if the user who is reacting to the message in the channel, is actually in the channel
        for current_message in channel['messages']:
            if current_message['message_id'] == message_id:
                valid_message_id = True
                break

    if user['u_id'] not in channel['all_members']:
        raise InputError(
            "The user is not part of the channel, hence, has no permissions")

    if react_id not in (0, 1):
        raise InputError('The react_id for this message is invalid')

    if valid_message_id:
        for react in current_message['reacts']:
            if user['u_id'] not in react['u_ids']:
                # React to the message by calling react_id == 1
                react_id = 1
                react['react_id'] = react_id
                react['u_ids'].append(user['u_id'])
                react['is_this_user_reacted'] = True
            else:
                raise InputError(
                    "The message with ID message_id already has an active react_id by the same user with ID u_id"
                )
    else:
        raise InputError(
            "The message_id does not match the message you are trying to react to"
        )

    return {}
Ejemplo n.º 22
0
def user_profile_uploadphoto(token, img_url, x_start, y_start, x_end, y_end):
    '''
    user_profile_uploadphoto 

    Args:
        token: authorises user.
        img_url: The url of the source image is provided.
        x_start, y_start, x_end, y_end: Image dimensions are specified by the user.

    Returns: 
        returns {}

    Raises:
        AccessError when the token is invalid
        InputError when img_url returns an HTTP status other than 200.
        InputError when any of the parameters are not within the dimensions of the image at the URL.
        InputError when the image uploaded is not a JPG
    '''

    user = token_validator(token)

    # Verify that the img_url is valid
    r = requests.head(img_url)
    valid_url = r.status_code == 200
    if not valid_url:
        raise InputError(
            "The image url returned a HTTP status other than 200.")

    # Verify that the image has JPG format
    image = imgspy.info(img_url)
    if image['type'] == None or image['type'] != 'jpg':
        raise InputError("Image uploaded is not a JPG.")

    # Verify that the parameters are within image dimensions
    # {'type': 'jpg', 'width': 2370, 'height': 1927}
    img_width = range(0, image['width'] + 1)
    img_height = range(0, image['height'] + 1)

    if (x_start in img_width and x_end in img_width and y_start in img_height
            and y_end in img_height):
        print("valid")
    else:
        raise InputError("x_start, y_start, x_end, y_end are not within \
                          the dimensions of the image at the URL.")

    # Generate unique image_id using uuid
    profile_img_url = str(uuid.uuid4())

    # Download and retrieve the image
    profile_image = f"{IMG_LOCATION}/{profile_img_url}.jpg"

    # Move the image into the appropriate directory
    urllib.request.urlretrieve(img_url, profile_image)

    # Crop the image
    imageObject = Image.open(profile_image)
    cropped = imageObject.crop((x_start, y_start, x_end, y_end))
    cropped.save(profile_image)

    # Add image url to the user's data
    for users in data['users']:
        if users['u_id'] == user['u_id']:
            users['profile_img_url'] = profile_img_url + '.jpg'

    return {}
Ejemplo n.º 23
0
def message_sendlater(token, channel_id, message, time_sent):
    '''
    message_sendlater

    Args:
        token: authorises user
        channel_id: the target channel for the message
        message: content of the message
        time_sent: the time at which the message will be sent into the channel
    
    Returns: 
        returns {message_id}

    Raises: 
        InputError when message is more than 1000 characters
        InputError when message is empty
        InputError when channel_id is not a valid channel
        InputError when the time sent is a time in the past
        AccessError when token is not valid
        AccessError when the user has not joined the channel they are trying to post to
    '''
    # Verify that the sender and channels are valid
    sender_u_id = token_validator(token)['u_id']
    channel_validator(channel_id)

    # Find the current time
    current_time = datetime.utcnow()
    current_timestamp = int(
        current_time.replace(tzinfo=timezone.utc).timestamp())

    # Verify that the is under 1000 characters
    if len(message) > 1000:
        raise InputError("Message is more than 1000 characters")
    # Verify that the message is not empty or contains just whitespace
    if message == "" or message.isspace():
        raise InputError("Message is empty or contains only whitespace")
    # Verify that the input time is not in the past
    if time_sent < current_timestamp:
        raise InputError("Scheduled time is in the past")
    # Verify that the user is in the channel
    for channel in data['channels']:
        if channel_id == channel['channel_id']:
            if sender_u_id not in channel['all_members']:
                raise AccessError(
                    "The authorised user has not joined the channel \
                                   that they are are trying to post to.")

    # Assign the message_id to be used for the queued up message
    message_id = data['message_counter']

    # Determine waiting time for the message to be sent
    waiting_time = int(time_sent - current_timestamp)

    # Start the timer to send the message
    delay_message = threading.Timer(
        waiting_time, queue_message,
        [sender_u_id, channel_id, message_id, message, time_sent])

    delay_message.start()

    # Update the message counter for other messages which may be sent
    data['message_counter'] += 1
    return {'message_id': message_id}