0.2.16-resolvers-revision
All checks were successful
deploy / deploy (push) Successful in 2m22s

This commit is contained in:
Untone 2023-11-28 10:53:48 +03:00
parent 3cf86d9e6e
commit 20f7c22441
15 changed files with 266 additions and 196 deletions

View File

@ -1,5 +1,7 @@
[0.2.16] [0.2.16]
- schema: Reaction.range -> Reaction.quote - schema: Reaction.range -> Reaction.quote
- resolvers: queries and mutations revision and renaming
- resolvers: delete_topic(slug) implemented
[0.2.15] [0.2.15]
- schema: Shout.created_by removed - schema: Shout.created_by removed

View File

@ -29,7 +29,7 @@ class ReactionKind(Enumeration):
class Reaction(Base): class Reaction(Base):
__tablename__ = "reaction" __tablename__ = "reaction"
body = Column(String, default='', comment="Reaction Body") body = Column(String, default="", comment="Reaction Body")
created_at = Column(Integer, nullable=False, default=lambda: int(time.time())) created_at = Column(Integer, nullable=False, default=lambda: int(time.time()))
created_by = Column(ForeignKey("author.id"), nullable=False, index=True) created_by = Column(ForeignKey("author.id"), nullable=False, index=True)
updated_at = Column(Integer, nullable=True, comment="Updated at") updated_at = Column(Integer, nullable=True, comment="Updated at")

View File

@ -60,7 +60,7 @@ class Shout(Base):
updated_at = Column(Integer, nullable=True) updated_at = Column(Integer, nullable=True)
published_at = Column(Integer, nullable=True) published_at = Column(Integer, nullable=True)
deleted_at = Column(Integer, nullable=True) deleted_at = Column(Integer, nullable=True)
deleted_by = Column(ForeignKey("author.id"), nullable=True) deleted_by = Column(ForeignKey("author.id"), nullable=True)
body = Column(String, nullable=False, comment="Body") body = Column(String, nullable=False, comment="Body")
@ -83,4 +83,3 @@ class Shout(Base):
lang = Column(String, nullable=False, default="ru", comment="Language") lang = Column(String, nullable=False, default="ru", comment="Language")
version_of = Column(ForeignKey("shout.id"), nullable=True) version_of = Column(ForeignKey("shout.id"), nullable=True)
oid = Column(String, nullable=True) oid = Column(String, nullable=True)

View File

@ -18,6 +18,9 @@ gql = {git = "https://github.com/graphql-python/gql.git", rev = "master"}
starlette = {git = "https://github.com/encode/starlette.git", rev = "master"} starlette = {git = "https://github.com/encode/starlette.git", rev = "master"}
ariadne = {git = "https://github.com/tonyrewin/ariadne.git", rev = "master"} ariadne = {git = "https://github.com/tonyrewin/ariadne.git", rev = "master"}
[tool.poetry.group.dev.dependencies]
setuptools = "^69.0.2"
[build-system] [build-system]
requires = ["poetry-core"] requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api" build-backend = "poetry.core.masonry.api"

View File

