Exemplo n.º 1
0
def mod_moderator(moderator: ModeratorModel):
    all_roles = ', '.join(roles.ALL_ROLES)
    all_board_roles = ', '.join(roles.ALL_BOARD_ROLES)

    add_moderator_board_form = AddModeratorBoardForm(request.form)
    add_moderator_board_form.action_url = url_for('.mod_moderator',
                                                  moderator=moderator)
    if request.method == 'POST' and request.form.get(
            'board_add') is not None and add_moderator_board_form.validate():
        try:
            board = board_service.find_board(
                add_moderator_board_form.board.data)
            board_service.add_moderator(board, moderator)
            flash('Assigned ' + board.name)
            mod_log('add board to {} /{}/'.format(moderator.username,
                                                  board.name))
        except ArgumentError as e:
            flash(e.message)

    if request.method == 'POST' and request.form.get('board_remove'):
        # HTML checkboxes are fun!
        board_names_to_remove = request.form.getlist('board_remove')
        boards_to_remove = []
        for board_name in board_names_to_remove:
            board = board_service.find_board(board_name)
            if not board:
                # we coded the name in the html, can't be an user error
                abort(400)
            boards_to_remove.append(board)

        for board in boards_to_remove:
            try:
                board_service.remove_moderator(board, moderator)
                flash('Revoked ' + board.name)
                mod_log('remove board from {} /{}/'.format(
                    moderator.username, board.name))
            except ArgumentError as e:
                flash(e.message)

    if request.method == 'POST' and request.form.get('role_remove'):
        pass

    moderating_boards = moderator_service.get_all_moderating_boards(moderator)

    return render_template('mod_moderator.html',
                           moderator=moderator,
                           moderating_boards=moderating_boards,
                           all_roles=all_roles,
                           all_board_roles=all_board_roles,
                           add_moderator_board_form=add_moderator_board_form)
Exemplo n.º 2
0
def add_ban(ban: BanModel) -> BanModel:
    if ban.length > MAX_BAN_TIME:
        raise ArgumentError(MESSAGE_BAN_TOO_LONG)

    if ban.ip4_end is not None and ban.ip4_end <= ban.ip4:
        raise ArgumentError(MESSAGE_IP4_ILLEGAL_RANGE)

    if ban.board:
        board = board_service.find_board(ban.board)
        if not board:
            raise ArgumentError(MESSAGE_BOARD_NOT_FOUND)

    if ban.reason and len(ban.reason) > MAX_REASON_LENGTH:
        raise ArgumentError(MESSAGE_BAN_TEXT_TOO_LONG)

    ban.date = now()

    ban = bans.create_ban(ban)

    for_board_text = ' on {}'.format(ban.board) if ban.board else ''
    ip4_end_text = ip4_to_str(ban.ip4_end) if ban.ip4_end is not None else '-'
    f = 'ban add {} from {} to {}{} for {} hours reason {}'
    text = f.format(ban.id, ip4_to_str(ban.ip4), ip4_end_text, for_board_text, ban.length / 60 / 60 / 1000, ban.reason)
    mod_log(text)

    return ban
Exemplo n.º 3
0
 def to_python(self, value):
     if not validation.check_board_name_validity(value):
         raise ValidationError()
     model = board_service.find_board(value)
     if not model:
         raise ValidationError()
     return model
Exemplo n.º 4
0
 def to_python(self, value):
     if not validation.check_board_name_validity(value):
         raise ValidationError()
     model = board_service.find_board(value)
     if not model:
         raise ValidationError()
     return model
Exemplo n.º 5
0
def view_thread(board_name, thread_refno):
    valid_id_range(thread_refno)

    board: BoardModel = board_service.find_board(board_name)
    if not board:
        abort(404)

    thread = posts_service.find_thread_by_board_thread_refno_with_posts(
        board, thread_refno)
    if not thread:
        abort(404)

    additional_page_details = {'threadRefno': thread.refno}
    if thread.locked:
        additional_page_details['locked'] = True
    if thread.sticky:
        additional_page_details['sticky'] = True

    # TODO: don't use the board id
    show_mod_buttons = show_moderator_buttons(thread.board.id)

    r: Response = app.make_response(
        render_template('thread.html',
                        thread=thread,
                        board=thread.board,
                        show_moderator_buttons=show_mod_buttons,
                        **get_board_view_params(board.config, 'thread',
                                                board_name,
                                                additional_page_details)))
    r.headers['Last-Modified'] = http_date(thread.last_modified / 1000)
    return r
Exemplo n.º 6
0
def board(board_name, page=None):
    if not validation.check_board_name_validity(board_name):
        abort(404)

    board: BoardModel = board_service.find_board(board_name)

    if not board:
        abort(404)

    # Page 1 is argument-less
    if page == 1:
        return redirect(url_for('board', board_name=board_name))

    if page is None:
        page = 1

    if page <= 0 or page > board.config.pages:
        abort(404)

    # Index starts from 0
    index = page - 1

    board_page = posts_service.get_board_page(board, index)

    # TODO: don't use the board id
    show_mod_buttons = show_moderator_buttons(board.id)

    return render_template('board.html',
                           board=board,
                           board_page=board_page,
                           page_index=index,
                           show_moderator_buttons=show_mod_buttons,
                           **get_board_view_params(board.config, 'board',
                                                   board_name))
Exemplo n.º 7
0
def view_thread(board_name, thread_refno):
    valid_id_range(thread_refno)

    board: BoardModel = board_service.find_board(board_name)
    if not board:
        abort(404)

    thread = posts_service.find_thread_by_board_thread_refno_with_posts(board, thread_refno)
    if not thread:
        abort(404)

    additional_page_details = {
        'threadRefno': thread.refno
    }
    if thread.locked:
        additional_page_details['locked'] = True
    if thread.sticky:
        additional_page_details['sticky'] = True

    # TODO: don't use the board id
    show_mod_buttons = show_moderator_buttons(thread.board.id)

    r: Response = app.make_response(render_template('thread.html', thread=thread, board=thread.board,
                                                    show_moderator_buttons=show_mod_buttons,
                                                    **get_board_view_params(board.config, 'thread', board_name,
                                                                            additional_page_details)))
    r.headers['Last-Modified'] = http_date(thread.last_modified / 1000)
    return r
Exemplo n.º 8
0
def board(board_name, page=None):
    if not validation.check_board_name_validity(board_name):
        abort(404)

    board: BoardModel = board_service.find_board(board_name)

    if not board:
        abort(404)

    # Page 1 is argument-less
    if page == 1:
        return redirect(url_for('board', board_name=board_name))

    if page is None:
        page = 1

    if page <= 0 or page > board.config.pages:
        abort(404)

    # Index starts from 0
    index = page - 1

    board_page = posts_service.get_board_page(board, index)

    # TODO: don't use the board id
    show_mod_buttons = show_moderator_buttons(board.id)

    return render_template('board.html', board=board, board_page=board_page, page_index=index,
                           show_moderator_buttons=show_mod_buttons,
                           **get_board_view_params(board.config, 'board', board_name))
Exemplo n.º 9
0
def add_ban(ban: BanModel) -> BanModel:
    if ban.length > MAX_BAN_TIME:
        raise ArgumentError(MESSAGE_BAN_TOO_LONG)

    if ban.ip4_end is not None and ban.ip4_end <= ban.ip4:
        raise ArgumentError(MESSAGE_IP4_ILLEGAL_RANGE)

    if ban.board:
        board = board_service.find_board(ban.board)
        if not board:
            raise ArgumentError(MESSAGE_BOARD_NOT_FOUND)

    if ban.reason and len(ban.reason) > MAX_REASON_LENGTH:
        raise ArgumentError(MESSAGE_BAN_TEXT_TOO_LONG)

    ban.date = now()

    ban = bans.create_ban(ban)

    for_board_text = ' on {}'.format(ban.board) if ban.board else ''
    ip4_end_text = ip4_to_str(ban.ip4_end) if ban.ip4_end is not None else '-'
    f = 'ban add {} from {} to {}{} for {} hours reason {}'
    text = f.format(ban.id, ip4_to_str(ban.ip4), ip4_end_text, for_board_text,
                    ban.length / 60 / 60 / 1000, ban.reason)
    mod_log(text)

    return ban
Exemplo n.º 10
0
    def __call__(self, form, field):
        if not validation.check_board_name_validity(field.data):
            raise ValidationError('Board name not valid.')

        board = board_service.find_board(field.data)
        if not board:
            raise ValidationError('Board does not exist')
        field.board = board
Exemplo n.º 11
0
def board_catalog(board_name):
    board: BoardModel = board_service.find_board(board_name)
    if not board:
        abort(404)

    catalog: CatalogModel = posts_service.get_catalog(board)

    return render_template('catalog.html', board=board, catalog=catalog,
                           **get_board_view_params(board.config, 'catalog', board_name))
Exemplo n.º 12
0
def api_catalog(board_name):
    board: BoardModel = board_service.find_board(board_name)
    if not board:
        abort(404)

    catalog: CatalogModel = posts_service.get_catalog(board)

    return {
        'threads': list(map(lambda i: build_thread_object(i), catalog.threads))
    }
Exemplo n.º 13
0
def mod_board_delete():
    board = board_service.find_board(request.form['board_name'])

    try:
        moderator_service.user_delete_board(request_moderator(), board)
        flash('Board deleted')
        mod_log('delete board /{}/'.format(board.name))
    except ArgumentError as e:
        flash(e.message)

    return redirect(url_for('.mod_boards'))
Exemplo n.º 14
0
def mod_board_delete():
    board = board_service.find_board(request.form['board_name'])

    try:
        moderator_service.user_delete_board(request_moderator(), board)
        flash('Board deleted')
        mod_log('delete board /{}/'.format(board.name))
    except ArgumentError as e:
        flash(e.message)

    return redirect(url_for('.mod_boards'))
Exemplo n.º 15
0
def board_catalog(board_name):
    board: BoardModel = board_service.find_board(board_name)
    if not board:
        abort(404)

    catalog: CatalogModel = posts_service.get_catalog(board)

    return render_template('catalog.html',
                           board=board,
                           catalog=catalog,
                           **get_board_view_params(board.config, 'catalog',
                                                   board_name))
Exemplo n.º 16
0
def api_thread(board_name, thread_refno):
    valid_id_range(thread_refno)

    board: BoardModel = board_service.find_board(board_name)
    if not board:
        abort(404)

    thread = posts_service.find_thread_by_board_thread_refno_with_posts(board, thread_refno)
    if not thread:
        abort(404)

    return {
        'thread': build_thread_object(thread)
    }
Exemplo n.º 17
0
def _gather_post_params() -> Tuple[BoardModel, PostDetails]:
    form = request.form

    # Gather params
    thread_refno_raw = form.get('thread', None)
    thread_refno = None
    if thread_refno_raw is not None:
        try:
            thread_refno = int(thread_refno_raw)
            valid_id_range(thread_refno)
        except ValueError:
            abort(400)

    board_name = form.get('board', None)
    if not validation.check_board_name_validity(board_name):
        abort(400)

    board = board_service.find_board(board_name)
    if not board:
        abort(404)

    text = form.get('comment', None)
    name = form.get('name', None)
    subject = form.get('subject', None)
    password = form.get('password', None)

    # Convert empty strings to None
    if not text:
        text = None
    if not name:
        name = None
    if not subject:
        subject = None
    if not password:
        password = None

    file = request.files.get('file', None)
    has_file = file is not None and file.filename is not None and len(file.filename) > 0

    ip4 = get_request_ip4()

    with_mod = form.get('with_mod', default=False, type=bool)
    mod_id = None
    if with_mod:
        moderator = request_moderator() if get_authed() else None
        if moderator is not None:
            mod_id = moderator.id

    return board, PostDetails(form, board_name, thread_refno, text, name, subject, password, has_file,
                              ip4, mod_id, None)
