morning-fixes

This commit is contained in:
tonyrewin 2022-11-26 03:55:45 +03:00
parent 839485873a
commit 228cdf21e9
5 changed files with 74 additions and 80 deletions

View File

@ -5,13 +5,15 @@ from sqlalchemy.sql.expression import desc, asc, select, case
from base.orm import local_session from base.orm import local_session
from base.resolvers import query from base.resolvers import query
from orm import ViewedEntry from orm import ViewedEntry
from orm.shout import Shout, ShoutAuthor from orm.shout import Shout
from orm.reaction import Reaction, ReactionKind from orm.reaction import Reaction, ReactionKind
from services.stat.reacted import ReactedStorage from services.zine.shoutauthor import ShoutAuthorStorage
from services.stat.viewed import ViewedStorage
def add_rating_column(q): def calc_reactions(q):
return q.join(Reaction).add_columns(sa.func.sum(case( return q.join(Reaction).add_columns(
sa.func.sum(case(
(Reaction.kind == ReactionKind.AGREE, 1), (Reaction.kind == ReactionKind.AGREE, 1),
(Reaction.kind == ReactionKind.DISAGREE, -1), (Reaction.kind == ReactionKind.DISAGREE, -1),
(Reaction.kind == ReactionKind.PROOF, 1), (Reaction.kind == ReactionKind.PROOF, 1),
@ -20,8 +22,15 @@ def add_rating_column(q):
(Reaction.kind == ReactionKind.REJECT, -1), (Reaction.kind == ReactionKind.REJECT, -1),
(Reaction.kind == ReactionKind.LIKE, 1), (Reaction.kind == ReactionKind.LIKE, 1),
(Reaction.kind == ReactionKind.DISLIKE, -1), (Reaction.kind == ReactionKind.DISLIKE, -1),
else_=0)
).label('rating'),
sa.func.sum(
case(
(Reaction.body.is_not(None), 1),
else_=0 else_=0
)).label('rating')) )
).label('commented')
)
def apply_filters(q, filters, user=None): def apply_filters(q, filters, user=None):
@ -50,27 +59,27 @@ def apply_filters(q, filters, user=None):
async def load_shout(_, info, slug): async def load_shout(_, info, slug):
with local_session() as session: with local_session() as session:
q = select(Shout).options( q = select(Shout).options(
# TODO add cation
joinedload(Shout.authors), joinedload(Shout.authors),
joinedload(Shout.topics), joinedload(Shout.topics),
) )
q = add_rating_column(q) q = calc_reactions(q)
q = q.filter( q = q.filter(
Shout.slug == slug Shout.slug == slug
).filter( ).filter(
Shout.deletedAt.is_(None) Shout.deletedAt.is_(None)
).group_by(Shout.id) ).group_by(Shout.id)
[shout, rating] = session.execute(q).unique().one() [shout, rating, commented] = session.execute(q).unique().one()
for a in shout.authors:
a.caption = await ShoutAuthorStorage.get_author_caption(a.slug)
viewed = await ViewedStorage.get_shout(shout.slug)
shout.stat = {
"rating": rating,
"viewed": viewed,
"commented": commented,
# "reacted": reacted
}
shout.stat = await ReactedStorage.get_shout_stat(shout.slug, rating)
return shout
def map_result_item(result_item):
shout = result_item[0]
shout.rating = result_item[1]
return shout return shout
@ -104,7 +113,7 @@ async def load_shouts_by(_, info, options):
) )
user = info.context["request"].user user = info.context["request"].user
q = apply_filters(q, options.get("filters"), user) q = apply_filters(q, options.get("filters"), user)
q = add_rating_column(q) q = calc_reactions(q)
o = options.get("order_by") o = options.get("order_by")
if o: if o:
@ -127,37 +136,22 @@ async def load_shouts_by(_, info, options):
order_by_desc = True if options.get('order_by_desc') is None else options.get('order_by_desc') order_by_desc = True if options.get('order_by_desc') is None else options.get('order_by_desc')
with_author_captions = False if options.get('with_author_captions') is None else options.get('with_author_captions')
query_order_by = desc(order_by) if order_by_desc else asc(order_by) query_order_by = desc(order_by) if order_by_desc else asc(order_by)
offset = options.get("offset", 0) offset = options.get("offset", 0)
limit = options.get("limit", 10) limit = options.get("limit", 10)
q = q.group_by(Shout.id).order_by(query_order_by).limit(limit).offset(offset) q = q.group_by(Shout.id).order_by(query_order_by).limit(limit).offset(offset)
shouts = []
with local_session() as session: with local_session() as session:
shouts = list(map(map_result_item, session.execute(q).unique())) for [shout, rating, commented] in session.execute(q).unique():
shout.stat = {
for shout in shouts: "rating": rating,
shout.stat = await ReactedStorage.get_shout_stat(shout.slug, shout.rating) "viewed": await ViewedStorage.get_shout(shout.slug),
del shout.rating "commented": commented,
# "reacted": reacted
author_captions = {} }
# NOTE: no need authors captions in arrays
if with_author_captions: # for author in shout.authors:
author_captions_result = session.query(ShoutAuthor).where( # author.caption = await ShoutAuthorStorage.get_author_caption(shout.slug, author.slug)
ShoutAuthor.shout.in_(map(lambda s: s.slug, shouts))).all() shouts.append(shout)
for author_captions_result_item in author_captions_result:
if author_captions.get(author_captions_result_item.shout) is None:
author_captions[author_captions_result_item.shout] = {}
author_captions[
author_captions_result_item.shout
][
author_captions_result_item.user
] = author_captions_result_item.caption
for author in shout.authors:
author.caption = author_captions[shout.slug][author.slug]
return shouts return shouts

