This commit is contained in:
@@ -7,9 +7,9 @@ from resolvers.author import (
|
||||
get_author_id,
|
||||
get_authors_all,
|
||||
load_authors_by,
|
||||
rate_author,
|
||||
update_author,
|
||||
)
|
||||
from resolvers.rating import rate_author
|
||||
from resolvers.community import get_communities_all, get_community
|
||||
from resolvers.editor import create_shout, delete_shout, update_shout
|
||||
from resolvers.follower import (
|
||||
|
@@ -1,14 +1,19 @@
|
||||
import json
|
||||
import time
|
||||
|
||||
from sqlalchemy import and_, desc, select, or_, distinct, func
|
||||
from sqlalchemy import desc, select, or_, distinct, func
|
||||
from sqlalchemy.orm import aliased
|
||||
|
||||
from orm.author import Author, AuthorFollower, AuthorRating
|
||||
from orm.author import Author, AuthorFollower
|
||||
from orm.shout import ShoutAuthor, ShoutTopic
|
||||
from orm.topic import Topic
|
||||
from resolvers.follower import query_follows
|
||||
from resolvers.stat import get_authors_with_stat, execute_with_ministat, author_follows_authors, author_follows_topics
|
||||
from resolvers.stat import (
|
||||
get_authors_with_stat,
|
||||
execute_with_ministat,
|
||||
author_follows_authors,
|
||||
author_follows_topics,
|
||||
)
|
||||
from services.auth import login_required
|
||||
from services.db import local_session
|
||||
from services.rediscache import redis
|
||||
@@ -47,7 +52,7 @@ def get_author(_, _info, slug='', author_id=None):
|
||||
if author_id:
|
||||
q = select(Author).where(Author.id == author_id)
|
||||
|
||||
[author, ] = get_authors_with_stat(q, ratings=True)
|
||||
[author] = get_authors_with_stat(q, ratings=True)
|
||||
except Exception as exc:
|
||||
logger.error(exc)
|
||||
return author
|
||||
@@ -67,7 +72,7 @@ async def get_author_by_user_id(user_id: str, ratings=False):
|
||||
logger.info(f'getting author id for {user_id}')
|
||||
q = select(Author).filter(Author.user == user_id)
|
||||
|
||||
[author, ] = get_authors_with_stat(q, ratings)
|
||||
[author] = get_authors_with_stat(q, ratings)
|
||||
except Exception as exc:
|
||||
logger.error(exc)
|
||||
return author
|
||||
@@ -115,7 +120,11 @@ def load_authors_by(_, _info, by, limit, offset):
|
||||
def get_author_follows(_, _info, slug='', user=None, author_id=None):
|
||||
with local_session() as session:
|
||||
if user or slug:
|
||||
author_id_result = session.query(Author.id).filter(or_(Author.user == user, Author.slug == slug)).first()
|
||||
author_id_result = (
|
||||
session.query(Author.id)
|
||||
.filter(or_(Author.user == user, Author.slug == slug))
|
||||
.first()
|
||||
)
|
||||
author_id = author_id_result[0] if author_id_result else None
|
||||
if author_id:
|
||||
follows = query_follows(author_id)
|
||||
@@ -128,7 +137,11 @@ def get_author_follows(_, _info, slug='', user=None, author_id=None):
|
||||
def get_author_follows_topics(_, _info, slug='', user=None, author_id=None):
|
||||
with local_session() as session:
|
||||
if user or slug:
|
||||
author_id_result = session.query(Author.id).filter(or_(Author.user == user, Author.slug == slug)).first()
|
||||
author_id_result = (
|
||||
session.query(Author.id)
|
||||
.filter(or_(Author.user == user, Author.slug == slug))
|
||||
.first()
|
||||
)
|
||||
author_id = author_id_result[0] if author_id_result else None
|
||||
if author_id:
|
||||
follows = author_follows_authors(author_id)
|
||||
@@ -141,7 +154,11 @@ def get_author_follows_topics(_, _info, slug='', user=None, author_id=None):
|
||||
def get_author_follows_authors(_, _info, slug='', user=None, author_id=None):
|
||||
with local_session() as session:
|
||||
if user or slug:
|
||||
author_id_result = session.query(Author.id).filter(or_(Author.user == user, Author.slug == slug)).first()
|
||||
author_id_result = (
|
||||
session.query(Author.id)
|
||||
.filter(or_(Author.user == user, Author.slug == slug))
|
||||
.first()
|
||||
)
|
||||
author_id = author_id_result[0] if author_id_result else None
|
||||
if author_id:
|
||||
follows = author_follows_topics(author_id)
|
||||
@@ -150,42 +167,6 @@ def get_author_follows_authors(_, _info, slug='', user=None, author_id=None):
|
||||
raise ValueError('Author not found')
|
||||
|
||||
|
||||
@mutation.field('rate_author')
|
||||
@login_required
|
||||
def rate_author(_, info, rated_slug, value):
|
||||
user_id = info.context['user_id']
|
||||
|
||||
with local_session() as session:
|
||||
rated_author = session.query(Author).filter(Author.slug == rated_slug).first()
|
||||
rater = session.query(Author).filter(Author.slug == user_id).first()
|
||||
if rater and rated_author:
|
||||
rating: AuthorRating = (
|
||||
session.query(AuthorRating)
|
||||
.filter(
|
||||
and_(
|
||||
AuthorRating.rater == rater.id,
|
||||
AuthorRating.author == rated_author.id,
|
||||
)
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if rating:
|
||||
rating.plus = value > 0
|
||||
session.add(rating)
|
||||
session.commit()
|
||||
return {}
|
||||
else:
|
||||
try:
|
||||
rating = AuthorRating(
|
||||
rater=rater.id, author=rated_author.id, plus=value > 0
|
||||
)
|
||||
session.add(rating)
|
||||
session.commit()
|
||||
except Exception as err:
|
||||
return {'error': err}
|
||||
return {}
|
||||
|
||||
|
||||
def create_author(user_id: str, slug: str, name: str = ''):
|
||||
with local_session() as session:
|
||||
new_author = Author(user=user_id, slug=slug, name=name)
|
||||
|
137
resolvers/rating.py
Normal file
137
resolvers/rating.py
Normal file
@@ -0,0 +1,137 @@
|
||||
from sqlalchemy import and_
|
||||
from sqlalchemy.orm import aliased
|
||||
|
||||
from orm.author import AuthorRating, Author
|
||||
from orm.reaction import Reaction, ReactionKind
|
||||
from orm.shout import Shout
|
||||
from services.auth import login_required
|
||||
from services.db import local_session
|
||||
from services.schema import mutation
|
||||
|
||||
|
||||
@mutation.field('rate_author')
|
||||
@login_required
|
||||
def rate_author(_, info, rated_slug, value):
|
||||
user_id = info.context['user_id']
|
||||
|
||||
with local_session() as session:
|
||||
rated_author = session.query(Author).filter(Author.slug == rated_slug).first()
|
||||
rater = session.query(Author).filter(Author.slug == user_id).first()
|
||||
if rater and rated_author:
|
||||
rating: AuthorRating = (
|
||||
session.query(AuthorRating)
|
||||
.filter(
|
||||
and_(
|
||||
AuthorRating.rater == rater.id,
|
||||
AuthorRating.author == rated_author.id,
|
||||
)
|
||||
)
|
||||
.first()
|
||||
)
|
||||
if rating:
|
||||
rating.plus = value > 0
|
||||
session.add(rating)
|
||||
session.commit()
|
||||
return {}
|
||||
else:
|
||||
try:
|
||||
rating = AuthorRating(
|
||||
rater=rater.id, author=rated_author.id, plus=value > 0
|
||||
)
|
||||
session.add(rating)
|
||||
session.commit()
|
||||
except Exception as err:
|
||||
return {'error': err}
|
||||
return {}
|
||||
|
||||
|
||||
def count_author_comments_rating(session, author_id) -> int:
|
||||
replied_alias = aliased(Reaction)
|
||||
replies_likes = (
|
||||
session.query(replied_alias)
|
||||
.join(Reaction, replied_alias.id == Reaction.reply_to)
|
||||
.where(
|
||||
and_(
|
||||
replied_alias.created_by == author_id,
|
||||
replied_alias.kind == ReactionKind.COMMENT.value,
|
||||
)
|
||||
)
|
||||
.filter(replied_alias.kind == ReactionKind.LIKE.value)
|
||||
.count()
|
||||
) or 0
|
||||
replies_dislikes = (
|
||||
session.query(replied_alias)
|
||||
.join(Reaction, replied_alias.id == Reaction.reply_to)
|
||||
.where(
|
||||
and_(
|
||||
replied_alias.created_by == author_id,
|
||||
replied_alias.kind == ReactionKind.COMMENT.value,
|
||||
)
|
||||
)
|
||||
.filter(replied_alias.kind == ReactionKind.DISLIKE.value)
|
||||
.count()
|
||||
) or 0
|
||||
|
||||
return replies_likes - replies_dislikes
|
||||
|
||||
|
||||
def count_author_shouts_rating(session, author_id) -> int:
|
||||
shouts_likes = (
|
||||
session.query(Reaction, Shout)
|
||||
.join(Shout, Shout.id == Reaction.shout)
|
||||
.filter(
|
||||
and_(
|
||||
Shout.authors.any(id=author_id),
|
||||
Reaction.kind == ReactionKind.LIKE.value,
|
||||
)
|
||||
)
|
||||
.count()
|
||||
or 0
|
||||
)
|
||||
shouts_dislikes = (
|
||||
session.query(Reaction, Shout)
|
||||
.join(Shout, Shout.id == Reaction.shout)
|
||||
.filter(
|
||||
and_(
|
||||
Shout.authors.any(id=author_id),
|
||||
Reaction.kind == ReactionKind.DISLIKE.value,
|
||||
)
|
||||
)
|
||||
.count()
|
||||
or 0
|
||||
)
|
||||
return shouts_likes - shouts_dislikes
|
||||
|
||||
|
||||
def load_author_ratings(author: Author):
|
||||
with local_session() as session:
|
||||
comments_count = (
|
||||
session.query(Reaction)
|
||||
.filter(
|
||||
and_(
|
||||
Reaction.created_by == author.id,
|
||||
Reaction.kind == ReactionKind.COMMENT.value,
|
||||
Reaction.deleted_at.is_(None),
|
||||
)
|
||||
)
|
||||
.count()
|
||||
)
|
||||
likes_count = (
|
||||
session.query(AuthorRating)
|
||||
.filter(and_(AuthorRating.author == author.id, AuthorRating.plus.is_(True)))
|
||||
.count()
|
||||
)
|
||||
dislikes_count = (
|
||||
session.query(AuthorRating)
|
||||
.filter(
|
||||
and_(AuthorRating.author == author.id, AuthorRating.plus.is_not(True))
|
||||
)
|
||||
.count()
|
||||
)
|
||||
author.stat['rating'] = likes_count - dislikes_count
|
||||
author.stat['rating_shouts'] = count_author_shouts_rating(session, author.id)
|
||||
author.stat['rating_comments'] = count_author_comments_rating(
|
||||
session, author.id
|
||||
)
|
||||
author.stat['commented'] = comments_count
|
||||
return author
|
@@ -57,7 +57,7 @@ def check_to_feature(session, approver_id, reaction):
|
||||
"""set shout to public if publicated approvers amount > 4"""
|
||||
if not reaction.reply_to and is_positive(reaction.kind):
|
||||
if is_featured_author(session, approver_id):
|
||||
approvers = [approver_id, ]
|
||||
approvers = [approver_id]
|
||||
# now count how many approvers are voted already
|
||||
reacted_readers = (
|
||||
session.query(Reaction).where(Reaction.shout == reaction.shout).all()
|
||||
@@ -148,6 +148,40 @@ async def _create_reaction(session, shout, author, reaction):
|
||||
return rdict
|
||||
|
||||
|
||||
def check_rating(reaction: dict, shout_id: int, session, author: Author):
|
||||
kind = reaction.get('kind')
|
||||
opposite_kind = (
|
||||
ReactionKind.DISLIKE.value if is_positive(kind) else ReactionKind.LIKE.value
|
||||
)
|
||||
|
||||
q = select(Reaction).filter(
|
||||
and_(
|
||||
Reaction.shout == shout_id,
|
||||
Reaction.created_by == author.id,
|
||||
Reaction.kind.in_(RATING_REACTIONS),
|
||||
)
|
||||
)
|
||||
reply_to = reaction.get('reply_to')
|
||||
if reply_to and isinstance(reply_to, int):
|
||||
q = q.filter(Reaction.reply_to == reply_to)
|
||||
rating_reactions = session.execute(q).all()
|
||||
same_rating = filter(
|
||||
lambda r: r.created_by == author.id and r.kind == opposite_kind,
|
||||
rating_reactions,
|
||||
)
|
||||
opposite_rating = filter(
|
||||
lambda r: r.created_by == author.id and r.kind == opposite_kind,
|
||||
rating_reactions,
|
||||
)
|
||||
if same_rating:
|
||||
return {'error': "You can't rate the same thing twice"}
|
||||
elif opposite_rating:
|
||||
return {'error': 'Remove opposite vote first'}
|
||||
elif filter(lambda r: r.created_by == author.id, rating_reactions):
|
||||
return {'error': "You can't rate your own thing"}
|
||||
return
|
||||
|
||||
|
||||
@mutation.field('create_reaction')
|
||||
@login_required
|
||||
async def create_reaction(_, info, reaction):
|
||||
@@ -174,37 +208,9 @@ async def create_reaction(_, info, reaction):
|
||||
return {'error': 'cannot create reaction without a kind'}
|
||||
|
||||
if kind in RATING_REACTIONS:
|
||||
opposite_kind = (
|
||||
ReactionKind.DISLIKE.value
|
||||
if is_positive(kind)
|
||||
else ReactionKind.LIKE.value
|
||||
)
|
||||
|
||||
q = select(Reaction).filter(
|
||||
and_(
|
||||
Reaction.shout == shout_id,
|
||||
Reaction.created_by == author.id,
|
||||
Reaction.kind.in_(RATING_REACTIONS),
|
||||
)
|
||||
)
|
||||
reply_to = reaction.get('reply_to')
|
||||
if reply_to and isinstance(reply_to, int):
|
||||
q = q.filter(Reaction.reply_to == reply_to)
|
||||
rating_reactions = session.execute(q).all()
|
||||
same_rating = filter(
|
||||
lambda r: r.created_by == author.id and r.kind == opposite_kind,
|
||||
rating_reactions,
|
||||
)
|
||||
opposite_rating = filter(
|
||||
lambda r: r.created_by == author.id and r.kind == opposite_kind,
|
||||
rating_reactions,
|
||||
)
|
||||
if same_rating:
|
||||
return {'error': "You can't rate the same thing twice"}
|
||||
elif opposite_rating:
|
||||
return {'error': 'Remove opposite vote first'}
|
||||
elif filter(lambda r: r.created_by == author.id, rating_reactions):
|
||||
return {'error': "You can't rate your own thing"}
|
||||
result = check_rating(reaction, shout_id, session, author)
|
||||
if result:
|
||||
return result
|
||||
|
||||
rdict = await _create_reaction(session, shout, author, reaction)
|
||||
return {'reaction': rdict}
|
||||
|
@@ -1,11 +1,11 @@
|
||||
from sqlalchemy import func, distinct, select, join, and_
|
||||
from sqlalchemy import func, distinct, select, join
|
||||
from sqlalchemy.orm import aliased
|
||||
|
||||
from orm.reaction import Reaction, ReactionKind
|
||||
from orm.topic import TopicFollower, Topic
|
||||
from resolvers.rating import load_author_ratings
|
||||
from services.db import local_session
|
||||
from orm.author import AuthorFollower, Author, AuthorRating
|
||||
from orm.shout import ShoutTopic, ShoutAuthor, Shout
|
||||
from orm.author import AuthorFollower, Author
|
||||
from orm.shout import ShoutTopic, ShoutAuthor
|
||||
from services.logger import root_logger as logger
|
||||
|
||||
|
||||
@@ -16,11 +16,22 @@ def add_topic_stat_columns(q):
|
||||
|
||||
q = (
|
||||
q.outerjoin(aliased_shout_topic, aliased_shout_topic.topic == Topic.id)
|
||||
.add_columns(func.count(distinct(aliased_shout_topic.shout)).label("shouts_stat"))
|
||||
.outerjoin(aliased_shout_author, aliased_shout_topic.shout == aliased_shout_author.shout)
|
||||
.add_columns(func.count(distinct(aliased_shout_author.author)).label("authors_stat"))
|
||||
.add_columns(
|
||||
func.count(distinct(aliased_shout_topic.shout)).label('shouts_stat')
|
||||
)
|
||||
.outerjoin(
|
||||
aliased_shout_author,
|
||||
aliased_shout_topic.shout == aliased_shout_author.shout,
|
||||
)
|
||||
.add_columns(
|
||||
func.count(distinct(aliased_shout_author.author)).label('authors_stat')
|
||||
)
|
||||
.outerjoin(aliased_topic_follower)
|
||||
.add_columns(func.count(distinct(aliased_topic_follower.follower)).label("followers_stat"))
|
||||
.add_columns(
|
||||
func.count(distinct(aliased_topic_follower.follower)).label(
|
||||
'followers_stat'
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
q = q.group_by(Topic.id)
|
||||
@@ -35,11 +46,21 @@ def add_author_stat_columns(q):
|
||||
|
||||
q = (
|
||||
q.outerjoin(aliased_shout_author, aliased_shout_author.author == Author.id)
|
||||
.add_columns(func.count(distinct(aliased_shout_author.shout)).label("shouts_stat"))
|
||||
.add_columns(
|
||||
func.count(distinct(aliased_shout_author.shout)).label('shouts_stat')
|
||||
)
|
||||
.outerjoin(aliased_author_authors, aliased_author_authors.follower == Author.id)
|
||||
.add_columns(func.count(distinct(aliased_shout_author.author)).label("authors_stat"))
|
||||
.outerjoin(aliased_author_followers, aliased_author_followers.author == Author.id)
|
||||
.add_columns(func.count(distinct(aliased_author_followers.follower)).label("followers_stat"))
|
||||
.add_columns(
|
||||
func.count(distinct(aliased_shout_author.author)).label('authors_stat')
|
||||
)
|
||||
.outerjoin(
|
||||
aliased_author_followers, aliased_author_followers.author == Author.id
|
||||
)
|
||||
.add_columns(
|
||||
func.count(distinct(aliased_author_followers.follower)).label(
|
||||
'followers_stat'
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
q = q.group_by(Author.id)
|
||||
@@ -47,104 +68,6 @@ def add_author_stat_columns(q):
|
||||
return q
|
||||
|
||||
|
||||
def count_author_comments_rating(session, author_id) -> int:
|
||||
replied_alias = aliased(Reaction)
|
||||
replies_likes = (
|
||||
session.query(replied_alias)
|
||||
.join(Reaction, replied_alias.id == Reaction.reply_to)
|
||||
.where(
|
||||
and_(
|
||||
replied_alias.created_by == author_id,
|
||||
replied_alias.kind == ReactionKind.COMMENT.value,
|
||||
)
|
||||
)
|
||||
.filter(replied_alias.kind == ReactionKind.LIKE.value)
|
||||
.count()
|
||||
) or 0
|
||||
replies_dislikes = (
|
||||
session.query(replied_alias)
|
||||
.join(Reaction, replied_alias.id == Reaction.reply_to)
|
||||
.where(
|
||||
and_(
|
||||
replied_alias.created_by == author_id,
|
||||
replied_alias.kind == ReactionKind.COMMENT.value,
|
||||
)
|
||||
)
|
||||
.filter(replied_alias.kind == ReactionKind.DISLIKE.value)
|
||||
.count()
|
||||
) or 0
|
||||
|
||||
return replies_likes - replies_dislikes
|
||||
|
||||
|
||||
def count_author_shouts_rating(session, author_id) -> int:
|
||||
shouts_likes = (
|
||||
session.query(Reaction, Shout)
|
||||
.join(Shout, Shout.id == Reaction.shout)
|
||||
.filter(
|
||||
and_(
|
||||
Shout.authors.any(id=author_id),
|
||||
Reaction.kind == ReactionKind.LIKE.value,
|
||||
)
|
||||
)
|
||||
.count()
|
||||
or 0
|
||||
)
|
||||
shouts_dislikes = (
|
||||
session.query(Reaction, Shout)
|
||||
.join(Shout, Shout.id == Reaction.shout)
|
||||
.filter(
|
||||
and_(
|
||||
Shout.authors.any(id=author_id),
|
||||
Reaction.kind == ReactionKind.DISLIKE.value,
|
||||
)
|
||||
)
|
||||
.count()
|
||||
or 0
|
||||
)
|
||||
return shouts_likes - shouts_dislikes
|
||||
|
||||
|
||||
def load_author_ratings(author: Author):
|
||||
with local_session() as session:
|
||||
comments_count = (
|
||||
session.query(Reaction)
|
||||
.filter(
|
||||
and_(
|
||||
Reaction.created_by == author.id,
|
||||
Reaction.kind == ReactionKind.COMMENT.value,
|
||||
Reaction.deleted_at.is_(None),
|
||||
)
|
||||
)
|
||||
.count()
|
||||
)
|
||||
likes_count = (
|
||||
session.query(AuthorRating)
|
||||
.filter(
|
||||
and_(AuthorRating.author == author.id, AuthorRating.plus.is_(True))
|
||||
)
|
||||
.count()
|
||||
)
|
||||
dislikes_count = (
|
||||
session.query(AuthorRating)
|
||||
.filter(
|
||||
and_(
|
||||
AuthorRating.author == author.id, AuthorRating.plus.is_not(True)
|
||||
)
|
||||
)
|
||||
.count()
|
||||
)
|
||||
author.stat['rating'] = likes_count - dislikes_count
|
||||
author.stat['rating_shouts'] = count_author_shouts_rating(
|
||||
session, author.id
|
||||
)
|
||||
author.stat['rating_comments'] = count_author_comments_rating(
|
||||
session, author.id
|
||||
)
|
||||
author.stat['commented'] = comments_count
|
||||
return author
|
||||
|
||||
|
||||
def execute_with_ministat(q):
|
||||
records = []
|
||||
with local_session() as session:
|
||||
@@ -176,11 +99,11 @@ def get_topics_with_stat(q):
|
||||
|
||||
|
||||
def author_follows_authors(author_id: int):
|
||||
af = aliased(AuthorFollower, name="af")
|
||||
af = aliased(AuthorFollower, name='af')
|
||||
q = (
|
||||
select(Author).select_from(
|
||||
join(Author, af, Author.id == int(af.author))
|
||||
).where(af.follower == author_id)
|
||||
select(Author)
|
||||
.select_from(join(Author, af, Author.id == int(af.author)))
|
||||
.where(af.follower == author_id)
|
||||
)
|
||||
q = add_author_stat_columns(q)
|
||||
return execute_with_ministat(q)
|
||||
@@ -188,9 +111,9 @@ def author_follows_authors(author_id: int):
|
||||
|
||||
def author_follows_topics(author_id: int):
|
||||
q = (
|
||||
select(Topic).select_from(
|
||||
join(Topic, TopicFollower, Topic.id == TopicFollower.topic)
|
||||
).where(TopicFollower.follower == author_id)
|
||||
select(Topic)
|
||||
.select_from(join(Topic, TopicFollower, Topic.id == TopicFollower.topic))
|
||||
.where(TopicFollower.follower == author_id)
|
||||
)
|
||||
|
||||
q = add_topic_stat_columns(q)
|
||||
@@ -207,5 +130,5 @@ def query_follows(author_id: int):
|
||||
'communities': [{'id': 1, 'name': 'Дискурс', 'slug': 'discours'}],
|
||||
}
|
||||
except Exception as e:
|
||||
logger.exception(f"An error occurred while executing query_follows: {e}")
|
||||
raise Exception("An error occurred while executing query_follows") from e
|
||||
logger.exception(f'An error occurred while executing query_follows: {e}')
|
||||
raise Exception('An error occurred while executing query_follows') from e
|
||||
|
Reference in New Issue
Block a user