Example #1
0
def user_create(nickname, payload=None):
    about = payload.get('about')
    email = payload.get('email')
    fullname = payload.get('fullname')
    try:
        with connection.xact():
            user_insert = connection.prepare(
                'INSERT INTO "user" VALUES (DEFAULT, $1::citext, $2::citext, $3::citext, $4::citext)'
            )
            user_insert(nickname, about, email, fullname)
    except UniqueError:
        user_select = connection.prepare(
            'SELECT * FROM "user" WHERE nickname = $1::citext OR email = $2::citext'
        )
        conflict_list = []
        for _, ex_nickname, ex_about, ex_email, ex_fullname in user_select(
                nickname, email):
            conflict_list.append(
                flush_dictionary({
                    'nickname': ex_nickname,
                    'about': ex_about,
                    'email': ex_email,
                    'fullname': ex_fullname
                }))
        return conflict_list, 409

    result = flush_dictionary({
        'nickname': nickname,
        'about': about,
        'email': email,
        'fullname': fullname
    })
    return result, 201
Example #2
0
def forum_create(payload):
    slug = payload.get('slug')
    title = payload.get('title')
    user = payload.get('user')

    try:
        with connection.xact():
            user_select = connection.prepare(
                'SELECT * FROM "user" WHERE nickname = $1::CITEXT')
            forum_insert = connection.prepare(
                'INSERT INTO forum VALUES (DEFAULT, $1::CITEXT, $2::TEXT, $3::BIGINT)'
            )

            user_record = user_select.first(user)
            if not user_record:
                resp = DEFAULT_ERROR_DICT
                return resp, 404
            user_id = user_record[0]

            forum_insert(slug, title, user_id)

            resp = {'slug': slug, 'user': user_record[1], 'title': title}
            return resp, 201
    except:
        forum_select = connection.prepare(
            'SELECT * FROM forum WHERE slug = $1::CITEXT')
        forum = forum_select.first(slug)

        if forum:
            user_select = connection.prepare(
                'SELECT * FROM "user" WHERE id = $1::BIGINT')
            user = user_select.first(forum[3])
            username = user[1]
            resp = {'slug': forum[1], 'user': username, 'title': forum[2]}
            return resp, 409
Example #3
0
def user_objects_get(slug, query_args):
    desc = query_args.get('desc', False)
    desc = True if desc == 'true' else False
    since = query_args.get('since')
    limit = query_args.get('limit')
    if limit:
        limit = int(limit)
    forum_id = connection.prepare(
        'SELECT id from forum WHERE slug = $1').first(slug)
    if not forum_id:
        error = DEFAULT_ERROR_DICT
        return error, 404
    sort_option = ['ASC', 'DESC'][desc]
    comp = ['>', '<'][desc]
    since_opt = ''

    if limit:
        limit_opt = 'LIMIT $2'
        if since:
            since_opt = 'AND usernick ' + comp + '$3'

        sql_query = '''
SELECT usr.*
FROM userforum
  JOIN "user" AS usr ON userid = usr.id
WHERE forumid = $1 {since}
ORDER BY usernick {sort} {limit}'''.format(sort=sort_option,
                                           limit=limit_opt,
                                           since=since_opt)
        users_select = connection.prepare(sql_query)

        if since:
            users = users_select(forum_id, limit, since)
        else:
            users = users_select(forum_id, limit)
    else:
        if since:
            since_opt = 'AND nickname ' + comp + '$2'

        sql_query = '''
SELECT usr.*
FROM userforum
  JOIN "user" AS usr ON userid = usr.id
WHERE forumid = $1 {since}
ORDER BY usernick {sort}'''.format(sort=sort_option, since=since_opt)
        users_select = connection.prepare(sql_query)

        if since:
            users = users_select(forum_id, since)
        else:
            users = users_select(forum_id)

    result = [{
        'nickname': user[1],
        'about': user[2],
        'email': user[3],
        'fullname': user[4]
    } for user in users]
    return result, 200