Exemplo n.º 18
0
def create_post(post_details: PostDetails) -> PostResultModel:
    start_time = now()

    board = board_service.find_board(post_details.board_name)
    if not board:
        raise ArgumentError(MESSAGE_BOARD_NOT_FOUND)

    to_thread = None
    if post_details.thread_refno is not None:
        to_thread = posts.find_thread_by_board_name_thread_refno(board.name, post_details.thread_refno)
        if to_thread is None:
            raise ArgumentError(MESSAGE_THREAD_NOT_FOUND)

    _check_post_details(post_details, to_thread, board)

    plugin_manager.execute_hook('on_handle_post', post_details)

    site_config = site_service.get_site_config()
    default_name = site_config.default_name

    # Get moderator if mod_id was set
    moderator = None
    if post_details.mod_id is not None:
        moderator = moderator_service.find_moderator_id(post_details.mod_id)
        if moderator is None:
            raise Exception('Moderator not found')

    post = PostModel()
    post.date = now()
    post.ip4 = post_details.ip4

    if moderator is not None and moderator_service.moderates_board(moderator, board):
        post.moderator = moderator

    _handle_text(post, post_details)
    sage = _handle_name(post, post_details, default_name)
    _handle_subject(post, post_details, to_thread)
    _handle_password(post, post_details)

    if post_details.uploaded_file is not None:
        # TODO
        post.file = FileModel()
        post.file.location = post_details.uploaded_file.location
        post.file.thumbnail_location = post_details.uploaded_file.thumbnail_location
        post.file.original_name = post_details.uploaded_file.original_name
        post.file.width = post_details.uploaded_file.width
        post.file.height = post_details.uploaded_file.height
        post.file.size = post_details.uploaded_file.size
        post.file.thumbnail_width = post_details.uploaded_file.thumbnail_width
        post.file.thumbnail_height = post_details.uploaded_file.thumbnail_height

    handle_time = now() - start_time

    if to_thread is None:
        res, insert_time, cache_time = posts.create_thread(board, post)
    else:
        res, insert_time, cache_time = posts.create_post(board, to_thread, post, sage)

    _log_post(post_details, res, handle_time + insert_time, cache_time)

    return res
