Exemple #1
0
def standup_active_v1(token, channel_id):
    """Summary
        For a given channel, return whether a standup is active in it, and what time the standup 
        finishes. If no standup is active, then time_finish returns None
    Args:
        token (string): A user session token
        channel_id (int): A channel id number
    
    Returns:
        output: Dictionary of the form { is_active, time_finish }, where is_active is a Boolean
                and time_finish is a time stamp if is_active is True, else None
    
    Raises:
        InputError: When the channel id parameter does not refer to a valid channel
        AccessError: When the token parameter is an invalid jwt token
    """
    check_token(token)

    target_channel = find_channel(channel_id)
    if target_channel == {}:
        raise InputError(f'Channel ID {channel_id} is not a valid channel')

    channel_standup = target_channel['standup']
    is_active = channel_standup['is_active']
    t_finish = channel_standup['time_finish']

    output = {
        'is_active': is_active,
        'time_finish': t_finish if is_active else None
    }
    return output
Exemple #2
0
def standup_handler(author_token, channel_id, duration):
    sleep(duration)
    channel_standup = find_channel(channel_id)['standup']
    channel_standup['is_active'] = False
    bundled_message = ''
    for msg in channel_standup['messages']:
        bundled_message += f"{msg['author_handle']}: {msg['message']}\n"
    message_send_v2(author_token, channel_id, bundled_message)
Exemple #3
0
def search_v2(token, query_str):
    """Summary
        Given a query string, return a collection of messages in all of the channels/DMs that the user has joined that match the query
    Args:
        token (string): A user session token
        query_str (string): a string for search message
    
    Returns:
        Dictionary: { messages } ({ message_id, u_id, message, time_created })  Contains the imformation of messages
    
    Raises:
        InputError: query_str is above 1000 characters
    """
    query_str = query_str.lower()

    # InputError: query_str is above 1000 characters
    if len(query_str) > 1000:
        raise InputError("query_str is above 1000 characters")

    check_token(token)
    auth_user_id = user_from_token(token)['u_id']

    output = []
    # search all the messages
    for message in messages:
        user_is_member = False

        # if this message is send to the channel, find the channel
        if message['channel_id'] != -1:
            channel = find_channel(message['channel_id'])
            user_is_member = (auth_user_id in channel['all_members']
                              and query_str in message['message'].lower())
        # if this message is send to the dm, find the dm
        else:
            dm = find_dm(message['dm_id'])
            user_is_member = (auth_user_id in dm['members']
                              and query_str in message['message'].lower())

        # list all the detail of this messagen, and append it to the putput
        if user_is_member:
            react_dict = {
                'react_id': 1,
                'u_ids': message['reacts'],
                'is_this_user_reacted': auth_user_id in message['reacts']
            }

            message_detail = {
                'message_id': message['message_id'],
                'u_id': message['author_id'],
                'message': message['message'],
                'time_created': message['time_created'],
                'reacts': [react_dict],
                'is_pinned': message['is_pinned']
            }
            output.append(message_detail)
    return {'messages': output}
Exemple #4
0
def channel_details_v2(token, channel_id):
    '''
    Summary:
        Given a Channel with ID channel_id that the authorised user is part of, 
        provide basic details about the channel
    Args:
        token (string): A user session token 
        channel_id (int): A channel_id number
    Returns: 
        a dictionary which contains:
            name of the channel 
            the is_public status of the channel (True for public, False for private)
            a list of owner_member for the channel 
            a list of members for a channel
    Raises:
        InputError when:
            Channel ID is not a valid channel
        AccessError when:
            Authorised user is not a member of channel with channel_id
    '''
    global users, channels
    assert check_token(token)
    auth_user = user_from_token(token)

    if valid_channel(channel_id) == False:
        raise InputError(f"Channel ID {channel_id} is not a valid channel")

    current_channel = find_channel(
        channel_id)  #current channel with the given channel id

    if auth_user['u_id'] not in current_channel['all_members']:
        raise AccessError(
            f"Authorised user {auth_user['u_id']} is not a member of channel with channel_id {channel_id}"
        )

    owner_members = []
    all_members = []
    for u_id in current_channel['all_members']:
        for user in users:
            if user['u_id'] == u_id:
                user_details = {}
                user_details['u_id'] = user['u_id']
                user_details['email'] = user['email']
                user_details['name_first'] = user['name_first']
                user_details['name_last'] = user['name_last']
                user_details['handle_str'] = user['handle_str']
                user_details['profile_img_url'] = user['profile_img_url']
                all_members.append(user_details)
                if u_id in current_channel['owner_members']:
                    owner_members.append(user_details)
    return {  #give the name of the dictonary then the values
        'name': current_channel['name'],
        'is_public': current_channel['is_public'],
        'owner_members': owner_members,
        'all_members': all_members
    }