Example #4
0
def post_details_update(post_id, payload):
    new_message = payload.get('message')
    post_id = int(post_id)
    message_update = connection.prepare('''
                WITH updated AS (
                    UPDATE message SET message = $2, isedited = sub.isedited OR sub.message IS DISTINCT FROM $2
                    FROM (
                        SELECT * FROM message WHERE id = $1 FOR UPDATE
                    ) as sub
                    JOIN "user" ON sub.authorid = "user".id
                    JOIN forum ON sub.forumid = forum.id
                    RETURNING sub.authorid, sub.threadid, sub.forumid, 
                    sub.created_on, message.message, message.isedited, slug, nickname
                )
                SELECT created_on, message, nickname, threadid, slug, isedited FROM updated'''
                                        )
    # Consider returning less  {remove thread} (Optimisation)
    # Consider using a pre-update trigger to determine isedited and prevent needless message updates (Optimisation)

    if new_message:
        message = message_update.first(post_id, new_message)
    else:
        message = connection.prepare('''
                    SELECT m.created_on, m.message, "user".nickname, m.threadid, forum.slug, isedited FROM (
                        SELECT created_on, message, authorid, threadid, forumid, isedited
                        FROM message WHERE id = $1
                    ) as m
                    JOIN "user" ON m.authorid = "user".id
                    JOIN forum ON m.forumid = forum.id''').first(post_id)

    if not message:
        error = DEFAULT_ERROR_DICT
        return error, 404
    # Consider returning less  {remove thread} (Optimisation)

    resp = {
        'id': post_id,
        'created': normalize_timestamp(message[0], time_to='+03:00'),
        'message': message[1],
        'author': message[2],
        'thread': message[3],
        'forum': message[4],
        'isEdited': message[5]
    }

    return resp, 200
Example #5
0
def thread_objects_get(slug, query_args):
    limit = query_args.get('limit')
    desc = query_args.get('desc', False)
    desc = True if desc == 'true' else False

    since = query_args.get('since')
    sort_option = ['ASC', 'DESC'][1 if desc else 0]
    since_cond = ''
    if since is not None:
        # since = normalize_timestamp(since.decode('utf-8'))
        since = normalize_timestamp(since)
        since_cond = ' AND created_on ' + [
            '>=', '<='
        ][1 if desc else 0] + '\'' + str(since) + '\''

    forum_select = connection.prepare(
        'SELECT * FROM forum WHERE slug = $1::CITEXT')
    forum = forum_select.first(slug)

    if not forum:
        resp = DEFAULT_ERROR_DICT
        return resp, 404
    thread_select = connection.prepare(
        'SELECT t.id, slug, created_on, message, title, nickname, voice'
        ' FROM thread as t'
        ' JOIN "user" as u ON t.authorid = u.id  WHERE t.forumid = $1::BIGINT'
        + since_cond + ' ORDER BY created_on ' + sort_option + ' LIMIT $2')
    threads = []

    for id, slug, created, message, title, nickname, voice in thread_select(
            forum[0],
            int(limit) if limit else None):
        thread = {
            'id': id,
            'slug': slug,
            'created': normalize_timestamp(created),
            'message': message,
            'title': title,
            'author': nickname,
            'forum': forum[1],
            'votes': voice,
        }

        threads.append(flush_dictionary(thread))
    return threads, 200
Example #6
0
def forum_details_get(slug):
    forum_select = connection.prepare(
        'SELECT * FROM forum WHERE slug = $1::CITEXT')
    forum = forum_select.first(slug)

    if forum:
        user_select = connection.prepare(
            'SELECT * FROM "user" WHERE id = $1::BIGINT')
        user = user_select.first(forum[3])
        username = user[1]
        resp = {
            'slug': forum[1],
            'user': username,
            'title': forum[2],
            'posts': forum[4],
            'threads': forum[5]
        }
        return resp, 200
    resp = DEFAULT_ERROR_DICT
    return resp, 404
