This commit is contained in:
parent
693d8b6aee
commit
7fa6fcf2d7
8
main.py
8
main.py
|
@ -1,18 +1,18 @@
|
||||||
import os
|
|
||||||
import asyncio
|
import asyncio
|
||||||
|
import os
|
||||||
from os.path import exists
|
from os.path import exists
|
||||||
|
|
||||||
from sentry_sdk.integrations.aiohttp import AioHttpIntegration
|
from sentry_sdk.integrations.aiohttp import AioHttpIntegration
|
||||||
from sentry_sdk.integrations.redis import RedisIntegration
|
from sentry_sdk.integrations.redis import RedisIntegration
|
||||||
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
|
from sentry_sdk.integrations.sqlalchemy import SqlalchemyIntegration
|
||||||
from sentry_sdk.integrations.strawberry import StrawberryIntegration
|
from sentry_sdk.integrations.strawberry import StrawberryIntegration
|
||||||
from strawberry.asgi import GraphQL
|
|
||||||
from starlette.applications import Starlette
|
from starlette.applications import Starlette
|
||||||
|
from strawberry.asgi import GraphQL
|
||||||
|
|
||||||
from services.rediscache import redis
|
|
||||||
from resolvers.listener import reactions_worker
|
from resolvers.listener import reactions_worker
|
||||||
from resolvers.schema import schema
|
from resolvers.schema import schema
|
||||||
from settings import DEV_SERVER_PID_FILE_NAME, SENTRY_DSN, MODE
|
from services.rediscache import redis
|
||||||
|
from settings import DEV_SERVER_PID_FILE_NAME, MODE, SENTRY_DSN
|
||||||
|
|
||||||
|
|
||||||
async def start_up():
|
async def start_up():
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
from enum import Enum as Enumeration
|
|
||||||
import time
|
import time
|
||||||
from sqlalchemy import Column, Enum, Integer, ForeignKey, JSON as JSONType
|
from enum import Enum as Enumeration
|
||||||
|
|
||||||
|
from sqlalchemy import JSON as JSONType
|
||||||
|
from sqlalchemy import Column, Enum, ForeignKey, Integer
|
||||||
from sqlalchemy.orm import relationship
|
from sqlalchemy.orm import relationship
|
||||||
|
|
||||||
from orm.author import Author
|
from orm.author import Author
|
||||||
|
|
|
@ -13,18 +13,20 @@ python = "^3.12"
|
||||||
SQLAlchemy = "^2.0.22"
|
SQLAlchemy = "^2.0.22"
|
||||||
psycopg2-binary = "^2.9.9"
|
psycopg2-binary = "^2.9.9"
|
||||||
redis = {extras = ["hiredis"], version = "^5.0.1"}
|
redis = {extras = ["hiredis"], version = "^5.0.1"}
|
||||||
uvicorn = "^0.24.0.post1"
|
uvicorn = "^0.24.0"
|
||||||
strawberry-graphql = {extras = ["asgi", "debug-server"], version = "^0.215.1" }
|
strawberry-graphql = {extras = ["asgi", "debug-server"], version = "^0.216.1" }
|
||||||
|
strawberry-sqlalchemy-mapper = "^0.4.0"
|
||||||
sentry-sdk = "^1.37.1"
|
sentry-sdk = "^1.37.1"
|
||||||
strawberry-sqlalchemy-mapper = "^0.3.1"
|
|
||||||
aiohttp = "^3.9.1"
|
aiohttp = "^3.9.1"
|
||||||
|
|
||||||
[tool.poetry.dev-dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
|
setuptools = "^69.0.2"
|
||||||
pytest = "^7.4.2"
|
pytest = "^7.4.2"
|
||||||
black = { version = "^23.12.0", python = ">=3.12" }
|
black = { version = "^23.12.0", python = ">=3.12" }
|
||||||
ruff = { version = "^0.1.8", python = ">=3.12" }
|
ruff = { version = "^0.1.8", python = ">=3.12" }
|
||||||
mypy = { version = "^1.7", python = ">=3.12" }
|
mypy = { version = "^1.7", python = ">=3.12" }
|
||||||
setuptools = "^69.0.2"
|
isort = "^5.13.2"
|
||||||
|
pyright = "^1.1.341"
|
||||||
|
|
||||||
[tool.black]
|
[tool.black]
|
||||||
line-length = 120
|
line-length = 120
|
||||||
|
@ -58,18 +60,33 @@ use_parentheses = true
|
||||||
ensure_newline_before_comments = true
|
ensure_newline_before_comments = true
|
||||||
line_length = 120
|
line_length = 120
|
||||||
|
|
||||||
|
|
||||||
[tool.pyright]
|
[tool.pyright]
|
||||||
venvPath = "."
|
venvPath = "."
|
||||||
venv = ".venv"
|
venv = ".venv"
|
||||||
include = ["."]
|
include = ["."]
|
||||||
exclude = ["**/__pycache__"]
|
useLibraryCodeForTypes = true
|
||||||
ignore = []
|
disableLanguageServices = false
|
||||||
defineConstant = { DEBUG = true }
|
disableOrganizeImports = false
|
||||||
reportMissingImports = true
|
reportMissingImports = false
|
||||||
reportMissingTypeStubs = false
|
reportMissingModuleSource = "warning"
|
||||||
pythonVersion = "312"
|
reportImportCycles = "warning"
|
||||||
pythonPlatform = "Linux"
|
maxMemoryForLargeFile = 4096
|
||||||
executionEnvironments = []
|
pythonVersion = "3.12"
|
||||||
|
autoImportCompletions = true
|
||||||
|
useVirtualEnv = true
|
||||||
|
typeCheckingMode = "basic"
|
||||||
|
disableJediCompletion = false
|
||||||
|
disableCompletion = false
|
||||||
|
disableSnippetCompletion = false
|
||||||
|
disableGoToDefinition = false
|
||||||
|
disableRenaming = false
|
||||||
|
disableSignatureHelp = false
|
||||||
|
diagnostics = true
|
||||||
|
logLevel = "Information"
|
||||||
|
pluginSearchPaths = []
|
||||||
|
typings = {}
|
||||||
|
mergeTypeStubPackages = false
|
||||||
|
|
||||||
[tool.mypy]
|
[tool.mypy]
|
||||||
python_version = "3.12"
|
python_version = "3.12"
|
||||||
|
|
|
@ -1,15 +1,18 @@
|
||||||
|
import logging
|
||||||
from typing import List
|
from typing import List
|
||||||
from sqlalchemy import and_, select
|
|
||||||
from sqlalchemy.orm import aliased
|
|
||||||
from sqlalchemy.exc import SQLAlchemyError
|
|
||||||
|
|
||||||
from orm.notification import Notification as NotificationMessage, NotificationSeen
|
import strawberry
|
||||||
|
from sqlalchemy import and_, select
|
||||||
|
from sqlalchemy.exc import SQLAlchemyError
|
||||||
|
from sqlalchemy.orm import aliased
|
||||||
|
from strawberry.schema.config import StrawberryConfig
|
||||||
|
from strawberry_sqlalchemy_mapper import StrawberrySQLAlchemyMapper
|
||||||
|
|
||||||
|
from orm.author import Author
|
||||||
|
from orm.notification import Notification as NotificationMessage
|
||||||
|
from orm.notification import NotificationSeen
|
||||||
from services.auth import LoginRequiredMiddleware
|
from services.auth import LoginRequiredMiddleware
|
||||||
from services.db import local_session
|
from services.db import local_session
|
||||||
import strawberry
|
|
||||||
from strawberry_sqlalchemy_mapper import StrawberrySQLAlchemyMapper
|
|
||||||
from strawberry.schema.config import StrawberryConfig
|
|
||||||
import logging
|
|
||||||
|
|
||||||
strawberry_sqlalchemy_mapper = StrawberrySQLAlchemyMapper()
|
strawberry_sqlalchemy_mapper = StrawberrySQLAlchemyMapper()
|
||||||
|
|
||||||
|
@ -39,7 +42,7 @@ class NotificationsResult:
|
||||||
total: int
|
total: int
|
||||||
|
|
||||||
|
|
||||||
def get_notifications(author_id: int, session, limit: int, offset: int) -> List[Notification]:
|
def get_notifications(author_id: int, session, after: int, limit: int = 9999, offset: int = 0) -> List[Notification]:
|
||||||
NotificationSeenAlias = aliased(NotificationSeen)
|
NotificationSeenAlias = aliased(NotificationSeen)
|
||||||
query = (
|
query = (
|
||||||
select(NotificationMessage, NotificationSeenAlias.viewer.label("seen"))
|
select(NotificationMessage, NotificationSeenAlias.viewer.label("seen"))
|
||||||
|
@ -47,6 +50,7 @@ def get_notifications(author_id: int, session, limit: int, offset: int) -> List[
|
||||||
NotificationSeen,
|
NotificationSeen,
|
||||||
and_(NotificationSeen.viewer == author_id, NotificationSeen.notification == NotificationMessage.id),
|
and_(NotificationSeen.viewer == author_id, NotificationSeen.notification == NotificationMessage.id),
|
||||||
)
|
)
|
||||||
|
.filter(NotificationMessage.created_at > after)
|
||||||
.group_by(NotificationSeen.notification)
|
.group_by(NotificationSeen.notification)
|
||||||
)
|
)
|
||||||
if limit:
|
if limit:
|
||||||
|
@ -77,7 +81,9 @@ class Query:
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
try:
|
try:
|
||||||
if author_id:
|
if author_id:
|
||||||
notifications = get_notifications(author_id, session, limit, offset)
|
author = session.query(Author).filter(Author.id == author_id).first()
|
||||||
|
after = author.last_seen
|
||||||
|
notifications = get_notifications(author_id, session, after, limit, offset)
|
||||||
if notifications and len(notifications) > 0:
|
if notifications and len(notifications) > 0:
|
||||||
nr = NotificationsResult(
|
nr = NotificationsResult(
|
||||||
notifications=notifications,
|
notifications=notifications,
|
||||||
|
@ -110,15 +116,15 @@ class Mutation:
|
||||||
f"[mark_notification_as_read] Ошибка при обновлении статуса прочтения уведомления: {str(e)}"
|
f"[mark_notification_as_read] Ошибка при обновлении статуса прочтения уведомления: {str(e)}"
|
||||||
)
|
)
|
||||||
return NotificationSeenResult(error="cant mark as read")
|
return NotificationSeenResult(error="cant mark as read")
|
||||||
return NotificationSeenResult()
|
return NotificationSeenResult(error=None)
|
||||||
|
|
||||||
@strawberry.mutation
|
@strawberry.mutation
|
||||||
async def mark_all_notifications_as_read(self, info) -> NotificationSeenResult:
|
async def mark_all_notifications_as_read(self, info) -> NotificationSeenResult:
|
||||||
author_id = info.context.get("author_id")
|
author_id = info.context.get("author_id")
|
||||||
if author_id:
|
if author_id:
|
||||||
try:
|
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
nslist = get_notifications(author_id, session, None, None)
|
try:
|
||||||
|
nslist = get_notifications(author_id, session)
|
||||||
for n in nslist:
|
for n in nslist:
|
||||||
if author_id not in n.seen:
|
if author_id not in n.seen:
|
||||||
ns = NotificationSeen(viewer=author_id, notification=n.id)
|
ns = NotificationSeen(viewer=author_id, notification=n.id)
|
||||||
|
@ -127,10 +133,10 @@ class Mutation:
|
||||||
except SQLAlchemyError as e:
|
except SQLAlchemyError as e:
|
||||||
session.rollback()
|
session.rollback()
|
||||||
logger.error(
|
logger.error(
|
||||||
f"[mark_all_notifications_as_read] Ошибка при обновлении статуса прочтения всех уведомлений: {str(e)}"
|
f"[mark_all_notifications_as_read] Ошибка обновления статуса прочтения всех уведомлений: {e}"
|
||||||
)
|
)
|
||||||
return NotificationSeenResult(error="cant mark as read")
|
return NotificationSeenResult(error="cant mark as read")
|
||||||
return NotificationSeenResult()
|
return NotificationSeenResult(error=None)
|
||||||
|
|
||||||
|
|
||||||
schema = strawberry.Schema(
|
schema = strawberry.Schema(
|
||||||
|
|
|
@ -7,7 +7,7 @@ from services.db import local_session
|
||||||
from settings import AUTH_URL
|
from settings import AUTH_URL
|
||||||
|
|
||||||
|
|
||||||
async def check_auth(req) -> (bool, int | None):
|
async def check_auth(req):
|
||||||
token = req.headers.get("Authorization")
|
token = req.headers.get("Authorization")
|
||||||
if token:
|
if token:
|
||||||
# Logging the authentication token
|
# Logging the authentication token
|
||||||
|
@ -62,7 +62,7 @@ async def check_auth(req) -> (bool, int | None):
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
# Handling and logging exceptions during authentication check
|
# Handling and logging exceptions during authentication check
|
||||||
print(f"[services.auth] {e}")
|
print(f"[services.auth] {e}")
|
||||||
raise HTTPUnauthorized(message="Please, login first")
|
raise HTTPUnauthorized(text="Please, login first")
|
||||||
|
|
||||||
return False, None
|
return False, None
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
from typing import List, Any
|
from typing import Any, List
|
||||||
|
|
||||||
import aiohttp
|
import aiohttp
|
||||||
|
|
||||||
from settings import API_BASE
|
from settings import API_BASE
|
||||||
|
|
||||||
headers = {"Content-Type": "application/json"}
|
headers = {"Content-Type": "application/json"}
|
||||||
|
@ -23,7 +25,7 @@ async def _request_endpoint(query_name, body):
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
async def get_followed_shouts(author_id: int) -> List[Any]:
|
async def get_followed_shouts(author_id: int):
|
||||||
query_name = "load_shouts_followed"
|
query_name = "load_shouts_followed"
|
||||||
query_type = "query"
|
query_type = "query"
|
||||||
operation = "GetFollowedShouts"
|
operation = "GetFollowedShouts"
|
||||||
|
|
|
@ -2,6 +2,7 @@ import asyncio
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import redis.asyncio as aredis
|
import redis.asyncio as aredis
|
||||||
|
|
||||||
from settings import REDIS_URL
|
from settings import REDIS_URL
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user