fixes-api

This commit is contained in:
tonyrewin 2022-11-21 11:13:57 +03:00
parent 4c4f18147e
commit 5ad8328c03
17 changed files with 187 additions and 170 deletions

View File

@ -7,18 +7,18 @@ from resolvers.auth import (
auth_send_link,
get_current_user,
)
from resolvers.collab import remove_author, invite_author
from resolvers.migrate import markdown_body
# from resolvers.collab import invite_author, remove_author
from resolvers.editor import create_shout, delete_shout, update_shout
from resolvers.profile import (
from resolvers.create.collab import remove_author, invite_author
from resolvers.create.migrate import markdown_body
from resolvers.create.editor import create_shout, delete_shout, update_shout
from resolvers.zine.profile import (
load_authors_by,
rate_user,
update_profile
)
from resolvers.reactions import (
from resolvers.zine.reactions import (
create_reaction,
delete_reaction,
update_reaction,
@ -26,7 +26,7 @@ from resolvers.reactions import (
reactions_follow,
load_reactions_by
)
from resolvers.topics import (
from resolvers.zine.topics import (
topic_follow,
topic_unfollow,
topics_by_author,
@ -35,9 +35,13 @@ from resolvers.topics import (
get_topic
)
from resolvers.zine import (
from resolvers.zine.following import (
follow,
unfollow,
unfollow
)
from resolvers.zine.load import (
load_shout,
load_shouts_by
)
@ -56,9 +60,10 @@ from resolvers.inbox.messages import (
)
from resolvers.inbox.load import (
load_chats,
load_messages_by
load_messages_by,
load_recipients
)
from resolvers.inbox.search import search_users
from resolvers.inbox.search import search_recipients
__all__ = [
# auth
@ -69,32 +74,34 @@ __all__ = [
"auth_send_link",
"sign_out",
"get_current_user",
# authors
# zine.profile
"load_authors_by",
"rate_user",
"update_profile",
"get_authors_all",
# zine
# zine.load
"load_shout",
"load_shouts_by",
# zine.following
"follow",
"unfollow",
# editor
# create.editor
"create_shout",
"update_shout",
"delete_shout",
# migrate
# create.migrate
"markdown_body",
# collab
# create.collab
"invite_author",
"remove_author",
# topics
# zine.topics
"topics_all",
"topics_by_community",
"topics_by_author",
"topic_follow",
"topic_unfollow",
"get_topic",
# reactions
# zine.reactions
"reactions_follow",
"reactions_unfollow",
"create_reaction",
@ -113,5 +120,6 @@ __all__ = [
"update_message",
"message_generator",
"mark_as_read",
"search_users"
"load_recipients",
"search_recipients"
]

View File

@ -17,7 +17,7 @@ from base.exceptions import (BaseHttpException, InvalidPassword, InvalidToken,
from base.orm import local_session
from base.resolvers import mutation, query
from orm import Role, User
from resolvers.profile import user_subscriptions
from resolvers.zine.profile import user_subscriptions
@mutation.field("refreshSession")

View File

@ -7,7 +7,7 @@ from orm.rbac import Resource
from orm.shout import Shout, ShoutAuthor, ShoutTopic
from orm.topic import TopicFollower
from orm.user import User
from resolvers.reactions import reactions_follow, reactions_unfollow
from resolvers.zine.reactions import reactions_follow, reactions_unfollow
from services.zine.gittask import GitTask

View File

@ -4,8 +4,7 @@ from datetime import datetime
from auth.authenticate import login_required
from base.redis import redis
from base.resolvers import mutation, query
from services.auth.users import UserStorage
from base.resolvers import mutation
async def add_user_to_chat(user_slug: str, chat_id: str, chat=None):
@ -122,10 +121,3 @@ async def delete_chat(_, info, chat_id: str):
return {
"error": "chat not exist"
}
@query.field("chatUsersAll")
@login_required
async def get_chat_users_all(_, info):
chat_users = await UserStorage.get_all_chat_users()
return chat_users

View File

@ -3,27 +3,11 @@ from datetime import datetime, timedelta
from auth.authenticate import login_required
from base.redis import redis
from base.orm import local_session
from base.resolvers import query
async def get_unread_counter(chat_id: str, user_slug: str):
try:
unread = await redis.execute("LLEN", f"chats/{chat_id}/unread/{user_slug}")
if unread:
return unread
except Exception:
return 0
async def get_total_unread_counter(user_slug: str):
chats = await redis.execute("GET", f"chats_by_user/{user_slug}")
unread = 0
if chats:
chats = json.loads(chats)
for chat_id in chats:
n = await get_unread_counter(chat_id, user_slug)
unread += n
return unread
from orm.user import User
from resolvers.zine.profile import followed_authors
from .unread import get_unread_counter
async def load_messages(chatId: str, limit: int, offset: int):
@ -100,3 +84,20 @@ async def load_messages_by(_, info, by, limit: int = 50, offset: int = 0):
"messages": messages,
"error": None
}
@query.field("loadRecipients")
async def load_recipients(_, info, limit=50, offset=0):
chat_users = []
user = info.context["request"].user
try:
chat_users += await followed_authors(user.slug)
limit = limit - len(chat_users)
except Exception:
pass
with local_session() as session:
chat_users += session.query(User).where(User.emailConfirmed).limit(limit).offset(offset)
return {
"members": chat_users,
"error": None
}

View File

@ -7,9 +7,9 @@ from base.orm import local_session
from orm.user import AuthorFollower
@query.field("searchUsers")
@query.field("searchRecipients")
@login_required
async def search_users(_, info, query: str, limit: int = 50, offset: int = 0):
async def search_recipients(_, info, query: str, limit: int = 50, offset: int = 0):
result = []
# TODO: maybe redis scan?
user = info.context["request"].user
@ -38,6 +38,6 @@ async def search_users(_, info, query: str, limit: int = 50, offset: int = 0):
result += session.query(AuthorFollower.follower).where(AuthorFollower.author.startswith(query))\
.offset(offset + len(result)).limit(offset + len(result) + limit)
return {
"slugs": list(result),
"members": list(result),
"error": None
}

22
resolvers/inbox/unread.py Normal file
View File

@ -0,0 +1,22 @@
from base.redis import redis
import json
async def get_unread_counter(chat_id: str, user_slug: str):
try:
unread = await redis.execute("LLEN", f"chats/{chat_id}/unread/{user_slug}")
if unread:
return unread
except Exception:
return 0
async def get_total_unread_counter(user_slug: str):
chats = await redis.execute("GET", f"chats_by_user/{user_slug}")
unread = 0
if chats:
chats = json.loads(chats)
for chat_id in chats:
n = await get_unread_counter(chat_id, user_slug)
unread += n
return unread

View File

@ -0,0 +1,47 @@
from auth.authenticate import login_required
from base.resolvers import mutation
# from resolvers.community import community_follow, community_unfollow
from resolvers.zine.profile import author_follow, author_unfollow
from resolvers.zine.reactions import reactions_follow, reactions_unfollow
from resolvers.zine.topics import topic_follow, topic_unfollow
@mutation.field("follow")
@login_required
async def follow(_, info, what, slug):
user = info.context["request"].user
try:
if what == "AUTHOR":
author_follow(user, slug)
elif what == "TOPIC":
topic_follow(user, slug)
elif what == "COMMUNITY":
# community_follow(user, slug)
pass
elif what == "REACTIONS":
reactions_follow(user, slug)
except Exception as e:
return {"error": str(e)}
return {}
@mutation.field("unfollow")
@login_required
async def unfollow(_, info, what, slug):
user = info.context["request"].user
try:
if what == "AUTHOR":
author_unfollow(user, slug)
elif what == "TOPIC":
topic_unfollow(user, slug)
elif what == "COMMUNITY":
# community_unfollow(user, slug)
pass
elif what == "REACTIONS":
reactions_unfollow(user, slug)
except Exception as e:
return {"error": str(e)}
return {}

View File

@ -1,21 +1,65 @@
#!/usr/bin/env python3.10
from datetime import datetime, timedelta
import sqlalchemy as sa
from sqlalchemy.orm import selectinload
from sqlalchemy.sql.expression import desc, asc, select, case
from auth.authenticate import login_required
from base.orm import local_session
from base.resolvers import mutation, query
from base.resolvers import query
from orm.shout import Shout
from orm.reaction import Reaction, ReactionKind
# from resolvers.community import community_follow, community_unfollow
from resolvers.profile import author_follow, author_unfollow
from resolvers.reactions import reactions_follow, reactions_unfollow
from resolvers.topics import topic_follow, topic_unfollow
from services.zine.shoutauthor import ShoutAuthorStorage
from services.stat.reacted import ReactedStorage
def apply_filters(filters, q, user=None):
if filters.get("reacted") and user:
q.join(Reaction, Reaction.createdBy == user.slug)
if filters.get("visibility"):
q = q.filter(Shout.visibility == filters.get("visibility"))
if filters.get("layout"):
q = q.filter(Shout.layout == filters.get("layout"))
if filters.get("author"):
q = q.filter(Shout.authors.any(slug=filters.get("author")))
if filters.get("topic"):
q = q.filter(Shout.topics.any(slug=filters.get("topic")))
if filters.get("title"):
q = q.filter(Shout.title.ilike(f'%{filters.get("title")}%'))
if filters.get("body"):
q = q.filter(Shout.body.ilike(f'%{filters.get("body")}%s'))
if filters.get("days"):
before = datetime.now() - timedelta(days=int(filters.get("days")) or 30)
q = q.filter(Shout.createdAt > before)
return q
def extract_order(o, q):
if o:
q = q.add_columns(sa.func.count(Reaction.id).label(o))
if o == 'comments':
q = q.join(Reaction, Shout.slug == Reaction.shout)
q = q.filter(Reaction.body.is_not(None))
elif o == 'reacted':
q = q.join(
Reaction
).add_columns(
sa.func.max(Reaction.createdAt).label(o)
)
elif o == "rating":
q = q.join(Reaction).add_columns(sa.func.sum(case(
(Reaction.kind == ReactionKind.AGREE, 1),
(Reaction.kind == ReactionKind.DISAGREE, -1),
(Reaction.kind == ReactionKind.PROOF, 1),
(Reaction.kind == ReactionKind.DISPROOF, -1),
(Reaction.kind == ReactionKind.ACCEPT, 1),
(Reaction.kind == ReactionKind.REJECT, -1),
(Reaction.kind == ReactionKind.LIKE, 1),
(Reaction.kind == ReactionKind.DISLIKE, -1),
else_=0
)).label(o))
return o
else:
return 'createdAt'
@query.field("loadShout")
async def load_shout(_, info, slug):
with local_session() as session:
@ -48,7 +92,7 @@ async def load_shouts_by(_, info, options):
offset: 0
limit: 50
order_by: 'createdAt'
order_by_desc: tr
order_by_desc: true
}
:return: Shout[]
@ -61,53 +105,9 @@ async def load_shouts_by(_, info, options):
).where(
Shout.deletedAt.is_(None)
)
if options.get("filters"):
if options.get("filters").get("reacted"):
user = info.context["request"].user
q.join(Reaction, Reaction.createdBy == user.slug)
if options.get("filters").get("visibility"):
q = q.filter(Shout.visibility == options.get("filters").get("visibility"))
if options.get("filters").get("layout"):
q = q.filter(Shout.layout == options.get("filters").get("layout"))
if options.get("filters").get("author"):
q = q.filter(Shout.authors.any(slug=options.get("filters").get("author")))
if options.get("filters").get("topic"):
q = q.filter(Shout.topics.any(slug=options.get("filters").get("topic")))
if options.get("filters").get("title"):
q = q.filter(Shout.title.ilike(f'%{options.get("filters").get("title")}%'))
if options.get("filters").get("body"):
q = q.filter(Shout.body.ilike(f'%{options.get("filters").get("body")}%s'))
if options.get("filters").get("days"):
before = datetime.now() - timedelta(days=int(options.get("filter").get("days")) or 30)
q = q.filter(Shout.createdAt > before)
o = options.get("order_by")
if o:
q = q.add_columns(sa.func.count(Reaction.id).label(o))
if o == 'comments':
q = q.join(Reaction, Shout.slug == Reaction.shout)
q = q.filter(Reaction.body.is_not(None))
elif o == 'reacted':
q = q.join(
Reaction
).add_columns(
sa.func.max(Reaction.createdAt).label(o)
)
elif o == "rating":
q = q.join(Reaction).add_columns(sa.func.sum(case(
(Reaction.kind == ReactionKind.AGREE, 1),
(Reaction.kind == ReactionKind.DISAGREE, -1),
(Reaction.kind == ReactionKind.PROOF, 1),
(Reaction.kind == ReactionKind.DISPROOF, -1),
(Reaction.kind == ReactionKind.ACCEPT, 1),
(Reaction.kind == ReactionKind.REJECT, -1),
(Reaction.kind == ReactionKind.LIKE, 1),
(Reaction.kind == ReactionKind.DISLIKE, -1),
else_=0
)).label(o))
order_by = o
else:
order_by = 'createdAt'
q = apply_filters(options.get("filters"), q, user)
order_by = extract_order(options.get("order_by"))
query_order_by = desc(order_by) if options.get("order_by_desc") else asc(order_by)
offset = options.get("offset", 0)
limit = options.get("limit", 10)
@ -121,44 +121,3 @@ async def load_shouts_by(_, info, options):
a.caption = await ShoutAuthorStorage.get_author_caption(s.slug, a.slug)
return shouts
@mutation.field("follow")
@login_required
async def follow(_, info, what, slug):
user = info.context["request"].user
try:
if what == "AUTHOR":
author_follow(user, slug)
elif what == "TOPIC":
topic_follow(user, slug)
elif what == "COMMUNITY":
# community_follow(user, slug)
pass
elif what == "REACTIONS":
reactions_follow(user, slug)
except Exception as e:
return {"error": str(e)}
return {}
@mutation.field("unfollow")
@login_required
async def unfollow(_, info, what, slug):
user = info.context["request"].user
try:
if what == "AUTHOR":
author_unfollow(user, slug)
elif what == "TOPIC":
topic_unfollow(user, slug)
elif what == "COMMUNITY":
# community_unfollow(user, slug)
pass
elif what == "REACTIONS":
reactions_unfollow(user, slug)
except Exception as e:
return {"error": str(e)}
return {}

View File

@ -14,7 +14,7 @@ from services.stat.topicstat import TopicStat
from services.zine.shoutauthor import ShoutAuthor
# from .community import followed_communities
from .inbox.load import get_total_unread_counter
from resolvers.inbox.unread import get_total_unread_counter
from .topics import get_topic_stat

View File

@ -9,7 +9,7 @@ from orm.topic import Topic, TopicFollower
from services.zine.topics import TopicStorage
from services.stat.reacted import ReactedStorage
from services.stat.topicstat import TopicStat
from services.stat.viewed import ViewedStorage
# from services.stat.viewed import ViewedStorage
async def get_topic_stat(slug):
@ -17,7 +17,7 @@ async def get_topic_stat(slug):
"shouts": len(TopicStat.shouts_by_topic.get(slug, {}).keys()),
"authors": len(TopicStat.authors_by_topic.get(slug, {}).keys()),
"followers": len(TopicStat.followers_by_topic.get(slug, {}).keys()),
"viewed": await ViewedStorage.get_topic(slug),
# "viewed": await ViewedStorage.get_topic(slug),
"reacted": len(await ReactedStorage.get_topic(slug)),
"commented": len(await ReactedStorage.get_topic_comments(slug)),
"rating": await ReactedStorage.get_topic_rating(slug)

View File

@ -24,9 +24,11 @@ type AuthResult {
}
type ChatMember {
id: Int!
slug: String!
name: String!
userpic: String
lastSeen: DateTime
invitedAt: DateTime
invitedBy: String # user slug
# TODO: add more
@ -261,8 +263,8 @@ type Query {
# inbox
loadChats( limit: Int, offset: Int): Result! # your chats
loadMessagesBy(by: MessagesBy!, limit: Int, offset: Int): Result!
searchUsers(query: String!, limit: Int, offset: Int): Result!
chatUsersAll: [ChatUser]!
loadRecipients(limit: Int, offset: Int): Result!
searchRecipients(query: String!, limit: Int, offset: Int): Result!
# auth
isEmailUsed(email: String!): Boolean!
@ -369,14 +371,6 @@ type User {
oid: String
}
type ChatUser {
id: Int!
slug: String!
name: String!
userpic: String
lastSeen: DateTime
}
type Collab {
authors: [String]!
invites: [String]
@ -482,7 +476,7 @@ type TopicStat {
shouts: Int!
followers: Int!
authors: Int!
viewed: Int
# viewed: Int
reacted: Int!
commented: Int
rating: Int

View File

@ -1,6 +1,5 @@
import asyncio
from sqlalchemy.orm import selectinload
from base.orm import local_session
from orm.user import User
@ -33,11 +32,6 @@ class UserStorage:
aaa.sort(key=lambda user: user.createdAt)
return aaa
@staticmethod
async def get_all_chat_users():
with local_session() as session:
return session.query(User).where(User.emailConfirmed).all()
@staticmethod
async def get_top_users():
self = UserStorage

View File

@ -2,7 +2,7 @@ import asyncio
import json
from base.redis import redis
from orm.shout import Shout
from resolvers.zine import load_shouts_by
from resolvers.zine.load import load_shouts_by
class SearchService: