Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found
Select Git revision

Target

Select target project
  • hive/hivemind
1 result
Select Git revision
Show changes
Commits on Source (7)
......@@ -484,21 +484,32 @@ def setup(db):
AS
$function$
DECLARE
post_id INT = 0;
__post_id INT = 0;
BEGIN
IF (_author <> '' OR _permlink <> '') THEN
SELECT INTO post_id COALESCE( (
SELECT INTO __post_id COALESCE( (
SELECT hp.id
FROM hive_posts hp
JOIN hive_accounts ha ON ha.id = hp.author_id
JOIN hive_permlink_data hpd ON hpd.id = hp.permlink_id
WHERE ha.name = _author AND hpd.permlink = _permlink AND hp.counter_deleted = 0
), 0 );
IF _check AND post_id = 0 THEN
RAISE EXCEPTION 'Post %/% does not exist', _author, _permlink;
IF _check AND __post_id = 0 THEN
SELECT INTO __post_id (
SELECT COUNT(hp.id)
FROM hive_posts hp
JOIN hive_accounts ha ON ha.id = hp.author_id
JOIN hive_permlink_data hpd ON hpd.id = hp.permlink_id
WHERE ha.name = _author AND hpd.permlink = _permlink
);
IF __post_id = 0 THEN
RAISE EXCEPTION 'Post %/% does not exist', _author, _permlink;
ELSE
RAISE EXCEPTION 'Post %/% was deleted % time(s)', _author, _permlink, __post_id;
END IF;
END IF;
END IF;
RETURN post_id;
RETURN __post_id;
END
$function$
;
......@@ -1673,6 +1684,8 @@ def setup(db):
"bridge_get_account_posts_by_replies.sql",
"bridge_get_relationship_between_accounts.sql",
"bridge_get_post.sql",
"condenser_api_post_ex_type.sql",
"condenser_get_content.sql",
"condenser_get_discussions_by_created.sql",
"condenser_get_discussions_by_blog.sql",
"hot_and_trends.sql",
......
DROP TYPE IF EXISTS condenser_api_post_ex CASCADE;
-- type for fat node style post of get_content()
CREATE TYPE condenser_api_post_ex AS (
id INT,
author VARCHAR(16),
permlink VARCHAR(255),
author_rep BIGINT,
title VARCHAR(512),
body TEXT,
category VARCHAR(255),
depth SMALLINT,
promoted DECIMAL(10,3),
payout DECIMAL(10,3),
pending_payout DECIMAL(10,3),
payout_at TIMESTAMP,
is_paidout BOOLEAN,
children INT,
votes INT,
created_at TIMESTAMP,
updated_at TIMESTAMP,
rshares NUMERIC,
abs_rshares NUMERIC,
json TEXT,
is_hidden BOOLEAN,
is_grayed BOOLEAN,
total_votes BIGINT,
net_votes BIGINT,
total_vote_weight NUMERIC,
parent_author VARCHAR(16),
parent_permlink_or_category VARCHAR(255),
curator_payout_value VARCHAR(30),
root_author VARCHAR(16),
root_permlink VARCHAR(255),
max_accepted_payout VARCHAR(30),
percent_hbd INT,
allow_replies BOOLEAN,
allow_votes BOOLEAN,
allow_curation_rewards BOOLEAN,
beneficiaries JSON,
url TEXT,
root_title VARCHAR(512),
active TIMESTAMP,
author_rewards BIGINT
);
DROP FUNCTION IF EXISTS condenser_get_content;
CREATE FUNCTION condenser_get_content( in _author VARCHAR, in _permlink VARCHAR )
RETURNS SETOF condenser_api_post_ex
AS
$function$
DECLARE
__post_id INT;
BEGIN
__post_id = find_comment_id( _author, _permlink, True );
RETURN QUERY SELECT
hp.id,
hp.author,
hp.permlink,
hp.author_rep,
hp.title,
hp.body,
hp.category,
hp.depth,
hp.promoted,
hp.payout,
hp.pending_payout,
hp.payout_at,
hp.is_paidout,
hp.children,
hp.votes,
hp.created_at,
hp.updated_at,
hp.rshares,
hp.abs_rshares,
hp.json,
hp.is_hidden,
hp.is_grayed,
hp.total_votes,
hp.net_votes,
hp.total_vote_weight,
hp.parent_author,
hp.parent_permlink_or_category,
hp.curator_payout_value,
hp.root_author,
hp.root_permlink,
hp.max_accepted_payout,
hp.percent_hbd,
hp.allow_replies,
hp.allow_votes,
hp.allow_curation_rewards,
hp.beneficiaries,
hp.url,
hp.root_title,
hp.active,
hp.author_rewards
FROM hive_posts_view hp
WHERE hp.id = __post_id;
END
$function$
language plpgsql STABLE;
DROP FUNCTION IF EXISTS condenser_get_content_replies;
CREATE FUNCTION condenser_get_content_replies( in _author VARCHAR, in _permlink VARCHAR )
RETURNS SETOF condenser_api_post_ex
AS
$function$
DECLARE
__post_id INT;
BEGIN
__post_id = find_comment_id( _author, _permlink, True );
RETURN QUERY SELECT
hp.id,
hp.author,
hp.permlink,
hp.author_rep,
hp.title,
hp.body,
hp.category,
hp.depth,
hp.promoted,
hp.payout,
hp.pending_payout,
hp.payout_at,
hp.is_paidout,
hp.children,
hp.votes,
hp.created_at,
hp.updated_at,
hp.rshares,
hp.abs_rshares,
hp.json,
hp.is_hidden,
hp.is_grayed,
hp.total_votes,
hp.net_votes,
hp.total_vote_weight,
hp.parent_author,
hp.parent_permlink_or_category,
hp.curator_payout_value,
hp.root_author,
hp.root_permlink,
hp.max_accepted_payout,
hp.percent_hbd,
hp.allow_replies,
hp.allow_votes,
hp.allow_curation_rewards,
hp.beneficiaries,
hp.url,
hp.root_title,
hp.active,
hp.author_rewards
FROM hive_posts_view hp
WHERE hp.parent_id = __post_id
ORDER BY hp.id;
END
$function$
language plpgsql STABLE;
......@@ -7,6 +7,7 @@ import logging
import datetime
from dateutil.relativedelta import relativedelta
from psycopg2.errors import RaiseException
from jsonrpcserver.exceptions import ApiError as RPCApiError
log = logging.getLogger(__name__)
......@@ -15,16 +16,22 @@ class ApiError(Exception):
# pylint: disable=unnecessary-pass
pass
# values -32768..-32000 are reserved
ACCESS_TO_DELETED_POST_ERROR_CODE = -31999
def return_error_info(function):
"""Async API method decorator which catches and formats exceptions."""
@wraps(function)
async def wrapper(*args, **kwargs):
"""Catch ApiError and AssersionError (always due to user error)."""
"""Catch ApiError and AssertionError (always due to user error)."""
try:
return await function(*args, **kwargs)
except (RaiseException) as e:
log.error("PGSQL: %s\n%s", repr(e), traceback.format_exc())
raise AssertionError(e.diag.message_primary)
msg = e.diag.message_primary
if 'was deleted' in msg:
raise RPCApiError('Invalid parameters', ACCESS_TO_DELETED_POST_ERROR_CODE, msg)
else:
raise AssertionError(msg)
except (ApiError, AssertionError, TypeError, Exception) as e:
if isinstance(e, KeyError):
#TODO: KeyError overloaded for method not found. Any KeyErrors
......
......@@ -3,7 +3,7 @@ from json import loads
from functools import wraps
import hive.server.condenser_api.cursor as cursor
from hive.server.condenser_api.objects import load_posts, load_posts_reblogs, resultset_to_posts
from hive.server.condenser_api.objects import load_posts, load_posts_reblogs
from hive.server.condenser_api.objects import _mute_votes, _condenser_post_object
from hive.server.common.helpers import (
ApiError,
......@@ -23,23 +23,24 @@ from hive.utils.normalize import time_string_with_t
SQL_TEMPLATE = """
SELECT
hp.id,
hp.community_id,
hp.author,
hp.permlink,
hp.author_rep,
hp.title,
hp.body,
hp.category,
hp.depth,
hp.promoted,
hp.payout,
hp.last_payout_at,
hp.cashout_time,
hp.pending_payout,
hp.payout_at,
hp.is_paidout,
hp.children,
hp.votes,
hp.created_at,
hp.updated_at,
hp.rshares,
hp.abs_rshares,
hp.json,
hp.is_hidden,
hp.is_grayed,
......@@ -59,13 +60,8 @@ SQL_TEMPLATE = """
hp.beneficiaries,
hp.url,
hp.root_title,
hp.abs_rshares,
hp.active,
hp.author_rewards,
hp.author_rep,
hp.payout_at,
hp.pending_payout,
hp.active_votes
hp.author_rewards
FROM hive_posts_view hp
"""
......@@ -168,12 +164,8 @@ async def _get_content_impl(db, fat_node_style, author: str, permlink: str, obse
"""Get a single post object."""
valid_account(author)
valid_permlink(permlink)
#force copy
sql = str(SQL_TEMPLATE)
sql += """
WHERE
hp.author = :author AND hp.permlink = :permlink
"""
sql = "SELECT * FROM condenser_get_content(:author, :permlink)"
post = None
result = await db.query_all(sql, author=author, permlink=permlink)
......@@ -187,7 +179,6 @@ async def _get_content_impl(db, fat_node_style, author: str, permlink: str, obse
blacklists_for_user = await Mutes.get_blacklists_for_observer(observer, context)
post['active_votes'] = _mute_votes(post['active_votes'], blacklists_for_user.keys())
assert post, 'post was not found in cache'
return post
@return_error_info
......@@ -201,19 +192,19 @@ async def _get_content_replies_impl(db, fat_node_style, author: str, permlink: s
valid_account(author)
valid_permlink(permlink)
#force copy
sql = str(SQL_TEMPLATE)
sql += """
WHERE
hp.parent_author = :author AND hp.parent_permlink_or_category = :permlink
ORDER BY
hp.id
LIMIT :limit
"""
sql = "SELECT * FROM condenser_get_content_replies(:author, :permlink)"
result = await db.query_all(sql, author=author, permlink=permlink)
muted_accounts = Mutes.all()
result = await db.query_all(sql, author=author, permlink=permlink, limit=5000)
posts = []
for row in result:
row = dict(row)
post = _condenser_post_object(row, get_content_additions=fat_node_style)
post['active_votes'] = await find_votes_impl(db, row['author'], row['permlink'], VotesPresentation.ActiveVotes if fat_node_style else VotesPresentation.CondenserApi)
post['active_votes'] = _mute_votes(post['active_votes'], muted_accounts)
posts.append(post)
posts = await resultset_to_posts(db=db, fat_node_style=fat_node_style, resultset=result, truncate_body=0)
return posts
# Discussion Queries
......@@ -238,78 +229,6 @@ def nested_query_compat(function):
return function(*args, **kwargs)
return wrapper
@return_error_info
@nested_query_compat
async def get_discussions_by(discussion_type, context, start_author: str = '',
start_permlink: str = '', limit: int = 20,
tag: str = None, truncate_body: int = 0,
filter_tags: list = None):
""" Common implementation for get_discussions_by calls """
assert not filter_tags, 'filter tags not supported'
assert discussion_type in ['trending', 'hot', 'created', 'promoted',
'payout', 'payout_comments'], 'invalid discussion type'
valid_account(start_author, allow_empty=True)
valid_permlink(start_permlink, allow_empty=True)
valid_limit(limit, 100, 20)
valid_tag(tag, allow_empty=True)
db = context['db']
sql = "---get_discussions_by_" + discussion_type + "\r\n" + str(SQL_TEMPLATE)
if discussion_type == 'trending':
sql = sql + """WHERE NOT hp.is_paidout %s ORDER BY hp.sc_trend DESC LIMIT :limit """
elif discussion_type == 'hot':
sql = sql + """WHERE NOT hp.is_paidout %s ORDER BY hp.sc_hot DESC LIMIT :limit """
elif discussion_type == 'created':
sql = sql + """WHERE hp.depth = 0 %s ORDER BY hp.created_at DESC LIMIT :limit """
elif discussion_type == 'promoted':
sql = sql + """WHERE NOT hp.is_paidout AND hp.promoted > 0
%s ORDER BY hp.promoted DESC LIMIT :limit """
elif discussion_type == 'payout': # wrong: now we should be using payout + pending_payout here
sql = sql + """WHERE NOT hp.is_paidout AND hp.depth = 0
%s ORDER BY hp.payout DESC LIMIT :limit """
elif discussion_type == 'payout_comments': # wrong: now we should be using payout + pending_payout here
sql = sql + """WHERE NOT hp.is_paidout AND hp.depth > 0
%s ORDER BY hp.payout DESC LIMIT :limit """
if tag and tag != 'all':
if tag[:5] == 'hive-':
sql = sql % """ %s AND hp.category = :tag """
else:
sql = sql % """ %s AND EXISTS
(SELECT NULL
FROM hive_post_tags hpt
INNER JOIN hive_tag_data htd ON hpt.tag_id=htd.id
WHERE hp.id = hpt.post_id AND htd.tag = :tag
) """
if start_author and start_permlink:
if discussion_type == 'trending':
sql = sql % """ AND hp.sc_trend <= (SELECT sc_trend FROM hp WHERE permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink) AND author_id = (SELECT id FROM hive_accounts WHERE name = :author))
AND hp.post_id != (SELECT post_id FROM hp WHERE permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink) AND author_id = (SELECT id FROM hive_accounts WHERE name = :author)) """
elif discussion_type == 'hot':
sql = sql % """ AND hp.sc_hot <= (SELECT sc_hot FROM hp WHERE permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink) AND author_id = (SELECT id FROM hive_accounts WHERE name = :author))
AND hp.post_id != (SELECT post_id FROM hp WHERE permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink) AND author_id = (SELECT id FROM hive_accounts WHERE name = :author)) """
elif discussion_type == 'created':
sql = sql % """ AND hp.post_id < (SELECT post_id FROM hp WHERE permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink) AND author_id = (SELECT id FROM hive_accounts WHERE name = :author)) """
elif discussion_type == 'promoted':
sql = sql % """ AND hp.promoted <= (SELECT promoted FROM hp WHERE permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink) AND author_id = (SELECT id FROM hive_accounts WHERE name = :author))
AND hp.post_id != (SELECT post_id FROM hp WHERE permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink) AND author_id = (SELECT id FROM hive_accounts WHERE name = :author)) """
else: # wrong: now we should be using payout + pending_payout here
sql = sql % """ AND hp.payout <= (SELECT payout FROM hp where permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink) AND author_id = (SELECT id FROM hive_accounts WHERE name = :author))
AND hp.post_id != (SELECT post_id FROM hp WHERE permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink) AND author_id = (SELECT id FROM hive_accounts WHERE name = :author)) """
else:
sql = sql % """ """
result = await db.query_all(sql, tag=tag, limit=limit, author=start_author, permlink=start_permlink)
posts = []
for row in result:
post = _condenser_post_object(row, truncate_body)
post['active_votes'] = await find_votes_impl(db, post['author'], post['permlink'], VotesPresentation.DatabaseApi )
post['active_votes'] = _mute_votes(post['active_votes'], Mutes.all())
posts.append(post)
return posts
@return_error_info
@nested_query_compat
async def get_posts_by_given_sort(context, sort: str, start_author: str = '', start_permlink: str = '',
......
......@@ -42,8 +42,8 @@ async def load_posts_keyed(db, ids, truncate_body=0):
# fetch posts and associated author reps
sql = """
SELECT hp.id,
hp.community_id,
hp.author,
hp.author_rep,
hp.permlink,
hp.title,
hp.body,
......@@ -56,7 +56,6 @@ async def load_posts_keyed(db, ids, truncate_body=0):
hp.is_paidout,
hp.children,
hp.votes,
hp.active_votes,
hp.created_at,
hp.updated_at,
hp.rshares,
......@@ -81,13 +80,11 @@ async def load_posts_keyed(db, ids, truncate_body=0):
WHERE hp.id IN :ids"""
result = await db.query_all(sql, ids=tuple(ids))
author_reps = await _query_author_rep_map(db, result)
muted_accounts = Mutes.all()
posts_by_id = {}
for row in result:
row = dict(row)
row['author_rep'] = author_reps[row['author']]
post = _condenser_post_object(row, truncate_body=truncate_body)
post['active_votes'] = await find_votes_impl(db, row['author'], row['permlink'], VotesPresentation.CondenserApi)
......@@ -131,28 +128,6 @@ async def load_posts(db, ids, truncate_body=0):
return [posts_by_id[_id] for _id in ids]
async def resultset_to_posts(db, fat_node_style, resultset, truncate_body=0):
author_reps = await _query_author_rep_map(db, resultset)
muted_accounts = Mutes.all()
posts = []
for row in resultset:
row = dict(row)
row['author_rep'] = author_reps[row['author']]
post = _condenser_post_object(row, truncate_body=truncate_body, get_content_additions=fat_node_style)
post['active_votes'] = await find_votes_impl(db, row['author'], row['permlink'], VotesPresentation.ActiveVotes if fat_node_style else VotesPresentation.CondenserApi)
posts.append(post)
return posts
async def _query_author_rep_map(db, posts):
"""Given a list of posts, returns an author->reputation map."""
if not posts:
return {}
names = tuple({post['author'] for post in posts})
sql = "SELECT name, reputation FROM hive_accounts WHERE name IN :names"
return {r['name']: r['reputation'] for r in await db.query_all(sql, names=names)}
def _condenser_account_object(row):
"""Convert an internal account record into legacy-steemd style."""
#The member `vote_weight` from `hive_accounts` is removed, so currently the member `net_vesting_shares` is equals to zero.
......
Subproject commit b76dcb51fe38d952078d44bfe811ddded9de642a
Subproject commit ae53a82f46e6338a04e40b4966f8e7b0e64e6c86