View File

@ -10,7 +10,6 @@ from orm.reaction import Reaction
from orm.shout import ShoutAuthor from orm.shout import ShoutAuthor
from orm.topic import Topic, TopicFollower from orm.topic import Topic, TopicFollower
from orm.user import AuthorFollower, Role, User, UserRating, UserRole from orm.user import AuthorFollower, Role, User, UserRating, UserRole
from services.stat.reacted import ReactedStorage
from services.stat.topicstat import TopicStat from services.stat.topicstat import TopicStat
# from .community import followed_communities # from .community import followed_communities
@ -23,13 +22,12 @@ async def user_subscriptions(slug: str):
"unread": await get_total_unread_counter(slug), # unread inbox messages counter "unread": await get_total_unread_counter(slug), # unread inbox messages counter
"topics": [t.slug for t in await followed_topics(slug)], # followed topics slugs "topics": [t.slug for t in await followed_topics(slug)], # followed topics slugs
"authors": [a.slug for a in await followed_authors(slug)], # followed authors slugs "authors": [a.slug for a in await followed_authors(slug)], # followed authors slugs
"reactions": await ReactedStorage.get_shouts_by_author(slug), "reactions": await followed_reactions(slug)
# "communities": [c.slug for c in followed_communities(slug)], # communities # "communities": [c.slug for c in followed_communities(slug)], # communities
} }
async def get_author_stat(slug): async def get_author_stat(slug):
# TODO: implement author stat
with local_session() as session: with local_session() as session:
return { return {
"shouts": session.query(ShoutAuthor).where(ShoutAuthor.user == slug).count(), "shouts": session.query(ShoutAuthor).where(ShoutAuthor.user == slug).count(),
@ -41,11 +39,29 @@ async def get_author_stat(slug):
).where( ).where(
Reaction.createdBy == slug Reaction.createdBy == slug
).filter( ).filter(
func.length(Reaction.body) > 0 Reaction.body.is_not(None)
).count() ).count()
} }
# @query.field("userFollowedDiscussions")
@login_required
async def followed_discussions(_, info, slug) -> List[Topic]:
return await followed_reactions(slug)
async def followed_reactions(slug):
with local_session() as session:
user = session.query(User).where(User.slug == slug).first()
return session.query(
Reaction.shout
).where(
Reaction.author == slug
).filter(
Reaction.createdAt > user.lastSeen
).all()
@query.field("userFollowedTopics") @query.field("userFollowedTopics")
@login_required @login_required
async def get_followed_topics(_, info, slug) -> List[Topic]: async def get_followed_topics(_, info, slug) -> List[Topic]:

View File

@ -6,7 +6,6 @@ from base.resolvers import mutation, query
from orm import Shout from orm import Shout
from orm.topic import Topic, TopicFollower from orm.topic import Topic, TopicFollower
from services.zine.topics import TopicStorage from services.zine.topics import TopicStorage
# from services.stat.reacted import ReactedStorage
from services.stat.topicstat import TopicStat from services.stat.topicstat import TopicStat
@ -17,11 +16,7 @@ async def get_topic_stat(slug):
return { return {
"shouts": len(TopicStat.shouts_by_topic.get(slug, {}).keys()), "shouts": len(TopicStat.shouts_by_topic.get(slug, {}).keys()),
"authors": len(TopicStat.authors_by_topic.get(slug, {}).keys()), "authors": len(TopicStat.authors_by_topic.get(slug, {}).keys()),
"followers": len(TopicStat.followers_by_topic.get(slug, {}).keys()), "followers": len(TopicStat.followers_by_topic.get(slug, {}).keys())
# "viewed": await ViewedStorage.get_topic(slug),
# "reacted": len(await ReactedStorage.get_topic(slug)),
# "commented": len(await ReactedStorage.get_topic_comments(slug)),
# "rating": await ReactedStorage.get_topic_rating(slug)
} }

View File

@ -20,11 +20,13 @@ class SearchService:
cached = await redis.execute("GET", text) cached = await redis.execute("GET", text)
if not cached: if not cached:
async with SearchService.lock: async with SearchService.lock:
by = { options = {
"title": text, "title": text,
"body": text "body": text,
"limit": limit,
"offset": offset
} }
payload = await load_shouts_by(None, None, by, limit, offset) payload = await load_shouts_by(None, None, options)
await redis.execute("SET", text, json.dumps(payload)) await redis.execute("SET", text, json.dumps(payload))
return payload return payload
else: else:

View File

@ -3,7 +3,6 @@ import time
from base.orm import local_session from base.orm import local_session
from orm.reaction import ReactionKind, Reaction from orm.reaction import ReactionKind, Reaction
from services.zine.topics import TopicStorage from services.zine.topics import TopicStorage
from services.stat.viewed import ViewedStorage
def kind_to_rate(kind) -> int: def kind_to_rate(kind) -> int:
@ -34,18 +33,6 @@ class ReactedStorage:
lock = asyncio.Lock() lock = asyncio.Lock()
modified_shouts = set([]) modified_shouts = set([])
@staticmethod
async def get_shout_stat(slug, rating):
viewed = int(await ViewedStorage.get_shout(slug))
# print(viewed)
return {
"viewed": viewed,
"reacted": len(await ReactedStorage.get_shout(slug)),
"commented": len(await ReactedStorage.get_comments(slug)),
# "rating": await ReactedStorage.get_rating(slug),
"rating": rating
}
@staticmethod @staticmethod
async def get_shout(shout_slug): async def get_shout(shout_slug):
self = ReactedStorage self = ReactedStorage
@ -59,7 +46,7 @@ class ReactedStorage:
return self.reacted["authors"].get(user_slug, []) return self.reacted["authors"].get(user_slug, [])
@staticmethod @staticmethod
async def get_shouts_by_author(user_slug): async def get_followed_reactions(user_slug):
self = ReactedStorage self = ReactedStorage
async with self.lock: async with self.lock:
author_reactions = self.reacted["authors"].get(user_slug, []) author_reactions = self.reacted["authors"].get(user_slug, [])