Example #7
0
def user_profile_update(nickname, payload):
    about = payload.get('about')
    email = payload.get('email')
    fullname = payload.get('fullname')
    try:
        with connection.xact():
            if payload:
                user_update = connection.prepare(
                    '''UPDATE "user" SET about = coalesce($2, about), 
                                                 email = coalesce($3, email),
                                                 fullname = coalesce($4, fullname) 
                                                 WHERE nickname = $1::CITEXT'''
                )
                affected = user_update.first(nickname, about, email, fullname)
                if affected is 0:
                    resp = DEFAULT_ERROR_DICT
                    return resp, 404

            user_select = connection.prepare(
                'SELECT * FROM "user" WHERE nickname = $1::CITEXT')
            user = user_select.first(nickname)
            if user:
                about = user[2]
                email = user[3]
                fullname = user[4]
            else:
                resp = DEFAULT_ERROR_DICT
                return resp, 404
        return {
            'fullname': fullname,
            'email': email,
            'nickname': nickname,
            'about': about
        }, 200
    except:
        resp = DEFAULT_ERROR_DICT
        return resp, 409
Example #8
0
def user_profile_get(nickname):
    with connection.xact():
        user_select = connection.prepare(
            'SELECT * FROM "user" WHERE nickname = $1::CITEXT')
        user = user_select.first(nickname)
    if user:
        resp = flush_dictionary({
            'nickname': user[1],
            'about': user[2],
            'email': user[3],
            'fullname': user[4]
        })
        return resp, 200
    else:
        resp = DEFAULT_ERROR_DICT
        return resp, 404
Example #9
0
def service_status_get():
    status = connection.prepare('''
        SELECT count(forum.id) FROM forum
        UNION ALL
        SELECT count(thread.id) FROM thread
        UNION ALL
        SELECT count("user".id) FROM "user"
        UNION ALL
        SELECT count(message.id) FROM message''')()

    resp = {
        'forum': status[0][0],
        'post': status[3][0],
        'thread': status[1][0],
        'user': status[2][0]
    }

    return resp, 200
Example #10
0
def thread_details_update(slug_or_id, payload):
    thread_slug, thread_id = parse_slug_or_id(slug_or_id)
    message = payload.get('message')
    title = payload.get('title')

    with connection.xact():
        thread_update = connection.prepare(
            '''UPDATE thread SET message = coalesce($2, message), title = coalesce($3, title) WHERE {cond}
            RETURNING id, slug, created_on, message, title, authorid, forumid, voice'''
            .format(cond='id = $1' if thread_id else 'slug = $1'))

        if thread_id:
            thread = thread_update.first(thread_id, message, title)
        else:
            thread = thread_update.first(thread_slug, message, title)

        if not thread:
            error = DEFAULT_ERROR_DICT
            return error, 404
        thread_id, thread_slug, thread_created_on, thread_message, \
        thread_title, thread_author_id, forum_id, voice \
            = thread

        author = api.methods.user_select_by_id.first(thread_author_id)[1]
        forum_slug = api.methods.forum_select_by_id.first(forum_id)[1]

    resp = {
        'slug': thread_slug,
        'forum': forum_slug,
        'message': thread_message,
        'title': thread_title,
        'author': author,
        'id': thread_id,
        'created': normalize_timestamp(thread_created_on),
        'votes': voice
    }
    return resp, 200
Example #11
0
from settings import connection


user_select_by_id = connection.prepare('SELECT * FROM "user" WHERE id = $1::BIGINT')
user_select_by_nickname = connection.prepare('SELECT * FROM "user" WHERE nickname = $1::CITEXT')

forum_select_by_id = connection.prepare('SELECT * FROM forum WHERE id = $1::BIGINT')

thread_select_by_id = connection.prepare('SELECT * FROM thread WHERE id = $1::BIGINT')
thread_select_by_slug = connection.prepare('SELECT * FROM thread WHERE slug = $1::CITEXT')

increment_thread_count = connection.prepare('''
UPDATE forum
SET threads_count = threads_count + 1
WHERE id = $1;''')
Example #12
0
def post_create(slug_or_id, payload):
    thread_id = None
    slug = None
    try:
        thread_id = int(slug_or_id)
    except:
        slug = slug_or_id

    created = normalize_timestamp(arrow.Arrow.utcnow())
    try:
        with connection.xact() as xact:
            # Оставить
            if thread_id is not None:
                thread_select = connection.prepare(
                    'SELECT * FROM thread WHERE id = $1::BIGINT')
                thread = thread_select.first(thread_id)
            else:
                thread_select = connection.prepare(
                    'SELECT * FROM thread WHERE slug = $1::CITEXT')
                thread = thread_select.first(slug)
            if not thread:
                error = DEFAULT_ERROR_DICT
                return error, 404
            if not payload:
                return [], 201

            thread_id = thread[0]

            forum_select = connection.prepare(
                'SELECT id, slug FROM forum WHERE id = $1::BIGINT')
            forum = forum_select.first(thread[6])
            forum_slug = forum[1]
            forum_id = forum[0]

            # Оставить

            message_insert = connection.prepare(
                '''INSERT INTO message (created_on, "message", authorid, threadid, forumid, parentid)
                    SELECT
                      $1 :: TEXT :: TIMESTAMP,
                      $2 :: TEXT,
                      usr.id,
                      $4 :: BIGINT,
                      $5 :: BIGINT,
                      $6 :: BIGINT
                    FROM "user" AS usr
                   WHERE nickname = $3 :: CITEXT RETURNING id, authorid;''')

            forum_user_insert = connection.prepare(
                '''INSERT INTO userforum (forumid, usernick, userid) VALUES ($1, $2::CITEXT, $3)
ON CONFLICT DO NOTHING;''')

            result = []
            forumuser = []
            created_str = normalize_timestamp(created,
                                              json_format=True,
                                              time_to='+03:00')

            try:
                for item in payload:
                    id = message_insert(created, item['message'],
                                        item['author'], thread_id, forum_id,
                                        item.get('parent', 0))
                    if len(id) != 1:
                        xact.rollback()
                        raise NotFoundException
                    message = {
                        'created': created_str,
                        'message': item['message'],
                        'author': item['author'],
                        'id': id[0][0],
                        'parent': to_int(item.get('parent', 0)),
                        'thread': thread_id,
                        'forum': forum_slug
                    }
                    forumuser.append((forum_id, item['author'], id[0][1]))
                    result.append(message)
            except KeyError:
                error = DEFAULT_ERROR_DICT
                return error, 404

            forumuser.sort(key=lambda val: val[1])
            forum_user_insert.load_rows(forumuser)

            connection.prepare('''
UPDATE forum
SET posts_count = posts_count + $1
WHERE id = $2;''')(len(payload), forum_id)

            return result, 201
    except NotFoundException:
        return DEFAULT_ERROR_DICT, 404
    except Exception as e:
        if e.message == 'invalid_foreign_key':
            error = DEFAULT_ERROR_DICT
            return error, 409
        import traceback
        print(traceback.format_exc())
