no-my-rate
All checks were successful
Deploy on push / deploy (push) Successful in 6s

This commit is contained in:
Untone 2024-11-18 11:31:19 +03:00
parent 821a4c0df1
commit 47a8493824
6 changed files with 104 additions and 59 deletions

View File

@ -25,7 +25,7 @@ from resolvers.notifier import (
notifications_seen_after,
notifications_seen_thread,
)
from resolvers.rating import rate_author
from resolvers.rating import get_my_rates_comments, get_my_rates_shouts, rate_author
from resolvers.reaction import (
create_reaction,
delete_reaction,
@ -63,7 +63,6 @@ __all__ = [
"get_author_follows_authors",
"get_authors_all",
"load_authors_by",
"rate_author",
"update_author",
## "search_authors",
# community
@ -110,4 +109,8 @@ __all__ = [
"notifications_seen_thread",
"notifications_seen_after",
"notification_mark_seen",
# rating
"rate_author",
"get_my_rates_comments",
"get_my_rates_shouts",
]

View File

@ -6,7 +6,71 @@ 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
from services.schema import mutation, query
@query.field("get_my_rates_comments")
@login_required
def get_my_rates_comments(info, comments: list[int], shout: int) -> list[dict]:
"""
Получение реакций пользователя на комментарии
"""
author_dict = info.context.get("author") if info.context else None
author_id = author_dict.get("id") if author_dict else None
if not author_id:
return {"error": "Author not found"}
# Подзапрос для реакций текущего пользователя
rated_query = (
select(Reaction.shout.label("shout_id"), Reaction.kind.label("my_rate"))
.where(
and_(
Reaction.shout == shout,
Reaction.reply_to.in_(comments),
Reaction.created_by == author_id,
Reaction.deleted_at.is_(None),
Reaction.kind.in_([ReactionKind.LIKE.value, ReactionKind.DISLIKE.value]),
)
)
.order_by(Reaction.shout, Reaction.created_at.desc())
.distinct(Reaction.shout)
.subquery()
)
with local_session() as session:
comments_result = session.execute(rated_query).all()
return [{"comment_id": row.shout_id, "my_rate": row.my_rate} for row in comments_result]
@query.field("get_my_rates_shouts")
@login_required
def get_my_rates_shouts(info, shouts):
"""
Получение реакций пользователя на публикации
"""
author_dict = info.context.get("author") if info.context else None
author_id = author_dict.get("id") if author_dict else None
if not author_id:
return {"error": "Author not found"}
# Подзапрос для реакций текущего пользователя
rated_query = (
select(Reaction.shout.label("shout_id"), Reaction.kind.label("my_rate"))
.where(
and_(
Reaction.shout.in_(shouts),
Reaction.reply_to.is_(None),
Reaction.created_by == author_id,
Reaction.deleted_at.is_(None),
Reaction.kind.in_([ReactionKind.LIKE.value, ReactionKind.DISLIKE.value]),
)
)
.order_by(Reaction.shout, Reaction.created_at.desc())
.distinct(Reaction.shout)
.subquery()
)
with local_session() as session:
shouts_result = session.execute(rated_query).all()
return [{"shout_id": row.shout_id, "my_rate": row.my_rate} for row in shouts_result]
@mutation.field("rate_author")

View File

@ -163,9 +163,7 @@ def query_with_stat(info):
)
.filter(Reaction.reply_to.is_(None))
.label("rating"),
func.max(Reaction.created_at)
.filter(Reaction.reply_to.is_(None))
.label("last_reacted_at"),
func.max(Reaction.created_at).filter(Reaction.reply_to.is_(None)).label("last_reacted_at"),
)
.where(Reaction.deleted_at.is_(None))
.group_by(Reaction.shout)
@ -182,30 +180,8 @@ def query_with_stat(info):
if author_id:
logger.info(f"Построение подзапроса реакций пользователя с ID: {author_id}")
# Подзапрос для реакций текущего пользователя
user_reaction_subquery = (
select(
Reaction.shout.label("shout_id"),
Reaction.kind.label("my_rate")
)
.where(
and_(
Reaction.created_by == author_id,
Reaction.deleted_at.is_(None),
Reaction.kind.in_([ReactionKind.LIKE.value, ReactionKind.DISLIKE.value]),
Reaction.reply_to.is_(None),
)
)
.order_by(Reaction.shout, Reaction.created_at.desc())
.distinct(Reaction.shout)
.subquery()
)
logger.info("Подзапрос реакций пользователя построен")
logger.info("Соединение основного запроса с подзапросом статистики")
q = q.outerjoin(stats_subquery, stats_subquery.c.shout == Shout.id)
logger.info("Соединение основного запроса с подзапросом реакций пользователя")
q = q.outerjoin(user_reaction_subquery, user_reaction_subquery.c.shout_id == Shout.id)
logger.info("Добавление колонок статистики в основной запрос")
q = q.add_columns(
@ -216,8 +192,6 @@ def query_with_stat(info):
func.coalesce(stats_subquery.c.rating, 0),
"last_reacted_at",
stats_subquery.c.last_reacted_at,
"my_rate",
user_reaction_subquery.c.my_rate
).label("stat")
)
logger.info("Колонки статистики добавлены")
@ -233,7 +207,7 @@ def query_with_stat(info):
"last_reacted_at",
stats_subquery.c.last_reacted_at,
"my_rate",
None
None,
).label("stat")
)
logger.info("Колонки статистики без my_rate добавлены")
@ -268,7 +242,7 @@ def get_shouts_with_links(info, q, limit=20, offset=0):
if hasattr(row, "Shout"):
shout = row.Shout
else:
if not row == 'stat':
if not row == "stat":
logger.warning(f"Строка {idx} не содержит атрибута 'Shout': {row}")
continue
@ -407,7 +381,6 @@ def apply_sorting(q, options):
@query.field("load_shouts_by")
@login_accepted
async def load_shouts_by(_, info: GraphQLResolveInfo, options):
"""
Загрузка публикаций с фильтрацией, сортировкой и пагинацией.
@ -426,7 +399,6 @@ async def load_shouts_by(_, info: GraphQLResolveInfo, options):
@query.field("load_shouts_search")
@login_accepted
async def load_shouts_search(_, info, text, options):
"""
Поиск публикаций по тексту.
@ -488,26 +460,14 @@ async def load_shouts_unrated(_, info, options):
.scalar_subquery()
)
q = (
select(Shout)
.where(and_(Shout.published_at.is_not(None), Shout.deleted_at.is_(None)))
)
q = select(Shout).where(and_(Shout.published_at.is_not(None), Shout.deleted_at.is_(None)))
q = q.join(Author, Author.id == Shout.created_by)
q = q.add_columns(
json_builder(
"id", Author.id,
"name", Author.name,
"slug", Author.slug,
"pic", Author.pic
).label("main_author")
json_builder("id", Author.id, "name", Author.name, "slug", Author.slug, "pic", Author.pic).label("main_author")
)
q = q.join(ShoutTopic, and_(ShoutTopic.shout == Shout.id, ShoutTopic.main.is_(True)))
q = q.join(Topic, Topic.id == ShoutTopic.topic)
q = q.add_columns(
json_builder(
"id", Topic.id, "title", Topic.title, "slug", Topic.slug
).label("main_topic")
)
q = q.add_columns(json_builder("id", Topic.id, "title", Topic.title, "slug", Topic.slug).label("main_topic"))
q = q.where(Shout.id.not_in(rated_shouts))
q = q.order_by(func.random())

