Ejemplo n.º 1
0
def channels_listall_v2(token):
    """ 
    Given a user's id, returns a list of all channels and their associated details

    Arguments:
        token (string) - token of a registered user

    Return value:
        { channels }
    """   
    
    # get data
    data = getData()
    
    findUser(token)
    
    # Creates the return list
    channel_list = []
    
    # Iterates through all the channels in the data dictionary
    for channels in data['channels']:

        # Adds the channel to the return list    
        channel_dic = {'channel_id': channels['channel_id'],
                       'name': channels['channel_name']}
        
        channel_list.append(channel_dic)
    
    writeData(data)
        
    return {'channels' : channel_list}
def new_added_notification(token, channel_id, dm_id, u_id):
    '''
    Returns a notification dictionary in the expected format after a user is 
    added to a channel/dm
    
    Arguments:
        token (str) - token of the auth user who added the new user
        channel_id (int) - id of the channel in which it occured
        dm_id (int) - id of the dm in which it occured
        u_id (int) - id of the user being added
        
    Return value:
        {
            'u_id': u_id
            'channel_id': channel_id,
            'dm_id': dm_id,
            'notification_message': message
        }
    '''
    
    database = getData()
    
    auth_user_id = findUser(token)
    user_handle = user_profile_v2(token, auth_user_id)['user']['handle_str']
    
    # Find the channel/dm name given channel/dm id
    src_name = get_channel_dm_name(database, channel_id, dm_id)

    return {
        'u_id': u_id,
        'channel_id': channel_id,
        'dm_id': dm_id,
        'notification_message': create_add_notif(user_handle, src_name)
    }
Ejemplo n.º 3
0
def user_profile_setname_v2(token, name_first, name_last):
    """ 
    Given  valid token and first/last names, changes a registered users name

    Arguments:
        token (string) - valid token associated with a registered user's session
        name_first (string) - first name the user wants to update to
        name_last (string) - last name the user wants to update to

    Exceptions:
        InputError - When either name_first or name_last is not between 1 and 50 characters, inclusive
        AccessError - Occurs if token is invalid


    Return value:
        {}
    """
    #Retrieving data from export.json
    data = getData()
    #Testing for a valid token and finding the associated u_id
    u_id = findUser(token)
    #Checking if the names are of valid length
    if len(name_first) > 50 or len(name_first) < 1:
        raise InputError(description="Length of first name is not valid")
    elif len(name_last) > 50 or len(name_last) < 1:
        raise InputError(description="Length of last name is not valid")
    #Finding the user and changing their names
    for user in data['users']:
        if u_id == user['u_id']:
            user['name_first'] = name_first
            user['name_last'] = name_last
            #Writing data to export.json
            writeData(data)
    return {}