Example #13
0
def post_objects_get(slug_or_id, query_args):
    thread_slug, thread_id = parse_slug_or_id(slug_or_id)
    sort = query_args.get('sort')
    since = query_args.get('since')
    if since is not None:
        since = int(since)

    desc = query_args.get('desc', False)
    desc = True if desc == 'true' else False
    if desc:
        sort_option = 'DESC'
    else:
        sort_option = 'ASC'

    limit = int(query_args.get('limit'))

    comp = ['>', '<'][1 if desc else 0]
    if since:
        since_cond_message = ' AND message.id ' + [
            '>', '<'
        ][1 if desc else 0] + ' $3::BIGINT'
        since_cond_m = ' WHERE m.id ' + ['>', '<'
                                         ][1 if desc else 0] + ' $3::BIGINT'
        since_cond_tree = 'WHERE m.parenttree' + comp + ' (SELECT parenttree FROM message WHERE id = $3::BIGINT)'  # AND (message.parenttree[2] ' + ['>', '<'][desc] + ' $3::BIGINT OR message.parenttree[2] IS NULL) '
    else:
        since_cond_tree = since_cond_message = since_cond_m = ''
    select_fields = 'SELECT m.id, m.created_on, m.message, m.threadid, m.parentid, "user".nickname, forum.slug'
    inner_select_fields = '''SELECT message.id, message.created_on, message.threadid, message.message,
                             message.parentid, message.authorid, message.forumid'''
    inner_select_fields_tree = inner_select_fields + ', message.parenttree'

    with connection.xact():
        messages = []
        if not thread_id:
            thread_id = connection.prepare(
                'SELECT id FROM thread WHERE slug = $1').first(thread_slug)
        else:
            thread_id = connection.prepare(
                'SELECT id FROM thread WHERE id = $1').first(thread_id)
        if not thread_id:
            error = DEFAULT_ERROR_DICT
            return error, 404
        if sort == 'flat' or sort is None:
            if thread_slug:
                message_select = connection.prepare('''
                    {select_fields}
                     FROM (
                         {select_inner}
                         FROM message JOIN thread ON message.threadid = thread.id 
                         WHERE thread.slug = $1 {since} ORDER BY message.id {sort} LIMIT $2
                     ) as m
                     JOIN "user" ON "user".id = m.authorid
                     JOIN forum ON m.forumid = forum.id
                     ORDER BY m.id  {sort}'''.format(
                    sort=sort_option,
                    since=since_cond_message,
                    select_fields=select_fields,
                    select_inner=inner_select_fields))
                if since:
                    messages = message_select(thread_slug, limit, since)
                else:
                    messages = message_select(thread_slug, limit)
            else:
                message_select = connection.prepare('''
                    {select_fields}
                     FROM (
                        {select_inner}
                        FROM message WHERE message.threadid = $1 {since} ORDER BY message.id {sort} LIMIT $2
                     ) as m
                     JOIN "user" ON "user".id = m.authorid
                     JOIN forum ON m.forumid = forum.id
                     ORDER BY m.id {sort}'''.format(
                    sort=sort_option,
                    since=since_cond_message,
                    select_fields=select_fields,
                    select_inner=inner_select_fields))
                if since:
                    messages = message_select(thread_id, limit, since)
                else:
                    messages = message_select(thread_id, limit)
        elif sort == 'tree':
            if thread_slug:
                message_select = connection.prepare('''
                        {select_fields}
                         FROM (
                             {select_inner} 
                             FROM message JOIN thread ON message.threadid = thread.id 
                             WHERE thread.slug = $1 ORDER BY message.parenttree {sort}
                         ) as m
                         JOIN "user" ON "user".id = m.authorid
                         JOIN forum ON m.forumid = forum.id
                         {since}
                         ORDER BY m.parenttree {sort} LIMIT $2'''.format(
                    sort=sort_option,
                    since=since_cond_tree,
                    select_fields=select_fields,
                    select_inner=inner_select_fields_tree))
                if since:
                    messages = message_select(thread_slug, limit, since)
                else:
                    messages = message_select(thread_slug, limit)
            else:
                message_select = connection.prepare('''
                        {select_fields}
                         FROM (
                             {select_inner}
                             FROM message
                             WHERE message.threadid = $1 ORDER BY message.parenttree {sort}
                         ) as m
                         JOIN "user" ON "user".id = m.authorid
                         JOIN forum ON m.forumid = forum.id
                         {since} 
                         ORDER BY m.parenttree {sort} LIMIT $2'''.format(
                    sort=sort_option,
                    since=since_cond_tree,
                    select_fields=select_fields,
                    select_inner=inner_select_fields_tree))
                if since:
                    messages = message_select(thread_id, limit, since)
                else:
                    messages = message_select(thread_id, limit)
        elif sort == 'parent_tree':
            if since:
                message_select = connection.prepare('''
                    {select_fields}
                    FROM (
                        SELECT * FROM message
                        WHERE message.threadid = $1 AND (message.parenttree)[1] in (
                            SELECT
                                m1.id
                                 FROM message m1
                                 WHERE m1.parentid = 0 AND m1.threadid = $1 AND m1.parenttree {comp} (
                                         SELECT m2.parenttree
                                         FROM message m2
                                         WHERE m2.id = $3
                                 )
                                 ORDER BY m1.parenttree {sort} LIMIT $2
                            )
                    ) as m
                    JOIN "user" ON "user".id = m.authorid
                    JOIN forum ON m.forumid = forum.id
                    ORDER BY m.parenttree {sort}'''.format(
                    sort=sort_option,
                    comp=comp,
                    since=since_cond_message,
                    select_fields=select_fields,
                    select_inner=inner_select_fields_tree))
                messages = message_select(thread_id, limit, since)
            else:
                message_select = connection.prepare('''
                    {select_fields}
                    FROM (
                        SELECT * FROM message
                        WHERE message.threadid = $1 AND message.parenttree [1] in (
                            SELECT
                                m1.id 
                                 FROM message m1
                                 WHERE m1.parentid = 0 AND m1.threadid = $1
                                 ORDER BY m1.parenttree {sort} LIMIT $2
                            )
                    ) as m
                    JOIN "user" ON "user".id = m.authorid
                    JOIN forum ON m.forumid = forum.id
                    ORDER BY m.parenttree {sort}'''.format(
                    sort=sort_option,
                    since=since_cond_message,
                    select_fields=select_fields,
                    select_inner=inner_select_fields_tree))
                messages = message_select(thread_id, limit)

    result = []
    for x in messages:
        message = {
            'id': x[0],
            'created': normalize_timestamp(x[1], json_format=True),
            'message': x[2],
            'thread': x[3],
            'parent': to_int(x[4]),
            'author': x[5],
            'forum': x[6]
        }
        result.append(message)
    return result, 200
Example #14
0
def thread_create(slug, payload):
    author = payload.get('author')
    created = payload.get('created')
    thread_slug = payload.get('slug')
    message = payload.get('message')
    title = payload.get('title')

    try:
        with connection.xact():
            if created:
                created = normalize_timestamp(created)

            author_select = connection.prepare('SELECT * FROM "user" WHERE nickname = $1::CITEXT')
            forum_select = connection.prepare('SELECT * FROM forum WHERE slug = $1::CITEXT')
            thread_create = connection.prepare(
                'INSERT INTO thread VALUES (DEFAULT, $1::CITEXT, $2::TEXT::TIMESTAMP, '
                '$3::TEXT, $4::TEXT, $5::BIGINT, $6::BIGINT) RETURNING id')
            forum = forum_select.first(slug)
            if not forum:
                resp = DEFAULT_ERROR_DICT
                return resp, 404
            author = author_select.first(author)
            if not author:
                resp = DEFAULT_ERROR_DICT
                return resp, 404
            thread_id = thread_create.first(thread_slug, created, message, title, author[0], forum[0])

            increment_thread_count(forum[0])

            connection.prepare('INSERT INTO userforum (forumid, usernick, userid) VALUES ($1, $2::CITEXT, $3) ON CONFLICT DO NOTHING;')(forum[0], author[1], author[0])

            raw_resp = {
                'slug': thread_slug,
                'forum': forum[1],
                'message': message,
                'title': title,
                'author': author[1],
                'id': thread_id,
                'created': created
            }
            resp = flush_dictionary(raw_resp)
            return resp, 201

    except UniqueError:
        thread_select = connection.prepare('SELECT * FROM thread WHERE slug = $1::CITEXT')
        thread = thread_select.first(thread_slug)
        thread_id = thread[0]
        author_id = thread[5]
        forum_id = thread[6]
        author = connection.prepare('SELECT * FROM "user" WHERE id = $1::BIGINT').first(author_id)
        forum = connection.prepare('SELECT * FROM forum WHERE id = $1::BIGINT').first(forum_id)

        raw_resp = {
            'slug': thread[1],
            'forum': forum[1],
            'message': thread[3],
            'title': thread[4],
            'author': author[1],
            'id': thread_id,
            'created': normalize_timestamp(thread[2])
        }
        resp = flush_dictionary(raw_resp)
        return resp, 409