Exemple #5
0
def standup_start_v1(token, channel_id, length):
    '''
    Summary:
       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): A user session token 
        channel_id (int): A channel_id number
        length (int): A length of how long the standup runs
    Returns: 
        dictionary which contains the time_finished 
    Raises:
        InputError when:
            Channel ID is not a valid channel
            An active standup is currently running in this channel
        AccessError when:
            Authorised user is not in the channel
    '''
    global channels
    check_token(token)

    if valid_channel(channel_id) == False:
        raise InputError(f'Channel ID {channel_id} is not a valid channel')

    auth_user_id = user_from_token(token)['u_id']

    if is_channel_member(auth_user_id, channel_id) == False:
        raise AccessError(f'Authorised user is not in the channel')

    current_channel = find_channel(channel_id)

    if current_channel['standup']['is_active'] == True:
        raise InputError(
            f'An active standup is currently running in this channel')

    standup_period_finish = datetime.now(
        timezone.utc) + timedelta(seconds=length)
    timestamp = standup_period_finish.replace(tzinfo=timezone.utc).timestamp()

    # what will i add to the message here
    #dummy = ''
    #message_id = message_sendlater_v1(token, channel_id, dummy, timestamp)
    #message id here or standup send
    #standup_info = {}
    #create the standup dicitonary in channel create
    current_channel['standup']['is_active'] = True
    current_channel['standup']['creator'] = auth_user_id
    current_channel['standup']['messages'] = []
    current_channel['standup']['time_finish'] = timestamp

    #current_channel['standup'] = standup_info

    return {'time_finish': timestamp}
Exemple #6
0
def sendlater_handler(message_id, time_sent):
    global messages, future_messages
    time_sent_dt = datetime.utcfromtimestamp(time_sent)
    now_dt = datetime.utcnow()
    duration = (time_sent_dt - now_dt).total_seconds()
    sleep(duration)
    for msg in list(future_messages):
        if msg['message_id'] == message_id:
            messages.append(msg)
            target_channel = find_channel(msg['channel_id'])
            target_channel['messages'].append(message_id)
            future_messages.remove(msg)
Exemple #7
0
def channel_invite_v2(token, channel_id, u_id):
    '''
    Summary:
        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): A user session token 
        channel_id (int): A channel_id number
        u_id (int): A user id 
    Returns: 
        empty dictionary

    Raises:
        InputError when:
            channel_id does not refer to a valid channel
            u_id does not refer to a valid user
        AccessError when:
            the authorised user is not already a member of the channel
    '''
    global users, channels
    assert check_token(token)
    auth_user = user_from_token(token)

    if valid_channel(channel_id) == False:
        raise InputError(f"Channel ID {channel_id} is not a valid channel")

    if valid_user(u_id) == False:
        raise InputError(f"u_id {u_id} does not refer to a valid user")

    current_channel = find_channel(
        channel_id)  #current channel with the given channel id
    invitee = user_from_id(u_id)

    if auth_user['u_id'] not in current_channel['all_members']:
        raise AccessError(
            f"Authorised user {auth_user['u_id']} is not a member of channel with channel_id {channel_id}"
        )

    if u_id in current_channel['all_members']:
        raise AccessError(
            f"u_id {u_id} you are inviting is already inside the channel")

    current_channel['all_members'].append(u_id)
    if invitee[
            'permission'] == 1:  # Dreams owner is automatically channel owner
        current_channel['owner_members'].append(u_id)
    invitee['channels'].append(channel_id)
    update_user_channel_stats(invitee['u_id'])
    send_channel_added_notification(auth_user['handle_str'], u_id,
                                    current_channel['channel_id'])
    return {}