@ -1,62 +1,67 @@
from resolvers.editor import create_shout, delete_shout, update_shout from resolvers.editor import create_shout, delete_shout, update_shout
from resolvers.author import load_authors_by, update_profile, get_authors_all, rate_author from resolvers.author import (
get_author,
get_authors_all,
get_author_followers,
get_author_followed,
load_authors_by,
update_profile,
rate_author,
)
from resolvers.reaction import ( from resolvers.reaction import (
create_reaction, create_reaction,
delete_reaction,
update_reaction, update_reaction,
reactions_unfollow, delete_reaction,
reactions_follow,
load_reactions_by, load_reactions_by,
load_shouts_followed,
) )
from resolvers.topic import ( from resolvers.topic import (
topic_follow, get_topics_by_author,
topic_unfollow, get_topics_by_community,
topics_by_author, get_topics_all,
topics_by_community,
topics_all,
get_topic, get_topic,
) )
from resolvers.follower import follow, unfollow from resolvers.follower import follow, unfollow, get_my_followed
from resolvers.reader import load_shout, load_shouts_by, search, load_my_subscriptions from resolvers.reader import get_shout, load_shouts_by, load_shouts_feed, load_shouts_search
from resolvers.community import get_community, get_communities_all from resolvers.community import get_community, get_communities_all
__all__ = [ __all__ = [
# author # author
"load_authors_by", "get_author",
"update_profile",
"get_authors_all", "get_authors_all",
"get_author_followers",
"get_author_followed",
"load_authors_by",
"rate_author", "rate_author",
"update_profile",
# community
"get_community",
"get_communities_all",
# topic
"get_topic",
"get_topics_all",
"get_topics_by_community",
"get_topics_by_author",
# reader # reader
"load_shout", "get_shout",
"load_shouts_by", "load_shouts_by",
"rate_author", "load_shouts_feed",
"load_my_subscriptions", "load_shouts_search",
"search", "load_shouts_followed",
# follower # follower
"follow", "follow",
"unfollow", "unfollow",
"get_my_followed",
# editor # editor
"create_shout", "create_shout",
"update_shout", "update_shout",
"delete_shout", "delete_shout",
# topic
"topics_all",
"topics_by_community",
"topics_by_author",
"topic_follow",
"topic_unfollow",
"get_topic",
# reaction # reaction
"reactions_follow",
"reactions_unfollow",
"create_reaction", "create_reaction",
"update_reaction", "update_reaction",
"delete_reaction", "delete_reaction",
"load_reactions_by", "load_reactions_by",
# community
"get_community",
"get_communities_all",
] ]

View File

@ -7,6 +7,7 @@ from services.auth import login_required
from services.db import local_session from services.db import local_session
from services.unread import get_total_unread_counter from services.unread import get_total_unread_counter
from services.schema import mutation, query from services.schema import mutation, query
from orm.community import Community
from orm.shout import ShoutAuthor, ShoutTopic from orm.shout import ShoutAuthor, ShoutTopic
from orm.topic import Topic from orm.topic import Topic
from orm.author import AuthorFollower, Author, AuthorRating from orm.author import AuthorFollower, Author, AuthorRating
@ -79,15 +80,15 @@ def get_authors_from_query(q):
async def author_followings(author_id: int): async def author_followings(author_id: int):
return { return {
"unread": await get_total_unread_counter(author_id), # unread inbox messages counter "unread": await get_total_unread_counter(author_id),
"topics": [t.slug for t in await followed_topics(author_id)], # followed topics slugs "topics": [t.slug for t in await followed_topics(author_id)],
"authors": [a.slug for a in await followed_authors(author_id)], # followed authors slugs "authors": [a.slug for a in await followed_authors(author_id)],
"reactions": [s.slug for s in await followed_reactions(author_id)], # fresh reacted shouts slugs "reactions": [s.slug for s in followed_reactions(author_id)],
"communities": [c.slug for c in await followed_communities(author_id)], # communities "communities": [c.slug for c in [followed_communities(author_id)] if isinstance(c, Community)],
} }
@mutation.field("updateProfile") @mutation.field("update_profile")
@login_required @login_required
async def update_profile(_, info, profile): async def update_profile(_, info, profile):
user_id = info.context["user_id"] user_id = info.context["user_id"]
@ -128,7 +129,7 @@ def author_unfollow(follower_id, slug):
return False return False
@query.field("authorsAll") @query.field("get_authors_all")
async def get_authors_all(_, _info): async def get_authors_all(_, _info):
q = select(Author) q = select(Author)
q = add_author_stat_columns(q) q = add_author_stat_columns(q)
@ -137,7 +138,7 @@ async def get_authors_all(_, _info):
return get_authors_from_query(q) return get_authors_from_query(q)
@query.field("getAuthor") @query.field("get_author")
async def get_author(_, _info, slug="", user=None, author_id=None): async def get_author(_, _info, slug="", user=None, author_id=None):
if slug or user or author_id: if slug or user or author_id:
if slug: if slug:
@ -152,7 +153,7 @@ async def get_author(_, _info, slug="", user=None, author_id=None):
return authors[0] return authors[0]
@query.field("loadAuthorsBy") @query.field("load_authors_by")
async def load_authors_by(_, _info, by, limit, offset): async def load_authors_by(_, _info, by, limit, offset):
q = select(Author) q = select(Author)
q = add_author_stat_columns(q) q = add_author_stat_columns(q)
@ -175,7 +176,8 @@ async def load_authors_by(_, _info, by, limit, offset):
return get_authors_from_query(q) return get_authors_from_query(q)
async def get_followed_authors(_, _info, slug) -> List[Author]: @query.field("get_author_followed")
async def get_author_followed(_, _info, slug="", user=None, author_id=None) -> List[Author]:
# First, we need to get the author_id for the given slug # First, we need to get the author_id for the given slug
with local_session() as session: with local_session() as session:
author_id_query = select(Author.id).where(Author.slug == slug) author_id_query = select(Author.id).where(Author.slug == slug)
@ -187,7 +189,8 @@ async def get_followed_authors(_, _info, slug) -> List[Author]:
return await followed_authors(author_id) return await followed_authors(author_id)
async def author_followers(_, _info, slug) -> List[Author]: @query.field("get_author_followers")
async def get_author_followers(_, _info, slug) -> List[Author]:
q = select(Author) q = select(Author)
q = add_author_stat_columns(q) q = add_author_stat_columns(q)
@ -209,28 +212,29 @@ async def followed_authors(follower_id):
return get_authors_from_query(q) return get_authors_from_query(q)
@mutation.field("rateAuthor") @mutation.field("rate_author")
@login_required @login_required
async def rate_author(_, info, rated_user_id, value): async def rate_author(_, info, rated_slug, value):
user_id = info.context["user_id"] user_id = info.context["user_id"]
with local_session() as session: with local_session() as session:
rater = session.query(Author).filter(Author.user == user_id).first() rater = session.query(Author).filter(Author.slug == rated_slug).first()
rating = ( if rater:
session.query(AuthorRating) rating = (
.filter(and_(AuthorRating.rater == rater.id, AuthorRating.user == rated_user_id)) session.query(AuthorRating)
.first() .filter(and_(AuthorRating.rater == rater.id, AuthorRating.user == rated_user_id))
) .first()
if rating: )
rating.value = value if rating:
session.add(rating) rating.value = value
session.commit()
return {}
else:
try:
rating = AuthorRating(rater=rater.id, user=rated_user_id, value=value)
session.add(rating) session.add(rating)
session.commit() session.commit()
except Exception as err: return {}
return {"error": err} else:
try:
rating = AuthorRating(rater=rater.id, user=rated_user_id, value=value)
session.add(rating)
session.commit()
except Exception as err:
return {"error": err}
return {} return {}

