async def get_post_discussions_by_payout(context, start_author: str = '', start_permlink: str = '', limit: int = 20, tag: str = None, truncate_body: int = 0): """Query top-level posts, sorted by payout.""" ids = await cursor.pids_by_query( context['db'], 'payout', valid_account(start_author, allow_empty=True), valid_permlink(start_permlink, allow_empty=True), valid_limit(limit, 100), valid_tag(tag, allow_empty=True)) return await load_posts(context['db'], ids, truncate_body=truncate_body)
async def get_discussions_by_created(context, start_author: str = '', start_permlink: str = '', limit: int = 20, tag: str = None, truncate_body: int = 0, filter_tags: list = None): """Query posts, sorted by creation date.""" assert not filter_tags, 'filter_tags not supported' ids = await cursor.pids_by_query( context['db'], 'created', valid_account(start_author, allow_empty=True), valid_permlink(start_permlink, allow_empty=True), valid_limit(limit, 100), valid_tag(tag, allow_empty=True)) return await load_posts(context['db'], ids, truncate_body=truncate_body)
async def get_trending_tags(context, start_tag: str = '', limit: int = 250): """Get top 250 trending tags among pending posts, with stats.""" limit = valid_limit(limit, 250, 250) start_tag = valid_tag(start_tag, allow_empty=True) sql = "SELECT * FROM condenser_get_trending_tags( (:tag)::VARCHAR, :limit )" out = [] for row in await context['db'].query_all(sql, limit=limit, tag=start_tag): out.append({ 'name': row['category'], 'comments': row['total_posts'] - row['top_posts'], 'top_posts': row['top_posts'], 'total_payouts': "%.3f HBD" % row['total_payouts']}) return out
async def get_trending_tags(context, start_tag: str = '', limit: int = 250): """Get top 250 trending tags among pending posts, with stats.""" limit = valid_limit(limit, ubound=250) start_tag = valid_tag(start_tag or '', allow_empty=True) if start_tag: seek = """ HAVING SUM(payout) <= ( SELECT SUM(payout) FROM hive_posts_cache WHERE is_paidout = '0' AND category = :start_tag) """ else: seek = '' sql = """ SELECT category, COUNT(*) AS total_posts, SUM(CASE WHEN depth = 0 THEN 1 ELSE 0 END) AS top_posts, SUM(payout) AS total_payouts FROM hive_posts_cache WHERE is_paidout = '0' GROUP BY category %s ORDER BY SUM(payout) DESC LIMIT :limit """ % seek out = [] for row in await context['db'].query_all(sql, limit=limit, start_tag=start_tag): out.append({ 'name': row['category'], 'comments': row['total_posts'] - row['top_posts'], 'top_posts': row['top_posts'], 'total_payouts': "%.3f SBD" % row['total_payouts'] }) return out
async def get_ranked_posts(context, sort, start_author='', start_permlink='', limit=20, tag=None, observer=None): """Query posts, sorted by given method.""" db = context['db'] observer_id = await get_account_id(db, observer) if observer else None assert sort in [ 'trending', 'hot', 'created', 'promoted', 'payout', 'payout_comments', 'muted' ], 'invalid sort' ids = await cursor.pids_by_ranked( context['db'], 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), observer_id) return await load_posts(context['db'], ids)
async def get_ranked_posts(context, sort:str, start_author:str='', start_permlink:str='', limit:int=20, tag:str='', observer:str=''): """Query posts, sorted by given method.""" supported_sort_list = ['trending', 'hot', 'created', 'promoted', 'payout', 'payout_comments', 'muted'] assert sort in supported_sort_list, "Unsupported sort, valid sorts: {}".format(", ".join(supported_sort_list)) db = context['db'] async def process_query_results( sql_result ): posts = [] for row in sql_result: post = _bridge_post_object(row) post['active_votes'] = await find_votes_impl(db, row['author'], row['permlink'], VotesPresentation.BridgeApi) post = append_statistics_to_post(post, row, row['is_pinned']) posts.append(post) return posts start_author = valid_account(start_author, allow_empty=True) start_permlink = valid_permlink(start_permlink, allow_empty=True) limit = valid_limit(limit, 100, 20) tag = valid_tag(tag, allow_empty=True) observer = valid_account(observer, allow_empty=(tag != "my")) if tag == "my": result = await _get_ranked_posts_for_observer_communities(db, sort, start_author, start_permlink, limit, observer) return await process_query_results(result) if tag and check_community(tag): result = await _get_ranked_posts_for_communities(db, sort, tag, start_author, start_permlink, limit, observer) return await process_query_results(result) if ( tag and tag != "all" ): result = await _get_ranked_posts_for_tag(db, sort, tag, start_author, start_permlink, limit, observer) return await process_query_results(result) result = await _get_ranked_posts_for_all(db, sort, start_author, start_permlink, limit, observer) return await process_query_results(result)
async def get_state(context, path: str): """`get_state` reimplementation. See: https://github.com/steemit/steem/blob/06e67bd4aea73391123eca99e1a22a8612b0c47e/libraries/app/database_api.cpp#L1937 """ (path, part) = _normalize_path(path) db = context['db'] state = { 'feed_price': await _get_feed_price(db), 'props': await _get_props_lite(db), 'tags': {}, 'accounts': {}, 'content': {}, 'tag_idx': { 'trending': [] }, 'discussion_idx': { "": {} } } # account - `/@account/tab` (feed, blog, comments, replies) if part[0] and part[0][0] == '@': assert not part[1] == 'transfers', 'transfers API not served here' assert not part[2], 'unexpected account path[2] %s' % path if part[1] == '': part[1] = 'blog' account = valid_account(part[0][1:]) state['accounts'][account] = await _load_account(db, account) if part[1] in ACCOUNT_TAB_KEYS: key = ACCOUNT_TAB_KEYS[part[1]] posts = await _get_account_discussion_by_key(db, account, key) state['content'] = _keyed_posts(posts) state['accounts'][account][key] = list(state['content'].keys()) elif part[1] in ACCOUNT_TAB_IGNORE: pass # condenser no-op URLs else: # invalid/undefined case; probably requesting `@user/permlink`, # but condenser still relies on a valid response for redirect. state['error'] = 'invalid get_state account path %s' % path # discussion - `/category/@account/permlink` elif part[1] and part[1][0] == '@': author = valid_account(part[1][1:]) permlink = valid_permlink(part[2]) state['content'] = await _load_discussion(db, author, permlink) state['accounts'] = await _load_content_accounts( db, state['content'], True) # ranked posts - `/sort/category` elif part[0] in POST_LIST_SORTS: assert not part[2], "unexpected discussion path part[2] %s" % path sort = valid_sort(part[0]) tag = valid_tag(part[1].lower(), allow_empty=True) pids = await get_posts_by_given_sort(context, sort, '', '', 20, tag) state['content'] = _keyed_posts(pids) state['discussion_idx'] = {tag: {sort: list(state['content'].keys())}} state['tag_idx'] = { 'trending': await get_top_trending_tags_summary(context) } # tag "explorer" - `/tags` elif part[0] == "tags": assert not part[1] and not part[2], 'invalid /tags request' for tag in await get_trending_tags(context): state['tag_idx']['trending'].append(tag['name']) state['tags'][tag['name']] = tag elif part[0] in CONDENSER_NOOP_URLS: assert not part[1] and not part[2] else: raise ApiError('unhandled path: /%s' % path) return state
async def get_posts_by_given_sort(context, sort: str, start_author: str = '', start_permlink: str = '', limit: int = 20, tag: str = None, truncate_body: int = 0, filter_tags: list = None, observer: str = None): """Query posts, sorted by creation date.""" assert not filter_tags, 'filter_tags not supported' db = context['db'] start_author = valid_account(start_author, allow_empty=True), start_permlink = valid_permlink(start_permlink, allow_empty=True), limit = valid_limit(limit, 100, 20), tag = valid_tag(tag, allow_empty=True) observer = valid_account(observer, allow_empty=True) truncate_body = valid_truncate(truncate_body) posts = [] is_community = tag[:5] == 'hive-' if sort == 'created': if is_community: sql = "SELECT * FROM bridge_get_ranked_post_by_created_for_community( (:tag)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, False, (:observer)::VARCHAR )" elif tag == '': sql = "SELECT * FROM bridge_get_ranked_post_by_created( (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, (:observer)::VARCHAR )" else: sql = "SELECT * FROM bridge_get_ranked_post_by_created_for_tag( (:tag)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, (:observer)::VARCHAR )" elif sort == 'trending': if is_community: sql = "SELECT * FROM bridge_get_ranked_post_by_trends_for_community( (:tag)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, False, (:observer)::VARCHAR )" elif tag == '': sql = "SELECT * FROM bridge_get_ranked_post_by_trends( (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, (:observer)::VARCHAR )" else: sql = "SELECT * FROM bridge_get_ranked_post_by_trends_for_tag( (:tag)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, (:observer)::VARCHAR )" elif sort == 'hot': if is_community: sql = "SELECT * FROM bridge_get_ranked_post_by_hot_for_community( (:tag)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, (:observer)::VARCHAR )" elif tag == '': sql = "SELECT * FROM bridge_get_ranked_post_by_hot( (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, (:observer)::VARCHAR )" else: sql = "SELECT * FROM bridge_get_ranked_post_by_hot_for_tag( (:tag)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, (:observer)::VARCHAR )" elif sort == 'promoted': if is_community: sql = "SELECT * FROM bridge_get_ranked_post_by_promoted_for_community( (:tag)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, (:observer)::VARCHAR )" elif tag == '': sql = "SELECT * FROM bridge_get_ranked_post_by_promoted( (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, (:observer)::VARCHAR )" else: sql = "SELECT * FROM bridge_get_ranked_post_by_promoted_for_tag( (:tag)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, (:observer)::VARCHAR )" elif sort == 'post_by_payout': if tag == '': sql = "SELECT * FROM bridge_get_ranked_post_by_payout( (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, False, (:observer)::VARCHAR )" else: sql = "SELECT * FROM bridge_get_ranked_post_by_payout_for_category( (:tag)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, False, (:observer)::VARCHAR )" elif sort == 'comment_by_payout': if tag == '': sql = "SELECT * FROM bridge_get_ranked_post_by_payout_comments( (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, (:observer)::VARCHAR )" else: sql = "SELECT * FROM bridge_get_ranked_post_by_payout_comments_for_category( (:tag)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, (:observer)::VARCHAR )" else: return posts sql_result = await db.query_all(sql, tag=tag, author=start_author, permlink=start_permlink, limit=limit, observer=observer) for row in sql_result: post = _condenser_post_object(row, truncate_body) post['active_votes'] = await find_votes_impl( db, row['author'], row['permlink'], VotesPresentation.CondenserApi) posts.append(post) return posts