parent
c150d28447
commit
a63cf24812
|
@ -1,3 +1,11 @@
|
||||||
|
[0.2.15]
|
||||||
|
- schema: Shout.created_by removed
|
||||||
|
- schema: Shout.mainTopic removed
|
||||||
|
- services: cached elasticsearch connector
|
||||||
|
- services: auth is using user_id from authorizer
|
||||||
|
- resolvers: notify_* usage fixes
|
||||||
|
- resolvers: login_required usage fixes
|
||||||
|
|
||||||
[0.2.14]
|
[0.2.14]
|
||||||
- schema: some fixes from migrator
|
- schema: some fixes from migrator
|
||||||
- schema: .days -> .time_ago
|
- schema: .days -> .time_ago
|
||||||
|
@ -5,7 +13,6 @@
|
||||||
- services: db access simpler, no contextmanager
|
- services: db access simpler, no contextmanager
|
||||||
- services: removed Base.create() method
|
- services: removed Base.create() method
|
||||||
- services: rediscache updated
|
- services: rediscache updated
|
||||||
- resolvers: many minor fixes
|
|
||||||
- resolvers: get_reacted_shouts_updates as followedReactions query
|
- resolvers: get_reacted_shouts_updates as followedReactions query
|
||||||
|
|
||||||
[0.2.13]
|
[0.2.13]
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
[tool.poetry]
|
[tool.poetry]
|
||||||
name = "discoursio-core"
|
name = "discoursio-core"
|
||||||
version = "0.2.14"
|
version = "0.2.15"
|
||||||
description = "core module for discours.io"
|
description = "core module for discours.io"
|
||||||
authors = ["discoursio devteam"]
|
authors = ["discoursio devteam"]
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
|
|
|
@ -1,11 +1,6 @@
|
||||||
from resolvers.editor import create_shout, delete_shout, update_shout
|
from resolvers.editor import create_shout, delete_shout, update_shout
|
||||||
|
|
||||||
from resolvers.author import (
|
from resolvers.author import load_authors_by, update_profile, get_authors_all, rate_author
|
||||||
load_authors_by,
|
|
||||||
update_profile,
|
|
||||||
get_authors_all,
|
|
||||||
rate_author
|
|
||||||
)
|
|
||||||
|
|
||||||
from resolvers.reaction import (
|
from resolvers.reaction import (
|
||||||
create_reaction,
|
create_reaction,
|
||||||
|
@ -25,7 +20,7 @@ from resolvers.topic import (
|
||||||
)
|
)
|
||||||
|
|
||||||
from resolvers.follower import follow, unfollow
|
from resolvers.follower import follow, unfollow
|
||||||
from resolvers.reader import load_shout, load_shouts_by
|
from resolvers.reader import load_shout, load_shouts_by, search
|
||||||
from resolvers.community import get_community, get_communities_all
|
from resolvers.community import get_community, get_communities_all
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
@ -62,4 +57,6 @@ __all__ = [
|
||||||
# community
|
# community
|
||||||
"get_community",
|
"get_community",
|
||||||
"get_communities_all",
|
"get_communities_all",
|
||||||
|
# search
|
||||||
|
"search",
|
||||||
]
|
]
|
||||||
|
|
|
@ -90,9 +90,9 @@ async def author_followings(author_id: int):
|
||||||
@mutation.field("updateProfile")
|
@mutation.field("updateProfile")
|
||||||
@login_required
|
@login_required
|
||||||
async def update_profile(_, info, profile):
|
async def update_profile(_, info, profile):
|
||||||
author_id = info.context["author_id"]
|
user_id = info.context["user_id"]
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
author = session.query(Author).where(Author.id == author_id).first()
|
author = session.query(Author).where(Author.user == user_id).first()
|
||||||
Author.update(author, profile)
|
Author.update(author, profile)
|
||||||
session.add(author)
|
session.add(author)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
@ -206,12 +206,13 @@ async def followed_authors(follower_id):
|
||||||
@mutation.field("rateAuthor")
|
@mutation.field("rateAuthor")
|
||||||
@login_required
|
@login_required
|
||||||
async def rate_author(_, info, rated_user_id, value):
|
async def rate_author(_, info, rated_user_id, value):
|
||||||
author_id = info.context["author_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()
|
||||||
rating = (
|
rating = (
|
||||||
session.query(AuthorRating)
|
session.query(AuthorRating)
|
||||||
.filter(and_(AuthorRating.rater == author_id, AuthorRating.user == rated_user_id))
|
.filter(and_(AuthorRating.rater == rater.id, AuthorRating.user == rated_user_id))
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
if rating:
|
if rating:
|
||||||
|
@ -221,7 +222,7 @@ async def rate_author(_, info, rated_user_id, value):
|
||||||
return {}
|
return {}
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
rating = AuthorRating(rater=author_id, user=rated_user_id, value=value)
|
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:
|
except Exception as err:
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
import time # For Unix timestamps
|
import time # For Unix timestamps
|
||||||
from sqlalchemy import and_, select
|
from sqlalchemy import and_, select
|
||||||
from sqlalchemy.orm import joinedload
|
from sqlalchemy.orm import joinedload
|
||||||
|
|
||||||
|
from orm.author import Author
|
||||||
from services.auth import login_required
|
from services.auth import login_required
|
||||||
from services.db import local_session
|
from services.db import local_session
|
||||||
from services.schema import mutation, query
|
from services.schema import mutation, query
|
||||||
|
@ -11,19 +13,21 @@ from services.notify import notify_shout
|
||||||
|
|
||||||
|
|
||||||
@query.field("loadDrafts")
|
@query.field("loadDrafts")
|
||||||
|
@login_required
|
||||||
async def get_drafts(_, info):
|
async def get_drafts(_, info):
|
||||||
author = info.context["request"].author
|
user_id = info.context["user_id"]
|
||||||
q = (
|
|
||||||
select(Shout)
|
|
||||||
.options(
|
|
||||||
joinedload(Shout.authors),
|
|
||||||
joinedload(Shout.topics),
|
|
||||||
)
|
|
||||||
.where(and_(Shout.deleted_at.is_(None), Shout.created_by == author.id))
|
|
||||||
)
|
|
||||||
q = q.group_by(Shout.id)
|
|
||||||
shouts = []
|
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
|
author = session.query(Author).filter(Author.user == user_id).first()
|
||||||
|
q = (
|
||||||
|
select(Shout)
|
||||||
|
.options(
|
||||||
|
joinedload(Shout.authors),
|
||||||
|
joinedload(Shout.topics),
|
||||||
|
)
|
||||||
|
.where(and_(Shout.deleted_at.is_(None), Shout.created_by == author.id))
|
||||||
|
)
|
||||||
|
q = q.group_by(Shout.id)
|
||||||
|
shouts = []
|
||||||
for [shout] in session.execute(q).unique():
|
for [shout] in session.execute(q).unique():
|
||||||
shouts.append(shout)
|
shouts.append(shout)
|
||||||
return shouts
|
return shouts
|
||||||
|
@ -32,10 +36,13 @@ async def get_drafts(_, info):
|
||||||
@mutation.field("createShout")
|
@mutation.field("createShout")
|
||||||
@login_required
|
@login_required
|
||||||
async def create_shout(_, info, inp):
|
async def create_shout(_, info, inp):
|
||||||
author_id = info.context["author_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()
|
||||||
topics = session.query(Topic).filter(Topic.slug.in_(inp.get("topics", []))).all()
|
topics = session.query(Topic).filter(Topic.slug.in_(inp.get("topics", []))).all()
|
||||||
# Replace datetime with Unix timestamp
|
authors = inp.get("authors", [])
|
||||||
|
if author.id not in authors:
|
||||||
|
authors.insert(0, author.id)
|
||||||
current_time = int(time.time())
|
current_time = int(time.time())
|
||||||
new_shout = Shout(
|
new_shout = Shout(
|
||||||
**{
|
**{
|
||||||
|
@ -45,11 +52,10 @@ async def create_shout(_, info, inp):
|
||||||
"description": inp.get("description"),
|
"description": inp.get("description"),
|
||||||
"body": inp.get("body", ""),
|
"body": inp.get("body", ""),
|
||||||
"layout": inp.get("layout"),
|
"layout": inp.get("layout"),
|
||||||
"authors": inp.get("authors", []),
|
"authors": authors,
|
||||||
"slug": inp.get("slug"),
|
"slug": inp.get("slug"),
|
||||||
"topics": inp.get("topics"),
|
"topics": inp.get("topics"),
|
||||||
"visibility": ShoutVisibility.AUTHORS,
|
"visibility": ShoutVisibility.AUTHORS,
|
||||||
"created_id": author_id,
|
|
||||||
"created_at": current_time, # Set created_at as Unix timestamp
|
"created_at": current_time, # Set created_at as Unix timestamp
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -57,10 +63,10 @@ async def create_shout(_, info, inp):
|
||||||
t = ShoutTopic(topic=topic.id, shout=new_shout.id)
|
t = ShoutTopic(topic=topic.id, shout=new_shout.id)
|
||||||
session.add(t)
|
session.add(t)
|
||||||
# NOTE: shout made by one first author
|
# NOTE: shout made by one first author
|
||||||
sa = ShoutAuthor(shout=new_shout.id, author=author_id)
|
sa = ShoutAuthor(shout=new_shout.id, author=author.id)
|
||||||
session.add(sa)
|
session.add(sa)
|
||||||
session.add(new_shout)
|
session.add(new_shout)
|
||||||
reactions_follow(author_id, new_shout.id, True)
|
reactions_follow(author.id, new_shout.id, True)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
if new_shout.slug is None:
|
if new_shout.slug is None:
|
||||||
|
@ -74,8 +80,9 @@ async def create_shout(_, info, inp):
|
||||||
@mutation.field("updateShout")
|
@mutation.field("updateShout")
|
||||||
@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):
|
||||||
author_id = info.context["author_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()
|
||||||
shout = (
|
shout = (
|
||||||
session.query(Shout)
|
session.query(Shout)
|
||||||
.options(
|
.options(
|
||||||
|
@ -87,7 +94,7 @@ async def update_shout(_, info, shout_id, shout_input=None, publish=False):
|
||||||
)
|
)
|
||||||
if not shout:
|
if not shout:
|
||||||
return {"error": "shout not found"}
|
return {"error": "shout not found"}
|
||||||
if shout.created_by != author_id:
|
if shout.created_by != author.id:
|
||||||
return {"error": "access denied"}
|
return {"error": "access denied"}
|
||||||
updated = False
|
updated = False
|
||||||
if shout_input is not None:
|
if shout_input is not None:
|
||||||
|
@ -154,12 +161,13 @@ async def update_shout(_, info, shout_id, shout_input=None, publish=False):
|
||||||
@mutation.field("deleteShout")
|
@mutation.field("deleteShout")
|
||||||
@login_required
|
@login_required
|
||||||
async def delete_shout(_, info, shout_id):
|
async def delete_shout(_, info, shout_id):
|
||||||
author_id = info.context["author_id"]
|
user_id = info.context["user_id"]
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
|
author = session.query(Author).filter(Author.id == user_id).first()
|
||||||
shout = session.query(Shout).filter(Shout.id == shout_id).first()
|
shout = session.query(Shout).filter(Shout.id == shout_id).first()
|
||||||
if not shout:
|
if not shout:
|
||||||
return {"error": "invalid shout id"}
|
return {"error": "invalid shout id"}
|
||||||
if author_id != shout.created_by:
|
if author.id not in shout.authors:
|
||||||
return {"error": "access denied"}
|
return {"error": "access denied"}
|
||||||
for author_id in shout.authors:
|
for author_id in shout.authors:
|
||||||
reactions_unfollow(author_id, shout_id)
|
reactions_unfollow(author_id, shout_id)
|
||||||
|
|
|
@ -7,32 +7,37 @@ 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
|
||||||
from services.notify import notify_follower
|
from services.notify import notify_follower
|
||||||
|
from services.schema import mutation
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
@mutation.field("follow")
|
||||||
async def follow(_, info, what, slug):
|
async def follow(_, info, what, slug):
|
||||||
follower_id = info.context["author_id"]
|
user_id = info.context["user_id"]
|
||||||
try:
|
try:
|
||||||
if what == "AUTHOR":
|
with local_session() as session:
|
||||||
if author_follow(follower_id, slug):
|
actor = session.query(Author).filter(Author.user == user_id).first()
|
||||||
result = FollowingResult("NEW", 'author', slug)
|
if actor:
|
||||||
await FollowingManager.push('author', result)
|
follower_id = actor.id
|
||||||
with local_session() as session:
|
if what == "AUTHOR":
|
||||||
author = session.query(Author.id).where(Author.slug == slug).one()
|
if author_follow(follower_id, slug):
|
||||||
follower = session.query(Author).where(Author.id == follower_id).one()
|
result = FollowingResult("NEW", "author", slug)
|
||||||
notify_follower(follower.dict(), author.id)
|
await FollowingManager.push("author", result)
|
||||||
elif what == "TOPIC":
|
author = session.query(Author.id).where(Author.slug == slug).one()
|
||||||
if topic_follow(follower_id, slug):
|
follower = session.query(Author).where(Author.id == follower_id).one()
|
||||||
result = FollowingResult("NEW", 'topic', slug)
|
await notify_follower(follower.dict(), author.id)
|
||||||
await FollowingManager.push('topic', result)
|
elif what == "TOPIC":
|
||||||
elif what == "COMMUNITY":
|
if topic_follow(follower_id, slug):
|
||||||
if community_follow(follower_id, slug):
|
result = FollowingResult("NEW", "topic", slug)
|
||||||
result = FollowingResult("NEW", 'community', slug)
|
await FollowingManager.push("topic", result)
|
||||||
await FollowingManager.push('community', result)
|
elif what == "COMMUNITY":
|
||||||
elif what == "REACTIONS":
|
if community_follow(follower_id, slug):
|
||||||
if reactions_follow(follower_id, slug):
|
result = FollowingResult("NEW", "community", slug)
|
||||||
result = FollowingResult("NEW", 'shout', slug)
|
await FollowingManager.push("community", result)
|
||||||
await FollowingManager.push('shout', result)
|
elif what == "REACTIONS":
|
||||||
|
if reactions_follow(follower_id, slug):
|
||||||
|
result = FollowingResult("NEW", "shout", slug)
|
||||||
|
await FollowingManager.push("shout", result)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(Exception(e))
|
print(Exception(e))
|
||||||
return {"error": str(e)}
|
return {"error": str(e)}
|
||||||
|
@ -41,30 +46,33 @@ async def follow(_, info, what, slug):
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
@mutation.field("unfollow")
|
||||||
async def unfollow(_, info, what, slug):
|
async def unfollow(_, info, what, slug):
|
||||||
follower_id = info.context["author_id"]
|
user_id = info.context["user_id"]
|
||||||
try:
|
try:
|
||||||
if what == "AUTHOR":
|
with local_session() as session:
|
||||||
if author_unfollow(follower_id, slug):
|
actor = session.query(Author).filter(Author.user == user_id).first()
|
||||||
result = FollowingResult("DELETED", 'author', slug)
|
if actor:
|
||||||
await FollowingManager.push('author', result)
|
follower_id = actor.id
|
||||||
|
if what == "AUTHOR":
|
||||||
with local_session() as session:
|
if author_unfollow(follower_id, slug):
|
||||||
author = session.query(Author.id).where(Author.slug == slug).one()
|
result = FollowingResult("DELETED", "author", slug)
|
||||||
follower = session.query(Author).where(Author.id == follower_id).one()
|
await FollowingManager.push("author", result)
|
||||||
notify_follower(follower.dict(), author.id, "unfollow")
|
author = session.query(Author.id).where(Author.slug == slug).one()
|
||||||
elif what == "TOPIC":
|
follower = session.query(Author).where(Author.id == follower_id).one()
|
||||||
if topic_unfollow(follower_id, slug):
|
await notify_follower(follower.dict(), author.id, "unfollow")
|
||||||
result = FollowingResult("DELETED", 'topic', slug)
|
elif what == "TOPIC":
|
||||||
await FollowingManager.push('topic', result)
|
if topic_unfollow(follower_id, slug):
|
||||||
elif what == "COMMUNITY":
|
result = FollowingResult("DELETED", "topic", slug)
|
||||||
if community_unfollow(follower_id, slug):
|
await FollowingManager.push("topic", result)
|
||||||
result = FollowingResult("DELETED", 'community', slug)
|
elif what == "COMMUNITY":
|
||||||
await FollowingManager.push('community', result)
|
if community_unfollow(follower_id, slug):
|
||||||
elif what == "REACTIONS":
|
result = FollowingResult("DELETED", "community", slug)
|
||||||
if reactions_unfollow(follower_id, slug):
|
await FollowingManager.push("community", result)
|
||||||
result = FollowingResult("DELETED", 'shout', slug)
|
elif what == "REACTIONS":
|
||||||
await FollowingManager.push('shout', result)
|
if reactions_unfollow(follower_id, slug):
|
||||||
|
result = FollowingResult("DELETED", "shout", slug)
|
||||||
|
await FollowingManager.push("shout", result)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
return {"error": str(e)}
|
return {"error": str(e)}
|
||||||
|
|
||||||
|
|
|
@ -159,18 +159,18 @@ def set_hidden(session, shout_id):
|
||||||
@mutation.field("createReaction")
|
@mutation.field("createReaction")
|
||||||
@login_required
|
@login_required
|
||||||
async def create_reaction(_, info, reaction):
|
async def create_reaction(_, info, reaction):
|
||||||
author_id = info.context["author_id"]
|
user_id = info.context["user_id"]
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
reaction["created_by"] = author_id
|
|
||||||
shout = session.query(Shout).where(Shout.id == reaction["shout"]).one()
|
shout = session.query(Shout).where(Shout.id == reaction["shout"]).one()
|
||||||
|
author = session.query(Author).where(Author.user == user_id).first()
|
||||||
|
reaction["created_by"] = author.id
|
||||||
if reaction["kind"] in [ReactionKind.DISLIKE.name, ReactionKind.LIKE.name]:
|
if reaction["kind"] in [ReactionKind.DISLIKE.name, ReactionKind.LIKE.name]:
|
||||||
existing_reaction = (
|
existing_reaction = (
|
||||||
session.query(Reaction)
|
session.query(Reaction)
|
||||||
.where(
|
.where(
|
||||||
and_(
|
and_(
|
||||||
Reaction.shout == reaction["shout"],
|
Reaction.shout == reaction["shout"],
|
||||||
Reaction.created_by == author_id,
|
Reaction.created_by == author.id,
|
||||||
Reaction.kind == reaction["kind"],
|
Reaction.kind == reaction["kind"],
|
||||||
Reaction.reply_to == reaction.get("reply_to"),
|
Reaction.reply_to == reaction.get("reply_to"),
|
||||||
)
|
)
|
||||||
|
@ -189,7 +189,7 @@ async def create_reaction(_, info, reaction):
|
||||||
.where(
|
.where(
|
||||||
and_(
|
and_(
|
||||||
Reaction.shout == reaction["shout"],
|
Reaction.shout == reaction["shout"],
|
||||||
Reaction.created_by == author_id,
|
Reaction.created_by == author.id,
|
||||||
Reaction.kind == opposite_reaction_kind,
|
Reaction.kind == opposite_reaction_kind,
|
||||||
Reaction.reply_to == reaction.get("reply_to"),
|
Reaction.reply_to == reaction.get("reply_to"),
|
||||||
)
|
)
|
||||||
|
@ -203,7 +203,7 @@ async def create_reaction(_, info, reaction):
|
||||||
r = Reaction(**reaction)
|
r = Reaction(**reaction)
|
||||||
|
|
||||||
# Proposal accepting logix
|
# Proposal accepting logix
|
||||||
if r.reply_to is not None and r.kind == ReactionKind.ACCEPT and author_id in shout.dict()["authors"]:
|
if r.reply_to is not None and r.kind == ReactionKind.ACCEPT and author.id in shout.dict()["authors"]:
|
||||||
replied_reaction = session.query(Reaction).where(Reaction.id == r.reply_to).first()
|
replied_reaction = session.query(Reaction).where(Reaction.id == r.reply_to).first()
|
||||||
if replied_reaction and replied_reaction.kind == ReactionKind.PROPOSE:
|
if replied_reaction and replied_reaction.kind == ReactionKind.PROPOSE:
|
||||||
if replied_reaction.range:
|
if replied_reaction.range:
|
||||||
|
@ -218,18 +218,17 @@ async def create_reaction(_, info, reaction):
|
||||||
session.commit()
|
session.commit()
|
||||||
rdict = r.dict()
|
rdict = r.dict()
|
||||||
rdict["shout"] = shout.dict()
|
rdict["shout"] = shout.dict()
|
||||||
author = session.query(Author).where(Author.id == author_id).first()
|
|
||||||
rdict["created_by"] = author.dict()
|
rdict["created_by"] = author.dict()
|
||||||
|
|
||||||
# self-regulation mechanics
|
# self-regulation mechanics
|
||||||
|
|
||||||
if check_to_hide(session, r):
|
if check_to_hide(session, r):
|
||||||
set_hidden(session, r.shout)
|
set_hidden(session, r.shout)
|
||||||
elif check_to_publish(session, author_id, r):
|
elif check_to_publish(session, author.id, r):
|
||||||
set_published(session, r.shout)
|
set_published(session, r.shout)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
reactions_follow(author_id, reaction["shout"], True)
|
reactions_follow(author.id, reaction["shout"], True)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"[resolvers.reactions] error on reactions auto following: {e}")
|
print(f"[resolvers.reactions] error on reactions auto following: {e}")
|
||||||
|
|
||||||
|
@ -244,7 +243,7 @@ async def create_reaction(_, info, reaction):
|
||||||
@mutation.field("updateReaction")
|
@mutation.field("updateReaction")
|
||||||
@login_required
|
@login_required
|
||||||
async def update_reaction(_, info, rid, reaction):
|
async def update_reaction(_, info, rid, reaction):
|
||||||
author_id = info.context["author_id"]
|
user_id = info.context["user_id"]
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
q = select(Reaction).filter(Reaction.id == rid)
|
q = select(Reaction).filter(Reaction.id == rid)
|
||||||
q = add_reaction_stat_columns(q)
|
q = add_reaction_stat_columns(q)
|
||||||
|
@ -254,41 +253,46 @@ async def update_reaction(_, info, rid, reaction):
|
||||||
|
|
||||||
if not r:
|
if not r:
|
||||||
return {"error": "invalid reaction id"}
|
return {"error": "invalid reaction id"}
|
||||||
if r.created_by != author_id:
|
author = session.query(Author).filter(Author.user == user_id).first()
|
||||||
return {"error": "access denied"}
|
if author:
|
||||||
body = reaction.get("body")
|
if r.created_by != author.id:
|
||||||
if body:
|
return {"error": "access denied"}
|
||||||
r.body = body
|
body = reaction.get("body")
|
||||||
r.updated_at = int(time.time())
|
if body:
|
||||||
if r.kind != reaction["kind"]:
|
r.body = body
|
||||||
# NOTE: change mind detection can be here
|
r.updated_at = int(time.time())
|
||||||
pass
|
if r.kind != reaction["kind"]:
|
||||||
|
# NOTE: change mind detection can be here
|
||||||
|
pass
|
||||||
|
|
||||||
# FIXME: range is not stable after body editing
|
# FIXME: range is not stable after body editing
|
||||||
if reaction.get("range"):
|
if reaction.get("range"):
|
||||||
r.range = reaction.get("range")
|
r.range = reaction.get("range")
|
||||||
|
|
||||||
session.commit()
|
session.commit()
|
||||||
r.stat = {
|
r.stat = {
|
||||||
"commented": commented_stat,
|
"commented": commented_stat,
|
||||||
"reacted": reacted_stat,
|
"reacted": reacted_stat,
|
||||||
"rating": rating_stat,
|
"rating": rating_stat,
|
||||||
}
|
}
|
||||||
|
|
||||||
await notify_reaction(r.dict(), "update")
|
await notify_reaction(r.dict(), "update")
|
||||||
|
|
||||||
return {"reaction": r}
|
return {"reaction": r}
|
||||||
|
else:
|
||||||
|
return {"error": "user"}
|
||||||
|
|
||||||
|
|
||||||
@mutation.field("deleteReaction")
|
@mutation.field("deleteReaction")
|
||||||
@login_required
|
@login_required
|
||||||
async def delete_reaction(_, info, rid):
|
async def delete_reaction(_, info, rid):
|
||||||
author_id = info.context["author_id"]
|
user_id = info.context["user_id"]
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
r = session.query(Reaction).filter(Reaction.id == rid).first()
|
r = session.query(Reaction).filter(Reaction.id == rid).first()
|
||||||
if not r:
|
if not r:
|
||||||
return {"error": "invalid reaction id"}
|
return {"error": "invalid reaction id"}
|
||||||
if r.created_by != author_id:
|
author = session.query(Author).filter(Author.user == user_id).first()
|
||||||
|
if not author or r.created_by != author.id:
|
||||||
return {"error": "access denied"}
|
return {"error": "access denied"}
|
||||||
|
|
||||||
if r.kind in [ReactionKind.LIKE, ReactionKind.DISLIKE]:
|
if r.kind in [ReactionKind.LIKE, ReactionKind.DISLIKE]:
|
||||||
|
@ -400,6 +404,11 @@ def reacted_shouts_updates(follower_id):
|
||||||
@login_required
|
@login_required
|
||||||
@query.field("followedReactions")
|
@query.field("followedReactions")
|
||||||
async def get_reacted_shouts(_, info) -> List[Shout]:
|
async def get_reacted_shouts(_, info) -> List[Shout]:
|
||||||
author_id = info.context["author_id"]
|
user_id = info.context["user_id"]
|
||||||
shouts = reacted_shouts_updates(author_id)
|
with local_session() as session:
|
||||||
return shouts
|
author = session.query(Author).filter(Author.user == user_id).first()
|
||||||
|
if author:
|
||||||
|
shouts = reacted_shouts_updates(author.id)
|
||||||
|
return shouts
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
|
@ -4,10 +4,12 @@ from sqlalchemy.sql.expression import desc, asc, select, func, case, and_, nulls
|
||||||
|
|
||||||
from services.auth import login_required
|
from services.auth import login_required
|
||||||
from services.db import local_session
|
from services.db import local_session
|
||||||
|
from services.schema import query
|
||||||
from orm.topic import TopicFollower
|
from orm.topic import TopicFollower
|
||||||
from orm.reaction import Reaction, ReactionKind
|
from orm.reaction import Reaction, ReactionKind
|
||||||
from orm.shout import Shout, ShoutAuthor, ShoutTopic
|
from orm.shout import Shout, ShoutAuthor, ShoutTopic
|
||||||
from orm.author import AuthorFollower
|
from orm.author import AuthorFollower, Author
|
||||||
|
from services.search import SearchService
|
||||||
from services.viewed import ViewedStorage
|
from services.viewed import ViewedStorage
|
||||||
|
|
||||||
|
|
||||||
|
@ -69,6 +71,7 @@ def apply_filters(q, filters, author_id=None):
|
||||||
return q
|
return q
|
||||||
|
|
||||||
|
|
||||||
|
@query.field("loadShout")
|
||||||
async def load_shout(_, _info, slug=None, shout_id=None):
|
async def load_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(
|
||||||
|
@ -111,6 +114,7 @@ async def load_shout(_, _info, slug=None, shout_id=None):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
@query.field("loadShoutsBy")
|
||||||
async def load_shouts_by(_, info, options):
|
async def load_shouts_by(_, info, options):
|
||||||
"""
|
"""
|
||||||
:param _:
|
:param _:
|
||||||
|
@ -145,8 +149,13 @@ async def load_shouts_by(_, info, options):
|
||||||
|
|
||||||
q = add_stat_columns(q)
|
q = add_stat_columns(q)
|
||||||
|
|
||||||
author_id = info.context["author_id"]
|
user_id = info.context["user_id"]
|
||||||
q = apply_filters(q, options.get("filters", {}), author_id)
|
filters = options.get("filters")
|
||||||
|
if filters:
|
||||||
|
with local_session() as session:
|
||||||
|
author = session.query(Author).filter(Author.user == user_id).first()
|
||||||
|
if author:
|
||||||
|
q = apply_filters(q, filters, author.id)
|
||||||
|
|
||||||
order_by = options.get("order_by", Shout.published_at)
|
order_by = options.get("order_by", Shout.published_at)
|
||||||
|
|
||||||
|
@ -180,11 +189,13 @@ async def load_shouts_by(_, info, options):
|
||||||
|
|
||||||
|
|
||||||
@login_required
|
@login_required
|
||||||
|
@query.field("loadFeed")
|
||||||
async def get_my_feed(_, info, options):
|
async def get_my_feed(_, info, options):
|
||||||
author_id = info.context["author_id"]
|
user_id = info.context["user_id"]
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
author_followed_authors = select(AuthorFollower.author).where(AuthorFollower.follower == author_id)
|
author = session.query(Author).filter(Author.user == user_id).first()
|
||||||
author_followed_topics = select(TopicFollower.topic).where(TopicFollower.follower == author_id)
|
author_followed_authors = select(AuthorFollower.author).where(AuthorFollower.follower == author.id)
|
||||||
|
author_followed_topics = select(TopicFollower.topic).where(TopicFollower.follower == author.id)
|
||||||
|
|
||||||
subquery = (
|
subquery = (
|
||||||
select(Shout.id)
|
select(Shout.id)
|
||||||
|
@ -209,7 +220,7 @@ async def get_my_feed(_, info, options):
|
||||||
)
|
)
|
||||||
|
|
||||||
q = add_stat_columns(q)
|
q = add_stat_columns(q)
|
||||||
q = apply_filters(q, options.get("filters", {}), author_id)
|
q = apply_filters(q, options.get("filters", {}), author.id)
|
||||||
|
|
||||||
order_by = options.get("order_by", Shout.published_at)
|
order_by = options.get("order_by", Shout.published_at)
|
||||||
|
|
||||||
|
@ -235,3 +246,11 @@ async def get_my_feed(_, info, options):
|
||||||
}
|
}
|
||||||
shouts.append(shout)
|
shouts.append(shout)
|
||||||
return shouts
|
return shouts
|
||||||
|
|
||||||
|
|
||||||
|
@query.field("search")
|
||||||
|
async def search(_, info, text, limit=50, offset=0):
|
||||||
|
if text and len(text) > 2:
|
||||||
|
return SearchService.search(text, limit, offset)
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
|
@ -135,13 +135,13 @@ def topic_follow(follower_id, slug):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def topic_unfollow(user_id, slug):
|
def topic_unfollow(follower_id, slug):
|
||||||
try:
|
try:
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
sub = (
|
sub = (
|
||||||
session.query(TopicFollower)
|
session.query(TopicFollower)
|
||||||
.join(Topic)
|
.join(Topic)
|
||||||
.filter(and_(TopicFollower.follower == user_id, Topic.slug == slug))
|
.filter(and_(TopicFollower.follower == follower_id, Topic.slug == slug))
|
||||||
.first()
|
.first()
|
||||||
)
|
)
|
||||||
if sub:
|
if sub:
|
||||||
|
@ -153,6 +153,7 @@ def topic_unfollow(user_id, slug):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
@query.field("topicsRandom")
|
||||||
async def topics_random(_, info, amount=12):
|
async def topics_random(_, info, amount=12):
|
||||||
q = select(Topic)
|
q = select(Topic)
|
||||||
q = q.join(ShoutTopic)
|
q = q.join(ShoutTopic)
|
||||||
|
|
|
@ -334,4 +334,6 @@ type Query {
|
||||||
|
|
||||||
communitiesAll: [Community]
|
communitiesAll: [Community]
|
||||||
getCommunity: Community
|
getCommunity: Community
|
||||||
|
|
||||||
|
search(text: String!, limit: Int, offset: Int): [Shout]
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ async def check_auth(req):
|
||||||
query_type = "query"
|
query_type = "query"
|
||||||
operation = "GetUserId"
|
operation = "GetUserId"
|
||||||
|
|
||||||
headers = {"Authorization": "Bearer " + token, "Content-Type": "application/json"}
|
headers = {"Authorization": token, "Content-Type": "application/json"}
|
||||||
|
|
||||||
gql = {
|
gql = {
|
||||||
"query": query_type + " " + operation + " { " + query_name + " { user { id } } " + " }",
|
"query": query_type + " " + operation + " { " + query_name + " { user { id } } " + " }",
|
||||||
|
@ -26,9 +26,7 @@ async def check_auth(req):
|
||||||
return False, None
|
return False, None
|
||||||
r = response.json()
|
r = response.json()
|
||||||
try:
|
try:
|
||||||
user_id = (
|
user_id = r.get("data", {}).get(query_name, {}).get("user", {}).get("id", None)
|
||||||
r.get("data", {}).get(query_name, {}).get("user", {}).get("id", None)
|
|
||||||
)
|
|
||||||
is_authenticated = user_id is not None
|
is_authenticated = user_id is not None
|
||||||
return is_authenticated, user_id
|
return is_authenticated, user_id
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
@ -47,7 +45,7 @@ def login_required(f):
|
||||||
raise Exception("You are not logged in")
|
raise Exception("You are not logged in")
|
||||||
else:
|
else:
|
||||||
# Добавляем author_id в контекст
|
# Добавляем author_id в контекст
|
||||||
context["author_id"] = user_id
|
context["user_id"] = user_id
|
||||||
|
|
||||||
# Если пользователь аутентифицирован, выполняем резолвер
|
# Если пользователь аутентифицирован, выполняем резолвер
|
||||||
return await f(*args, **kwargs)
|
return await f(*args, **kwargs)
|
||||||
|
@ -63,7 +61,7 @@ def auth_request(f):
|
||||||
if not is_authenticated:
|
if not is_authenticated:
|
||||||
raise HTTPError("please, login first")
|
raise HTTPError("please, login first")
|
||||||
else:
|
else:
|
||||||
req["author_id"] = user_id
|
req["user_id"] = user_id
|
||||||
return await f(*args, **kwargs)
|
return await f(*args, **kwargs)
|
||||||
|
|
||||||
return decorated_function
|
return decorated_function
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
|
import httpx
|
||||||
from services.rediscache import redis
|
from services.rediscache import redis
|
||||||
from orm.shout import Shout
|
from orm.shout import Shout
|
||||||
from resolvers.reader import load_shouts_by
|
|
||||||
|
|
||||||
|
|
||||||
class SearchService:
|
class SearchService:
|
||||||
|
@ -20,15 +20,13 @@ class SearchService:
|
||||||
cached = await redis.execute("GET", text)
|
cached = await redis.execute("GET", text)
|
||||||
if not cached:
|
if not cached:
|
||||||
async with SearchService.lock:
|
async with SearchService.lock:
|
||||||
options = {
|
# Use httpx to send a request to ElasticSearch
|
||||||
"title": text,
|
async with httpx.AsyncClient() as client:
|
||||||
"body": text,
|
search_url = f"https://search.discours.io/search?q={text}"
|
||||||
"limit": limit,
|
response = await client.get(search_url)
|
||||||
"offset": offset,
|
if response.status_code == 200:
|
||||||
}
|
payload = response.json()
|
||||||
# FIXME: use elastic request here
|
await redis.execute("SET", text, payload)
|
||||||
payload = await load_shouts_by(None, None, options)
|
return json.loads(payload)
|
||||||
await redis.execute("SET", text, json.dumps(payload))
|
|
||||||
return payload
|
|
||||||
else:
|
else:
|
||||||
return json.loads(cached)
|
return json.loads(cached)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user