shout rating and views count fixed

This commit is contained in:
bniwredyc 2023-01-17 22:07:44 +01:00
parent 50a76e8534
commit f772f41784
7 changed files with 107 additions and 54 deletions

3
.gitignore vendored
View File

@ -148,5 +148,6 @@ dump
.vscode
*dump.sql
*.csv
dev-server-status.txt
dev-server.pid
/resetdb.sh
backups/

View File

@ -1,4 +1,5 @@
import asyncio
import os
from importlib import import_module
from os.path import exists
from ariadne import load_schema_from_path, make_executable_schema
@ -18,7 +19,7 @@ from resolvers.auth import confirm_email_handler
from services.main import storages_init
from services.stat.viewed import ViewedStorage
from services.zine.gittask import GitTask
from settings import DEV_SERVER_STATUS_FILE_NAME, SENTRY_DSN
from settings import DEV_SERVER_PID_FILE_NAME, SENTRY_DSN
# from sse.transport import GraphQLSSEHandler
# from services.inbox.presence import on_connect, on_disconnect
from services.inbox.sse import sse_messages
@ -50,12 +51,12 @@ async def start_up():
async def dev_start_up():
if exists(DEV_SERVER_STATUS_FILE_NAME):
if exists(DEV_SERVER_PID_FILE_NAME):
await redis.connect()
return
else:
with open(DEV_SERVER_STATUS_FILE_NAME, 'w', encoding='utf-8') as f:
f.write('running')
with open(DEV_SERVER_PID_FILE_NAME, 'w', encoding='utf-8') as f:
f.write(str(os.getpid()))
await start_up()

View File

@ -1,31 +0,0 @@
from sqlalchemy import func, case
from sqlalchemy.orm import aliased
from orm.reaction import Reaction, ReactionKind
def add_common_stat_columns(q):
aliased_reaction = aliased(Reaction)
q = q.outerjoin(aliased_reaction).add_columns(
func.sum(
aliased_reaction.id
).label('reacted_stat'),
func.sum(
case(
(aliased_reaction.body.is_not(None), 1),
else_=0
)
).label('commented_stat'),
func.sum(case(
(aliased_reaction.kind == ReactionKind.AGREE, 1),
(aliased_reaction.kind == ReactionKind.DISAGREE, -1),
(aliased_reaction.kind == ReactionKind.PROOF, 1),
(aliased_reaction.kind == ReactionKind.DISPROOF, -1),
(aliased_reaction.kind == ReactionKind.ACCEPT, 1),
(aliased_reaction.kind == ReactionKind.REJECT, -1),
(aliased_reaction.kind == ReactionKind.LIKE, 1),
(aliased_reaction.kind == ReactionKind.DISLIKE, -1),
else_=0)
).label('rating_stat'))
return q

View File

