Add content,comment opinions to comment server #48
8 changed files with 187 additions and 21 deletions
|
@ -28,4 +28,7 @@ logging:
|
|||
datefmt: "%Y-%m-%d %H:%M:%S"
|
||||
host: localhost
|
||||
port: 5921
|
||||
lbrynet: http://localhost:5279
|
||||
lbrynet: http://localhost:5279
|
||||
notifications:
|
||||
url: https://api.lbry.com/event/comment
|
||||
auth_token: mytoken
|
|
@ -48,3 +48,33 @@ ALTER TABLE COMMENT
|
|||
|
||||
CREATE INDEX `claim_comment_index` ON `COMMENT` (`lbryclaimid`, `commentid`);
|
||||
CREATE INDEX `channel_comment_index` ON `COMMENT` (`channelid`, `commentid`);
|
||||
|
||||
CREATE TABLE `COMMENTOPINION` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`commentid` char(64) COLLATE utf8mb4_unicode_ci NOT NULL,
|
||||
`channelid` char(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`signature` char(128) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`signingts` varchar(22) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`timestamp` int NOT NULL,
|
||||
`rating` tinyint DEFAULT '1',
|
||||
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `comment_channel_fk` (`channelid`),
|
||||
CONSTRAINT `comment_fk` FOREIGN KEY (`commentid`) REFERENCES `COMMENT` (`commentid`) ON DELETE CASCADE ON UPDATE CASCADE,
|
||||
CONSTRAINT `comment_channel_fk` FOREIGN KEY (`channelid`) REFERENCES `CHANNEL` (`claimid`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
|
||||
CREATE TABLE `CONTENTOPINION` (
|
||||
`id` bigint unsigned NOT NULL AUTO_INCREMENT,
|
||||
`claimid` char(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`channelid` char(40) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`signature` char(128) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`signingts` varchar(22) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
|
||||
`timestamp` int NOT NULL,
|
||||
`rating` tinyint DEFAULT '1',
|
||||
|
||||
PRIMARY KEY (`id`),
|
||||
KEY `comment_channel_fk` (`channelid`),
|
||||
KEY `lbryclaimid` (`lbryclaimid`),
|
||||
CONSTRAINT `comment_channel_fk` FOREIGN KEY (`channelid`) REFERENCES `CHANNEL` (`claimid`) ON DELETE CASCADE ON UPDATE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
|
@ -51,6 +51,50 @@ class Comment(Model):
|
|||
)
|
||||
|
||||
|
||||
class CommentOpinion(Model):
|
||||
id = BigAutoField(column_name='id', primary_key=True)
|
||||
comment = ForeignKeyField(
|
||||
backref='opinions',
|
||||
column_name='commentid',
|
||||
field='comment_id',
|
||||
model=Comment,
|
||||
null=True
|
||||
)
|
||||
channel = ForeignKeyField(
|
||||
backref='opinions',
|
||||
column_name='channelid',
|
||||
field='claim_id',
|
||||
model=Channel,
|
||||
null=True
|
||||
)
|
||||
signature = FixedCharField(max_length=128, column_name='signature', null=True, unique=True)
|
||||
signing_ts = TextField(column_name='signingts', null=True)
|
||||
timestamp = IntegerField(column_name='timestamp')
|
||||
rating = SmallIntegerField(column_name='rating', null=False)
|
||||
|
||||
class Meta:
|
||||
table_name = 'COMMENTOPINION'
|
||||
|
||||
|
||||
class ContentOpinion(Model):
|
||||
id = BigAutoField(column_name='id', primary_key=True)
|
||||
channel = ForeignKeyField(
|
||||
backref='opinions',
|
||||
column_name='channelid',
|
||||
field='claim_id',
|
||||
model=Channel,
|
||||
null=True
|
||||
)
|
||||
claim_id = FixedCharField(max_length=40, column_name='lbryclaimid')
|
||||
signature = FixedCharField(max_length=128, column_name='signature', null=True, unique=True)
|
||||
signing_ts = TextField(column_name='signingts', null=True)
|
||||
timestamp = IntegerField(column_name='timestamp')
|
||||
rating = SmallIntegerField(column_name='rating', null=False, default=0)
|
||||
|
||||
class Meta:
|
||||
table_name = 'CONTENTOPINION'
|
||||
|
||||
|
||||
FIELDS = {
|
||||
'comment': Comment.comment,
|
||||
'comment_id': Comment.comment_id,
|
||||
|
@ -66,17 +110,21 @@ FIELDS = {
|
|||
}
|
||||
|
||||
|
||||
def comment_list(claim_id: str = None, parent_id: str = None,
|
||||
top_level: bool = False, exclude_mode: str = None,
|
||||
page: int = 1, page_size: int = 50, expressions=None,
|
||||
select_fields: list = None, exclude_fields: list = None) -> dict:
|
||||
def comment_list(claim_id: str = None,
|
||||
parent_id: str = None,
|
||||
top_level: bool = False,
|
||||
exclude_mode: str = None,
|
||||
page: int = 1,
|
||||
page_size: int = 50, expressions=None,
|
||||
select_fields: list = None,
|
||||
exclude_fields: list = None) -> dict:
|
||||
fields = FIELDS.keys()
|
||||
if exclude_fields:
|
||||
fields -= set(exclude_fields)
|
||||
if select_fields:
|
||||
fields &= set(select_fields)
|
||||
attributes = [FIELDS[field] for field in fields]
|
||||
query = Comment.select(*attributes)
|
||||
query = Comment.select(fn.SUM(CommentOpinion.rating).alias('rating'), *attributes)
|
||||
|
||||
# todo: allow this process to be more automated, so it can just be an expression
|
||||
if claim_id:
|
||||
|
@ -97,6 +145,8 @@ def comment_list(claim_id: str = None, parent_id: str = None,
|
|||
total = query.count()
|
||||
query = (query
|
||||
.join(Channel, JOIN.LEFT_OUTER)
|
||||
.join(CommentOpinion, JOIN.LEFT_OUTER)
|
||||
.group_by(Comment.comment_id)
|
||||
.order_by(Comment.timestamp.desc())
|
||||
.paginate(page, page_size))
|
||||
items = [clean(item) for item in query.dicts()]
|
||||
|
@ -203,6 +253,26 @@ def set_hidden_flag(comment_ids: typing.List[str], hidden=True) -> bool:
|
|||
return update.execute() > 0
|
||||
|
||||
|
||||
def create_comment_opinion(comment_id: str = None,
|
||||
channel_id: str = None,
|
||||
channel_name: str = None,
|
||||
signature: str = None,
|
||||
signing_ts: str = None,
|
||||
rating: int = None) -> dict:
|
||||
|
||||
channel, _ = Channel.get_or_create(name=channel_name, claim_id=channel_id)
|
||||
|
||||
timestamp = int(time.time())
|
||||
new_comment_opinion = CommentOpinion.create(
|
||||
commentid=comment_id,
|
||||
channel=channel,
|
||||
signature=signature,
|
||||
signing_ts=signing_ts,
|
||||
timestamp=timestamp,
|
||||
rating=rating,
|
||||
)
|
||||
return new_comment_opinion
|
||||
|
||||
if __name__ == '__main__':
|
||||
logger = logging.getLogger('peewee')
|
||||
logger.addHandler(logging.StreamHandler())
|
||||
|
|
|
@ -10,9 +10,9 @@ from aiohttp import web
|
|||
|
||||
from peewee import *
|
||||
from src.server.handles import api_endpoint, get_api_endpoint
|
||||
from src.database.models import Comment, Channel
|
||||
from src.database.models import Comment, Channel, CommentOpinion, ContentOpinion
|
||||
|
||||
MODELS = [Comment, Channel]
|
||||
MODELS = [Comment, Channel, CommentOpinion, ContentOpinion]
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ from src.server.external import send_notification
|
|||
from src.server.validation import validate_signature_from_claim
|
||||
from src.misc import clean_input_params, get_claim_from_id
|
||||
from src.server.errors import make_error, report_error
|
||||
from src.database.models import Comment, Channel
|
||||
from src.database.models import Comment, Channel, create_comment_opinion
|
||||
from src.database.models import get_comment
|
||||
from src.database.models import comment_list
|
||||
from src.database.models import create_comment
|
||||
|
@ -19,7 +19,6 @@ 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__)
|
||||
|
||||
|
||||
|
@ -151,10 +150,10 @@ async def handle_hide_comments(app: web.Application, pieces: list, hide: bool =
|
|||
channel = claims[claim_id]['signing_channel']
|
||||
piece = pieces_by_id[comment_id]
|
||||
is_valid_signature = validate_signature_from_claim(
|
||||
claim=channel,
|
||||
signature=piece['signature'],
|
||||
signing_ts=piece['signing_ts'],
|
||||
data=piece['comment_id']
|
||||
claim=channel,
|
||||
signature=piece['signature'],
|
||||
signing_ts=piece['signing_ts'],
|
||||
data=piece['comment_id']
|
||||
)
|
||||
if not is_valid_signature:
|
||||
raise ValueError(f'could not validate signature on comment_id: {comment_id}')
|
||||
|
@ -192,8 +191,8 @@ async def handle_edit_comment(app, comment: str = None, comment_id: str = None,
|
|||
|
||||
# TODO: retrieve stake amounts for each channel & store in db
|
||||
async 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:
|
||||
parent_id: str = None, channel_id: str = None, channel_name: str = None,
|
||||
signature: str = None, signing_ts: str = None) -> dict:
|
||||
with app['db'].atomic():
|
||||
comment = create_comment(
|
||||
comment=comment,
|
||||
|
@ -208,18 +207,37 @@ async def handle_create_comment(app, comment: str = None, claim_id: str = None,
|
|||
return comment
|
||||
|
||||
|
||||
async def handle_create_comment_opinion(app,
|
||||
comment_id: str = None,
|
||||
channel_id: str = None,
|
||||
channel_name: str = None,
|
||||
signature: str = None,
|
||||
signing_ts: str = None,
|
||||
rating: int = None) -> dict:
|
||||
with app['db'].atomic():
|
||||
return create_comment_opinion(
|
||||
comment_id=comment_id,
|
||||
channel_id=channel_id,
|
||||
channel_name=channel_name,
|
||||
signature=signature,
|
||||
signing_ts=signing_ts,
|
||||
rating=rating,
|
||||
)
|
||||
|
||||
|
||||
METHODS = {
|
||||
'ping': ping,
|
||||
'get_claim_comments': handle_get_claim_comments, # this gets used
|
||||
'get_claim_comments': handle_get_claim_comments, # this gets used
|
||||
'get_claim_hidden_comments': handle_get_claim_hidden_comments, # this gets used
|
||||
'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
|
||||
'create_comment': handle_create_comment, # this gets used
|
||||
'create_comment': handle_create_comment, # this gets used
|
||||
'create_comment_opinion': handle_create_comment_opinion, # this gets used
|
||||
'delete_comment': handle_abandon_comment,
|
||||
'abandon_comment': handle_abandon_comment, # this gets used
|
||||
'hide_comments': handle_hide_comments, # this gets used
|
||||
'edit_comment': handle_edit_comment # this gets used
|
||||
'edit_comment': handle_edit_comment # this gets used
|
||||
}
|
||||
|
||||
|
||||
|
|
21
test/http_requests/comment-request_local.http
Normal file
21
test/http_requests/comment-request_local.http
Normal file
|
@ -0,0 +1,21 @@
|
|||
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection).
|
||||
#
|
||||
# Following HTTP Request Live Templates are available:
|
||||
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||
POST http://localhost:5921/api
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": null,
|
||||
"method": "get_claim_comments",
|
||||
"params": {
|
||||
"claim_id": "6d266af6c25c80fa2ac6cc7662921ad2e90a07e7"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
###
|
24
test/http_requests/create-comment-opinion-local.http
Normal file
24
test/http_requests/create-comment-opinion-local.http
Normal file
|
@ -0,0 +1,24 @@
|
|||
# For a quick start check out our HTTP Requests collection (Tools|HTTP Client|Open HTTP Requests Collection).
|
||||
#
|
||||
# Following HTTP Request Live Templates are available:
|
||||
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||
POST http://localhost:5921/api
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
"jsonrpc": "2.0",
|
||||
"id": null,
|
||||
"method": "create_comment_opinion",
|
||||
"params": {
|
||||
"comment_id": "34c7b8266e12eb4887da31ef5401c36484e5c450e979736c1caa19a0d2fd1470",
|
||||
"channel_name": "@bbbbb",
|
||||
"channel_id": "9cb713f01bf247a0e03170b5ed00d5161340c486",
|
||||
"signing_ts": "1234567",
|
||||
"rating": 1
|
||||
}
|
||||
}
|
||||
|
||||
###
|
||||
|
|
@ -4,7 +4,7 @@
|
|||
# * 'gtrp' and 'gtr' create a GET request with or without query parameters;
|
||||
# * 'ptr' and 'ptrp' create a POST request with a simple or parameter-like body;
|
||||
# * 'mptr' and 'fptr' create a POST request to submit a form with a text or file field (multipart/form-data);
|
||||
POST http://localhost:5922/api
|
||||
POST http://localhost:5921/api
|
||||
Content-Type: application/json
|
||||
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue