Example #1
0
async def get_post_header(context, author, permlink):
    """Fetch basic post data"""
    db = context['db']
    valid_account(author)
    valid_permlink(permlink)
    sql = """
        SELECT 
            hp.id, ha_a.name as author, hpd_p.permlink as permlink, hcd.category as category, depth
        FROM 
            hive_posts hp
        INNER JOIN hive_accounts ha_a ON ha_a.id = hp.author_id
        INNER JOIN hive_permlink_data hpd_p ON hpd_p.id = hp.permlink_id
        LEFT JOIN hive_category_data hcd ON hcd.id = hp.category_id
        WHERE ha_a.name = :author
            AND hpd_p.permlink = :permlink
            AND counter_deleted = 0
    """

    row = await db.query_row(sql, author=author, permlink=permlink)

    assert row, 'Post {}/{} does not exist'.format(author, permlink)

    return dict(author=row['author'],
                permlink=row['permlink'],
                category=row['category'],
                depth=row['depth'])
Example #2
0
async def get_discussions_by_blog(context,
                                  tag: str,
                                  start_author: str = '',
                                  start_permlink: str = '',
                                  limit: int = 20,
                                  truncate_body: int = 0,
                                  filter_tags: list = None):
    """Retrieve account's blog posts, including reblogs."""
    assert not filter_tags, 'filter_tags not supported'
    tag = valid_account(tag)
    start_author = valid_account(start_author, allow_empty=True)
    start_permlink = valid_permlink(start_permlink, allow_empty=True)
    limit = valid_limit(limit, 100, 20)
    truncate_body = valid_truncate(truncate_body)

    sql = "SELECT * FROM bridge_get_account_posts_by_blog( (:account)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::INTEGER, False )"

    db = context['db']
    result = await db.query_all(sql,
                                account=tag,
                                author=start_author,
                                permlink=start_permlink,
                                limit=limit)
    posts_by_id = []

    for row in result:
        row = dict(row)
        post = _condenser_post_object(row, truncate_body=truncate_body)
        post['active_votes'] = await find_votes_impl(
            db, post['author'], post['permlink'],
            VotesPresentation.CondenserApi)
        posts_by_id.append(post)

    return posts_by_id
Example #3
0
async def get_active_votes(context, author: str, permlink: str):
    """ Returns all votes for the given post. """
    valid_account(author)
    valid_permlink(permlink)
    db = context['db']

    return await find_votes_impl(db, author, permlink,
                                 VotesPresentation.ActiveVotes)
Example #4
0
async def find_votes(context, author: str, permlink: str):
    """ Returns all votes for the given post """
    valid_account(author)
    valid_permlink(permlink)
    return {
        'votes':
        await find_votes_impl(context['db'], author, permlink,
                              VotesPresentation.DatabaseApi)
    }
Example #5
0
async def unread_notifications(context, account, min_score=25):
    """Load notification status for a named account."""
    db = context['db']
    valid_account(account)
    min_score = valid_score(min_score, 100, 25)

    sql = """SELECT * FROM get_number_of_unread_notifications( :account, (:min_score)::SMALLINT)"""
    row = await db.query_row(sql, account=account, min_score=min_score)
    return dict(lastread=str(row['lastread_at']), unread=row['unread'])
