core/resolvers/author.py
Untone f9abe421aa
All checks were successful
deploy / deploy (push) Successful in 1m29s
commented-fix
2023-12-24 20:46:50 +03:00

244 lines
8.4 KiB
Python

import time
from typing import List
from sqlalchemy import and_, case, distinct, func, literal, select
from sqlalchemy.orm import aliased
from orm.author import Author, AuthorFollower, AuthorRating
from orm.community import Community
from orm.reaction import Reaction, ReactionKind
from orm.shout import ShoutAuthor, ShoutTopic
from orm.topic import Topic
from resolvers.community import followed_communities
from resolvers.reaction import reacted_shouts_updates as followed_reactions
from resolvers.topic import followed_topics
from services.auth import login_required
from services.db import local_session
from services.schema import mutation, query
from services.unread import get_total_unread_counter
def add_author_stat_columns(q):
shout_author_aliased = aliased(ShoutAuthor)
q = q.outerjoin(shout_author_aliased, shout_author_aliased.author == Author.id).add_columns(
func.count(distinct(shout_author_aliased.shout)).label("shouts_stat")
)
followers_table = aliased(AuthorFollower)
q = q.outerjoin(followers_table, followers_table.author == Author.id).add_columns(
func.count(distinct(followers_table.follower)).label("followers_stat")
)
followings_table = aliased(AuthorFollower)
q = q.outerjoin(followings_table, followings_table.follower == Author.id).add_columns(
func.count(distinct(followers_table.author)).label("followings_stat")
)
q = q.group_by(Author.id)
return q
def get_authors_from_query(q):
authors = []
with local_session() as session:
for [author, shouts_stat, followers_stat, followings_stat] in session.execute(q):
author.stat = {
"shouts": shouts_stat,
"followers": followers_stat,
"followings": followings_stat,
}
authors.append(author)
# print(f"[resolvers.author] get_authors_from_query {authors}")
return authors
async def author_followings(author_id: int):
# NOTE: topics, authors, shout-reactions and communities slugs list
return {
"unread": await get_total_unread_counter(author_id),
"topics": [t.slug for t in await followed_topics(author_id)],
"authors": [a.slug for a in await followed_authors(author_id)],
"reactions": [s.slug for s in followed_reactions(author_id)],
"communities": [c.slug for c in [followed_communities(author_id)] if isinstance(c, Community)],
}
@mutation.field("update_profile")
@login_required
async def update_profile(_, info, profile):
user_id = info.context["user_id"]
with local_session() as session:
author = session.query(Author).where(Author.user == user_id).first()
Author.update(author, profile)
session.add(author)
session.commit()
return {"error": None, "author": author}
# for mutation.field("follow")
def author_follow(follower_id, slug):
try:
with local_session() as session:
author = session.query(Author).where(Author.slug == slug).one()
af = AuthorFollower(follower=follower_id, author=author.id)
session.add(af)
session.commit()
return True
except Exception:
return False
# for mutation.field("unfollow")
def author_unfollow(follower_id, slug):
with local_session() as session:
flw = (
session.query(AuthorFollower)
.join(Author, Author.id == AuthorFollower.author)
.filter(and_(AuthorFollower.follower == follower_id, Author.slug == slug))
.first()
)
if flw:
session.delete(flw)
session.commit()
return True
return False
# TODO: caching query
@query.field("get_authors_all")
async def get_authors_all(_, _info):
with local_session() as session:
return session.query(Author).all()
@query.field("get_author_id")
async def get_author_id(_, _info, user: str):
with local_session() as session:
print(f"[resolvers.author] getting author id for {user}")
a = session.query(Author).filter(Author.user == user).first()
if a:
print(f"[resolvers.author] got @{a.slug}")
return a
@query.field("get_author")
async def get_author(_, _info, slug="", author_id=None):
q = None
if slug or author_id:
if slug != "":
q = select(Author).where(Author.slug == slug)
elif author_id:
q = select(Author).where(Author.id == author_id)
q = add_author_stat_columns(q)
authors = get_authors_from_query(q)
if authors:
author = authors[0]
with local_session() as session:
comments_count = (
session.query(Reaction)
.where(and_(Reaction.createdBy == author.id, Reaction.kind == ReactionKind.COMMENT.value))
.count()
)
author.stat["commented"] = comments_count
else:
return {"error": "cant find author"}
@query.field("load_authors_by")
async def load_authors_by(_, _info, by, limit, offset):
q = select(Author)
q = add_author_stat_columns(q)
if by.get("slug"):
q = q.filter(Author.slug.ilike(f"%{by['slug']}%"))
elif by.get("name"):
q = q.filter(Author.name.ilike(f"%{by['name']}%"))
elif by.get("topic"):
q = q.join(ShoutAuthor).join(ShoutTopic).join(Topic).where(Topic.slug == by["topic"])
if by.get("last_seen"): # in unixtime
before = int(time.time()) - by["last_seen"]
q = q.filter(Author.last_seen > before)
elif by.get("created_at"): # in unixtime
before = int(time.time()) - by["created_at"]
q = q.filter(Author.created_at > before)
q = q.order_by(by.get("order", Author.created_at)).limit(limit).offset(offset)
return get_authors_from_query(q)
@query.field("get_author_followed")
async def get_author_followed(_, _info, slug="", user=None, author_id=None) -> List[Author]:
author_id_query = None
if slug:
author_id_query = select(Author.id).where(Author.slug == slug)
elif user:
author_id_query = select(Author.id).where(Author.user == user)
if not author_id:
with local_session() as session:
author_id = session.execute(author_id_query).scalar()
if author_id is None:
raise ValueError("Author not found")
else:
return await followed_authors(author_id) # Author[]
@query.field("get_author_followers")
async def get_author_followers(_, _info, slug) -> List[Author]:
q = select(Author)
q = add_author_stat_columns(q)
aliased_author = aliased(Author)
q = (
q.join(AuthorFollower, AuthorFollower.follower == Author.id)
.join(aliased_author, aliased_author.id == AuthorFollower.author)
.where(aliased_author.slug == slug)
)
return get_authors_from_query(q)
async def followed_authors(follower_id):
q = select(Author)
q = add_author_stat_columns(q)
q = q.join(AuthorFollower, AuthorFollower.author == Author.id).where(AuthorFollower.follower == follower_id)
# Pass the query to the get_authors_from_query function and return the results
return get_authors_from_query(q)
@mutation.field("rate_author")
@login_required
async 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 = (
session.query(AuthorRating)
.filter(and_(AuthorRating.rater == rater.id, AuthorRating.author == rated_author.id))
.first()
)
if value > 0:
rating.plus = True
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 {}
async 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)
session.add(new_author)
session.commit()
print(f"[resolvers.author] created by webhook {new_author.dict()}")