authorid-context
All checks were successful
deploy / deploy (push) Successful in 1m18s

This commit is contained in:
Untone 2023-11-28 19:04:45 +03:00
parent 2d89a4ec86
commit 68fce283bc
10 changed files with 47 additions and 300 deletions

View File

@ -1,25 +0,0 @@
import time
from sqlalchemy import Column, ForeignKey, Integer, String
from services.db import Base
class ShoutCollection(Base):
__tablename__ = "shout_collection"
id = None # type: ignore
shout = Column(ForeignKey("shout.id"), primary_key=True)
collection = Column(ForeignKey("collection.id"), primary_key=True)
class Collection(Base):
__tablename__ = "collection"
slug = Column(String, unique=True)
title = Column(String, nullable=False, comment="Title")
body = Column(String, nullable=True, comment="Body")
pic = Column(String, nullable=True, comment="Picture")
created_at = Column(Integer, default=lambda: int(time.time()))
created_by = Column(ForeignKey("author.id"), comment="Created By")
publishedAt = Column(Integer, default=lambda: int(time.time()))

View File

@ -1,41 +0,0 @@
import time
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import relationship
from orm.author import Author
from services.db import Base, local_session
class CommunityAuthor(Base):
__tablename__ = "community_author"
id = None # type: ignore
follower = Column(ForeignKey("author.id"), primary_key=True)
community = Column(ForeignKey("community.id"), primary_key=True)
joined_at = Column(Integer, nullable=False, default=lambda: int(time.time()))
role = Column(String, nullable=False)
class Community(Base):
__tablename__ = "community"
name = Column(String, nullable=False)
slug = Column(String, nullable=False, unique=True)
desc = Column(String, nullable=False, default="")
pic = Column(String, nullable=False, default="")
created_at = Column(Integer, nullable=False, default=lambda: int(time.time()))
authors = relationship(lambda: Author, secondary=CommunityAuthor.__tablename__)
@staticmethod
def init_table():
with local_session("orm.community") as session:
d = session.query(Community).filter(Community.slug == "discours").first()
if not d:
d = Community(name="Дискурс", slug="discours")
session.add(d)
session.commit()
print("[orm.community] created community %s" % d.slug)
Community.default_community = d
print("[orm.community] default community is %s" % d.slug)

View File

@ -1,43 +0,0 @@
import time
from enum import Enum as Enumeration
from sqlalchemy import Column, Enum, ForeignKey, Integer, String
from services.db import Base
class ReactionKind(Enumeration):
# TYPE = <reaction index> # rating diff
# editor mode
AGREE = 1 # +1
DISAGREE = 2 # -1
ASK = 3 # +0
PROPOSE = 4 # +0
PROOF = 5 # +1
DISPROOF = 6 # -1
ACCEPT = 7 # +1
REJECT = 8 # -1
# public feed
QUOTE = 9 # +0
COMMENT = 0 # +0
LIKE = 11 # +1
DISLIKE = 12 # -1
class Reaction(Base):
__tablename__ = "reaction"
body = Column(String, default='', comment="Reaction Body")
created_at = Column(Integer, nullable=False, default=lambda: int(time.time()))
created_by = Column(ForeignKey("author.id"), nullable=False, index=True)
updated_at = Column(Integer, nullable=True, comment="Updated at")
deleted_at = Column(Integer, nullable=True, comment="Deleted at")
deleted_by = Column(ForeignKey("author.id"), nullable=True, index=True)
shout = Column(ForeignKey("shout.id"), nullable=False, index=True)
reply_to = Column(ForeignKey("reaction.id"), nullable=True)
quote = Column(String, nullable=True, comment="Original quoted text")
kind = Column(Enum(ReactionKind), nullable=False)
oid = Column(String)

View File

