Пример #1
0
def scrub_inactive_pastes():
    """
    Goes through the database and deletes all pastes that are either inactive or have expired. This method is not
    intended to be called from within the application, but rather externally either manually or via a script/cron job.

    For example, in a Python shell:
        > import database.paste
        > database.paste.scrub_inactive_pastes()
    """
    inactive_pastes = models.Paste.query.filter(
        or_(
            models.Paste.is_active.is_(False),
            models.Paste.expiry_time < time.time(),
        ))
    inactive_paste_ids = [paste.paste_id for paste in inactive_pastes]
    if not inactive_paste_ids:
        # No inactive pastes to scrub; quit without taking further action
        return
    inactive_attachments = models.Attachment.query.filter(
        models.Attachment.paste_id.in_(inactive_paste_ids))

    # Attempt to remove the attachment files, if they exist
    for paste_id in inactive_paste_ids:
        try:
            shutil.rmtree('{attachment_dir}/{paste_id}'.format(
                attachment_dir=config.ATTACHMENTS_DIR, paste_id=paste_id))
        except OSError as err:
            if err.errno != errno.ENOENT:
                raise

    # Then, delete the database entries
    inactive_pastes.delete(synchronize_session='fetch')
    inactive_attachments.delete(synchronize_session='fetch')
    session.commit()
Пример #2
0
def create_new_user(username, password, signup_ip, name=None, email=None):
    """
    Creates a new user with the specified username and password.

    :param username: Requested username of the new user
    :param password: Password for the new user
    :param signup_ip: IP address from which the user signed up
    :param name: Name of the user (optional)
    :param email: Email of the user (optional)
    :return: Newly created User object
    :raises InvalidEmailException: If an invalid email is passed
    :raises UsernameNotAvailableException: If the username is not available
    """
    # Input validation
    if not is_username_available(username):
        raise UsernameNotAvailableException(
            'The username {username} is not available'.format(
                username=username))
    if email and not is_email_address_valid(email):
        raise InvalidEmailException(
            '{email_addr} is not a valid email address'.format(
                email_addr=email))

    new_user = models.User(
        signup_ip=signup_ip,
        username=username,
        password_hash=util.cryptography.secure_hash(password),
        name=name,
        email=email,
    )
    session.add(new_user)
    session.commit()
    return new_user
Пример #3
0
def scrub_inactive_pastes():
    """
    Goes through the database and deletes all pastes that are either inactive or have expired. This method is not
    intended to be called from within the application, but rather externally either manually or via a script/cron job.

    For example, in a Python shell:
        > import database.paste
        > database.paste.scrub_inactive_pastes()
    """
    inactive_pastes = models.Paste.query.filter(or_(
        models.Paste.is_active.is_(False),
        models.Paste.expiry_time < time.time(),
    ))
    inactive_paste_ids = [paste.paste_id for paste in inactive_pastes]
    if not inactive_paste_ids:
        # No inactive pastes to scrub; quit without taking further action
        return
    inactive_attachments = models.Attachment.query.filter(
        models.Attachment.paste_id.in_(inactive_paste_ids)
    )

    # Attempt to remove the attachment files, if they exist
    for paste_id in inactive_paste_ids:
        try:
            shutil.rmtree('{attachment_dir}/{paste_id}'.format(attachment_dir=config.ATTACHMENTS_DIR, paste_id=paste_id))
        except OSError as err:
            if err.errno != errno.ENOENT:
                raise

    # Then, delete the database entries
    inactive_pastes.delete(synchronize_session='fetch')
    inactive_attachments.delete(synchronize_session='fetch')
    session.commit()
Пример #4
0
def create_new_paste(contents,
                     user_id=None,
                     expiry_time=None,
                     title=None,
                     language=None,
                     password=None,
                     is_api_post=False):
    """
    Create a new paste.

    :param user_id: User ID of the paste poster
    :param contents: Contents of the paste
    :param expiry_time: Unix time at which the paste should expire (optional, default to no expiry)
    :param title: Title of the paste (optional)
    :param language: Language of the paste (optional, defaults to plain text)
    :param password: Password of the paste (optional)
    :param is_api_post: True to indicate that the post was posted externally via the API interface (optional)
    :return: An instance of models.Paste representing the newly added paste.
    """
    new_paste = models.Paste(
        user_id=user_id,
        contents=contents,
        expiry_time=int(expiry_time) if expiry_time is not None else None,
        title=title if title else 'Untitled',
        language=language or 'text',
        password_hash=util.cryptography.secure_hash(password)
        if password is not None else None,
        is_api_post=is_api_post,
    )
    session.add(new_paste)
    session.commit()
    return new_paste