View File

@ -51,13 +51,16 @@ def get_communities_from_query(q):
return ccc return ccc
SINGLE_COMMUNITY = True
def followed_communities(follower_id): def followed_communities(follower_id):
amount = select(Community).count() if SINGLE_COMMUNITY:
if amount < 2: with local_session() as session:
# no need to run long query most of the cases c = session.query(Community).first()
return [ return [
select(Community).first(), c,
] ]
else: else:
q = select(Community) q = select(Community)
q = add_community_stat_columns(q) q = add_community_stat_columns(q)
@ -97,7 +100,7 @@ def community_unfollow(follower_id, slug):
return False return False
@query.field("communitiesAll") @query.field("get_communities_all")
async def get_communities_all(_, _info): async def get_communities_all(_, _info):
q = select(Author) q = select(Author)
q = add_community_stat_columns(q) q = add_community_stat_columns(q)
@ -105,7 +108,7 @@ async def get_communities_all(_, _info):
return get_communities_from_query(q) return get_communities_from_query(q)
@query.field("getCommunity") @query.field("get_community")
async def get_community(_, _info, slug): async def get_community(_, _info, slug):
q = select(Community).where(Community.slug == slug) q = select(Community).where(Community.slug == slug)
q = add_community_stat_columns(q) q = add_community_stat_columns(q)

View File