Example #6
0
async def get_discussion(context,
                         author: str,
                         permlink: str,
                         observer: str = ''):
    """Modified `get_state` thread implementation."""
    db = context['db']

    author = valid_account(author)
    permlink = valid_permlink(permlink)
    observer = valid_account(observer, allow_empty=True)

    sql = "SELECT * FROM bridge_get_discussion(:author,:permlink,:observer)"
    rows = await db.query_all(sql,
                              author=author,
                              permlink=permlink,
                              observer=observer)
    if not rows or len(rows) == 0:
        return {}
    root_id = rows[0]['id']
    all_posts = {}
    root_post = _bridge_post_object(rows[0])
    root_post['active_votes'] = await find_votes_impl(
        db, rows[0]['author'], rows[0]['permlink'],
        VotesPresentation.BridgeApi)
    root_post = append_statistics_to_post(root_post, rows[0], False)
    root_post['replies'] = []
    all_posts[root_id] = root_post

    parent_to_children_id_map = {}

    for index in range(1, len(rows)):
        parent_id = rows[index]['parent_id']
        if parent_id not in parent_to_children_id_map:
            parent_to_children_id_map[parent_id] = []
        parent_to_children_id_map[parent_id].append(rows[index]['id'])
        post = _bridge_post_object(rows[index])
        post['active_votes'] = await find_votes_impl(
            db, rows[index]['author'], rows[index]['permlink'],
            VotesPresentation.BridgeApi)
        post = append_statistics_to_post(post, rows[index], False)
        post['replies'] = []
        all_posts[post['post_id']] = post

    for key in parent_to_children_id_map:
        children = parent_to_children_id_map[key]
        post = all_posts[key]
        for child_id in children:
            post['replies'].append(_ref(all_posts[child_id]))

    #result has to be in form of dictionary of dictionaries {post_ref: post}
    results = {}
    for key in all_posts:
        post_ref = _ref(all_posts[key])
        results[post_ref] = all_posts[key]
    return results
Example #7
0
async def get_content_replies(context, author: str, permlink: str):
    """Get a list of post objects based on parent."""
    db = context['db']
    valid_account(author)
    valid_permlink(permlink)
    parent_id = await cursor.get_post_id(db, author, permlink)
    if parent_id:
        child_ids = await cursor.get_child_ids(db, parent_id)
        if child_ids:
            return await load_posts(db, child_ids)
    return []
Example #8
0
async def get_content(context, author: str, permlink: str):
    """Get a single post object."""
    db = context['db']
    valid_account(author)
    valid_permlink(permlink)
    post_id = await cursor.get_post_id(db, author, permlink)
    if not post_id:
        return {'id': 0, 'author': '', 'permlink': ''}
    posts = await load_posts(db, [post_id])
    assert posts, 'post was not found in cache'
    return posts[0]
Example #9
0
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

    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 == 'feed':
        res = await cursor.pids_by_feed_with_reblog(db, account, *start, limit)
        return await load_posts_reblogs(context['db'], res)
    elif sort == 'posts':
        start = start if start_permlink else (account, None)
        assert account == start[
            0], 'comments - account must match start author'
        ids = await cursor.pids_by_posts(db, *start, limit)
        return await load_posts(context['db'], ids)
    elif sort == 'comments':
        start = start if start_permlink else (account, None)
        assert account == start[
            0], 'comments - account must match start author'
        ids = await cursor.pids_by_comments(db, *start, limit)
        return await load_posts(context['db'], ids)
    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)
    elif sort == 'payout':
        start = start if start_permlink else (account, None)
        ids = await cursor.pids_by_payout(db, account, *start, limit)
        return await load_posts(context['db'], ids)
Example #10
0
async def get_profile(context, account, observer=None):
    """Load account/profile data."""
    db = context['db']
    account = valid_account(account)
    observer = valid_account(observer, allow_empty=True)

    ret = await load_profiles(db, [valid_account(account)])
    assert ret, 'Account \'{}\' does not exist'.format(account) # should not be needed

    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]
Example #11
0
async def get_discussions_by_feed(context, tag: str = None, start_author: str = '',
                                  start_permlink: str = '', limit: int = 20,
                                  truncate_body: int = 0, filter_tags: list = None):
    """Retrieve account's personalized feed."""
    assert tag, '`tag` cannot be blank'
    assert not filter_tags, 'filter_tags not supported'
    res = await cursor.pids_by_feed_with_reblog(
        context['db'],
        valid_account(tag),
        valid_account(start_author, allow_empty=True),
        valid_permlink(start_permlink, allow_empty=True),
        valid_limit(limit, 100))
    return await load_posts_reblogs(context['db'], res, truncate_body=truncate_body)