Пример #5
0
def create_new_paste(contents, user_id=None, expiry_time=None, title=None, language=None, password=None, is_api_post=False):
    """
    Create a new paste.

    :param user_id: User ID of the paste poster
    :param contents: Contents of the paste
    :param expiry_time: Unix time at which the paste should expire (optional, default to no expiry)
    :param title: Title of the paste (optional)
    :param language: Language of the paste (optional, defaults to plain text)
    :param password: Password of the paste (optional)
    :param is_api_post: True to indicate that the post was posted externally via the API interface (optional)
    :return: An instance of models.Paste representing the newly added paste.
    """
    new_paste = models.Paste(
        user_id=user_id,
        contents=contents,
        expiry_time=int(expiry_time) if expiry_time is not None else None,
        title=title if title else 'Untitled',
        language=language or 'text',
        password_hash=util.cryptography.secure_hash(password) if password is not None else None,
        is_api_post=is_api_post,
    )
    session.add(new_paste)
    session.commit()
    return new_paste
Пример #6
0
def create_new_attachment(paste_id, file_name, file_size, mime_type,
                          file_data):
    """
    Create a new database entry for an attachment with the given file_name, associated with a particular paste ID.

    :param paste_id: Paste ID to associate with this attachment
    :param file_name: Raw name of the file
    :param file_size: Size of the file in bytes
    :param mime_type: MIME type of the file
    :param file_data: Binary, base64-encoded file data
    :return: An instance of models.Attachment describing this attachment entry
    :raises PasteDoesNotExistException: If the associated paste does not exist
    """
    # Add an entry into the database describing this file
    new_attachment = models.Attachment(
        paste_id=paste_id,
        file_name=secure_filename(file_name),
        file_size=file_size,
        mime_type=mime_type,
    )

    _store_attachment_file(paste_id, file_data, new_attachment)

    session.add(new_attachment)
    session.commit()

    return new_attachment
Пример #7
0
def create_new_user(username, password, signup_ip, name=None, email=None):
    """
    Creates a new user with the specified username and password.

    :param username: Requested username of the new user
    :param password: Password for the new user
    :param signup_ip: IP address from which the user signed up
    :param name: Name of the user (optional)
    :param email: Email of the user (optional)
    :return: Newly created User object
    :raises InvalidEmailException: If an invalid email is passed
    :raises UsernameNotAvailableException: If the username is not available
    """
    # Input validation
    if not is_username_available(username):
        raise UsernameNotAvailableException('The username {username} is not available'.format(username=username))
    if email and not is_email_address_valid(email):
        raise InvalidEmailException('{email_addr} is not a valid email address'.format(email_addr=email))

    new_user = models.User(
        signup_ip=signup_ip,
        username=username,
        password_hash=util.cryptography.secure_hash(password),
        name=name,
        email=email,
    )
    session.add(new_user)
    session.commit()
    return new_user
Пример #8
0
def increment_paste_views(paste_id):
    """
    Increment (by 1) the number of times this paste has been viewed.

    :param paste_id: The paste whose view count should be incremented
    :return: The models.Paste object representing the paste whose view was incremented
    :raises PasteDoesNotExistException: If the paste does not exist
    """
    paste = get_paste_by_id(paste_id)
    paste.views += 1
    session.commit()
    return paste
Пример #9
0
def deactivate_paste(paste_id):
    """
    Deactivate the specified paste by ID.

    :param paste_id: Paste ID to deactivate
    :return: An instance of models.Paste of the deactivated paste
    :raises PasteDoesNotExistException: If the paste does not exist
    """
    paste = get_paste_by_id(paste_id)
    paste.is_active = False
    session.commit()
    return paste
Пример #10
0
def increment_paste_views(paste_id):
    """
    Increment (by 1) the number of times this paste has been viewed.

    :param paste_id: The paste whose view count should be incremented
    :return: The models.Paste object representing the paste whose view was incremented
    :raises PasteDoesNotExistException: If the paste does not exist
    """
    paste = get_paste_by_id(paste_id)
    paste.views += 1
    session.commit()
    return paste
Пример #11
0
def deactivate_paste(paste_id):
    """
    Deactivate the specified paste by ID.

    :param paste_id: Paste ID to deactivate
    :return: An instance of models.Paste of the deactivated paste
    :raises PasteDoesNotExistException: If the paste does not exist
    """
    paste = get_paste_by_id(paste_id)
    paste.is_active = False
    session.commit()
    return paste
Пример #12
0
def generate_new_api_key(user_id):
    """
    Generate a new API key for the user.

    :param user_id: User ID for which to generate a new API key
    :return: User object for that user ID with a modified API key
    :raises UserDoesNotExistException: If no user exists with the given user_id
    """
    user = get_user_by_id(user_id)
    user.api_key = util.string.random_alphanumeric_string(length=64)
    session.commit()
    return user
Пример #13
0
def generate_new_api_key(user_id):
    """
    Generate a new API key for the user.

    :param user_id: User ID for which to generate a new API key
    :return: User object for that user ID with a modified API key
    :raises UserDoesNotExistException: If no user exists with the given user_id
    """
    user = get_user_by_id(user_id)
    user.api_key = util.testing.random_alphanumeric_string(length=64)
    session.commit()
    return user