Exemplo n.º 19
0
def mod_board(board_name):
    board = board_service.find_board(board_name)
    if not board:
        abort(404)

    moderator = request_moderator()
    if not moderator_service.moderates_board(moderator, board):
        abort(404)

    # These are purely for configuring the visibility of the various elements on the page,
    # the actions are still checked with the authorizer on post.
    can_update_board_config = moderator_service.can_update_board_config(
        moderator, board)
    can_update_advanced_board_configs = moderator_service.can_update_advanced_board_configs(
        moderator)
    can_update_roles = moderator_service.can_update_roles(moderator, board)
    can_invite_moderator = moderator_service.can_invite_moderator(
        moderator, board)
    can_remove_moderator = moderator_service.can_remove_moderator(
        moderator, board)
    can_delete = moderator_service.can_delete_board(moderator)

    for_action = request.form.get('for_action')
    action_configure = for_action == 'configuration'
    action_update_roles = for_action == 'update_roles'
    action_invite_moderator = for_action == 'moderator_invite'
    action_remove_moderator = for_action == 'moderator_remove'

    board_configuration_form = None
    invite_messages = []
    invite_moderator_form = None
    roles_messages = []

    if request.method == 'POST':
        if action_configure:
            board_configuration_form = BoardConfigurationForm(request.form)
            if board_configuration_form.validate():
                board.config.full_name = board_configuration_form.full_name.data
                board.config.description = board_configuration_form.description.data

                if can_update_advanced_board_configs:
                    board.config.pages = board_configuration_form.pages.data
                    board.config.per_page = board_configuration_form.per_page.data
                    board.config.bump_limit = board_configuration_form.bump_limit.data
                    board.config.file_posting = board_configuration_form.file_posting.data
                    board.config.posting_verification_required = board_configuration_form.posting_verification.data

                moderator_service.user_update_board_config(moderator, board)
        elif action_invite_moderator:
            invite_moderator_form = InviteModeratorForm(request.form)
            if invite_moderator_form.validate():
                moderator_username = invite_moderator_form.username.data

                try:
                    moderator_service.user_invite_moderator(
                        request_moderator(), board, moderator_username)
                    invite_messages.append('Moderator invited')
                except ArgumentError as e:
                    invite_messages.append(str(e))
        elif action_remove_moderator:
            # No wtform for this action
            if not check_csrf_token(request.form.get('token')):
                abort(400)

            moderator_username = request.form['username']

            removed_self = False
            try:
                removed_self = moderator_service.user_remove_moderator(
                    moderator, board, moderator_username)
                roles_messages.append('Moderator removed')
            except ArgumentError as e:
                roles_messages.append(str(e))

            if removed_self:
                return redirect(url_for('.mod_boards'))
        elif action_update_roles:
            # Also no wtform
            if not check_csrf_token(request.form.get('token')):
                abort(400)

            moderator_username = request.form['username']

            checked_roles = []
            for board_role in roles.ALL_BOARD_ROLES:
                if request.form.get(board_role) == 'on':
                    checked_roles.append(board_role)

            try:
                moderator_service.user_update_roles(moderator, board,
                                                    moderator_username,
                                                    checked_roles)
                roles_messages.append('Roles updated')
            except ArgumentError as e:
                roles_messages.append(str(e))
            except NoPermissionError as e:
                roles_messages.append('No permission')
        else:
            abort(400)

    if not board_configuration_form:
        board_configuration_form = BoardConfigurationForm(
            full_name=board.config.full_name,
            description=board.config.description,
            pages=board.config.pages,
            per_page=board.config.per_page,
            bump_limit=board.config.bump_limit,
            file_posting=board.config.file_posting,
            posting_verification=board.config.posting_verification_required,
        )

    if not can_update_advanced_board_configs:
        del board_configuration_form.pages
        del board_configuration_form.per_page
        del board_configuration_form.bump_limit
        del board_configuration_form.file_posting
        del board_configuration_form.posting_verification

    if not invite_moderator_form:
        invite_moderator_form = InviteModeratorForm()

    board_configuration_form.action_url = url_for('.mod_board',
                                                  board_name=board_name)
    invite_moderator_form.action_url = url_for('.mod_board',
                                               board_name=board_name,
                                               _anchor='invite')

    board_moderators = moderator_service.get_all_board_moderators_by_board(
        board)

    # Put the request moderator on top for the permissions table
    board_moderators_unsorted = sorted(
        board_moderators,
        key=lambda board_moderator: board_moderator.moderator.id)
    board_moderators = []
    for item in board_moderators_unsorted:
        if item.moderator == moderator:
            board_moderators.append(item)
            break
    for item in board_moderators_unsorted:
        if item.moderator != moderator:
            board_moderators.append(item)

    all_board_roles = roles.ALL_BOARD_ROLES

    return render_template(
        'mod_board.html',
        board=board,
        board_configuration_form=board_configuration_form,
        invite_messages=invite_messages,
        roles_messages=roles_messages,
        invite_moderator_form=invite_moderator_form,
        can_update_board_config=can_update_board_config,
        can_update_advanced_board_configs=can_update_advanced_board_configs,
        can_delete=can_delete,
        can_update_roles=can_update_roles,
        can_invite_moderator=can_invite_moderator,
        can_remove_moderator=can_remove_moderator,
        board_moderators=board_moderators,
        all_board_roles=all_board_roles)