Example #15
0
def post_details_get(post_id, query_args):
    post_id = int(post_id)
    related = query_args.get('related')

    related_items = {'user': False, 'thread': False, 'forum': False}

    if related:
        related = related.split(',')
        for item in related:
            if item in ['user', 'thread', 'forum']:
                related_items[item] = True

    message_fields_len = 7

    message_select = connection.prepare('''
        SELECT m.created_on, m.message, "user".nickname, m.threadid, forum.slug, isedited, m.parentid
        {thread_fields}
        {forum_fields}
        {user_fields}
        FROM
        (SELECT authorid, threadid, forumid, parentid, created_on, message, isedited FROM message
        WHERE id = $1) as m
        JOIN "user" ON "user".id = m.authorid
        JOIN forum ON m.forumid = forum.id
        {join_thread}
        {join_forum_author}'''.format(
        join_thread='JOIN thread on m.threadid = thread.id '
        'JOIN "user" AS thread_author ON thread_author.id = thread.authorid'
        if related_items['thread'] else '',
        thread_fields=', thread.id, thread.slug, thread.created_on, '
        'thread.message, thread.title, thread.voice, thread_author.nickname'
        if related_items['thread'] else '',
        join_forum_author=
        'JOIN "user" AS forum_author ON forum_author.id = forum.userid'
        if related_items['forum'] else '',
        forum_fields=
        ', forum.id, forum.title, forum_author.nickname, forum.posts_count, forum.threads_count'
        if related_items['forum'] else '',
        user_fields=', "user".about, "user".email, "user".fullname'
        if related_items['user'] else ''))

    message = message_select.first(post_id)
    if not message:
        error = DEFAULT_ERROR_DICT
        return error, 404

    if related_items['thread']:
        thread_offset = message_fields_len

        thread = {
            'id': message[thread_offset],
            'slug': message[thread_offset + 1],
            'created': normalize_timestamp(message[thread_offset + 2]),
            'message': message[thread_offset + 3],
            'title': message[thread_offset + 4],
            'votes': message[thread_offset + 5],
            'author': message[thread_offset + 6],
            'forum': message[4]
        }

        thread_fields_len = 7
    else:
        thread = None
        thread_fields_len = 0

    if related_items['forum']:
        forum_offset = message_fields_len + thread_fields_len
        forum_fields_len = 5

        forum = {
            'id': message[forum_offset],
            'slug': message[4],
            'title': message[forum_offset + 1],
            'user': message[forum_offset + 2],
            'posts': message[forum_offset + 3],
            'threads': message[forum_offset + 4]
        }

    else:
        forum = None
        forum_fields_len = 0

    if related_items['user']:
        user_offset = message_fields_len + forum_fields_len + thread_fields_len

        user = {
            'nickname': message[2],
            'about': message[user_offset],
            'email': message[user_offset + 1],
            'fullname': message[user_offset + 2]
        }
    else:
        user = None

    post = {
        'id': post_id,
        'created': normalize_timestamp(message[0], time_to='+03:00'),
        'message': message[1],
        'author': message[2],
        'thread': message[3],
        'forum': message[4],
        'isEdited': message[5],
        'parent': message[6]
    }

    resp = {'post': post, 'thread': thread, 'forum': forum, 'author': user}

    return flush_dictionary(resp), 200