Example #12
0
async def get_account_posts(context, sort:str, account:str, start_author:str='', start_permlink:str='',
                            limit:int=20, observer:str=None):
    """Get posts for an account -- blog, feed, comments, or replies."""
    supported_sort_list = ['blog', 'feed', 'posts', 'comments', 'replies', 'payout']
    assert sort in supported_sort_list, "Unsupported sort, valid sorts: {}".format(", ".join(supported_sort_list))

    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)
    observer =        valid_account(observer, allow_empty=True)
    limit =           valid_limit(limit, 100, 20)

    sql = None
    account_posts = True # set when only posts (or reblogs) of given account are supposed to be in results
    if sort == 'blog':
        sql = "SELECT * FROM bridge_get_account_posts_by_blog( (:account)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::INTEGER, True )"
    elif sort == 'feed':
        sql = "SELECT * FROM bridge_get_by_feed_with_reblog((:account)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::INTEGER)"
    elif sort == 'posts':
        sql = "SELECT * FROM bridge_get_account_posts_by_posts( (:account)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT )"
    elif sort == 'comments':
        sql = "SELECT * FROM bridge_get_account_posts_by_comments( (:account)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT )"
    elif sort == 'replies':
        account_posts = False
        sql = "SELECT * FROM bridge_get_account_posts_by_replies( (:account)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT, True )"
    elif sort == 'payout':
        sql = "SELECT * FROM bridge_get_account_posts_by_payout( (:account)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT )"

    sql_result = await db.query_all(sql, account=account, author=start_author, permlink=start_permlink, limit=limit )
    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)
        if sort == 'blog':
            if post['author'] != account:
                post['reblogged_by'] = [account]
        elif sort == 'feed':
            reblogged_by = set(row['reblogged_by'])
            reblogged_by.discard(row['author']) # Eliminate original author of reblogged post
            if reblogged_by:
                reblogged_by_list = list(reblogged_by)
                reblogged_by_list.sort()
                post['reblogged_by'] = reblogged_by_list

        post = append_statistics_to_post(post, row, False if account_posts else row['is_pinned'])
        posts.append(post)
    return posts
Example #13
0
async def get_following(context, account: str, start: str, follow_type: str = None,
                        limit: int = None, **kwargs):
    """Get all accounts `account` follows. (EOL)"""
    # `type` reserved word workaround
    if not follow_type and 'type' in kwargs:
        follow_type = kwargs['type']
    if not follow_type:
        follow_type = 'blog'
    following = await cursor.get_following(
        context['db'],
        valid_account(account),
        valid_account(start, allow_empty=True),
        valid_follow_type(follow_type),
        valid_limit(limit, 1000))
    return [_legacy_follower(account, name, follow_type) for name in following]
Example #14
0
async def get_discussions_by_feed(context,
                                  tag: str,
                                  start_author: str = '',
                                  start_permlink: str = '',
                                  limit: int = 20,
                                  truncate_body: int = 0,
                                  filter_tags: list = None,
                                  observer: str = None):
    """Retrieve account's personalized feed."""
    assert not filter_tags, 'filter_tags not supported'
    return await get_discussions_by_feed_impl(
        context['db'], valid_account(tag),
        valid_account(start_author, allow_empty=True),
        valid_permlink(start_permlink, allow_empty=True),
        valid_limit(limit, 100, 20), valid_truncate(truncate_body), observer)
Example #15
0
async def get_follow_count(context, account: str):
    """Get follow count stats. (EOL)"""
    count = await cursor.get_follow_counts(context['db'],
                                           valid_account(account))
    return dict(account=account,
                following_count=count['following'],
                follower_count=count['followers'])
Example #16
0
async def get_discussions_by_comments(context,
                                      start_author: str,
                                      start_permlink: str = '',
                                      limit: int = 20,
                                      truncate_body: int = 0,
                                      filter_tags: list = None):
    """Get comments by made by author."""
    assert not filter_tags, 'filter_tags not supported'
    start_author = valid_account(start_author)
    start_permlink = valid_permlink(start_permlink, allow_empty=True)
    limit = valid_limit(limit, 100, 20)
    truncate_body = valid_truncate(truncate_body)

    posts = []
    db = context['db']

    sql = "SELECT * FROM bridge_get_account_posts_by_comments( (:account)::VARCHAR, (:author)::VARCHAR, (:permlink)::VARCHAR, (:limit)::SMALLINT )"
    result = await db.query_all(sql,
                                account=start_author,
                                author=start_author if start_permlink else '',
                                permlink=start_permlink,
                                limit=limit)

    for row in result:
        row = dict(row)
        post = _condenser_post_object(row, truncate_body=truncate_body)
        post['active_votes'] = await find_votes_impl(
            db, post['author'], post['permlink'],
            VotesPresentation.CondenserApi)
        posts.append(post)

    return posts
Example #17
0
async def list_communities(context,
                           last='',
                           limit=100,
                           query=None,
                           sort='rank',
                           observer=None):
    """List all communities, paginated. Returns lite community list."""
    # pylint: disable=too-many-arguments, too-many-locals
    last = valid_community(last, True)
    limit = valid_limit(limit, 100, 100)
    supported_sort_list = ['rank', 'new', 'subs']
    assert sort in supported_sort_list, "Unsupported sort, valid sorts: {}".format(
        ", ".join(supported_sort_list))
    observer = valid_account(observer, True)
    search = query
    db = context['db']

    sql = "SELECT * FROM bridge_list_communities_by_" + \
          sort + "( (:observer)::VARCHAR, (:last)::VARCHAR, (:search)::VARCHAR, (:limit)::INT )"

    rows = await db.query_all(sql,
                              observer=observer,
                              last=last,
                              search=search,
                              limit=limit)

    return remove_empty_admins_field(rows)
Example #18
0
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_account(observer, allow_empty=True)
    valid_permlink(permlink)

    sql = "SELECT * FROM bridge_get_post( (:author)::VARCHAR, (:permlink)::VARCHAR )"
    result = await db.query_all(sql, author=author, permlink=permlink)

    post = _bridge_post_object(result[0])
    post['active_votes'] = await find_votes_impl(db, author, permlink, VotesPresentation.BridgeApi)
    post = append_statistics_to_post(post, result[0], False)
    return post
Example #19
0
async def get_follow_list(context, observer, follow_type='blacklisted'):
    """ For given observer gives directly blacklisted/muted accounts or
        list of blacklists/mute lists followed by observer
    """
    observer = valid_account(observer)
    valid_types = dict(blacklisted=1, follow_blacklist=2, muted=4, follow_muted=8)
    assert follow_type in valid_types, "Unsupported follow_type, valid values: {}".format(", ".join(valid_types.keys()))

    db = context['db']

    results = []
    if follow_type == 'follow_blacklist' or follow_type == 'follow_muted':
        blacklists_for_user = await Mutes.get_blacklists_for_observer(observer, context, follow_type == 'follow_blacklist', follow_type == 'follow_muted')
        for row in blacklists_for_user:
            metadata = safe_db_profile_metadata(row['posting_json_metadata'], row['json_metadata'])

            #list_data = await get_profile(context, row['list'])
            #metadata = list_data["metadata"]["profile"]
            blacklist_description = metadata["blacklist_description"] if "blacklist_description" in metadata else ''
            muted_list_description = metadata["muted_list_description"] if "muted_list_description" in metadata else ''
            results.append({'name': row['list'], 'blacklist_description': blacklist_description, 'muted_list_description': muted_list_description})
    else: # blacklisted or muted
        blacklisted_for_user = await Mutes.get_blacklisted_for_observer(observer, context, valid_types[follow_type])
        for account in blacklisted_for_user.keys():
            results.append({'name': account, 'blacklist_description': '', 'muted_list_description': ''})

    return results
Example #20
0
async def list_all_subscriptions(context, account):
    """Lists all communities `account` subscribes to, plus role and title in each."""
    db = context['db']
    account = valid_account(account)

    sql = "SELECT * FROM bridge_list_all_subscriptions( (:account)::VARCHAR )"
    rows = await db.query_all(sql, account=account)
    return [(r[0], r[1], r[2], r[3]) for r in rows]
Example #21
0
async def list_subscribers(context, community, last='', limit=100):
    """Lists subscribers of `community`."""
    community = valid_community(community)
    last = valid_account(last, True)
    limit = valid_limit(limit, 100, 100)
    db = context['db']
    sql = "SELECT * FROM bridge_list_subscribers( (:community)::VARCHAR, (:last)::VARCHAR, (:limit)::INT )"
    rows = await db.query_all(sql, community=community, last=last, limit=limit)
    return [(r[0], r[1], r[2], json_date(r[3])) for r in rows]
Example #22
0
async def get_follow_count(context, account: str):
    """Get follow count stats. (EOL)"""
    db = context['db']
    account = valid_account(account)
    sql = "SELECT * FROM condenser_get_follow_count( (:account)::VARCHAR )"
    counters = await db.query_row(sql, account=account)
    return dict(account=account,
                following_count=counters[0],
                follower_count=counters[1])
Example #23
0
async def get_replies_by_last_update(context, start_author: str = None, start_permlink: str = '',
                                     limit: int = 20, truncate_body: int = 0):
    """Get all replies made to any of author's posts."""
    assert start_author, '`start_author` cannot be blank'
    ids = await cursor.pids_by_replies_to_account(
        context['db'],
        valid_account(start_author),
        valid_permlink(start_permlink, allow_empty=True),
        valid_limit(limit, 100))
    return await load_posts(context['db'], ids, truncate_body=truncate_body)
Example #24
0
async def get_community_context(context, name, account):
    """For a community/account: returns role, title, subscribed state"""
    db = context['db']
    name = valid_community(name)
    account = valid_account(account)

    sql = "SELECT * FROM bridge_get_community_context( (:account)::VARCHAR, (:name)::VARCHAR )"
    row = await db.query_row(sql, account=account, name=name)

    return dict(row['bridge_get_community_context'])
Example #25
0
async def get_discussion(context, author, permlink):
    """Modified `get_state` thread implementation."""
    db = context['db']

    author = valid_account(author)
    permlink = valid_permlink(permlink)
    root_id = await _get_post_id(db, author, permlink)
    if not root_id:
        return {}

    return await _load_discussion(db, root_id)
Example #26
0
async def list_community_roles(context, community, last='', limit=50):
    """List community account-roles (anyone with non-guest status)."""
    db = context['db']
    community = valid_community(community)
    last = valid_account(last, True)
    limit = valid_limit(limit, 1000, 50)

    sql = "SELECT * FROM bridge_list_community_roles( (:community)::VARCHAR, (:last)::VARCHAR, (:limit)::INT )"
    rows = await db.query_all(sql, community=community, last=last, limit=limit)

    return [(r['name'], r['role'], r['title']) for r in rows]
Example #27
0
async def get_post(context, author, permlink, observer=None):
    """Fetch a single post"""
    # pylint: disable=unused-variable
    #TODO: `observer` logic
    db = context['db']
    observer_id = await get_account_id(db, observer) if observer else None
    pid = await _get_post_id(db, valid_account(author),
                             valid_permlink(permlink))
    posts = await load_posts(db, [pid])
    assert len(posts) == 1, 'cache post not found'
    return posts[0]
Example #28
0
async def get_profile(context, account, observer=None):
    """Load account/profile data."""
    db = context['db']
    ret = await load_profiles(db, [valid_account(account)])
    if not ret:
        return None

    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]
Example #29
0
async def account_notifications(context,
                                account,
                                min_score=25,
                                last_id=None,
                                limit=100):
    """Load notifications for named account."""
    db = context['db']
    valid_account(account)
    min_score = valid_score(min_score, 100, 25)
    last_id = valid_number(last_id, 0, "last_id")
    limit = valid_limit(limit, 100, 100)

    sql_query = "SELECT * FROM account_notifications( (:account)::VARCHAR, (:min_score)::SMALLINT, (:last_id)::BIGINT, (:limit)::SMALLINT )"

    rows = await db.query_all(sql_query,
                              account=account,
                              min_score=min_score,
                              last_id=last_id,
                              limit=limit)
    return [_render(row) for row in rows]
Example #30
0
async def _get_content_replies_impl(db, fat_node_style, author: str,
                                    permlink: str):
    """Get a list of post objects based on parent."""
    valid_account(author)
    valid_permlink(permlink)

    sql = "SELECT * FROM condenser_get_content_replies(:author, :permlink)"
    result = await db.query_all(sql, author=author, permlink=permlink)

    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)
        posts.append(post)

    return posts