@ -1,86 +0,0 @@
import time
from enum import Enum as Enumeration
from sqlalchemy import JSON, Boolean, Column, Enum, ForeignKey, Integer, String
from sqlalchemy.orm import relationship
from orm.author import Author
from orm.community import Community
from orm.reaction import Reaction
from orm.topic import Topic
from services.db import Base
class ShoutTopic(Base):
__tablename__ = "shout_topic"
id = None # type: ignore
shout = Column(ForeignKey("shout.id"), primary_key=True, index=True)
topic = Column(ForeignKey("topic.id"), primary_key=True, index=True)
class ShoutReactionsFollower(Base):
__tablename__ = "shout_reactions_followers"
id = None # type: ignore
follower = Column(ForeignKey("author.id"), primary_key=True, index=True)
shout = Column(ForeignKey("shout.id"), primary_key=True, index=True)
auto = Column(Boolean, nullable=False, default=False)
created_at = Column(Integer, nullable=False, default=lambda: int(time.time()))
deleted_at = Column(Integer, nullable=True)
class ShoutAuthor(Base):
__tablename__ = "shout_author"
id = None # type: ignore
shout = Column(ForeignKey("shout.id"), primary_key=True, index=True)
author = Column(ForeignKey("author.id"), primary_key=True, index=True)
caption = Column(String, nullable=True, default="")
class ShoutCommunity(Base):
__tablename__ = "shout_community"
id = None # type: ignore
shout = Column(ForeignKey("shout.id"), primary_key=True, index=True)
community = Column(ForeignKey("community.id"), primary_key=True, index=True)
class ShoutVisibility(Enumeration):
AUTHORS = 0
COMMUNITY = 1
PUBLIC = 2
class Shout(Base):
__tablename__ = "shout"
created_at = Column(Integer, nullable=False, default=lambda: int(time.time()))
updated_at = Column(Integer, nullable=True)
published_at = Column(Integer, nullable=True)
deleted_at = Column(Integer, nullable=True)
deleted_by = Column(ForeignKey("author.id"), nullable=True)
body = Column(String, nullable=False, comment="Body")
slug = Column(String, unique=True)
cover = Column(String, nullable=True, comment="Cover image url")
lead = Column(String, nullable=True)
description = Column(String, nullable=True)
title = Column(String, nullable=True)
subtitle = Column(String, nullable=True)
layout = Column(String, nullable=True)
media = Column(JSON, nullable=True)
authors = relationship(lambda: Author, secondary="shout_author")
topics = relationship(lambda: Topic, secondary="shout_topic")
communities = relationship(lambda: Community, secondary="shout_community")
reactions = relationship(lambda: Reaction)
visibility = Column(Enum(ShoutVisibility), default=ShoutVisibility.AUTHORS)
lang = Column(String, nullable=False, default="ru", comment="Language")
version_of = Column(ForeignKey("shout.id"), nullable=True)
oid = Column(String, nullable=True)

View File

@ -1,26 +0,0 @@
import time
from sqlalchemy import Boolean, Column, ForeignKey, Integer, String
from services.db import Base
class TopicFollower(Base):
__tablename__ = "topic_followers"
id = None # type: ignore
follower = Column(ForeignKey("author.id"), primary_key=True, index=True)
topic = Column(ForeignKey("topic.id"), primary_key=True, index=True)
created_at = Column(Integer, nullable=False, default=lambda: int(time.time()))
auto = Column(Boolean, nullable=False, default=False)
class Topic(Base):
__tablename__ = "topic"
slug = Column(String, unique=True)
title = Column(String, nullable=False, comment="Title")
body = Column(String, nullable=True, comment="Body")
pic = Column(String, nullable=True, comment="Picture")
community = Column(ForeignKey("community.id"), default=1)
oid = Column(String, nullable=True, comment="Old ID")

View File

@ -25,6 +25,9 @@ black = { version = "^23.9.1", python = ">=3.12" }
mypy = { version = "^1.7", python = ">=3.12" }
setuptools = "^69.0.2"
[tool.poetry.group.dev.dependencies]
setuptools = "^69.0.2"
[tool.black]
line-length = 120
target-version = ['py312']

View File

@ -1,6 +1,3 @@
import json
import asyncio
from orm.notification import Notification
from services.db import local_session
from services.rediscache import redis

View File

