Something went wrong on our end
methods.py 16.16 KiB
"""Bridge API public endpoints for posts"""
import hive.server.bridge_api.cursor as cursor
from hive.server.bridge_api.objects import load_posts, load_posts_reblogs, load_profiles, _bridge_post_object
from hive.server.database_api.methods import find_votes_impl, VotesPresentation
from hive.server.common.helpers import (
return_error_info,
valid_account,
valid_permlink,
valid_tag,
valid_limit)
from hive.server.hive_api.common import get_account_id
from hive.server.hive_api.objects import _follow_contexts
from hive.server.hive_api.community import list_top_communities
from hive.server.common.mutes import Mutes
ROLES = {-2: 'muted', 0: 'guest', 2: 'member', 4: 'mod', 6: 'admin', 8: 'owner'}
SQL_TEMPLATE = """
SELECT
hp.id,
hp.author,
hp.parent_author,
hp.author_rep,
hp.root_title,
hp.beneficiaries,
hp.max_accepted_payout,
hp.percent_hbd,
hp.url,
hp.permlink,
hp.parent_permlink_or_category,
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.sc_trend,
hp.role_title,
hp.community_title,
hp.role_id,
hp.is_pinned,
hp.curator_payout_value
FROM hive_posts_view hp
WHERE
"""
#pylint: disable=too-many-arguments, no-else-return
@return_error_info
async def get_profile(context, account, observer=None):
"""Load account/profile data."""
db = context['db']
ret = await load_profiles(db, [valid_account(account)])
assert ret, 'Account \'{}\' does not exist'.format(account)
observer_id = await get_account_id(db, observer) if observer else None
if observer_id:
await _follow_contexts(db, {ret[0]['id']: ret[0]}, observer_id, True)
return ret[0]
@return_error_info
async def get_trending_topics(context, limit=10, observer=None):
"""Return top trending topics across pending posts."""
# pylint: disable=unused-argument
#db = context['db']
#observer_id = await get_account_id(db, observer) if observer else None
#assert not observer, 'observer not supported'
limit = valid_limit(limit, 25)
out = []
cells = await list_top_communities(context, limit)
for name, title in cells:
out.append((name, title or name))
for tag in ('photography', 'travel', 'gaming',
'crypto', 'newsteem', 'music', 'food'):
if len(out) < limit:
out.append((tag, '#' + tag))
return out
@return_error_info
async def get_post(context, author, permlink, observer=None):
"""Fetch a single post"""
# pylint: disable=unused-variable
#TODO: `observer` logic for user-post state
db = context['db']
valid_account(author)
valid_permlink(permlink)
blacklists_for_user = None
if observer and context:
blacklists_for_user = await Mutes.get_blacklists_for_observer(observer, context)
sql = "---bridge_api.get_post\n" + SQL_TEMPLATE + """ hp.author = :author AND hp.permlink = :permlink """
result = await db.query_all(sql, author=author, permlink=permlink)
assert len(result) == 1, 'invalid author/permlink or post not found in cache'
post = _bridge_post_object(result[0])
post['active_votes'] = await find_votes_impl({'db':db}, author, permlink, VotesPresentation.BridgeApi)
post = await append_statistics_to_post(post, result[0], False, blacklists_for_user)
return post
@return_error_info
async def get_ranked_posts(context, sort, start_author='', start_permlink='',
limit=20, tag=None, observer=None):
"""Query posts, sorted by given method."""
assert sort in ['trending', 'hot', 'created', 'promoted',
'payout', 'payout_comments', 'muted'], 'invalid sort'
valid_account(start_author, allow_empty=True)
valid_permlink(start_permlink, allow_empty=True)
valid_limit(limit, 100)
valid_tag(tag, allow_empty=True)
db = context['db']
if sort == 'trending' and not ( start_author and start_permlink ) and ( not tag or tag == 'all' ):
sql = "SELECT * FROM bridge_get_ranked_post_by_trends( (:limit)::SMALLINT )"
posts = []
sql_result = await db.query_all(sql, limit=limit )
for row in sql_result:
post = _bridge_post_object(row)
post['active_votes'] = await find_votes_impl({'db':db}, row['author'], row['permlink'], VotesPresentation.BridgeApi)
post = await append_statistics_to_post(post, row, False, None)
posts.append(post)
return posts
sql = ''
pinned_sql = ''
if sort == 'trending':
sql = SQL_TEMPLATE + """ NOT hp.is_paidout AND hp.depth = 0
%s ORDER BY hp.sc_trend DESC, hp.id LIMIT :limit """
elif sort == 'hot':
sql = SQL_TEMPLATE + """ NOT hp.is_paidout AND hp.depth = 0
%s ORDER BY hp.sc_hot DESC, hp.id LIMIT :limit """
elif sort == 'created':
sql = SQL_TEMPLATE + """ hp.depth = 0 AND NOT hp.is_grayed
%s ORDER BY hp.created_at DESC, hp.id LIMIT :limit """
elif sort == 'promoted':
sql = SQL_TEMPLATE + """ hp.depth > 0 AND hp.promoted > 0
AND NOT hp.is_paidout %s ORDER BY hp.promoted DESC, hp.id LIMIT :limit """
elif sort == 'payout':
sql = SQL_TEMPLATE + """ NOT hp.is_paidout %s
AND hp.payout_at BETWEEN now() + interval '12 hours' AND now() + interval '36 hours'
ORDER BY hp.payout DESC, hp.id LIMIT :limit """
elif sort == 'payout_comments':
sql = SQL_TEMPLATE + """ NOT hp.is_paidout AND hp.depth > 0
%s ORDER BY hp.payout DESC, hp.id LIMIT :limit """
elif sort == 'muted':
sql = SQL_TEMPLATE + """ NOT hp.is_paidout AND hp.is_grayed
AND hp.payout > 0 %s ORDER BY hp.payout DESC, hp.id LIMIT :limit """
sql = "---bridge_api.get_ranked_posts\n" + sql
if start_author and start_permlink:
if sort == 'trending':
sql = sql % """ AND hp.sc_trend <= (SELECT sc_trend FROM hive_posts WHERE author_id = (SELECT id FROM hive_accounts WHERE name = :author) AND permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink))
AND hp.id != (SELECT id FROM hive_posts WHERE author_id = (SELECT id FROM hive_accounts WHERE name = :author) AND permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink)) %s """
elif sort == 'hot':
sql = sql % """ AND hp.sc_hot <= (SELECT sc_hot FROM hive_posts WHERE author_id = (SELECT id FROM hive_accounts WHERE name = :author) AND permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink))
AND hp.id != (SELECT id FROM hive_posts WHERE author_id = (SELECT id FROM hive_accounts WHERE name = :author) AND permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink)) %s """
elif sort == 'created':
sql = sql % """ AND hp.id < (SELECT id FROM hive_posts WHERE author_id = (SELECT id FROM hive_accounts WHERE name = :author) AND permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink)) %s """
elif sort == 'promoted':
sql = sql % """ AND hp.promoted <= (SELECT promoted FROM hive_posts WHERE author_id = (SELECT id FROM hive_accounts WHERE name = :author) AND permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink))
AND hp.id != (SELECT id FROM hive_posts WHERE author_id = (SELECT id FROM hive_accounts WHERE name = :author) AND permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink)) %s """
else:
sql = sql % """ AND hp.payout <= (SELECT payout FROM hive_posts WHERE author_id = (SELECT id FROM hive_accounts WHERE name = :author) AND permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink))
AND hp.id != (SELECT id FROM hive_posts WHERE author_id = (SELECT id FROM hive_accounts WHERE name = :author) AND permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink)) %s """
else:
sql = sql % """ %s """
if not tag or tag == 'all':
sql = sql % """ """
elif tag == 'my':
sql = sql % """ AND hp.community_id IN (SELECT community_id FROM hive_subscriptions WHERE account_id =
(SELECT id FROM hive_accounts WHERE name = :observer) ) """
elif tag[:5] == 'hive-':
if start_author and start_permlink:
sql = sql % """ AND hp.community_id = (SELECT hive_communities.id FROM hive_communities WHERE name = :community_name ) """
else:
sql = sql % """ AND hp.community_name = :community_name """
if sort == 'trending' or sort == 'created':
pinned_sql = SQL_TEMPLATE + """ hp.is_pinned AND hp.community_name = :community_name ORDER BY hp.created_at DESC """
else:
if sort in ['payout', 'payout_comments']:
sql = sql % """ AND hp.category = :tag """
else:
sql = sql % """ 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 not observer:
observer = ''
posts = []
pinned_post_ids = []
blacklists_for_user = None
if observer and context:
blacklists_for_user = await Mutes.get_blacklists_for_observer(observer, context)
if pinned_sql:
pinned_result = await db.query_all(pinned_sql, author=start_author, limit=limit, tag=tag, permlink=start_permlink, community_name=tag, observer=observer)
for row in pinned_result:
post = _bridge_post_object(row)
post['active_votes'] = await find_votes_impl({'db':db}, row['author'], row['permlink'], VotesPresentation.BridgeApi)
post = await append_statistics_to_post(post, row, True, blacklists_for_user)
limit = limit - 1
posts.append(post)
pinned_post_ids.append(post['post_id'])
sql_result = await db.query_all(sql, author=start_author, limit=limit, tag=tag, permlink=start_permlink, community_name=tag, observer=observer)
for row in sql_result:
post = _bridge_post_object(row)
post['active_votes'] = await find_votes_impl({'db':db}, row['author'], row['permlink'], VotesPresentation.BridgeApi)
post = await append_statistics_to_post(post, row, False, blacklists_for_user)
if post['post_id'] in pinned_post_ids:
continue
posts.append(post)
return posts
async def append_statistics_to_post(post, row, is_pinned, blacklists_for_user=None):
""" apply information such as blacklists and community names/roles to a given post """
if not blacklists_for_user:
post['blacklists'] = Mutes.lists(row['author'], row['author_rep'])
else:
post['blacklists'] = []
if row['author'] in blacklists_for_user:
blacklists = blacklists_for_user[row['author']]
for blacklist in blacklists:
post['blacklists'].append(blacklist)
reputation = int(row['author_rep'])
if reputation < 1:
post['blacklists'].append('reputation-0')
elif reputation == 1:
post['blacklists'].append('reputation-1')
if 'community_title' in row and row['community_title']:
post['community'] = row['category']
post['community_title'] = row['community_title']
if row['role_id']:
post['author_role'] = ROLES[row['role_id']]
post['author_title'] = row['role_title']
else:
post['author_role'] = 'guest'
post['author_title'] = ''
else:
post['stats']['gray'] = row['is_grayed']
post['stats']['hide'] = 'irredeemables' in post['blacklists']
if is_pinned:
post['stats']['is_pinned'] = True
return post
@return_error_info
async def get_account_posts(context, sort, account, start_author='', start_permlink='',
limit=20, observer=None):
"""Get posts for an account -- blog, feed, comments, or replies."""
valid_sorts = ['blog', 'feed', 'posts', 'comments', 'replies', 'payout']
assert sort in valid_sorts, 'invalid account sort'
assert account, 'account is required'
db = context['db']
account = valid_account(account)
start_author = valid_account(start_author, allow_empty=True)
start_permlink = valid_permlink(start_permlink, allow_empty=True)
start = (start_author, start_permlink)
limit = valid_limit(limit, 100)
# pylint: disable=unused-variable
observer_id = await get_account_id(db, observer) if observer else None # TODO
sql = "---bridge_api.get_account_posts\n " + SQL_TEMPLATE + """ %s """
if sort == 'blog':
ids = await cursor.pids_by_blog(db, account, *start, limit)
posts = await load_posts(context['db'], ids)
for post in posts:
if post['author'] != account:
post['reblogged_by'] = [account]
return posts
elif sort == 'posts':
sql = sql % """ hp.author = :account AND hp.depth = 0 %s ORDER BY hp.id DESC LIMIT :limit"""
elif sort == 'comments':
sql = sql % """ hp.author = :account AND hp.depth > 0 %s ORDER BY hp.id DESC, hp.depth LIMIT :limit"""
elif sort == 'payout':
sql = sql % """ hp.author = :account AND NOT hp.is_paidout %s ORDER BY hp.payout DESC, hp.id LIMIT :limit"""
elif sort == 'feed':
res = await cursor.pids_by_feed_with_reblog(db, account, *start, limit)
return await load_posts_reblogs(context['db'], res)
elif sort == 'replies':
start = start if start_permlink else (account, None)
ids = await cursor.pids_by_replies(db, *start, limit)
return await load_posts(context['db'], ids)
if start_author and start_permlink:
sql = sql % """ AND hp.id < (SELECT id FROM hive_posts WHERE author_id = (SELECT id FROM hive_accounts WHERE name = :author) AND permlink_id = (SELECT id FROM hive_permlink_data WHERE permlink = :permlink)) """
else:
sql = sql % """ """
posts = []
blacklists_for_user = None
if observer:
blacklists_for_user = await Mutes.get_blacklists_for_observer(observer, context)
sql_result = await db.query_all(sql, account=account, author=start_author, permlink=start_permlink, limit=limit)
for row in sql_result:
post = _bridge_post_object(row)
post['active_votes'] = await find_votes_impl({'db':db}, row['author'], row['permlink'], VotesPresentation.BridgeApi)
post = await append_statistics_to_post(post, row, False, blacklists_for_user)
posts.append(post)
return posts
@return_error_info
async def get_relationship_between_accounts(context, account1, account2, observer=None):
valid_account(account1)
valid_account(account2)
db = context['db']
sql = """
SELECT state, blacklisted, follow_blacklists FROM hive_follows WHERE
follower = (SELECT id FROM hive_accounts WHERE name = :account1) AND
following = (SELECT id FROM hive_accounts WHERE name = :account2)
"""
sql_result = await db.query_all(sql, account1=account1, account2=account2)
result = {
'follows': False,
'ignores': False,
'is_blacklisted': False,
'follows_blacklists': False
}
for row in sql_result:
state = row['state']
if state == 1:
result['follows'] = True
elif state == 2:
result['ignores'] = True
if row['blacklisted']:
result['is_blacklisted'] = True
if row['follow_blacklists']:
result['follows_blacklists'] = True
return result