@ -1,25 +1,48 @@
from datetime import datetime, timedelta, timezone
from sqlalchemy.orm import joinedload, aliased
from sqlalchemy.sql.expression import desc, asc, select, func
from sqlalchemy.sql.expression import desc, asc, select, func, case
from auth.credentials import AuthCredentials
from base.exceptions import ObjectNotExist
from base.orm import local_session
from base.resolvers import query
from base.exceptions import ObjectNotExist
from orm import ViewedEntry
from orm.reaction import Reaction, ReactionKind
from orm.shout import Shout, ShoutAuthor
from orm.reaction import Reaction
from resolvers.zine._common import add_common_stat_columns
def add_stat_columns(q):
q = q.outerjoin(ViewedEntry).add_columns(func.sum(ViewedEntry.amount).label('viewed_stat'))
aliased_reaction = aliased(Reaction)
return add_common_stat_columns(q)
q = q.outerjoin(aliased_reaction).add_columns(
func.sum(
aliased_reaction.id
).label('reacted_stat'),
func.sum(
case(
(aliased_reaction.body.is_not(None), 1),
else_=0
)
).label('commented_stat'),
func.sum(case(
# do not count comments' reactions
(aliased_reaction.replyTo.is_not(None), 0),
(aliased_reaction.kind == ReactionKind.AGREE, 1),
(aliased_reaction.kind == ReactionKind.DISAGREE, -1),
(aliased_reaction.kind == ReactionKind.PROOF, 1),
(aliased_reaction.kind == ReactionKind.DISPROOF, -1),
(aliased_reaction.kind == ReactionKind.ACCEPT, 1),
(aliased_reaction.kind == ReactionKind.REJECT, -1),
(aliased_reaction.kind == ReactionKind.LIKE, 1),
(aliased_reaction.kind == ReactionKind.DISLIKE, -1),
else_=0)
).label('rating_stat'))
return q
def apply_filters(q, filters, user_id=None):
if filters.get("reacted") and user_id:
q.join(Reaction, Reaction.createdBy == user_id)
@ -59,8 +82,25 @@ async def load_shout(_, info, slug):
).filter(
Shout.deletedAt.is_(None)
).group_by(Shout.id)
try:
[shout, viewed_stat, reacted_stat, commented_stat, rating_stat] = session.execute(q).first()
[shout, reacted_stat, commented_stat, rating_stat] = session.execute(q).first()
viewed_stat_query = select().select_from(
Shout
).where(
Shout.id == shout.id
).join(
ViewedEntry
).group_by(
Shout.id
).add_columns(
func.sum(ViewedEntry.amount).label('viewed_stat')
)
# Debug tip:
# print(viewed_stat_query.compile(compile_kwargs={"literal_binds": True}))
viewed_stat = session.execute(viewed_stat_query).scalar()
shout.stat = {
"viewed": viewed_stat,
@ -125,15 +165,32 @@ async def load_shouts_by(_, info, options):
with local_session() as session:
shouts = []
shouts_map = {}
for [shout, viewed_stat, reacted_stat, commented_stat, rating_stat] in session.execute(q).unique():
for [shout, reacted_stat, commented_stat, rating_stat] in session.execute(q).unique():
shouts.append(shout)
shout.stat = {
"viewed": viewed_stat,
"viewed": 0,
"reacted": reacted_stat,
"commented": commented_stat,
"rating": rating_stat
}
shouts_map[shout.id] = shout
viewed_stat_query = select(
Shout.id
).where(
Shout.id.in_(shouts_map.keys())
).join(
ViewedEntry
).group_by(
Shout.id
).add_columns(
func.sum(ViewedEntry.amount).label('viewed_stat')
)
for [shout_id, viewed_stat] in session.execute(viewed_stat_query).unique():
shouts.append(shout)
shouts_map[shout_id].stat['viewed'] = viewed_stat
return shouts

View File

@ -1,5 +1,7 @@
from datetime import datetime, timedelta, timezone
from sqlalchemy import and_, asc, desc, select, text, func
from sqlalchemy import and_, asc, desc, select, text, func, case
from sqlalchemy.orm import aliased
from auth.authenticate import login_required
from auth.credentials import AuthCredentials
from base.orm import local_session
@ -7,11 +9,34 @@ from base.resolvers import mutation, query
from orm.reaction import Reaction, ReactionKind
from orm.shout import Shout, ShoutReactionsFollower
from orm.user import User
from resolvers.zine._common import add_common_stat_columns
def add_reaction_stat_columns(q):
return add_common_stat_columns(q)
aliased_reaction = aliased(Reaction)
q = q.outerjoin(aliased_reaction).add_columns(
func.sum(
aliased_reaction.id
).label('reacted_stat'),
func.sum(
case(
(aliased_reaction.body.is_not(None), 1),
else_=0
)
).label('commented_stat'),
func.sum(case(
(aliased_reaction.kind == ReactionKind.AGREE, 1),
(aliased_reaction.kind == ReactionKind.DISAGREE, -1),
(aliased_reaction.kind == ReactionKind.PROOF, 1),
(aliased_reaction.kind == ReactionKind.DISPROOF, -1),
(aliased_reaction.kind == ReactionKind.ACCEPT, 1),
(aliased_reaction.kind == ReactionKind.REJECT, -1),
(aliased_reaction.kind == ReactionKind.LIKE, 1),
(aliased_reaction.kind == ReactionKind.DISLIKE, -1),
else_=0)
).label('rating_stat'))
return q
def reactions_follow(user_id, shout_id: int, auto=False):

View File

@ -2,7 +2,7 @@ import sys
import os
import uvicorn
from settings import PORT, DEV_SERVER_STATUS_FILE_NAME
from settings import PORT, DEV_SERVER_PID_FILE_NAME
def exception_handler(exception_type, exception, traceback, debug_hook=sys.excepthook):
@ -69,8 +69,8 @@ if __name__ == "__main__":
if len(sys.argv) > 1:
x = sys.argv[1]
if x == "dev":
if os.path.exists(DEV_SERVER_STATUS_FILE_NAME):
os.remove(DEV_SERVER_STATUS_FILE_NAME)
if os.path.exists(DEV_SERVER_PID_FILE_NAME):
os.remove(DEV_SERVER_PID_FILE_NAME)
want_reload = False
if "reload" in sys.argv:
print("MODE: DEV + RELOAD")

View File

@ -29,4 +29,4 @@ SESSION_TOKEN_HEADER = "Authorization"
SENTRY_DSN = environ.get("SENTRY_DSN")
# for local development
DEV_SERVER_STATUS_FILE_NAME = 'dev-server-status.txt'
DEV_SERVER_PID_FILE_NAME = 'dev-server.pid'