Reimplements API methods using ORM

This commit is contained in:
Oleg Silkin 2020-03-31 13:55:44 -04:00
parent e0b6d16c89
commit 1153711636
2 changed files with 126 additions and 59 deletions

View file

@ -126,37 +126,6 @@ def get_comment(comment_id: str) -> dict:
.pop()) .pop())
def get_comment_ids(claim_id: str = None, parent_id: str = None,
page: int = 1, page_size: int = 50, flattened=False) -> dict:
results = comment_list(
claim_id, parent_id,
top_level=(parent_id is None),
page=page, page_size=page_size,
select_fields=['comment_id', 'parent_id']
)
if flattened:
results.update({
'items': [item['comment_id'] for item in results['items']],
'replies': [(item['comment_id'], item.get('parent_id')) for item in results['items']]
})
return results
def get_comments_by_id(comment_ids: typing.Union[list, tuple]) -> dict:
expression = Comment.comment_id.in_(comment_ids)
return comment_list(expressions=expression, page_size=len(comment_ids))
def get_channel_from_comment_id(comment_id: str) -> dict:
results = comment_list(
expressions=(Comment.comment_id == comment_id),
select_fields=['channel_name', 'channel_id', 'channel_url'],
page_size=1
)
# todo: make the return type here consistent
return results['items'].pop()
def create_comment_id(comment: str, channel_id: str, timestamp: int): def create_comment_id(comment: str, channel_id: str, timestamp: int):
# We convert the timestamp from seconds into minutes # We convert the timestamp from seconds into minutes
# to prevent spammers from commenting the same BS everywhere. # to prevent spammers from commenting the same BS everywhere.

View file

