fixes-api
This commit is contained in:
parent
4c4f18147e
commit
5ad8328c03
|
@ -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"
|
||||
]
|
||||
|
|
|
@ -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")
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
22
resolvers/inbox/unread.py
Normal 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
|
47
resolvers/zine/following.py
Normal file
47
resolvers/zine/following.py
Normal 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 {}
|
|
@ -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 {}
|
|
@ -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
|
||||
|
||||
|
|
@ -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)
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
Loading…
Reference in New Issue
Block a user