shout rating and views count fixed
This commit is contained in:
parent
50a76e8534
commit
f772f41784
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -148,5 +148,6 @@ dump
|
||||||
.vscode
|
.vscode
|
||||||
*dump.sql
|
*dump.sql
|
||||||
*.csv
|
*.csv
|
||||||
dev-server-status.txt
|
dev-server.pid
|
||||||
/resetdb.sh
|
/resetdb.sh
|
||||||
|
backups/
|
||||||
|
|
9
main.py
9
main.py
|
@ -1,4 +1,5 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import os
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from os.path import exists
|
from os.path import exists
|
||||||
from ariadne import load_schema_from_path, make_executable_schema
|
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.main import storages_init
|
||||||
from services.stat.viewed import ViewedStorage
|
from services.stat.viewed import ViewedStorage
|
||||||
from services.zine.gittask import GitTask
|
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 sse.transport import GraphQLSSEHandler
|
||||||
# from services.inbox.presence import on_connect, on_disconnect
|
# from services.inbox.presence import on_connect, on_disconnect
|
||||||
from services.inbox.sse import sse_messages
|
from services.inbox.sse import sse_messages
|
||||||
|
@ -50,12 +51,12 @@ async def start_up():
|
||||||
|
|
||||||
|
|
||||||
async def dev_start_up():
|
async def dev_start_up():
|
||||||
if exists(DEV_SERVER_STATUS_FILE_NAME):
|
if exists(DEV_SERVER_PID_FILE_NAME):
|
||||||
await redis.connect()
|
await redis.connect()
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
with open(DEV_SERVER_STATUS_FILE_NAME, 'w', encoding='utf-8') as f:
|
with open(DEV_SERVER_PID_FILE_NAME, 'w', encoding='utf-8') as f:
|
||||||
f.write('running')
|
f.write(str(os.getpid()))
|
||||||
|
|
||||||
await start_up()
|
await start_up()
|
||||||
|
|
||||||
|
|
|
@ -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
|
|
|
@ -1,25 +1,48 @@
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import datetime, timedelta, timezone
|
||||||
|
|
||||||
from sqlalchemy.orm import joinedload, aliased
|
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 auth.credentials import AuthCredentials
|
||||||
|
from base.exceptions import ObjectNotExist
|
||||||
from base.orm import local_session
|
from base.orm import local_session
|
||||||
from base.resolvers import query
|
from base.resolvers import query
|
||||||
from base.exceptions import ObjectNotExist
|
|
||||||
from orm import ViewedEntry
|
from orm import ViewedEntry
|
||||||
|
from orm.reaction import Reaction, ReactionKind
|
||||||
from orm.shout import Shout, ShoutAuthor
|
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):
|
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):
|
def apply_filters(q, filters, user_id=None):
|
||||||
|
|
||||||
if filters.get("reacted") and user_id:
|
if filters.get("reacted") and user_id:
|
||||||
q.join(Reaction, Reaction.createdBy == user_id)
|
q.join(Reaction, Reaction.createdBy == user_id)
|
||||||
|
|
||||||
|
@ -59,8 +82,25 @@ async def load_shout(_, info, slug):
|
||||||
).filter(
|
).filter(
|
||||||
Shout.deletedAt.is_(None)
|
Shout.deletedAt.is_(None)
|
||||||
).group_by(Shout.id)
|
).group_by(Shout.id)
|
||||||
|
|
||||||
try:
|
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 = {
|
shout.stat = {
|
||||||
"viewed": viewed_stat,
|
"viewed": viewed_stat,
|
||||||
|
@ -125,15 +165,32 @@ async def load_shouts_by(_, info, options):
|
||||||
|
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
shouts = []
|
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)
|
shouts.append(shout)
|
||||||
|
|
||||||
shout.stat = {
|
shout.stat = {
|
||||||
"viewed": viewed_stat,
|
"viewed": 0,
|
||||||
"reacted": reacted_stat,
|
"reacted": reacted_stat,
|
||||||
"commented": commented_stat,
|
"commented": commented_stat,
|
||||||
"rating": rating_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
|
return shouts
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
from datetime import datetime, timedelta, timezone
|
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.authenticate import login_required
|
||||||
from auth.credentials import AuthCredentials
|
from auth.credentials import AuthCredentials
|
||||||
from base.orm import local_session
|
from base.orm import local_session
|
||||||
|
@ -7,11 +9,34 @@ from base.resolvers import mutation, query
|
||||||
from orm.reaction import Reaction, ReactionKind
|
from orm.reaction import Reaction, ReactionKind
|
||||||
from orm.shout import Shout, ShoutReactionsFollower
|
from orm.shout import Shout, ShoutReactionsFollower
|
||||||
from orm.user import User
|
from orm.user import User
|
||||||
from resolvers.zine._common import add_common_stat_columns
|
|
||||||
|
|
||||||
|
|
||||||
def add_reaction_stat_columns(q):
|
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):
|
def reactions_follow(user_id, shout_id: int, auto=False):
|
||||||
|
|
|
@ -2,7 +2,7 @@ import sys
|
||||||
import os
|
import os
|
||||||
import uvicorn
|
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):
|
def exception_handler(exception_type, exception, traceback, debug_hook=sys.excepthook):
|
||||||
|
@ -69,8 +69,8 @@ if __name__ == "__main__":
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
x = sys.argv[1]
|
x = sys.argv[1]
|
||||||
if x == "dev":
|
if x == "dev":
|
||||||
if os.path.exists(DEV_SERVER_STATUS_FILE_NAME):
|
if os.path.exists(DEV_SERVER_PID_FILE_NAME):
|
||||||
os.remove(DEV_SERVER_STATUS_FILE_NAME)
|
os.remove(DEV_SERVER_PID_FILE_NAME)
|
||||||
want_reload = False
|
want_reload = False
|
||||||
if "reload" in sys.argv:
|
if "reload" in sys.argv:
|
||||||
print("MODE: DEV + RELOAD")
|
print("MODE: DEV + RELOAD")
|
||||||
|
|
|
@ -29,4 +29,4 @@ SESSION_TOKEN_HEADER = "Authorization"
|
||||||
SENTRY_DSN = environ.get("SENTRY_DSN")
|
SENTRY_DSN = environ.get("SENTRY_DSN")
|
||||||
|
|
||||||
# for local development
|
# for local development
|
||||||
DEV_SERVER_STATUS_FILE_NAME = 'dev-server-status.txt'
|
DEV_SERVER_PID_FILE_NAME = 'dev-server.pid'
|
||||||
|
|
Loading…
Reference in New Issue
Block a user