Exemple #8
0
def message_pin_v1(token, message_id):
    '''Summary
        Given a message within a channel or DM, mark it as "pinned" to be given special display treatment by the frontend
    Args:
        token (string): A user session token
        message_id (int): A message_id of the message
    
    Returns:
        A empty dictionary
    
    Raises:
       Raises:
        InputError when:
            message_id is not a valid message
            Message with ID message_id is already pinned
        AccessError when:
            The authorised user is not a member of the channel
            The authorised user is not a member of the DM that the message is within
            The authorised user is not an owner of the channel or DM
    '''
    check_token(token)
    auth_user = user_from_token(token)
    if valid_message(message_id) == False:
        raise InputError("message_id is not a valid message")

    message = get_message_from_message_id(message_id)

    if message['is_pinned'] == True:
        raise InputError("Message with ID message_id is already pinned")

    if message['channel_id'] == -1:  #this means this is a dm message
        current_dm = find_dm(message['dm_id'])
        if auth_user['u_id'] not in current_dm['members']:
            raise AccessError("The authorised user is not a member of the DM")
        if auth_user['u_id'] != current_dm[
                'creator']:  # this error will get raised twice is this ok? / this is kinda redundent because if u have to be the owner to pin whats the point of checking for members?
            raise AccessError("The authorised user is not an owner of the DM")
        message['is_pinned'] = True

    if message['dm_id'] == -1:  # this means this a channel message
        current_channel = find_channel(message['channel_id'])
        if auth_user['u_id'] not in current_channel['all_members']:
            raise AccessError(
                "The authorised user is not a member of the channel")
        if auth_user['u_id'] not in current_channel['owner_members']:
            raise AccessError(
                "The authorised user is not an owner of the channel")
        message['is_pinned'] = True

    return {}
Exemple #9
0
def channel_join_v2(token, channel_id):
    '''
    Summary:
        Given a channel_id of a channel that the authorised user can join, 
        add them to that channel members
    Args:
        token (string): A user session token 
        channel_id (int): A channel_id number
    Returns: 
        a empty dictionary
    Raises:
        InputError when:
            Channel ID is not a valid channel
        AccessError when:
            channel_id refers to a channel that is private 
            (when the authorised user is not a global owner)
    '''
    global users, channels
    assert check_token(token)
    auth_user = user_from_token(token)

    if valid_channel(channel_id) == False:
        raise InputError(f"Channel ID {channel_id} is not a valid channel")
    current_channel = find_channel(
        channel_id)  #current channel with the given channel id

    is_dreams_owner = auth_user['permission'] == 1

    not_in_current_channel = auth_user['u_id'] not in current_channel[
        'all_members']

    if current_channel['is_public'] == True:
        if not_in_current_channel:
            if is_dreams_owner:
                current_channel['owner_members'].append(auth_user['u_id'])
            current_channel['all_members'].append(auth_user['u_id'])
            auth_user['channels'].append(channel_id)
            update_user_channel_stats(auth_user['u_id'])
    else:
        if is_dreams_owner and not_in_current_channel:
            current_channel['owner_members'].append(auth_user['u_id'])
            current_channel['all_members'].append(auth_user['u_id'])
            auth_user['channels'].append(channel_id)
            update_user_channel_stats(auth_user['u_id'])
        else:
            raise AccessError(
                f"channel_id {channel_id} refers to a channel that is private ( authorised user is not a global owner)"
            )

    return {}
Exemple #10
0
def message_unpin_v1(token, message_id):
    '''
    Summary:
        Given a message within a channel or DM, remove it's mark as unpinned
    Args:
        token (string): A user session token 
        message_id (int): A message_id number
    Returns: 
        empty dictionary 
    Raises:
        InputError when:
            message_id is not a valid message
            Message with ID message_id is already unpinned
        AccessError when:
            The authorised user is not a member of the channel or DM that the message is within
            The authorised user is not an owner of the channel or DM
    '''
    check_token(token)
    auth_user = user_from_token(token)
    if valid_message(message_id) == False:
        raise InputError("message_id is not a valid message")

    message = get_message_from_message_id(message_id)

    if message['is_pinned'] == False:
        raise InputError("Message with ID message_id is already unpinned")

    if message['channel_id'] == -1:  #this means this is a dm message
        current_dm = find_dm(message['dm_id'])
        if auth_user['u_id'] not in current_dm['members']:
            raise AccessError("The authorised user is not a member of the DM")
        if auth_user['u_id'] != current_dm['creator']:
            raise AccessError("The authorised user is not an owner of the DM")
        message['is_pinned'] = False

    if message['dm_id'] == -1:  # this means this a channel message
        current_channel = find_channel(message['channel_id'])
        if auth_user['u_id'] not in current_channel['all_members']:
            raise AccessError(
                "The authorised user is not a member of the channel")
        if auth_user['u_id'] not in current_channel['owner_members']:
            raise AccessError(
                "The authorised user is not an owner of the channel")
        message['is_pinned'] = False

    return {}
Exemple #11
0
def channel_addowner_v1(token, channel_id, u_id):
    '''
    Summary:
        Make user with user id u_id an owner of this channel
    Args:
        token (string): A user session token 
        channel_id (int): A channel_id number
        u_id (int): A user id number
    Returns: 
        a empty dictionary
    Raises:
        InputError when:
            Channel ID is not a valid channel
            When user with user id u_id is already an owner of the channel
        AccessError when:
           the authorised user is not an owner of the **Dreams**, 
           or an owner of this channel
    '''
    global users, channels
    assert check_token(token)
    assert valid_user(u_id)
    if valid_channel(channel_id) == False:
        raise InputError(f"Channel ID is not a valid channel")
    auth_user = user_from_token(token)
    current_channel = find_channel(
        channel_id)  #current channel with the given channel id

    if not is_channel_owner(auth_user['u_id'],
                            channel_id) and not is_dreams_owner(
                                auth_user['u_id']):
        raise AccessError(
            f"the authorised user is not an owner of the channel or Dreams")
    if is_channel_owner(u_id, channel_id) == True:
        raise InputError(
            f"User with user id {u_id} is already an owner of the channel")

    target_user = user_from_id(u_id)

    current_channel['owner_members'].append(u_id)
    if u_id not in current_channel['all_members']:
        current_channel['all_members'].append(u_id)
        target_user['channels'].append(channel_id)
        update_user_channel_stats(u_id)
        send_channel_added_notification(auth_user['handle_str'], u_id,
                                        current_channel['channel_id'])
    return {}