Ejemplo n.º 4
0
def user_profile_uploadphoto_v1(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.
            
    Arguments:
        token (string) - valid token associated with a registered user's session
        img_url (string) - URl to a jpg online
        x_start (int) - indicates leftmost point on image
        y_start (int) - indicates topmost point on image
        x_end (int) - indicates righttmost point on image
        y_end (int) - indicates bottommost point on image
  
    Exceptions:
        InputError - img_url returns an HTTP status other than 200.
        InputError - any of x_start, y_start, x_end, y_end are not within the dimensions of the image at the URL.
        InputError - Image uploaded is not a JPG

    Return value:
        { }
    """
    #Retrieving data from dictionary
    data = getData()
    #Find user id from their token
    u_id = findUser(token)
    #Define URL
    URL = f'{img_url}'
    #Define file path
    fileName = f'src/static/{u_id}.jpg'
    #Trying to open URL, if it fails raise an InputError
    try:
        status = requests.get(URL).status_code
    except:
        status = -1

    if status != 200:
        raise InputError(description='Invalid URL')
    #Raising an error if the URL does not point to a jpg
    if not URL.endswith('.jpg'):
        raise InputError(description='Image is not a jpg')
    #Retrieve the URL abd save the image as fileName
    urllib.request.urlretrieve(URL, fileName)
    #Open the image
    img = Image.open(fileName)
    #Define the size of the image
    width, height = img.size
    #Raising an error if the crop points aren't valid
    if x_start < 0 or y_start < 0 or x_end > width or y_end > height or x_end < x_start or y_end < y_start:
        raise InputError(description='Crop start or end points not valid')
    #Cropping and saving the image
    crop_img = img.crop((x_start, y_start, x_end, y_end))
    crop_img.save(fileName)
    #Changin the user's associated URL to the new image
    for user in data['users']:
        if u_id == user['u_id']:
            user['profile_img_url'] = f'{config.url}/images/{u_id}.jpg'
    #Writing data to dictionary
    writeData(data)
    return {}
Ejemplo n.º 5
0
def message_unreact_v1(token, message_id, react_id):
    '''
    Arguments:
        token (string) - the token of the user who wants to create a channel
        message_id - the id of the message being reacted to
        react_id (int) - the id of the react

    Exceptions:
        InputError - message_id is not a valid message within a channel or DM that the authorised user has joined
        InputError - react_id is not a valid React ID. The only valid react ID the frontend has is 1
        InputError - Message with ID message_id does not contain an active React with ID react_id from the authorised user
        AccessError - The authorised user is not a member of the channel or DM that the message is within

    Return value:
        Returns {}
    '''

    # get data
    data = getData()

    # get id
    auth_user_id = findUser(token)

    # Gets message
    msg = get_message(message_id, data)

    # Message does not exist (has been removed or invalid message_id passed in)
    if msg == -1:
        raise InputError("Message is not a valid.")

    # Gets message key
    msg_key = data['messages'].index(msg)

    # Gets list of dictionary containing all the reacts for that message
    react_list = data['messages'][msg_key]['reacts']

    # Checks react id is valid and in use already
    if react_id != 1:
        raise InputError("React ID is not valid.")
    elif not has_user_reacted(auth_user_id, react_id, react_list, data):
        raise InputError("User has not already reacted with this react.")

    # Checks the user is part of the channel/dm
    check_user_permissions(data, msg_key, auth_user_id)

    # Remove/update react
    react_key = get_react(react_id, react_list, msg_key, data)
    data['messages'][msg_key]['reacts'][react_key]['u_ids'].remove(
        auth_user_id)
    if data['messages'][msg_key]['reacts'][react_key]['u_ids'] == []:
        data['messages'][msg_key]['reacts'].remove({
            'react_id': react_id,
            'u_ids': []
        })

    writeData(data)

    return {}
Ejemplo n.º 6
0
def channel_leave_v1(token, channel_id):
    """Given channel id, removes an authorised user from that channel.

    Arguments:
        token (string)              - token of an authenticated user
        channel_id (integer)        - id of channel to leave

    Exceptions:
        InputError  - Occurs when channel_id is not a valid channel
                    - Occurs when the last owner tries to leave
        AccessError - Occurs when token refers to a user who is not
                      a member of the channel
                    - Occurs when token is not a valid

    Return value:
        {}
    """

    # Load .json data store
    data_store = getData()

    # Check validity of channel_id
    ch_index = check_validity(data_store["channels"], channel_id, "channel_id",
                              INVALID_CHANNEL_ID)
    ch_src = data_store["channels"][ch_index]

    # Check validity of token
    u_index = findUser(token) - 1
    u_src = data_store["users"][u_index]

    # Check user is actually a member
    if not is_member(ch_src, u_src):
        raise AccessError(description="user is not a member of this channel.")

    # Check not last owner
    owner = is_owner(ch_src, u_src)
    if owner and len(ch_src["owner_members"]) == 1:
        raise InputError(description="last owner cannot leave the channel.")

    # Remove user from *_members
    user_remove = {
        "u_id": u_src["u_id"],
        "name_first": u_src["name_first"],
        "name_last": u_src["name_last"],
        "email": u_src["email"],
        "handle_str": u_src["handle_str"],
        "profile_img_url": u_src["profile_img_url"],
    }
    if owner:
        ch_src["owner_members"].remove(user_remove)
    ch_src["all_members"].remove(user_remove)

    append_user_stats(findUser(token), data_store)
    append_dream_stats(findUser(token), data_store)

    writeData(data_store)

    return {}
Ejemplo n.º 7
0
def admin_userpermission_change_v1(token, u_id, permission_id):
    """
    Given a User by their user ID, set their permissions to new permissions
    described by permission_id.

    Arguments:
        token (str)          - token passed in to the function
        u_id (int)           - id of user to change permission of
        permission_id (int)  - new permission id

    Exceptions:
        AccessError - when token passed in is not a valid id
        InputError  - when u_id does not refer to a valid user
        InputError  - when permission_id does not refer to a valid permission
        AccessError - when authorised user is not an owner

    Return value:
        {}
    """

    data_store = getData()

    # Check for exceptions
    # validate token
    auth_user_id = findUser(token)

    # check if u_id is a valid user, and also get index of position if valid
    valid = False
    for user_index, user in enumerate(data_store["users"]):
        if user["u_id"] == u_id:
            valid = True
            break

    if not valid:
        raise InputError(description="u_id does not refer to a valid user")

    # Check permission_id is valid
    if permission_id != 1 and permission_id != 2:
        raise InputError(description="Invalid permission_id")

    # Check if authorised user is an owner (with permission 1)
    for user in data_store["users"]:
        if user["u_id"] == auth_user_id:
            if user["permission_id"] != 1:
                raise AccessError(description="Authorised user is not an owner.")

    # Cannot change permission to permission_id 2 if there is only one
    # owner remaining in Dreams
    if permission_id == 2:
        if get_dream_owners_count(data_store) > 1:
            data_store["users"][user_index]["permission_id"] = permission_id
    else:
        data_store["users"][user_index]["permission_id"] = permission_id

    writeData(data_store)

    return {}
Ejemplo n.º 8
0
def message_edit_v2(token, message_id, message):
    '''
    Arguments:
        token (string) - the token of the user who wants to create a channel
        message_id (int) - the id of the message being edited
        message (string) - the new message

    Exceptions:
        InputError - Message is more than 1000 characters or the message id refers to a deleted message
        AccessError - The authorised user has not joined the channel they are trying to post to

    Return value:
        Returns {}
    '''

    # get data
    data = getData()

    # get id
    auth_user_id = findUser(token)

    # Checks that the length is not above 1000 characters
    if len(message) > 1000:
        raise InputError(
            description="Message must be less than 1000 characters")

    # Finds the message
    msg = get_message(message_id, data)

    if msg == -1:
        raise AccessError(description="Message does not exist")

    # Checks the message was sent by the user requesting to edit it or
    # the user is a channel owner
    if msg['u_id'] != auth_user_id and get_user_details(
            auth_user_id, data)['permission_id'] != 1:
        raise AccessError(
            description=
            "User requesting edit did not post message or not channel owner")

    # Delete the message if message is empty, updates the message if it isn't
    if message == '':
        remove_msg_from_channel_or_dm(data, msg)
    else:
        msg_key = data['messages'].index(msg)
        data['messages'][msg_key]['message'] = message

    # Sends notification
    send_msg_notification(data, token, message, msg['channel_id'],
                          msg['dm_id'], False, -1)

    append_user_stats(findUser(token), data)
    append_dream_stats(findUser(token), data)

    writeData(data)

    return {}
Ejemplo n.º 9
0
def message_senddm_v1(token, dm_id, message):
    '''
    Arguments:
        token (string) - the token of the user who wants to create a channel
        dm_id (int) - the id of the dm the message is being sent to
        message (string) - the message being sent

    Exceptions:
        InputError - Message is more than 1000 characters
        AccessError - The authorised user has not joined the dm they are trying to post to

    Return value:
        Returns {'message_id': message_id}
    '''

    # get data
    data = getData()

    # get id
    auth_user_id = findUser(token)

    # Checks the message is not more than 1000 characters
    if len(message) > 1000:
        raise InputError(
            description="Message must be less than 1000 characters")

    # Checks the auth_user_id is part of the dm
    dm_members = get_dm_members(dm_id, data)
    if auth_user_id not in dm_members:
        raise AccessError(description="User not in DM being posted to")

    # Get new message id
    new_message_id = get_new_message_id(data)

    # Adds message to data dictionary
    add_data(data, new_message_id, auth_user_id, -1, dm_id, message,
             int(time.time()), [], False)

    # Adds message to dm
    for dm in data['dms']:
        if dm_id == dm['dm_id']:
            dm['message_ids'].append(new_message_id)

    # Sends notification
    send_msg_notification(data, token, message, -1, dm_id, False, -1)

    append_user_stats(findUser(token), data)
    append_dream_stats(findUser(token), data)

    # Adds message to dm and makes notification
    writeData(data)

    return {
        'message_id': new_message_id,
    }
Ejemplo n.º 10
0
def channel_join_v2(token, channel_id):
    """Given channel id, adds an authorised user to that channel.

    Arguments:
        token (string)              - token of an authenticated user
        channel_id (integer)        - id of channel to be joined

    Exceptions:
        InputError  - Occurs when channel_id is not a valid channel
        AccessError - Occurs when channel_id refers to private channel
                      and user is not a global owner
                    - Occurs when token is not a valid id

    Return value:
        {}
    """

    # Load .json data store
    data_store = getData()

    # Check validity of channel_id
    ch_index = check_validity(data_store["channels"], channel_id, "channel_id",
                              INVALID_CHANNEL_ID)
    ch_src = data_store["channels"][ch_index]

    # Check validity of token
    u_id = findUser(token)
    for user in data_store["users"]:
        if user["u_id"] == u_id:
            u_src = user

    # Check permissions of channel and user
    u_permission = u_src["permission_id"]

    if not ch_src["is_public"] and u_permission != 1:
        raise AccessError(description="Can't join a private channel")

    # Add user to the channel
    user_add = {
        "u_id": u_src["u_id"],
        "name_first": u_src["name_first"],
        "name_last": u_src["name_last"],
        "email": u_src["email"],
        "handle_str": u_src["handle_str"],
        "profile_img_url": u_src["profile_img_url"],
    }
    ch_src["all_members"].append(user_add)

    append_user_stats(findUser(token), data_store)
    append_dream_stats(findUser(token), data_store)

    writeData(data_store)

    return {}
Ejemplo n.º 11
0
def user_profile_v2(token, u_id):
    """ 
    Given  valid token and u_id, returns information regarding the user with u_id 'u_id'

    Arguments:
        token (string) - valid token associated with a registered user's session
        u_id (int) - user id associated with a registered user

    Exceptions:
        InputError - Occurs when u_id is not associated with a valid user
        AccessError - Occurs if token is invalid


    Return value:
        {'user' : {'u_id' : u_id, 
                   'email' :email,
                   'name_first' : name_first,
                   'name_last' : name_last,
                   'handle_str' : handle_str,} 
        }
    """
    #Retrieving data from export.json
    data = getData()
    #Testing for a valid token
    findUser(token)
    #Cycling through all users to find the user with user id u_id
    for user in data['users']:
        if u_id == user['u_id']:
            #Returning the users information
            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'],
                    'profile_img_url': user['profile_img_url']
                },
            }
    #Repeating the process with 'removed_users' to assist in other functions
    for user in data['removed_users']:
        if u_id == user['u_id']:
            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'],
                    'profile_img_url': user['profile_img_url']
                },
            }
    #Raising an input error if the user could not be found
    raise InputError(description="User with u_id is not a valid user")
Ejemplo n.º 12
0
def send_msg_notification(data, token, message, channel_id, dm_id,
                          is_sendlater, new_message_id):
    if (is_sendlater):
        data = getData()
        if dm_id == -1:
            # Append message to channel messages
            for channel in data["channels"]:
                if channel_id == channel["channel_id"]:
                    channel["messages"].append(new_message_id)
        else:
            # Append message to dm messages
            for dm in data["dms"]:
                if dm_id == dm["dm_id"]:
                    dm["message_ids"].append(new_message_id)

    words = message.split()
    handle_list = []
    for word in words:
        if word[0] == '@':
            word = word.replace(',', '')
            handle_list.append(word[1:])

    u_id = -1
    handle_status = False
    member_status = False
    for handle in handle_list:
        u_id = -1
        handle_status = False
        member_status = False
        for user in data['users']:
            if handle == user['handle_str']:
                handle_status = True
                u_id = user['u_id']

        if dm_id == -1:
            channel_ids = {'channel_id': channel_id}
            channel = get_channel_details(channel_ids, data)
            for members in channel['all_members']:
                if u_id == members['u_id']:
                    member_status = True
        else:
            dm_ids = {'dm_id': dm_id}
            dm = get_dm_details(dm_ids, data)

            if u_id in dm['dm_members']:
                member_status = True

        if handle_status == True and member_status == True:
            user_notification = new_tagged_notification(
                token, channel_id, dm_id, u_id, message)
            data['user_notifications'].append(user_notification)

    writeData(data)
Ejemplo n.º 13
0
def channel_details_v2(token, channel_id):
    """
    Given a Channel with ID channel_id that the authorised user is part of,
    provide basic details about the channel.

    Arguments:
        token (str)           - token passed in to the function
        channel_id (int)      - channel_id of the channel to show details of

    Exceptions:
        InputError  - Occurs when channel ID is not a valid channel.
        AccessError - Occurs when token does not refer to a valid user.
        AccessError - Occurs when authorised user is not a member of channel
                      with channel_id.

    Return Value:
        Returns a dictionary { name, owner_members, all_members } on successful
        call.

    """

    database = getData()

    auth_user_id = findUser(token)

    # Check for exceptions
    channel_index = check_validity(database["channels"], channel_id,
                                   "channel_id", INVALID_CHANNEL_ID)

    channel_src = database["channels"][channel_index]

    check_validity(channel_src["all_members"], auth_user_id, "u_id",
                   UNAUTHORISED_AUTH_U_ID)

    # Copy details from "database" to empty dictionaries
    owner_members_list = []
    all_members_list = []

    owner_members_list = copy_channel_member_details(
        channel_src["owner_members"], owner_members_list, database)
    all_members_list = copy_channel_member_details(channel_src["all_members"],
                                                   all_members_list, database)

    # Create and return a dictionary with copied data
    channel_details = {
        "name": channel_src.get("channel_name"),
        "owner_members": owner_members_list,
        "all_members": all_members_list,
    }

    return channel_details
Ejemplo n.º 14
0
def message_remove_v1(token, message_id):
    '''
    Arguments:
        token (string) - the token of the user who wants to create a channel
        message_id (int) - the id of the message being removed

    Exceptions:
        InputError - Message id no longer exists
        AccessError - User did not send message and is not an owner of the channel/dm or dreams

    Return value:
        Returns {}
    '''

    # get data
    data = getData()

    # get id
    auth_user_id = findUser(token)

    # Checks the message was sent by the user requesting to edit it or
    # the user is a channel owner
    msg = get_message(message_id, data)

    if msg == -1:
        raise AccessError(description="Message does not exist")

    chan_owners = []
    if msg['channel_id'] != -1:
        chan = get_channel_details(msg, data)
        chan_owners = get_channel_owners(chan['channel_id'], data)

    if msg['u_id'] != auth_user_id and get_user_details(
            auth_user_id,
            data)['permission_id'] != 1 and auth_user_id not in chan_owners:
        raise AccessError(
            description=
            "User requesting edit did not post message or not channel/DREAMS owner"
        )

    # Remove from channels/dms list
    remove_msg_from_channel_or_dm(data, msg)

    append_user_stats(findUser(token), data)
    append_dream_stats(findUser(token), data)

    writeData(data)

    return {}
Ejemplo n.º 15
0
def users_stats(token):
    """ 
    Fetches the required statistics about the use of UNSW Dreams
        
    Arguments:
        token (string) - valid token associated with a registered user's session

  
    Return value:
        { dreams_stats }
    """
    #Retreive data
    data = getData()
    #Retrieve and return dreams stats
    return {'dreams_stats': data['dream_stats']}
def new_react_notification(token, channel_id, dm_id, u_id):
    database = getData()
    
    auth_user_id = findUser(token)
    user_handle = user_profile_v2(token, auth_user_id)['user']['handle_str']
    
    # Find the channel/dm name given channel/dm id
    src_name = get_channel_dm_name(database, channel_id, dm_id)    

    return {
        'u_id': u_id,
        'channel_id': channel_id,
        'dm_id': dm_id,
        'notification_message': create_react_notif(user_handle, src_name)
    }
def notifications_get_v1(token):
    """
    Return the user's most recent 20 notifications
    
    Arguments:
        token (str) - token passed in to the function
    
    Exceptions:
        AccessError - when the token passed in is not a valid id
    
    Return value:
        {notifications} - a list of dictionaries, where each dictionary contains
                          types { channel_id, dm_id, notification_message }
                          where channel_id is the id of the channel that the
                          event happened in, and is -1 if it is being sent to a
                          DM. dm_id is the DM that the event happened in, and is
                          -1 if it is being sent to a channel. The list should
                          be ordered from most to least recent.
                          Notification_message is a string of the following
                          format for each trigger action:
                            tagged: "{User’s handle} tagged you in
                                     {channel/DM name}: {first 20 characters
                                     of the message}"
                            added to a channel/DM: "{User’s handle} added you to
                                                    {channel/DM name}"
    """

    auth_user_id = findUser(token)

    database = getData()

    # Extract all notifications relating to the concerned user from database, and
    # format each to expected "notifications type" as defined in the spec
    user_notifications_list = []

    for user_notification in database['user_notifications']:
        if user_notification['u_id'] == auth_user_id:
            formatted_notification = {
                'channel_id': user_notification['channel_id'],
                'dm_id': user_notification['dm_id'],
                'notification_message': user_notification['notification_message']
            }
            user_notifications_list.append(formatted_notification)
            
    # Reverse the user_notifications_list to get the reversed chronological order,
    # and return the 20 most recent notifications
    user_notifications_list.reverse()
    return {'notifications': user_notifications_list[0:20]}
Ejemplo n.º 18
0
def message_unpin_v1(token, message_id):
    '''
    Arguments:
        token (string) - the token of the user who wants to create a channel
        message_id - the id of the message being pinned

    Exceptions:
        InputError - message_id is not a valid message
        InputError - Message with ID message_id is already unpinned
        AccessError - The authorised user is not a member of the channel or DM that the message is within or the authorised user is not an owner of the channel or DM

    Return value:
        Returns {}
    '''

    # get data
    data = getData()

    # get id
    auth_user_id = findUser(token)

    # Gets message
    msg = get_message(message_id, data)

    # Message does not exist (has been removed or invalid message_id passed in)
    if msg == -1:
        raise InputError("Message is not a valid.")

    # Gets message key
    msg_key = data['messages'].index(msg)

    # Checks if message is already unpinned
    if not data['messages'][msg_key]['is_pinned']:
        raise InputError("Message is already unpinned.")

    # Checks the user is part of/an owner of the channel/dm
    check_user_owners_permissions(data, msg_key, auth_user_id)

    # Add pin
    data['messages'][msg_key]['is_pinned'] = False

    writeData(data)

    return {}
Ejemplo n.º 19
0
def users_all_v1(token):
    """ 
    Given  valid token, returns a list of all users and their associated details

    Arguments:
        token (string) - valid token associated with a registered user's session

    Exceptions:
        AccessError - Occurs if token is invalid


    Return value:
        { 'users' : [ user' : {'u_id' : u_id, 
                               'email' :email,
                               'name_first' : name_first,
                               'name_last' : name_last,
                               'handle_str' : handle_str,} 
                    ]
        }
    """
    #Retrieving data from export.json
    data = getData()
    #Checking for invalid token
    findUser(token)
    #Creating a user list
    user_list = []
    #Appending every user's info to the user_list
    for user in data['users']:
        info = {
            'u_id': user['u_id'],
            'email': user['email'],
            'name_first': user['name_first'],
            'name_last': user['name_last'],
            'handle_str': user['handle_str'],
            'profile_img_url': user['profile_img_url']
        }
        user_list.append(info)
    #Returning a dictionary with user_list
    return {
        'users': user_list,
    }
Ejemplo n.º 20
0
def user_profile_sethandle_v1(token, handle_str):
    """ 
    Given  valid token and handle, changes a registered users handle

    Arguments:
        token (string) - valid token associated with a registered user's session
        handle (string) - handle the user wants to update to


    Exceptions:
        InputError - Occurs if the handle is not between 3 and 20 characters, inclusive
        InputError - Occurs if the handle is already in use
        AccessError - Occurs if token is invalid


    Return value:
        {}
    """
    #Retrieving data from export.json
    data = getData()
    #Checking for an invalid token
    u_id = findUser(token)
    #Checking for @ and whitespace - as per the assumption in assumptions.md
    if handle_str.find('@') != -1:
        raise InputError(description="Handle cannot contain '@' symbol")
    elif handle_str.find(' ') != -1:
        raise InputError(description="Handle cannot contain whitespace")
    #Checking if the handle is of valid length
    elif len(handle_str) > 20 or len(handle_str) < 3:
        raise InputError(description="Length of handle is not valid")
    #Checking if the handle is in use
    for user in data['users']:
        if handle_str == user['handle_str']:
            raise InputError(description='Handle is already in use')
    #Changing the given users handle
    for user in data['users']:
        if u_id == user['u_id']:
            user['handle_str'] = handle_str
            #Writing data to export.json
            writeData(data)
    return {}
Ejemplo n.º 21
0
def user_stats(token):
    """ 
    Fetches the required statistics about this user's use of UNSW Dreams
    
    Arguments:
        token (string) - valid token associated with a registered user's session

  
    Return value:
        { users_stats }
    """
    #Retrieving data
    data = getData()
    #Finding a users id from their token
    u_id = findUser(token)
    #Retrieving total channel, dm and message counts for involvement rate calculation
    total_channel_count = data['dream_stats']['channels_exist'][-1][
        'num_channels_exist']
    total_dm_count = data['dream_stats']['dms_exist'][-1]['num_dms_exist']
    total_message_count = data['dream_stats']['messages_exist'][-1][
        'num_messages_exist']
    total_count = total_message_count + total_dm_count + total_channel_count

    #For the provided user, retrieve their personal message, channel and dm counts whilst also calculating their involvement rate
    for user in data['users']:
        if u_id == user['u_id']:
            message_count = user['user_stats']['messages_sent'][-1][
                'num_messages_sent']
            channel_count = user['user_stats']['channels_joined'][-1][
                'num_channels_joined']
            dm_count = user['user_stats']['dms_joined'][-1]['num_dms_joined']
            if total_count != 0:
                involve_rate = (message_count + dm_count +
                                channel_count) / total_count
            else:
                involve_rate = 0
            user['user_stats']['involvement_rate'] = involve_rate
            stat_data = user['user_stats']

    return {'user_stats': stat_data}
Ejemplo n.º 22
0
def user_profile_setemail_v2(token, email):
    """ 
    Given  valid token and email, changes a registered users email

    Arguments:
        token (string) - valid token associated with a registered user's session
        email (string) - email the user wants to update to


    Exceptions:
        InputError - Occurs if the email is not of valid formation
        InputError - Occurs if the email is already in use
        AccessError - Occurs if token is invalid


    Return value:
        {}
    """
    #Retrieving data from export.json
    data = getData()
    #Checking for an invalid token
    u_id = findUser(token)
    #Checking if the inputted email is valid
    if check_email(email) == False:
        raise InputError(description='Invalid email')
    #Checking if the email is already in use
    for user in data['users']:
        if email == user['email']:
            raise InputError(description='Email address is already in use')
    #Changing the given users email
    for user in data['users']:
        if u_id == user['u_id']:
            user['email'] = email
            #Writing data to export.json
            writeData(data)
    return {}
Ejemplo n.º 23
0
def channels_list_v2(token):
    """ 
    Given a user's token, returns a list of all channels and their associated details that the user is in

    Arguments:
        token (string) - token of a registered user

    Return value:
        { channels }
    """
    
    # get data
    data = getData()
    
    # get user id
    auth_user_id = findUser(token)
    
    # Creates the return list
    channel_list = []
    
    # Iterates through all the channels in the data dictionary
    for channels in data['channels']:
        
        # Checks if the user is a member in the channel
        for users in channels['all_members']:
            if auth_user_id == users['u_id']:
            
                # If member - adds the channel details to the return list
                channel_dic = {'channel_id': channels['channel_id'],
                               'name': channels['channel_name']}
                
                channel_list.append(channel_dic)
          
    writeData(data)
            
    return {'channels' : channel_list}
Ejemplo n.º 24
0
def channel_removeowner_v1(token, channel_id, u_id):
    """Given channel id, removes u_id from owners of the channel.

    Arguments:
        token (string)              - token of an authenticated user who is
                                      either an owner of the channel or a global owner
        channel_id (integer)        - id of channel with ownership
        u_id (integer)              - id of user to be removed of channel ownership

    Exceptions:
        InputError  - Occurs when channel_id is not a valid channel
                    - Occurs when u_id refers to a user who is not an owner
                    - Occurs when u_id is currently the only owner
        AccessError - Occurs when token refers to a user who is not a global owner
                      or an owner of the target channel
                    - Occurs when token is not valid

    Return value:
        {}
    """

    # Load .json data store
    data_store = getData()

    # Check validity of channel_id
    ch_index = check_validity(data_store["channels"], channel_id, "channel_id",
                              INVALID_CHANNEL_ID)
    ch_src = data_store["channels"][ch_index]

    # Check validity of token
    token_index = findUser(token) - 1
    token_src = data_store["users"][token_index]

    # Check validity of u_id
    u_index = check_validity(data_store["users"], u_id, "u_id", INVALID_U_ID)
    u_src = data_store["users"][u_index]

    # Check user to be removed of ownership is actually an owner
    if not is_owner(ch_src, u_src):
        raise InputError(description="user is not an owner of this channel.")

    # Check token user is either global owner or an owner of the channel
    token_permission = token_src["permission_id"]
    if token_permission != 1 and not is_owner(ch_src, token_src):
        raise AccessError(
            description="token does not have permission to remove owner.")

    # Check user is not the only owner
    if len(ch_src["owner_members"]) == 1:
        raise InputError(description="user is the only owner remaining.")

    # Remove user from owner_members
    owner_remove = {
        "u_id": u_src["u_id"],
        "name_first": u_src["name_first"],
        "name_last": u_src["name_last"],
        "email": u_src["email"],
        "handle_str": u_src["handle_str"],
        "profile_img_url": u_src["profile_img_url"],
    }
    ch_src["owner_members"].remove(owner_remove)

    append_user_stats(u_id, data_store)
    append_dream_stats(u_id, data_store)

    writeData(data_store)

    return {}
Ejemplo n.º 25
0
def message_sendlater_v1(token, channel_id, message, time_sent):
    ''' Send a message from authorised user to the channel, 
    automatically at a specified time in the future

    Arguments:
        token (string)              - token of an authenticated user
                                      who is part of the channel
        channel_id (integer)        - id of channel to send message in
        message (string)            - actual message content
        time_sent (integer)         - unix timestamp of when message will be sent
    
    Exceptions:
        InputError  - Occurs when channel_id is not a valid channel
                    - Occurs when message is more than 1000 characters
                    - Occurs when time_sent before current time
        AccessError - Occurs when authorised user is not a member of channel
                    - Occurs when token is not valid

    Return value:
        {
            message_id
        }
    '''
    current_time = int(time.time())

    # Load .json data store
    data_store = getData()

    # Check validity of channel_id
    check_validity(data_store["channels"], channel_id, "channel_id", 0)

    # Check message is less than 1000 characters
    if len(message) > 1000:
        raise InputError(
            description="Message must be less than 1000 characters")

    # Check time_sent is in the future
    if time_sent < current_time:
        raise InputError(description="Cannot send a message in the past")

    # Get user from token and check they are member of channel
    u_id = findUser(token)
    channel_members = get_channel_members(channel_id, data_store)
    if u_id not in channel_members:
        raise AccessError(description="User not in channel!")

    # Get new message_id
    new_message_id = get_new_message_id(data_store)

    # Add message to data_store
    add_data(data_store, new_message_id, u_id, channel_id, -1, message,
             time_sent, [], False)

    # Set up thread to send message in channel later
    if (time_sent == current_time):
        # Append message to channel messages
        for channel in data_store["channels"]:
            if channel_id == channel["channel_id"]:
                channel["messages"].append(new_message_id)
        send_msg_notification(data_store, token, message, channel_id, -1,
                              False, new_message_id)
    else:
        sendlater_thread = Timer(time_sent - current_time,
                                 send_msg_notification,
                                 args=[
                                     data_store, token, message, channel_id,
                                     -1, True, new_message_id
                                 ])
        sendlater_thread.start()

    append_user_stats(findUser(token), data_store)
    append_dream_stats(findUser(token), data_store)

    writeData(data_store)

    return {"message_id": new_message_id}
Ejemplo n.º 26
0
def admin_user_remove_v1(token, u_id):
    """
    Given a User by their user ID, remove the user from the Dreams. Dreams
    owners can remove other **Dreams** owners (including the original first
    owner). Once users are removed from **Dreams**, the contents of the messages
    they sent will be replaced by 'Removed user'. Their profile must still be
    retrievable with user/profile/v2, with their name replaced by 'Removed user'

    Arguments:
        token (str) - token passed in to the function
        u_id (int)  - id of user to remove

    Exceptions:
        AccessError - when token passed in is not a valid id
        InputError  - when u_id does not refer to a valid user
        InputError  - when the user is currently the only owner
        AccessError - when the authorised user is not an owner

    Return value:
        {}
    """

    data_store = getData()

    # Check for exceptions
    # validate token
    auth_user_id = findUser(token)

    # check if u_id is a valid user, and also get index of position if valid
    valid = False
    for user_index, user in enumerate(data_store["users"]):
        if user["u_id"] == u_id:
            valid = True
            break

    if not valid:
        raise InputError(description="u_id does not refer to a valid user")

    # Check if authorised user is an owner (with permission 1)
    for user in data_store["users"]:
        if user["u_id"] == auth_user_id:
            if user["permission_id"] != 1:
                raise AccessError(description="Authorised user is not an owner.")
            break

    # Check if the user is currently the only owner
    if get_dream_owners_count(data_store) == 1 and auth_user_id == u_id:
        raise InputError(description="user is currently the only owner.")

    # Move user dictionary from users list to removed_users list
    data_store["removed_users"].append(data_store["users"][user_index])
    del data_store["users"][user_index]

    # Remove user from all channels
    for channel in data_store["channels"]:
        for member in channel["all_members"]:
            if member["u_id"] == u_id:
                channel["all_members"].remove(member)
                break
        for owner in channel["owner_members"]:
            if owner["u_id"] == u_id:
                channel["owner_members"].remove(owner)
                break

    # Remove user from all dms
    for dm in data_store["dms"]:
        for member in dm["dm_members"]:
            if member == u_id:
                dm["dm_members"].remove(member)
                break

    # Replace name of user with "Removed user", and also clear token and
    # session lists
    removed_user_index = len(data_store["removed_users"]) - 1
    removed_user_profile = data_store["removed_users"][removed_user_index]

    removed_user_profile["name_first"] = "Removed user"
    removed_user_profile["name_last"] = ""
    removed_user_profile["token_list"] = []
    removed_user_profile["sessions_lists"] = []

    # Replace the contents that the user sent with "Removed user"
    for user_message in data_store["messages"]:
        if user_message["u_id"] == u_id:
            user_message["message"] = "Removed user"

    writeData(data_store)

    return {}
Ejemplo n.º 27
0
def channel_addowner_v1(token, channel_id, u_id):
    """Given channel id, makes a u_id owner of that channel.

    Arguments:
        token (string)              - token of an authenticated user who is
                                      either an owner of the channel or a global owner
        channel_id (integer)        - id of channel for ownership
        u_id (integer)              - id of user to be granted ownership of channel

    Exceptions:
        InputError  - Occurs when channel_id is not a valid channel
                    - Occurs when u_id refers to a user who is already an owner
        AccessError - Occurs when token refers to a user who is not a global owner
                      or an owner of the target channel
                    - Occurs when token is not valid

    Return value:
        {}
    """

    # Load .json data store
    data_store = getData()

    # Check validity of channel_id
    ch_index = check_validity(data_store["channels"], channel_id, "channel_id",
                              INVALID_CHANNEL_ID)
    ch_src = data_store["channels"][ch_index]

    # Check validity of token
    token_index = findUser(token) - 1
    token_src = data_store["users"][token_index]

    # Check validity of u_id
    u_index = check_validity(data_store["users"], u_id, "u_id", INVALID_U_ID)
    u_src = data_store["users"][u_index]

    # Check user to be added is not already an owner
    if is_owner(ch_src, u_src):
        raise InputError(
            description="user is already an owner of this channel.")

    # Check token user is either global owner
    # or an owner of the channel
    token_permission = token_src["permission_id"]
    if token_permission != 1 and not is_owner(ch_src, token_src):
        raise AccessError(
            description="token does not have permission to add owner")

    # Add user to owner_members
    owner_add = {
        "u_id": u_src["u_id"],
        "name_first": u_src["name_first"],
        "name_last": u_src["name_last"],
        "email": u_src["email"],
        "handle_str": u_src["handle_str"],
        "profile_img_url": u_src["profile_img_url"],
    }
    ch_src["owner_members"].append(owner_add)

    # If user was not originally member of channel,
    # add them to all_members too
    if not is_member(ch_src, u_src):
        ch_src["all_members"].append(owner_add)

        # Create a notification for the added user
        user_notification = new_added_notification(token, channel_id, -1, u_id)
        data_store["user_notifications"].append(user_notification)

    append_user_stats(u_id, data_store)
    append_dream_stats(u_id, data_store)

    writeData(data_store)

    return {}
Ejemplo n.º 28
0
def channels_create_v2(token, name, is_public):
    '''
    Arguments:
        token (string) - the token of the one who wants to create a channel
        name (string) - the name of the channel which is going to be created
        is_public (boolean) - whether the channel is public or private

    Exceptions:
        Inputerror - occur when the name of channel is larger than 20 characters
        Accesserror - occur when the token is not valid or hasn't been registered.

    Return value:
        Returns {'channel_id': } when there is no exception being raised
    '''
    
    data = getData()
    auth_user_id = findUser(token)
    
    if len(name) > 20:
        raise InputError(description="Name too long.")
    else:
        new_channel_id = len(data['channels']) + 1
        name_last = data['users'][auth_user_id - 1]['name_last']
        name_first = data['users'][auth_user_id - 1]['name_first']
        email = data['users'][auth_user_id - 1]['email']
        handle_str = data['users'][auth_user_id - 1]['handle_str']

        is_active = False
        stand_up_finished_time = 0
        stand_up_length = 0

        data['channels'].append({  
            'channel_id': new_channel_id,  
            'channel_name' : name,      
            'all_members':  [{
                                'u_id':auth_user_id,
                                'name_last': name_last,
                                'name_first': name_first,
                                'email': email,
                                'handle_str': handle_str,
                                'profile_img_url' : data['users'][auth_user_id - 1]['profile_img_url'],

                            },],   
            'owner_members':[{
                                'u_id':auth_user_id,
                                'name_last': name_last,
                                'name_first': name_first,
                                'email': email,
                                'handle_str': handle_str,
                                'profile_img_url' : data['users'][auth_user_id - 1]['profile_img_url'],

                            },],
            'is_public' : is_public,
            'standup': {        
                                'is_active': is_active,
                                'messages':"",
                                'time_finish': stand_up_finished_time,
                                'stand_up_length': stand_up_length,
                        },

            'messages' : [],
        })

        append_user_stats(auth_user_id, data)
        append_dream_stats(auth_user_id, data)  
    
        writeData(data)
    
        return {
            'channel_id': new_channel_id,
        }
Ejemplo n.º 29
0
def channel_messages_v2(token, channel_id, start):
    """Given channel id, return up to 50 messages

    Arguments:
        token (string)              - token of an authenticated user who is
                                      part of the channel
        channel_id (integer)        - id of channel where messages come from
        start (integer)             - starting index (counting backwards, most
                                      recent messages returned first)

    Exceptions:
        InputError  - Occurs when channel_id is not a valid channel
                    - Occurs when start is greater than total number of messages
        AccessError - Occurs when authorised user is not a member of the channel
                    - Occurs when token is not valid

    Return value:
        {
            messages,   - List of dictionaries,
                            where each dictionary contains types:
                            {message_id, u_id, message, time_created, reacts, is_pinned}
            start,      - integer
            end         - integer (value of start+50 or -1)
        }
    """
    current_time = int(time.time())

    # Load .json data store
    data_store = getData()

    # Check validity of channel_id
    ch_index = check_validity(data_store["channels"], channel_id, "channel_id",
                              INVALID_CHANNEL_ID)
    ch_src = data_store["channels"][ch_index]

    # Check validity of token
    u_id = findUser(token)
    for user in data_store["users"]:
        if user["u_id"] == u_id:
            u_src = user

    # Check user is a member of channel
    check_validity(ch_src["all_members"], u_src["u_id"], "u_id",
                   UNAUTHORISED_AUTH_U_ID)

    # Check start is less than total number of messages
    total_messages = len(ch_src["messages"])
    if total_messages > 0 and start > total_messages - 1:
        raise InputError(
            description="There aren't that many messages in this channel.")

    # Return type
    message_dict = {
        "messages": [],
        "start": start,
        "end": -1,
    }

    # Go through channel messages backwards
    msg_reverse = list(reversed(ch_src["messages"]))

    if start + 50 < total_messages - 1:
        message_dict["messages"] = msg_reverse[start:(start + 50)]
        message_dict["end"] = start + 50
    else:
        message_dict["messages"] = msg_reverse[start:]

    message_list = []
    for message_id in message_dict["messages"]:
        message_to_add = get_message_from_id(message_id, u_id, data_store)
        if message_to_add["time_created"] <= current_time:
            message_list.append(message_to_add)
    message_dict["messages"] = message_list

    return message_dict
Ejemplo n.º 30
0
def channel_invite_v2(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.

    Arguments:
        token (str)           - token passed in to the function
        channel_id (int)      - the id of the channel to invite to
        u_id (int)            - the id of the user that is being invited

    Exceptions:
        InputError  - Occurs when channel_id does not refer to a valid channel.
        InputError  - Occurs when u_id does not refer to a valid user.
        AccessError - Occurs when token pass in is not a valid id.
        AccessError - Occurs when the authorised user is not already a member of the channel.

    Return Value:
        Returns {} on successful invite

    """

    auth_user_id = findUser(token)

    database = getData()

    # Check for exceptions
    channel_index = check_validity(database["channels"], channel_id,
                                   "channel_id", INVALID_CHANNEL_ID)
    channel_src = database["channels"][channel_index]

    user_index = check_validity(database["users"], u_id, "u_id", INVALID_U_ID)
    user_src = database["users"][user_index]

    check_validity(channel_src["all_members"], auth_user_id, "u_id",
                   UNAUTHORISED_AUTH_U_ID)

    # Only add the user if they are not already in the channel
    for member in channel_src["all_members"]:
        if u_id in member.values():
            return {}

    # Create a new dictionary for the added user with their details
    # and add them to the channel
    new_member = {
        "u_id": user_src["u_id"],
        "name_first": user_src["name_first"],
        "name_last": user_src["name_last"],
        "email": user_src["email"],
        "handle_str": user_src["handle_str"],
        "profile_img_url": user_src["profile_img_url"],
    }

    channel_src["all_members"].append(new_member)

    # Create a notification for the added user
    user_notification = new_added_notification(token, channel_id, -1, u_id)
    database["user_notifications"].append(user_notification)

    append_user_stats(u_id, database)
    append_dream_stats(u_id, database)

    writeData(database)

    return {}