async def _get_account_discussion_by_key(account, key): assert account, 'account must be specified' assert key, 'discussion key must be specified' if key == 'recent_replies': posts = load_posts(cursor.pids_by_replies_to_account(account, '', 20)) elif key == 'comments': posts = load_posts(cursor.pids_by_account_comments(account, '', 20)) elif key == 'blog': posts = load_posts(cursor.pids_by_blog(account, '', '', 20)) elif key == 'feed': res = cursor.pids_by_feed_with_reblog(account, '', '', 20) posts = load_posts_reblogs(res) else: raise ApiError("unknown account discussion key %s" % key) return posts
async def get_account_votes(context, account): """Return an info message about get_acccount_votes being unsupported.""" # pylint: disable=unused-argument raise ApiError( "get_account_votes is no longer supported, for details see " "https://steemit.com/steemit/@steemitdev/additional-public-api-change")
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']) # 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 cursor.pids_by_query(db, sort, '', '', 20, tag) state['content'] = _keyed_posts(await load_posts(db, 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 call(context, api, method, params): """Routes legacy-style `call` method requests. Example: ``` {"id":0,"jsonrpc":"2.0","method":"call", "params":["database_api","get_state",["trending"]]} ```""" # pylint: disable=too-many-return-statements, too-many-branches assert api == 'condenser_api', "`call` requires condenser_api" # Follows if method == 'get_followers': return await get_followers(context, *_strict_list(params, 4)) elif method == 'get_following': return await get_following(context, *_strict_list(params, 4)) elif method == 'get_follow_count': return await get_follow_count(context, *_strict_list(params, 1)) # Content primitives elif method == 'get_content': return await get_content(context, *_strict_list(params, 2)) elif method == 'get_content_replies': return await get_content_replies(context, *_strict_list(params, 2)) # Trending tags elif method == 'get_trending_tags': return await get_trending_tags(context, *_strict_list(params, 2)) # Content monolith elif method == 'get_state': return await get_state(context, *_strict_list(params, 1)) # Global discussion queries elif method == 'get_discussions_by_trending': return await get_discussions_by_trending(context, **_strict_query(params)) elif method == 'get_discussions_by_hot': return await get_discussions_by_hot(context, **_strict_query(params)) elif method == 'get_discussions_by_promoted': return await get_discussions_by_promoted(context, **_strict_query(params)) elif method == 'get_discussions_by_created': return await get_discussions_by_created(context, **_strict_query(params)) elif method == 'get_post_discussions_by_payout': return await get_post_discussions_by_payout(context, **_strict_query(params)) elif method == 'get_comment_discussions_by_payout': return await get_comment_discussions_by_payout(context, **_strict_query(params)) # Account discussion queries elif method == 'get_discussions_by_blog': return await get_discussions_by_blog(context, **_strict_query(params)) elif method == 'get_discussions_by_feed': return await get_discussions_by_feed(context, **_strict_query(params)) elif method == 'get_discussions_by_comments': return await get_discussions_by_comments(context, **_strict_query(params)) elif method == 'get_replies_by_last_update': return await get_replies_by_last_update(context, *_strict_list(params, 3)) # Exotic account discussion queries elif method == 'get_discussions_by_author_before_date': return await get_discussions_by_author_before_date( context, *_strict_list(params, 4)) elif method == 'get_blog': return await get_blog(context, *_strict_list(params, 3, 2)) elif method == 'get_blog_entries': return await get_blog_entries(context, *_strict_list(params, 3, 2)) # Misc/dummy elif method == 'get_account_votes': return await get_account_votes(context, *_strict_list(params, 1)) raise ApiError("unknown method: %s.%s" % (api, method))
async def get_state(path: str): """`get_state` reimplementation. See: https://github.com/steemit/steem/blob/06e67bd4aea73391123eca99e1a22a8612b0c47e/libraries/app/database_api.cpp#L1937 """ (path, part) = _normalize_path(path) state = { 'feed_price': _get_feed_price(), 'props': _get_props_lite(), '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[1] == 'blog', 'canonical blog route is `/@account`' assert not part[2], 'unexpected account path[2] %s' % path account = valid_account(part[0][1:]) state['accounts'][account] = _load_account(account) if not account: state['error'] = 'account not found' elif part[1] in ACCOUNT_TAB_KEYS: key = ACCOUNT_TAB_KEYS[part[1]] posts = await _get_account_discussion_by_key(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`. state['error'] = 'invalid account path requested.' # discussion - `/category/@account/permlink` elif part[1] and part[1][0] == '@': author = valid_account(part[1][1:]) permlink = valid_permlink(part[2]) state['content'] = _load_discussion(author, permlink) state['accounts'] = _load_content_accounts(state['content']) # ranked posts - `/sort/category` elif part[0] in ['trending', 'promoted', 'hot', 'created']: 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) posts = load_posts(cursor.pids_by_query(sort, '', '', 20, tag)) state['content'] = _keyed_posts(posts) state['discussion_idx'] = {tag: {sort: list(state['content'].keys())}} state['tag_idx'] = {'trending': await get_top_trending_tags_summary()} # 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(): state['tag_idx']['trending'].append(tag['name']) state['tags'][tag['name']] = tag elif part[0] == 'witnesses' or part[0] == '~witnesses': assert not part[1] and not part[2] raise ApiError("not implemented: /%s" % path) elif part[0] in CONDENSER_NOOP_URLS: assert not part[1] and not part[2] else: log.warning('unhandled path /%s', path) return state