@ -35,15 +35,16 @@ class NotificationsResult:
total: int
def get_notifications(author, session, limit, offset) -> List[Notification]:
def get_notifications(author_id, session, limit, offset) -> List[Notification]:
NotificationSeenAlias = aliased(NotificationSeen)
query = select(
NotificationMessage,
NotificationSeenAlias.viewer.label("seen")
).outerjoin(
NotificationSeen,
and_(NotificationSeen.viewer == author.id, NotificationSeen.notification == NotificationMessage.id),
).group_by(NotificationSeen.notification)
query = (
select(NotificationMessage, NotificationSeenAlias.viewer.label("seen"))
.outerjoin(
NotificationSeen,
and_(NotificationSeen.viewer == author_id, NotificationSeen.notification == NotificationMessage.id),
)
.group_by(NotificationSeen.notification)
)
if limit:
query = query.limit(limit)
if offset:
@ -69,26 +70,21 @@ class Query:
@strawberry.field
@login_required
async def load_notifications(self, info, limit: int = 50, offset: int = 0) -> NotificationsResult:
user_id = info.context["user_id"]
author_id = info.context.get("author_id")
with local_session() as session:
try:
author = session.query(Author).filter(Author.user == user_id).first()
if author:
notifications = get_notifications(author, session, limit, offset)
if author_id:
notifications = get_notifications(author_id, session, limit, offset)
if notifications and len(notifications) > 0:
nr = NotificationsResult(
notifications=notifications,
unread=sum(1 for n in notifications if author.id in n.seen),
total=session.query(NotificationMessage).count()
unread=sum(1 for n in notifications if author_id in n.seen),
total=session.query(NotificationMessage).count(),
)
return nr
except Exception as ex:
print(f"[resolvers.schema] {ex}")
return NotificationsResult(
notifications=[],
total=0,
unread=0
)
return NotificationsResult(notifications=[], total=0, unread=0)
@strawberry.type
@ -96,34 +92,31 @@ class Mutation:
@strawberry.mutation
@login_required
async def mark_notification_as_read(self, info, notification_id: int) -> NotificationSeenResult:
user_id = info.context["user_id"]
with local_session() as session:
try:
author = session.query(Author).filter(Author.user == user_id).first()
if author:
ns = NotificationSeen(notification=notification_id, viewer=author.id)
author_id = info.context.get("author_id")
if author_id:
with local_session() as session:
try:
ns = NotificationSeen(notification=notification_id, viewer=author_id)
session.add(ns)
session.commit()
except SQLAlchemyError as e:
session.rollback()
print(f"[mark_notification_as_read] error: {str(e)}")
nsr = NotificationSeenResult(error="cant mark as read")
return nsr
except SQLAlchemyError as e:
session.rollback()
print(f"[mark_notification_as_read] error: {str(e)}")
nsr = NotificationSeenResult(error="cant mark as read")
return nsr
return NotificationSeenResult()
@strawberry.mutation
@login_required
async def mark_all_notifications_as_read(self, info) -> NotificationSeenResult:
user_id = info.context["user_id"]
with local_session() as session:
author_id = info.context.get("author_id")
if author_id:
try:
author = session.query(Author).filter(Author.user == user_id).first()
if author:
nslist = get_notifications(author, session, None, None)
with local_session() as session:
nslist = get_notifications(author_id, session, None, None)
for n in nslist:
if author.id not in n.seen:
ns = NotificationSeen(viewer=author.id, notification=n.id)
if author_id not in n.seen:
ns = NotificationSeen(viewer=author_id, notification=n.id)
session.add(ns)
session.commit()
except SQLAlchemyError as e:

View File

@ -1,5 +1,8 @@
from functools import wraps
from httpx import AsyncClient, HTTPError
from httpx import AsyncClient
from orm.author import Author
from services.db import local_session
from settings import AUTH_URL
@ -42,23 +45,14 @@ def login_required(f):
raise Exception("You are not logged in")
else:
# Добавляем author_id в контекст
context["user_id"] = user_id
with local_session() as session:
author = session.query(Author).filter(Author.user == user_id).first()
if author:
context["author_id"] = author.id
if user_id:
context["user_id"] = user_id
# Если пользователь аутентифицирован, выполняем резолвер
return await f(*args, **kwargs)
return decorated_function
def auth_request(f):
@wraps(f)
async def decorated_function(*args, **kwargs):
req = args[0]
is_authenticated, user_id = await check_auth(req)
if not is_authenticated:
raise HTTPError("please, login first")
else:
req["user_id"] = user_id
return await f(*args, **kwargs)
return decorated_function

View File

@ -1,9 +1,5 @@
from typing import List
from typing import List, Any
from httpx import AsyncClient
from orm.author import Author
from orm.shout import Shout
from settings import API_BASE
headers = {"Content-Type": "application/json"}
@ -27,22 +23,7 @@ async def _request_endpoint(query_name, body):
traceback.print_exc()
async def get_author(author_id) -> Author:
query_name = "get_author"
query_type = "query"
operation = "GetAuthor"
query_fields = "id slug pic name"
gql = {
"query": query_type + " " + operation + " { " + query_name + " { " + query_fields + "} " + " }",
"operationName": operation,
"variables": None,
}
return await _request_endpoint(query_name, gql)
async def get_followed_shouts(author_id: int) -> List[Shout]:
async def get_followed_shouts(author_id: int) -> List[Any]:
query_name = "load_shouts_followed"
query_type = "query"
operation = "GetFollowedShouts"
@ -55,7 +36,7 @@ async def get_followed_shouts(author_id: int) -> List[Shout]:
body = {
"query": query,
"operationName": operation,
"variables": {"author_id": author_id, "limit": 1000, "offset": 0}, # FIXME: too big
"variables": {"author_id": author_id, "limit": 1000, "offset": 0}, # FIXME: too big limit
}
return await _request_endpoint(query_name, body)