Exemplo n.º 20
0
def mod_board(board_name):
    board = board_service.find_board(board_name)
    if not board:
        abort(404)

    moderator = request_moderator()
    if not moderator_service.moderates_board(moderator, board):
        abort(404)

    # These are purely for configuring the visibility of the various elements on the page,
    # the actions are still checked with the authorizer on post.
    can_update_board_config = moderator_service.can_update_board_config(moderator, board)
    can_update_advanced_board_configs = moderator_service.can_update_advanced_board_configs(moderator)
    can_update_roles = moderator_service.can_update_roles(moderator, board)
    can_invite_moderator = moderator_service.can_invite_moderator(moderator, board)
    can_remove_moderator = moderator_service.can_remove_moderator(moderator, board)
    can_delete = moderator_service.can_delete_board(moderator)

    for_action = request.form.get('for_action')
    action_configure = for_action == 'configuration'
    action_update_roles = for_action == 'update_roles'
    action_invite_moderator = for_action == 'moderator_invite'
    action_remove_moderator = for_action == 'moderator_remove'

    board_configuration_form = None
    invite_messages = []
    invite_moderator_form = None
    roles_messages = []

    if request.method == 'POST':
        if action_configure:
            board_configuration_form = BoardConfigurationForm(request.form)
            if board_configuration_form.validate():
                board.config.full_name = board_configuration_form.full_name.data
                board.config.description = board_configuration_form.description.data

                if can_update_advanced_board_configs:
                    board.config.pages = board_configuration_form.pages.data
                    board.config.per_page = board_configuration_form.per_page.data
                    board.config.bump_limit = board_configuration_form.bump_limit.data
                    board.config.file_posting = board_configuration_form.file_posting.data
                    board.config.posting_verification_required = board_configuration_form.posting_verification.data

                moderator_service.user_update_board_config(moderator, board)
        elif action_invite_moderator:
            invite_moderator_form = InviteModeratorForm(request.form)
            if invite_moderator_form.validate():
                moderator_username = invite_moderator_form.username.data

                try:
                    moderator_service.user_invite_moderator(request_moderator(), board, moderator_username)
                    invite_messages.append('Moderator invited')
                except ArgumentError as e:
                    invite_messages.append(str(e))
        elif action_remove_moderator:
            # No wtform for this action
            if not check_csrf_token(request.form.get('token')):
                abort(400)

            moderator_username = request.form['username']

            removed_self = False
            try:
                removed_self = moderator_service.user_remove_moderator(moderator, board, moderator_username)
                roles_messages.append('Moderator removed')
            except ArgumentError as e:
                roles_messages.append(str(e))

            if removed_self:
                return redirect(url_for('.mod_boards'))
        elif action_update_roles:
            # Also no wtform
            if not check_csrf_token(request.form.get('token')):
                abort(400)

            moderator_username = request.form['username']

            checked_roles = []
            for board_role in roles.ALL_BOARD_ROLES:
                if request.form.get(board_role) == 'on':
                    checked_roles.append(board_role)

            try:
                moderator_service.user_update_roles(moderator, board, moderator_username, checked_roles)
                roles_messages.append('Roles updated')
            except ArgumentError as e:
                roles_messages.append(str(e))
            except NoPermissionError as e:
                roles_messages.append('No permission')
        else:
            abort(400)

    if not board_configuration_form:
        board_configuration_form = BoardConfigurationForm(
            full_name=board.config.full_name,
            description=board.config.description,

            pages=board.config.pages,
            per_page=board.config.per_page,
            bump_limit=board.config.bump_limit,
            file_posting=board.config.file_posting,
            posting_verification=board.config.posting_verification_required,
        )

    if not can_update_advanced_board_configs:
        del board_configuration_form.pages
        del board_configuration_form.per_page
        del board_configuration_form.bump_limit
        del board_configuration_form.file_posting
        del board_configuration_form.posting_verification

    if not invite_moderator_form:
        invite_moderator_form = InviteModeratorForm()

    board_configuration_form.action_url = url_for('.mod_board', board_name=board_name)
    invite_moderator_form.action_url = url_for('.mod_board', board_name=board_name, _anchor='invite')

    board_moderators = moderator_service.get_all_board_moderators_by_board(board)

    # Put the request moderator on top for the permissions table
    board_moderators_unsorted = sorted(board_moderators, key=lambda board_moderator: board_moderator.moderator.id)
    board_moderators = []
    for item in board_moderators_unsorted:
        if item.moderator == moderator:
            board_moderators.append(item)
            break
    for item in board_moderators_unsorted:
        if item.moderator != moderator:
            board_moderators.append(item)

    all_board_roles = roles.ALL_BOARD_ROLES

    return render_template('mod_board.html', board=board,
                           board_configuration_form=board_configuration_form,
                           invite_messages=invite_messages,
                           roles_messages=roles_messages,
                           invite_moderator_form=invite_moderator_form,
                           can_update_board_config=can_update_board_config,
                           can_update_advanced_board_configs=can_update_advanced_board_configs,
                           can_delete=can_delete,
                           can_update_roles=can_update_roles,
                           can_invite_moderator=can_invite_moderator,
                           can_remove_moderator=can_remove_moderator,
                           board_moderators=board_moderators,
                           all_board_roles=all_board_roles)