Пример #14
0
def deactivate_user(user_id):
    """
    Deactivate the specified user by ID. This procedure also deactivates all of the user's pastes.

    :param user_id: User ID to deactivate
    :return: An instance of models.User of the deactivated user
    :raises UserDoesNotExistException: If the user does not exist
    """
    user = get_user_by_id(user_id)
    user.is_active = False
    session.commit()
    for paste in database.paste.get_all_pastes_for_user(user.user_id, active_only=True):
        database.paste.deactivate_paste(paste.paste_id)
    return user
Пример #15
0
def set_paste_password(paste_id, password):
    """
    Set a paste's password. This can either change a password that already exists, set a password that did not
    previously exist, or remove a password that already exists.

    :param paste_id: Paste ID for which to set the password
    :param password: New password to set for the paste, can be None to remove any existing password
    :return: An instance of models.Paste of the affected paste
    :raises PasteDoesNotExistException: If the paste does not exist
    """
    paste = get_paste_by_id(paste_id, active_only=True)
    paste.password_hash = util.cryptography.secure_hash(password) if password is not None else None
    session.commit()
    return paste
Пример #16
0
def set_paste_password(paste_id, password):
    """
    Set a paste's password. This can either change a password that already exists, set a password that did not
    previously exist, or remove a password that already exists.

    :param paste_id: Paste ID for which to set the password
    :param password: New password to set for the paste, can be None to remove any existing password
    :return: An instance of models.Paste of the affected paste
    :raises PasteDoesNotExistException: If the paste does not exist
    """
    paste = get_paste_by_id(paste_id, active_only=True)
    paste.password_hash = util.cryptography.secure_hash(password) if password is not None else None
    session.commit()
    return paste
Пример #17
0
def deactivate_user(user_id):
    """
    Deactivate the specified user by ID. This procedure also deactivates all of the user's pastes.

    :param user_id: User ID to deactivate
    :return: An instance of models.User of the deactivated user
    :raises UserDoesNotExistException: If the user does not exist
    """
    user = get_user_by_id(user_id)
    user.is_active = False
    session.commit()
    for paste in database.paste.get_all_pastes_for_user(user.user_id, active_only=True):
        database.paste.deactivate_paste(paste.paste_id)
    return user
Пример #18
0
def update_user_details(user_id, name, email, new_password):
    """
    Update an existing user, identified by user_id, with the provided fields. If name or email is None, this will
    remove these fields from the user entry. If new_password is None, the user's password will not be updated.

    :param user_id: User ID of the user to update
    :param name: Updated name, can be empty string or None to indicate no update
    :param email: Updated email, can be empty string or None to indicate no update
    :param new_password: New password, if updating the user's password
    :return: models.User object representing the updated user
    :raises InvalidEmailException: If an invalid email is passed
    """
    if email and not is_email_address_valid(email):
        raise InvalidEmailException('{email_addr} is not a valid email address'.format(email_addr=email))

    user = get_user_by_id(user_id, active_only=True)
    user.name = name
    user.email = email
    if new_password:
        user.password_hash = util.cryptography.secure_hash(new_password)
    session.commit()
    return user
Пример #19
0
def update_user_details(user_id, name, email, new_password):
    """
    Update an existing user, identified by user_id, with the provided fields. If name or email is None, this will
    remove these fields from the user entry. If new_password is None, the user's password will not be updated.

    :param user_id: User ID of the user to update
    :param name: Updated name, can be empty string or None to indicate no update
    :param email: Updated email, can be empty string or None to indicate no update
    :param new_password: New password, if updating the user's password
    :return: models.User object representing the updated user
    :raises InvalidEmailException: If an invalid email is passed
    """
    if email and not is_email_address_valid(email):
        raise InvalidEmailException('{email_addr} is not a valid email address'.format(email_addr=email))

    user = get_user_by_id(user_id, active_only=True)
    user.name = name
    user.email = email
    if new_password:
        user.password_hash = util.cryptography.secure_hash(new_password)
    session.commit()
    return user
Пример #20
0
def create_new_attachment(paste_id, file_name, file_size, mime_type, file_data):
    """
    Create a new database entry for an attachment with the given file_name, associated with a particular paste ID.

    :param paste_id: Paste ID to associate with this attachment
    :param file_name: Raw name of the file
    :param file_size: Size of the file in bytes
    :param mime_type: MIME type of the file
    :param file_data: Binary, base64-encoded file data
    :return: An instance of models.Attachment describing this attachment entry
    :raises PasteDoesNotExistException: If the associated paste does not exist
    """
    # Add an entry into the database describing this file
    new_attachment = models.Attachment(
        paste_id=paste_id, file_name=secure_filename(file_name), file_size=file_size, mime_type=mime_type
    )

    _store_attachment_file(paste_id, file_data, new_attachment.hash_name)

    session.add(new_attachment)
    session.commit()

    return new_attachment