@ -12,9 +12,9 @@ from resolvers.reaction import reactions_follow, reactions_unfollow
from services.notify import notify_shout from services.notify import notify_shout
@query.field("loadDrafts") @query.field("get_shouts_drafts")
@login_required @login_required
async def get_drafts(_, info): async def get_shouts_drafts(_, info):
user_id = info.context["user_id"] user_id = info.context["user_id"]
with local_session() as session: with local_session() as session:
author = session.query(Author).filter(Author.user == user_id).first() author = session.query(Author).filter(Author.user == user_id).first()
@ -34,7 +34,7 @@ async def get_drafts(_, info):
return shouts return shouts
@mutation.field("createShout") @mutation.field("create_shout")
@login_required @login_required
async def create_shout(_, info, inp): async def create_shout(_, info, inp):
user_id = info.context["user_id"] user_id = info.context["user_id"]
@ -79,7 +79,7 @@ async def create_shout(_, info, inp):
return {"shout": new_shout} return {"shout": new_shout}
@mutation.field("updateShout") @mutation.field("update_shout")
@login_required @login_required
async def update_shout(_, info, shout_id, shout_input=None, publish=False): async def update_shout(_, info, shout_id, shout_input=None, publish=False):
user_id = info.context["user_id"] user_id = info.context["user_id"]
@ -161,7 +161,7 @@ async def update_shout(_, info, shout_id, shout_input=None, publish=False):
return {"shout": shout} return {"shout": shout}
@mutation.field("deleteShout") @mutation.field("delete_shout")
@login_required @login_required
async def delete_shout(_, info, shout_id): async def delete_shout(_, info, shout_id):
user_id = info.context["user_id"] user_id = info.context["user_id"]

View File

@ -1,3 +1,7 @@
from sqlalchemy import select
from orm.community import Community, CommunityAuthor as CommunityFollower
from orm.topic import Topic, TopicFollower
from services.auth import login_required from services.auth import login_required
from resolvers.author import author_follow, author_unfollow from resolvers.author import author_follow, author_unfollow
from resolvers.reaction import reactions_follow, reactions_unfollow from resolvers.reaction import reactions_follow, reactions_unfollow
@ -5,9 +9,9 @@ from resolvers.topic import topic_follow, topic_unfollow
from resolvers.community import community_follow, community_unfollow from resolvers.community import community_follow, community_unfollow
from services.following import FollowingManager, FollowingResult from services.following import FollowingManager, FollowingResult
from services.db import local_session from services.db import local_session
from orm.author import Author from orm.author import Author, AuthorFollower
from services.notify import notify_follower from services.notify import notify_follower
from services.schema import mutation from services.schema import mutation, query
@login_required @login_required
@ -77,3 +81,36 @@ async def unfollow(_, info, what, slug):
return {"error": str(e)} return {"error": str(e)}
return {} return {}
@query.field("get_my_followed")
@login_required
async def get_my_followed(_, info):
user_id = info.context["user_id"]
with local_session() as session:
author = session.query(Author).filter(Author.user == user_id).first()
if author:
authors_query = (
select(Author)
.join(AuthorFollower, AuthorFollower.author == Author.id)
.where(AuthorFollower.follower == author.id)
)
topics_query = select(Topic).join(TopicFollower).where(TopicFollower.follower == author.id)
communities_query = (
select(Community)
.join(CommunityFollower, CommunityFollower.author == Author.id)
.where(CommunityFollower.follower == author.id)
)
topics = []
authors = []
communities = []
for [author] in session.execute(authors_query):
authors.append(author)
for [topic] in session.execute(topics_query):
topics.append(topic)
for [c] in session.execute(communities_query):
communities.append(c)
return {"topics": topics, "authors": authors, "communities": communities}

View File