Exemplo n.º 21
0
def create_post(post_details: PostDetails) -> PostResultModel:
    start_time = now()

    board = board_service.find_board(post_details.board_name)
    if not board:
        raise ArgumentError(MESSAGE_BOARD_NOT_FOUND)

    to_thread = None
    if post_details.thread_refno is not None:
        to_thread = posts.find_thread_by_board_name_thread_refno(
            board.name, post_details.thread_refno)
        if to_thread is None:
            raise ArgumentError(MESSAGE_THREAD_NOT_FOUND)

    _check_post_details(post_details, to_thread, board)

    plugin_manager.execute_hook('on_handle_post', post_details)

    site_config = site_service.get_site_config()
    default_name = site_config.default_name

    # Get moderator if mod_id was set
    moderator = None
    if post_details.mod_id is not None:
        moderator = moderator_service.find_moderator_id(post_details.mod_id)
        if moderator is None:
            raise Exception('Moderator not found')

    post = PostModel()
    post.date = now()
    post.ip4 = post_details.ip4

    if moderator is not None and moderator_service.moderates_board(
            moderator, board):
        post.moderator = moderator

    _handle_text(post, post_details)
    sage = _handle_name(post, post_details, default_name)
    _handle_subject(post, post_details, to_thread)
    _handle_password(post, post_details)

    if post_details.uploaded_file is not None:
        # TODO
        post.file = FileModel()
        post.file.location = post_details.uploaded_file.location
        post.file.thumbnail_location = post_details.uploaded_file.thumbnail_location
        post.file.original_name = post_details.uploaded_file.original_name
        post.file.width = post_details.uploaded_file.width
        post.file.height = post_details.uploaded_file.height
        post.file.size = post_details.uploaded_file.size
        post.file.thumbnail_width = post_details.uploaded_file.thumbnail_width
        post.file.thumbnail_height = post_details.uploaded_file.thumbnail_height

    handle_time = now() - start_time

    if to_thread is None:
        res, insert_time, cache_time = posts.create_thread(board, post)
    else:
        res, insert_time, cache_time = posts.create_post(
            board, to_thread, post, sage)

    _log_post(post_details, res, handle_time + insert_time, cache_time)

    return res