@ -1,16 +1,22 @@
import asyncio import asyncio
import logging import logging
import time import time
import typing
from aiohttp import web from aiohttp import web
from aiojobs.aiohttp import atomic from aiojobs.aiohttp import atomic
import src.database.queries as db from src.server.validation import validate_signature_from_claim
from src.database.writes import abandon_comment, create_comment from src.misc import clean_input_params, get_claim_from_id
from src.database.writes import hide_comments
from src.database.writes import edit_comment
from src.misc import clean_input_params
from src.server.errors import make_error, report_error from src.server.errors import make_error, report_error
from src.database.models import Comment, Channel
from src.database.models import get_comment
from src.database.models import comment_list
from src.database.models import create_comment
from src.database.models import edit_comment
from src.database.models import delete_comment
from src.database.models import set_hidden_flag
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -20,37 +26,127 @@ def ping(*args):
return 'pong' return 'pong'
def handle_get_channel_from_comment_id(app, kwargs: dict): def handle_get_channel_from_comment_id(app: web.Application, comment_id: str) -> dict:
return db.get_channel_id_from_comment_id(app['reader'], **kwargs) comment = get_comment(comment_id)
return {
'channel_id': comment['channel_id'],
'channel_name': comment['channel_name']
}
def handle_get_comment_ids(app, kwargs): def handle_get_comment_ids(
return db.get_comment_ids(app['reader'], **kwargs) app: web.Application,
claim_id: str,
parent_id: str = None,
page: int = 1,
page_size: int = 50,
flattened=False
) -> dict:
results = comment_list(
claim_id=claim_id,
parent_id=parent_id,
top_level=(parent_id is None),
page=page,
page_size=page_size,
select_fields=['comment_id', 'parent_id']
)
if flattened:
results.update({
'items': [item['comment_id'] for item in results['items']],
'replies': [(item['comment_id'], item.get('parent_id'))
for item in results['items']]
})
return results
def handle_get_claim_comments(app, kwargs): def handle_get_comments_by_id(
return db.get_claim_comments(app['reader'], **kwargs) app: web.Application,
comment_ids: typing.Union[list, tuple]
) -> dict:
expression = Comment.comment_id.in_(comment_ids)
return comment_list(expressions=expression, page_size=len(comment_ids))
def handle_get_comments_by_id(app, kwargs): def handle_get_claim_comments(
return db.get_comments_by_id(app['reader'], **kwargs) app: web.Application,
claim_id: str,
parent_id: str = None,
page: int = 1,
page_size: int = 50,
top_level: bool = False
) -> dict:
return comment_list(
claim_id=claim_id,
parent_id=parent_id,
page=page,
page_size=page_size,
top_level=top_level
)
def handle_get_claim_hidden_comments(app, kwargs): def handle_get_claim_hidden_comments(
return db.get_claim_hidden_comments(app['reader'], **kwargs) app: web.Application,
claim_id: str,
hidden: bool,
page: int = 1,
page_size: int = 50,
) -> dict:
exclude = 'hidden' if hidden else 'visible'
return comment_list(
claim_id=claim_id,
exclude_mode=exclude,
page=page,
page_size=page_size
)
def get_channel_from_comment_id(app, comment_id: str) -> dict:
results = comment_list(
expressions=(Comment.comment_id == comment_id),
select_fields=['channel_name', 'channel_id', 'channel_url'],
page_size=1
)
# todo: make the return type here consistent
return results['items'].pop()
async def handle_abandon_comment(app, params): async def handle_abandon_comment(app, params):
return {'abandoned': await abandon_comment(app, **params)} # return {'abandoned': await abandon_comment(app, **params)}
raise NotImplementedError
async def handle_hide_comments(app, params): async def handle_hide_comments(app, pieces: list = None, claim_id: str = None) -> dict:
return {'hidden': await hide_comments(app, **params)}
# return {'hidden': await hide_comments(app, **params)}
raise NotImplementedError
async def handle_edit_comment(app, params): async def handle_edit_comment(app, comment: str = None, comment_id: str = None,
if await edit_comment(app, **params): signature: str = None, signing_ts: str = None, **params) -> dict:
return db.get_comment_or_none(app['reader'], params['comment_id']) current = get_comment(comment_id)
channel_claim = await get_claim_from_id(app, current['channel_id'])
if not validate_signature_from_claim(channel_claim, signature, signing_ts, comment):
raise ValueError('Signature could not be validated')
with app['db'].atomic():
if not edit_comment(comment_id, comment, signature, signing_ts):
raise ValueError('Comment could not be edited')
return get_comment(comment_id)
def handle_create_comment(app, comment: str = None, claim_id: str = None,
parent_id: str = None, channel_id: str = None, channel_name: str = None,
signature: str = None, signing_ts: str = None) -> dict:
with app['db'].atomic():
return create_comment(
comment=comment,
claim_id=claim_id,
parent_id=parent_id,
channel_id=channel_id,
channel_name=channel_name,
signature=signature,
signing_ts=signing_ts
)
METHODS = { METHODS = {
@ -59,8 +155,8 @@ METHODS = {
'get_claim_hidden_comments': handle_get_claim_hidden_comments, # this gets used 'get_claim_hidden_comments': handle_get_claim_hidden_comments, # this gets used
'get_comment_ids': handle_get_comment_ids, 'get_comment_ids': handle_get_comment_ids,
'get_comments_by_id': handle_get_comments_by_id, # this gets used 'get_comments_by_id': handle_get_comments_by_id, # this gets used
'get_channel_from_comment_id': handle_get_channel_from_comment_id, # this gets used 'get_channel_from_comment_id': get_channel_from_comment_id, # this gets used
'create_comment': create_comment, # this gets used 'create_comment': handle_create_comment, # this gets used
'delete_comment': handle_abandon_comment, 'delete_comment': handle_abandon_comment,
'abandon_comment': handle_abandon_comment, # this gets used 'abandon_comment': handle_abandon_comment, # this gets used
'hide_comments': handle_hide_comments, # this gets used 'hide_comments': handle_hide_comments, # this gets used
@ -78,17 +174,19 @@ async def process_json(app, body: dict) -> dict:
start = time.time() start = time.time()
try: try:
if asyncio.iscoroutinefunction(METHODS[method]): if asyncio.iscoroutinefunction(METHODS[method]):
result = await METHODS[method](app, params) result = await METHODS[method](app, **params)
else: else:
result = METHODS[method](app, params) result = METHODS[method](app, **params)
response['result'] = result
except Exception as err: except Exception as err:
logger.exception(f'Got {type(err).__name__}:') logger.exception(f'Got {type(err).__name__}:\n{err}')
if type(err) in (ValueError, TypeError): # param error, not too important if type(err) in (ValueError, TypeError): # param error, not too important
response['error'] = make_error('INVALID_PARAMS', err) response['error'] = make_error('INVALID_PARAMS', err)
else: else:
response['error'] = make_error('INTERNAL', err) response['error'] = make_error('INTERNAL', err)
await app['webhooks'].spawn(report_error(app, err, body)) await app['webhooks'].spawn(report_error(app, err, body))
else:
response['result'] = result
finally: finally:
end = time.time() end = time.time()