@ -17,7 +17,7 @@ def add_reaction_stat_columns(q):
q = q.outerjoin(aliased_reaction, Reaction.id == aliased_reaction.reply_to).add_columns( q = q.outerjoin(aliased_reaction, Reaction.id == aliased_reaction.reply_to).add_columns(
func.sum(aliased_reaction.id).label("reacted_stat"), func.sum(aliased_reaction.id).label("reacted_stat"),
func.sum(case((aliased_reaction.body.is_not(''), 1), else_=0)).label("commented_stat"), func.sum(case((aliased_reaction.body.is_not(""), 1), else_=0)).label("commented_stat"),
func.sum( func.sum(
case( case(
(aliased_reaction.kind == ReactionKind.AGREE, 1), (aliased_reaction.kind == ReactionKind.AGREE, 1),
@ -91,7 +91,7 @@ def is_published_author(session, author_id):
return ( return (
session.query(Shout) session.query(Shout)
.where(Shout.authors.contains(author_id)) .where(Shout.authors.contains(author_id))
.filter(and_(Shout.published_at.is_not(''), Shout.deleted_at.is_(None))) .filter(and_(Shout.published_at.is_not(""), Shout.deleted_at.is_(None)))
.count() .count()
> 0 > 0
) )
@ -156,7 +156,7 @@ def set_hidden(session, shout_id):
session.commit() session.commit()
@mutation.field("createReaction") @mutation.field("create_reaction")
@login_required @login_required
async def create_reaction(_, info, reaction): async def create_reaction(_, info, reaction):
user_id = info.context["user_id"] user_id = info.context["user_id"]
@ -241,7 +241,7 @@ async def create_reaction(_, info, reaction):
return {"reaction": rdict} return {"reaction": rdict}
@mutation.field("updateReaction") @mutation.field("update_reaction")
@login_required @login_required
async def update_reaction(_, info, rid, reaction): async def update_reaction(_, info, rid, reaction):
user_id = info.context["user_id"] user_id = info.context["user_id"]
@ -284,7 +284,7 @@ async def update_reaction(_, info, rid, reaction):
return {"error": "user"} return {"error": "user"}
@mutation.field("deleteReaction") @mutation.field("delete_reaction")
@login_required @login_required
async def delete_reaction(_, info, rid): async def delete_reaction(_, info, rid):
user_id = info.context["user_id"] user_id = info.context["user_id"]
@ -293,21 +293,24 @@ async def delete_reaction(_, info, rid):
if not r: if not r:
return {"error": "invalid reaction id"} return {"error": "invalid reaction id"}
author = session.query(Author).filter(Author.user == user_id).first() author = session.query(Author).filter(Author.user == user_id).first()
if not author or r.created_by != author.id: if author:
if r.created_by != author.id:
return {"error": "access denied"}
if r.kind in [ReactionKind.LIKE, ReactionKind.DISLIKE]:
session.delete(r)
else:
r.deleted_at = int(time.time())
session.commit()
await notify_reaction(r.dict(), "delete")
return {"reaction": r}
else:
return {"error": "access denied"} return {"error": "access denied"}
if r.kind in [ReactionKind.LIKE, ReactionKind.DISLIKE]:
session.delete(r)
else:
r.deleted_at = int(time.time())
session.commit()
await notify_reaction(r.dict(), "delete") @query.field("load_reactions_by")
return {"reaction": r}
@query.field("loadReactionsBy")
async def load_reactions_by(_, info, by, limit=50, offset=0): async def load_reactions_by(_, info, by, limit=50, offset=0):
""" """
:param info: graphql meta :param info: graphql meta
@ -387,29 +390,31 @@ async def load_reactions_by(_, info, by, limit=50, offset=0):
return reactions return reactions
def reacted_shouts_updates(follower_id): def reacted_shouts_updates(follower_id: int, limit=50, offset=0) -> List[Shout]:
shouts = [] shouts: List[Shout] = []
with local_session() as session: with local_session() as session:
author = session.query(Author).where(Author.id == follower_id).first() author = session.query(Author).where(Author.id == follower_id).first()
if author: if author:
shouts = ( shouts = (
session.query(Reaction.shout) session.query(Shout)
.join(Shout) .join(Reaction)
.filter(Reaction.created_by == author.id) .filter(Reaction.created_by == author.id)
.filter(Reaction.created_at > author.last_seen) .filter(Reaction.created_at > author.last_seen)
.all() .limit(limit)
.offset(offset)
) )
return shouts return shouts
# @query.field("followedReactions")
@login_required @login_required
@query.field("followedReactions") @query.field("load_shouts_followed")
async def get_reacted_shouts(_, info) -> List[Shout]: async def load_shouts_followed(_, info, limit=50, offset=0) -> List[Shout]:
user_id = info.context["user_id"] user_id = info.context["user_id"]
with local_session() as session: with local_session() as session:
author = session.query(Author).filter(Author.user == user_id).first() author = session.query(Author).filter(Author.user == user_id).first()
if author: if author:
shouts = reacted_shouts_updates(author.id) shouts = reacted_shouts_updates(author.id, limit, offset)
return shouts return shouts
else: else:
return [] return []

View File

@ -70,8 +70,8 @@ def apply_filters(q, filters, author_id=None):
return q return q
@query.field("loadShout") @query.field("get_shout")
async def load_shout(_, _info, slug=None, shout_id=None): async def get_shout(_, _info, slug=None, shout_id=None):
with local_session() as session: with local_session() as session:
q = select(Shout).options( q = select(Shout).options(
joinedload(Shout.authors), joinedload(Shout.authors),
@ -95,7 +95,9 @@ async def load_shout(_, _info, slug=None, shout_id=None):
commented_stat, commented_stat,
rating_stat, rating_stat,
_last_comment, _last_comment,
] = session.execute(q).first() or [] ] = (
session.execute(q).first() or []
)
if shout: if shout:
shout.stat = { shout.stat = {
"viewed": viewed_stat, "viewed": viewed_stat,
@ -113,7 +115,7 @@ async def load_shout(_, _info, slug=None, shout_id=None):
return None return None
@query.field("loadShouts") @query.field("load_shouts_by")
async def load_shouts_by(_, info, options): async def load_shouts_by(_, info, options):
""" """
:param _: :param _:
@ -186,8 +188,8 @@ async def load_shouts_by(_, info, options):
@login_required @login_required
@query.field("loadFeed") @query.field("load_shouts_feed")
async def get_my_feed(_, info, options): async def load_shouts_feed(_, info, options):
user_id = info.context["user_id"] user_id = info.context["user_id"]
with local_session() as session: with local_session() as session:
author = session.query(Author).filter(Author.user == user_id).first() author = session.query(Author).filter(Author.user == user_id).first()
@ -199,7 +201,9 @@ async def get_my_feed(_, info, options):
select(Shout.id) select(Shout.id)
.where(Shout.id == ShoutAuthor.shout) .where(Shout.id == ShoutAuthor.shout)
.where(Shout.id == ShoutTopic.shout) .where(Shout.id == ShoutTopic.shout)
.where((ShoutAuthor.author.in_(author_followed_authors)) | (ShoutTopic.topic.in_(author_followed_topics))) .where(
(ShoutAuthor.author.in_(author_followed_authors)) | (ShoutTopic.topic.in_(author_followed_topics))
)
) )
q = ( q = (
@ -247,36 +251,9 @@ async def get_my_feed(_, info, options):
return [] return []
@query.field("search") @query.field("load_shouts_search")
async def search(_, info, text, limit=50, offset=0): async def load_shouts_search(_, info, text, limit=50, offset=0):
if text and len(text) > 2: if text and len(text) > 2:
return SearchService.search(text, limit, offset) return SearchService.search(text, limit, offset)
else: else:
return [] return []
@query.field("loadMySubscriptions")
@login_required
async def load_my_subscriptions(_, info):
user_id = info.context["user_id"]
with local_session() as session:
author = session.query(Author).filter(Author.user == user_id).first()
if author:
authors_query = (
select(Author)
.join(AuthorFollower, AuthorFollower.author == Author.id)
.where(AuthorFollower.follower == author.id)
)
topics_query = select(Topic).join(TopicFollower).where(TopicFollower.follower == author.id)
topics = []
authors = []
for [author] in session.execute(authors_query):
authors.append(author)
for [topic] in session.execute(topics_query):
topics.append(topic)
return {"topics": topics, "authors": authors}

View File

@ -64,32 +64,37 @@ def topics_followed_by(author_id):
return get_topics_from_query(q) return get_topics_from_query(q)
@query.field("topicsAll") @query.field("get_topics_all")
async def topics_all(_, _info): async def get_topics_all(_, _info):
q = select(Topic) q = select(Topic)
q = add_topic_stat_columns(q) q = add_topic_stat_columns(q)
return get_topics_from_query(q) return get_topics_from_query(q)
@query.field("topicsByCommunity") @query.field("get_topics_by_community")
async def topics_by_community(_, info, community): async def get_topics_by_community(_, _info, community_id: int):
q = select(Topic).where(Topic.community == community) q = select(Topic).where(Topic.community == community_id)
q = add_topic_stat_columns(q) q = add_topic_stat_columns(q)
return get_topics_from_query(q) return get_topics_from_query(q)
@query.field("topicsByAuthor") @query.field("get_topics_by_author")
async def topics_by_author(_, _info, author_id): async def get_topics_by_author(_, _info, author_id=None, slug="", user=""):
q = select(Topic) q = select(Topic)
q = add_topic_stat_columns(q) q = add_topic_stat_columns(q)
q = q.join(Author).where(Author.id == author_id) if author_id:
q = q.join(Author).where(Author.id == author_id)
elif slug:
q = q.join(Author).where(Author.slug == slug)
elif user:
q = q.join(Author).where(Author.user == user)
return get_topics_from_query(q) return get_topics_from_query(q)
@query.field("getTopic") @query.field("get_topic")
async def get_topic(_, _info, slug): async def get_topic(_, _info, slug):
q = select(Topic).where(Topic.slug == slug) q = select(Topic).where(Topic.slug == slug)
q = add_topic_stat_columns(q) q = add_topic_stat_columns(q)
@ -98,7 +103,7 @@ async def get_topic(_, _info, slug):
return topics[0] return topics[0]
@mutation.field("createTopic") @mutation.field("create_topic")
@login_required @login_required
async def create_topic(_, _info, inp): async def create_topic(_, _info, inp):
with local_session() as session: with local_session() as session:
@ -110,6 +115,7 @@ async def create_topic(_, _info, inp):
return {"topic": new_topic} return {"topic": new_topic}
@mutation.field("update_topic")
@login_required @login_required
async def update_topic(_, _info, inp): async def update_topic(_, _info, inp):
slug = inp["slug"] slug = inp["slug"]
@ -125,6 +131,27 @@ async def update_topic(_, _info, inp):
return {"topic": topic} return {"topic": topic}
@mutation.field("delete_topic")
@login_required
async def delete_topic(_, info, slug: str):
user_id = info.context["user_id"]
with local_session() as session:
t: Topic = session.query(Topic).filter(Topic.slug == slug).first()
if not t:
return {"error": "invalid topic slug"}
author = session.query(Author).filter(Author.user == user_id).first()
if author:
if t.created_by != author.id:
return {"error": "access denied"}
session.delete(t)
session.commit()
return {}
else:
return {"error": "access denied"}
def topic_follow(follower_id, slug): def topic_follow(follower_id, slug):
try: try:
with local_session() as session: with local_session() as session:
@ -153,8 +180,8 @@ def topic_unfollow(follower_id, slug):
return False return False
@query.field("topicsRandom") @query.field("get_topics_random")
async def topics_random(_, info, amount=12): async def get_topics_random(_, info, amount=12):
q = select(Topic) q = select(Topic)
q = q.join(ShoutTopic) q = q.join(ShoutTopic)
q = q.group_by(Topic.id) q = q.group_by(Topic.id)

View File

@ -291,50 +291,68 @@ type Result {
# Мутации # Мутации
type Mutation { type Mutation {
createShout(inp: ShoutInput!): Result! # author
updateShout(shout_id: Int!, shout_input: ShoutInput, publish: Boolean): Result! rate_author(rated_slug: String!, value: Int!): Result!
deleteShout(shout_id: Int!): Result! update_profile(profile: ProfileInput!): Result!
rateAuthor(slug: String!, value: Int!): Result!
updateOnlineStatus: Result! # editor
updateProfile(profile: ProfileInput!): Result! create_shout(inp: ShoutInput!): Result!
createTopic(input: TopicInput!): Result! update_shout(shout_id: Int!, shout_input: ShoutInput, publish: Boolean): Result!
updateTopic(input: TopicInput!): Result! delete_shout(shout_id: Int!): Result!
destroyTopic(slug: String!): Result!
createReaction(reaction: ReactionInput!): Result! # follower
updateReaction(id: Int!, reaction: ReactionInput!): Result!
deleteReaction(id: Int!): Result!
follow(what: FollowingEntity!, slug: String!): Result! follow(what: FollowingEntity!, slug: String!): Result!
unfollow(what: FollowingEntity!, slug: String!): Result! unfollow(what: FollowingEntity!, slug: String!): Result!
# FIXME!
updateOnlineStatus: Result!
# topic
create_topic(input: TopicInput!): Result!
update_topic(input: TopicInput!): Result!
delete_topic(slug: String!): Result!
# reaction
create_reaction(reaction: ReactionInput!): Result!
update_reaction(id: Int!, reaction: ReactionInput!): Result!
delete_reaction(id: Int!): Result!
} }
# Запросы # Запросы
type Query { type Query {
loadShout(slug: String, shout_id: Int): Shout # author
loadShouts(options: LoadShoutsOptions): [Shout] get_author(slug: String, user: String, author_id: Int): Author
loadFeed(options: LoadShoutsOptions): [Shout] get_authors_all: [Author]
loadMySubscriptions: Result get_author_followers(slug: String, user: String, author_id: Int): [Author]
loadDrafts: [Shout] get_author_followed(slug: String, user: String, author_id: Int): [Author]
load_authors_by(by: AuthorsBy, limit: Int, offset: Int): [Author]
search(text: String!, limit: Int, offset: Int): [Shout] # community
get_community: Community
get_communities_all: [Community]
loadReactionsBy(by: ReactionBy!, limit: Int, offset: Int): [Reaction] # editor
followedReactions(follower_id: Int!): [Shout] get_shouts_drafts: [Shout]
authorsAll: [Author] # follower
authorFollowers(slug: String!): [Author] get_my_followed: Result # { authors topics communities }
authorFollowedAuthors(slug: String!): [Author]
authorFollowedTopics(slug: String!): [Topic]
loadAuthorsBy(by: AuthorsBy, limit: Int, offset: Int): [Author]
getAuthor(slug: String, user: String, author: Int): Author
topicsAll: [Topic] # reaction
getTopic(slug: String!): Topic load_reactions_by(by: ReactionBy!, limit: Int, offset: Int): [Reaction]
topicsRandom(amount: Int): [Topic]
topicsByCommunity(community: String!): [Topic]
topicsByAuthor(author_id: Int!): [Topic]
communitiesAll: [Community] # reader
getCommunity: Community get_shout(slug: String, shout_id: Int): Shout
load_shouts_followed(follower_id: Int!, limit: Int, offset: Int): [Shout]
load_shouts_by(options: LoadShoutsOptions): [Shout]
load_shouts_search(text: String!, limit: Int, offset: Int): [Shout]
load_shouts_feed(options: LoadShoutsOptions): [Shout]
# topic
get_topic(slug: String!): Topic
get_topics_all: [Topic]
get_topics_random(amount: Int): [Topic]
get_topics_by_author(slug: String, user: String, author_id: Int): [Topic]
get_topics_by_community(slug: String, community_id: Int): [Topic]
} }

View File

@ -57,11 +57,6 @@ if __name__ == "__main__":
sys.excepthook = exception_handler sys.excepthook = exception_handler
if "dev" in sys.argv: if "dev" in sys.argv:
import os import os
os.environ.set("MODE", "development") os.environ.set("MODE", "development")
uvicorn.run( uvicorn.run("main:app", host="0.0.0.0", port=PORT, proxy_headers=True, server_header=True)
"main:app",
host="0.0.0.0",
port=PORT,
proxy_headers=True,
server_header=True
)

View File

@ -18,12 +18,7 @@ class Following:
class FollowingManager: class FollowingManager:
lock = asyncio.Lock() lock = asyncio.Lock()
data = { data = {"author": [], "topic": [], "shout": [], "community": []}
'author': [],
'topic': [],
'shout': [],
'community': []
}
@staticmethod @staticmethod
async def register(kind, uid): async def register(kind, uid):
@ -40,7 +35,7 @@ class FollowingManager:
try: try:
async with FollowingManager.lock: async with FollowingManager.lock:
for entity in FollowingManager[kind]: for entity in FollowingManager[kind]:
if payload.shout['created_by'] == entity.uid: if payload.shout["created_by"] == entity.uid:
entity.queue.put_nowait(payload) entity.queue.put_nowait(payload)
except Exception as e: except Exception as e:
print(Exception(e)) print(Exception(e))