Exemple #12
0
def message_send_v2(token, channel_id, message):
    '''
    Summary:
        Send a message from authorised_user to the channel specified by channel_id. 
        Note: Each message should have it's own unique ID. 
        I.E. No messages should share an ID with another message, 
        even if that other message is in a different channel.
    Args:
        token (string): A user session token 
        channel_id (int): A channel_id number
        message (string): a message string 
    Returns: 
        empty dictionary which contains the message_id
    Raises:
        InputError when:
            Message is more than 1000 characters
        AccessError when:
            the authorised user has not joined the channel they are trying to post to
    '''
    global users, channels, next_message_id, messages
    assert check_token(token)
    assert valid_channel(channel_id)

    auth_user = user_from_token(token)
    current_channel = find_channel(
        channel_id)  #current channel with the given channel id

    if current_channel['standup']['is_active']:
        standup_send_v1(token, channel_id, message)
        return

    if len(message) > 1000:
        raise InputError(f"Message more than 1000 characters")
    if auth_user['u_id'] not in current_channel['all_members']:
        raise AccessError(
            f"the authorised user has not joined the channel they are trying to post to"
        )

    current_time = current_unix_timestamp()  #gives us the current timestamp
    current_message = {}
    current_message['message_id'] = next_message_id['id']  #message_id
    current_message['channel_id'] = channel_id
    current_message[
        'dm_id'] = -1  #this is a channel message not dm so for all dm's give -1
    current_message['author_id'] = auth_user['u_id']
    current_message['message'] = message
    current_message['reacts'] = []
    current_message['time_created'] = current_time
    current_message['is_pinned'] = False
    current_channel['messages'].append(current_message['message_id'])
    next_message_id[
        'id'] += 1  #update the global message id so we get unique ids

    message_words = message.split(' ')

    # Standup start checker
    # Start a standup if message is exactly "/standup X" where X is a number of seconds
    if message.startswith('/standup') and len(
            message_words) == 2 and message_words[1].isdigit():
        duration = int(message_words[1])
        standup_start_v1(token, channel_id, duration)

    #notications checker and handler
    contains_tag = False
    tag_strings = []
    if '@' in message:
        for word in message_words:
            if word.startswith('@'):
                tag_strings.append(word[1:])
                contains_tag = True
    if contains_tag:
        for user_id in current_channel['all_members']:
            user = user_from_id(user_id)
            if user['handle_str'] in tag_strings:
                send_channel_tag_notification(auth_user['handle_str'], user_id,
                                              channel_id, message)

    messages.append(current_message)

    update_user_message_stats(auth_user['u_id'])

    update_message_stats()

    return {
        'message_id': current_message['message_id']  #message_id
    }
Exemple #13
0
def message_sendlater_v1(token, channel_id, message, time_sent):
    """Summary
        Send a message from authorised_user to the channel specified by channel_id automatically at a specified time in the future
    Args:
        token (string): A user session token
        channel_id (int): A channel id number which the message will be sented to
        message (string): The text with which the user wishes to sent to channel
        time_sent (int): the time of when this message will be sent
    
    Returns:
        Dictionary: { message_id } the new message
    
    Raises:
        AccessError: the authorised user has not joined the channel they are trying to post to
        InputError:  Channel ID is not a valid channel
                     Message is more than 1000 characters
                     Time sent is a time in the past
    """

    # current_time = current_unix_timestamp()
    # time_intervel = time_sent - current_time

    # # InputError: Time sent is a time in the past
    # if time_intervel < 0:
    #     raise InputError("Time sent is a time in the past")

    # time.sleep(time_intervel)
    # message_id = message_send_v2(token, channel_id, message)

    # return { 'message_id': message_id }

    global users, channels, next_message_id, messages
    assert check_token(token)

    if valid_channel(channel_id) == False:
        raise InputError(f"Channel ID {channel_id} is not a valid channel")

    # InputError: Message is more than 1000 characters
    if len(message) > 1000:
        raise InputError(f"Message {message} is more than 1000 characters")

    current_time = current_unix_timestamp()
    time_intervel = time_sent - current_time

    # if datetime.fromtimestamp(time_sent) < datetime.fromtimestamp(current_time):
    #     raise InputError("Time sent is a time in the past")

    # InputError: Time sent is a time in the past
    if time_intervel < 0:
        raise InputError("Time sent is a time in the past")

    auth_user = user_from_token(token)
    current_channel = find_channel(
        channel_id)  #current channel with the given channel id

    if auth_user['u_id'] not in current_channel['all_members']:
        raise AccessError(
            f"the authorised user has not joined the channel they are trying to post to"
        )

    message_id = next_message_id['id']
    next_message_id['id'] += 1

    future_message = {}
    future_message['message_id'] = message_id  #message_id
    future_message['channel_id'] = channel_id
    future_message[
        'dm_id'] = -1  #this is a channel message not dm so for all dm's give -1
    future_message['author_id'] = auth_user['u_id']
    future_message['message'] = message
    future_message['reacts'] = []
    future_message['time_created'] = time_sent
    future_message['is_pinned'] = False

    future_messages.append(future_message)

    return {
        'message_id': future_message['message_id']  #message_id
    }