View File

@ -32,6 +32,10 @@ type Query {
load_shouts_search(text: String!, options: LoadShoutsOptions): [SearchResult]
load_shouts_bookmarked(options: LoadShoutsOptions): [Shout]
# rating
get_my_rates_shouts(shouts: [Int!]!): [MyRateShout]
get_my_rates_comments(comments: [Int!]!, shout: Int!): [MyRateComment]
# public feeds
load_shouts_with_topic(slug: String, options: LoadShoutsOptions): [Shout] # topic feed
load_shouts_random_top(options: LoadShoutsOptions): [Shout] # random order, fixed filter, limit offset can be used

View File

@ -112,7 +112,6 @@ type Stat {
viewed: Int
# followed: Int
last_reacted_at: Int
my_rate: ReactionKind
}
type CommunityStat {
@ -234,3 +233,15 @@ type NotificationsResult {
total: Int!
error: String
}
type MyRateShout {
shout_id: Int!
my_rate: ReactionKind
}
type MyRateComment {
shout_id: Int
comment_id: Int!
my_rate: ReactionKind
}

View File

@ -123,7 +123,9 @@ def login_accepted(f):
# Предполагается, что `author` является объектом с атрибутом `id`
info.context["author"] = author.dict()
else:
logger.error(f"login_accepted: Профиль автора не найден для пользователя {user_id}. Используем базовые данные.")# Используем базовую информацию об автор
logger.error(
f"login_accepted: Профиль автора не найден для пользователя {user_id}. Используем базовые данные."
) # Используем базовую информацию об автор
else:
logger.debug("login_accepted: Пользователь не авторизован. Очищаем контекст.")
info.context["user_id"] = None
@ -131,4 +133,5 @@ def login_accepted(f):
info.context["author"] = None
return await f(*args, **kwargs)
return decorated_function