comment-delete-handling-patch
All checks were successful
Deploy on push / deploy (push) Successful in 1m15s
All checks were successful
Deploy on push / deploy (push) Successful in 1m15s
This commit is contained in:
parent
354bda0efa
commit
ae48a18536
|
@ -1,3 +1,6 @@
|
||||||
|
#### [0.4.12] - 2025-02-12
|
||||||
|
- `delete_reaction` detects comments and uses `deleted_at` update
|
||||||
|
|
||||||
#### [0.4.11] - 2025-02-12
|
#### [0.4.11] - 2025-02-12
|
||||||
- `create_draft` resolver requires draft_id fixed
|
- `create_draft` resolver requires draft_id fixed
|
||||||
- `create_draft` resolver defaults body and title fields to empty string
|
- `create_draft` resolver defaults body and title fields to empty string
|
||||||
|
|
6
requirements.dev.txt
Normal file
6
requirements.dev.txt
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
fakeredis
|
||||||
|
pytest
|
||||||
|
pytest-asyncio
|
||||||
|
pytest-cov
|
||||||
|
mypy
|
||||||
|
ruff
|
|
@ -4,11 +4,8 @@ authlib
|
||||||
passlib
|
passlib
|
||||||
|
|
||||||
google-analytics-data
|
google-analytics-data
|
||||||
dogpile-cache
|
|
||||||
opensearch-py
|
|
||||||
colorlog
|
colorlog
|
||||||
psycopg2-binary
|
psycopg2-binary
|
||||||
dogpile-cache
|
|
||||||
httpx
|
httpx
|
||||||
redis[hiredis]
|
redis[hiredis]
|
||||||
sentry-sdk[starlette,sqlalchemy]
|
sentry-sdk[starlette,sqlalchemy]
|
||||||
|
@ -18,9 +15,3 @@ ariadne
|
||||||
granian
|
granian
|
||||||
|
|
||||||
pydantic
|
pydantic
|
||||||
fakeredis
|
|
||||||
pytest
|
|
||||||
pytest-asyncio
|
|
||||||
pytest-cov
|
|
||||||
mypy
|
|
||||||
ruff
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from operator import or_
|
|
||||||
import time
|
import time
|
||||||
|
from operator import or_
|
||||||
|
|
||||||
from sqlalchemy.sql import and_
|
from sqlalchemy.sql import and_
|
||||||
|
|
||||||
|
@ -56,9 +56,11 @@ async def load_drafts(_, info):
|
||||||
return {"error": "User ID and author ID are required"}
|
return {"error": "User ID and author ID are required"}
|
||||||
|
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
drafts = session.query(Draft).filter(or_(
|
drafts = (
|
||||||
Draft.authors.any(Author.id == author_id),
|
session.query(Draft)
|
||||||
Draft.created_by == author_id)).all()
|
.filter(or_(Draft.authors.any(Author.id == author_id), Draft.created_by == author_id))
|
||||||
|
.all()
|
||||||
|
)
|
||||||
return {"drafts": drafts}
|
return {"drafts": drafts}
|
||||||
|
|
||||||
|
|
||||||
|
@ -123,23 +125,29 @@ async def create_draft(_, info, draft_input):
|
||||||
|
|
||||||
@mutation.field("update_draft")
|
@mutation.field("update_draft")
|
||||||
@login_required
|
@login_required
|
||||||
async def update_draft(_, info, draft_input):
|
async def update_draft(_, info, draft_id: int, draft_input):
|
||||||
|
"""Обновляет черновик публикации.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
draft_id: ID черновика для обновления
|
||||||
|
draft_input: Данные для обновления черновика
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
dict: Обновленный черновик или сообщение об ошибке
|
||||||
|
"""
|
||||||
user_id = info.context.get("user_id")
|
user_id = info.context.get("user_id")
|
||||||
author_dict = info.context.get("author", {})
|
author_dict = info.context.get("author", {})
|
||||||
author_id = author_dict.get("id")
|
author_id = author_dict.get("id")
|
||||||
draft_id = draft_input.get("id")
|
|
||||||
if not draft_id:
|
|
||||||
return {"error": "Draft ID is required"}
|
|
||||||
if not user_id or not author_id:
|
if not user_id or not author_id:
|
||||||
return {"error": "Author ID are required"}
|
return {"error": "Author ID are required"}
|
||||||
|
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
draft = session.query(Draft).filter(Draft.id == draft_id).first()
|
draft = session.query(Draft).filter(Draft.id == draft_id).first()
|
||||||
del draft_input["id"]
|
|
||||||
Draft.update(draft, {**draft_input})
|
|
||||||
if not draft:
|
if not draft:
|
||||||
return {"error": "Draft not found"}
|
return {"error": "Draft not found"}
|
||||||
|
|
||||||
|
Draft.update(draft, draft_input)
|
||||||
draft.updated_at = int(time.time())
|
draft.updated_at = int(time.time())
|
||||||
session.commit()
|
session.commit()
|
||||||
return {"draft": draft}
|
return {"draft": draft}
|
||||||
|
|
|
@ -133,21 +133,18 @@ def check_to_feature(session, approver_id, reaction) -> bool:
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def check_to_unfeature(session, rejecter_id, reaction) -> bool:
|
def check_to_unfeature(session, reaction) -> bool:
|
||||||
"""
|
"""
|
||||||
Unfeature a shout if 20% of reactions are negative.
|
Unfeature a shout if 20% of reactions are negative.
|
||||||
|
|
||||||
:param session: Database session.
|
:param session: Database session.
|
||||||
:param rejecter_id: Rejecter author ID.
|
|
||||||
:param reaction: Reaction object.
|
:param reaction: Reaction object.
|
||||||
:return: True if shout should be unfeatured, else False.
|
:return: True if shout should be unfeatured, else False.
|
||||||
"""
|
"""
|
||||||
if not reaction.reply_to and is_negative(reaction.kind):
|
if not reaction.reply_to and is_negative(reaction.kind):
|
||||||
total_reactions = (
|
total_reactions = (
|
||||||
session.query(Reaction)
|
session.query(Reaction)
|
||||||
.filter(
|
.filter(Reaction.shout == reaction.shout, Reaction.reply_to.is_(None), Reaction.kind.in_(RATING_REACTIONS))
|
||||||
Reaction.shout == reaction.shout, Reaction.kind.in_(RATING_REACTIONS), Reaction.deleted_at.is_(None)
|
|
||||||
)
|
|
||||||
.count()
|
.count()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -217,7 +214,7 @@ async def _create_reaction(session, shout_id: int, is_author: bool, author_id: i
|
||||||
|
|
||||||
# Handle rating
|
# Handle rating
|
||||||
if r.kind in RATING_REACTIONS:
|
if r.kind in RATING_REACTIONS:
|
||||||
if check_to_unfeature(session, author_id, r):
|
if check_to_unfeature(session, r):
|
||||||
set_unfeatured(session, shout_id)
|
set_unfeatured(session, shout_id)
|
||||||
elif check_to_feature(session, author_id, r):
|
elif check_to_feature(session, author_id, r):
|
||||||
await set_featured(session, shout_id)
|
await set_featured(session, shout_id)
|
||||||
|
@ -354,7 +351,7 @@ async def update_reaction(_, info, reaction):
|
||||||
|
|
||||||
result = session.execute(reaction_query).unique().first()
|
result = session.execute(reaction_query).unique().first()
|
||||||
if result:
|
if result:
|
||||||
r, author, shout, commented_stat, rating_stat = result
|
r, author, _shout, commented_stat, rating_stat = result
|
||||||
if not r or not author:
|
if not r or not author:
|
||||||
return {"error": "Invalid reaction ID or unauthorized"}
|
return {"error": "Invalid reaction ID or unauthorized"}
|
||||||
|
|
||||||
|
@ -406,15 +403,24 @@ async def delete_reaction(_, info, reaction_id: int):
|
||||||
if r.created_by != author_id and "editor" not in roles:
|
if r.created_by != author_id and "editor" not in roles:
|
||||||
return {"error": "Access denied"}
|
return {"error": "Access denied"}
|
||||||
|
|
||||||
logger.debug(f"{user_id} user removing his #{reaction_id} reaction")
|
|
||||||
reaction_dict = r.dict()
|
|
||||||
session.delete(r)
|
|
||||||
session.commit()
|
|
||||||
|
|
||||||
# Update author stat
|
|
||||||
if r.kind == ReactionKind.COMMENT.value:
|
if r.kind == ReactionKind.COMMENT.value:
|
||||||
|
r.deleted_at = int(time.time())
|
||||||
update_author_stat(author.id)
|
update_author_stat(author.id)
|
||||||
|
session.add(r)
|
||||||
|
session.commit()
|
||||||
|
elif r.kind == ReactionKind.PROPOSE.value:
|
||||||
|
r.deleted_at = int(time.time())
|
||||||
|
session.add(r)
|
||||||
|
session.commit()
|
||||||
|
# TODO: add more reaction types here
|
||||||
|
else:
|
||||||
|
logger.debug(f"{user_id} user removing his #{reaction_id} reaction")
|
||||||
|
session.delete(r)
|
||||||
|
session.commit()
|
||||||
|
if check_to_unfeature(session, r):
|
||||||
|
set_unfeatured(session, r.shout)
|
||||||
|
|
||||||
|
reaction_dict = r.dict()
|
||||||
await notify_reaction(reaction_dict, "delete")
|
await notify_reaction(reaction_dict, "delete")
|
||||||
|
|
||||||
return {"error": None, "reaction": reaction_dict}
|
return {"error": None, "reaction": reaction_dict}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user