This commit is contained in:
69
services/auth.py
Normal file
69
services/auth.py
Normal file
@@ -0,0 +1,69 @@
|
||||
from functools import wraps
|
||||
from httpx import AsyncClient, HTTPError
|
||||
from settings import AUTH_URL
|
||||
|
||||
|
||||
async def check_auth(req):
|
||||
token = req.headers.get("Authorization")
|
||||
print(f"[services.auth] checking auth token: {token}")
|
||||
|
||||
query_name = "session"
|
||||
query_type = "query"
|
||||
operation = "GetUserId"
|
||||
|
||||
headers = {"Authorization": "Bearer " + token, "Content-Type": "application/json"}
|
||||
|
||||
gql = {
|
||||
"query": query_type + " " + operation + " { " + query_name + " { user { id } } " + " }",
|
||||
"operationName": operation,
|
||||
"variables": None,
|
||||
}
|
||||
|
||||
async with AsyncClient(timeout=30.0) as client:
|
||||
response = await client.post(AUTH_URL, headers=headers, json=gql)
|
||||
print(f"[services.auth] response: {response.status_code} {response.text}")
|
||||
if response.status_code != 200:
|
||||
return False, None
|
||||
r = response.json()
|
||||
try:
|
||||
user_id = (
|
||||
r.get("data", {}).get(query_name, {}).get("user", {}).get("id", None)
|
||||
)
|
||||
is_authenticated = user_id is not None
|
||||
return is_authenticated, user_id
|
||||
except Exception as e:
|
||||
print(f"{e}: {r}")
|
||||
return False, None
|
||||
|
||||
|
||||
def login_required(f):
|
||||
@wraps(f)
|
||||
async def decorated_function(*args, **kwargs):
|
||||
info = args[1]
|
||||
context = info.context
|
||||
req = context.get("request")
|
||||
is_authenticated, user_id = await check_auth(req)
|
||||
if not is_authenticated:
|
||||
raise Exception("You are not logged in")
|
||||
else:
|
||||
# Добавляем author_id в контекст
|
||||
context["author_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["author_id"] = user_id
|
||||
return await f(*args, **kwargs)
|
||||
|
||||
return decorated_function
|
@@ -1,12 +1,12 @@
|
||||
import json
|
||||
from services.redis import redis
|
||||
from services.rediscache import redis
|
||||
|
||||
|
||||
async def notify_reaction(reaction):
|
||||
async def notify_reaction(reaction, action: str = "create"):
|
||||
channel_name = "reaction"
|
||||
data = {
|
||||
"payload": reaction,
|
||||
"action": "create"
|
||||
"action": action
|
||||
}
|
||||
try:
|
||||
await redis.publish(channel_name, json.dumps(data))
|
||||
@@ -14,11 +14,11 @@ async def notify_reaction(reaction):
|
||||
print(f"Failed to publish to channel {channel_name}: {e}")
|
||||
|
||||
|
||||
async def notify_shout(shout):
|
||||
async def notify_shout(shout, action: str = "create"):
|
||||
channel_name = "shout"
|
||||
data = {
|
||||
"payload": shout,
|
||||
"action": "create"
|
||||
"action": action
|
||||
}
|
||||
try:
|
||||
await redis.publish(channel_name, json.dumps(data))
|
||||
@@ -26,7 +26,7 @@ async def notify_shout(shout):
|
||||
print(f"Failed to publish to channel {channel_name}: {e}")
|
||||
|
||||
|
||||
async def notify_follower(follower: dict, author_id: int):
|
||||
async def notify_follower(follower: dict, author_id: int, action: str = "follow"):
|
||||
fields = follower.keys()
|
||||
for k in fields:
|
||||
if k not in ["id", "name", "slug", "userpic"]:
|
||||
@@ -34,7 +34,7 @@ async def notify_follower(follower: dict, author_id: int):
|
||||
channel_name = f"follower:{author_id}"
|
||||
data = {
|
||||
"payload": follower,
|
||||
"action": "follow",
|
||||
"action": action
|
||||
}
|
||||
try:
|
||||
await redis.publish(channel_name, json.dumps(data))
|
||||
|
@@ -1,6 +1,6 @@
|
||||
import asyncio
|
||||
import json
|
||||
from services.redis import redis
|
||||
from services.rediscache import redis
|
||||
from orm.shout import Shout
|
||||
from resolvers.load import load_shouts_by
|
||||
|
||||
|
67
services/server.py
Normal file
67
services/server.py
Normal file
@@ -0,0 +1,67 @@
|
||||
import sys
|
||||
import uvicorn
|
||||
from uvicorn.main import logger
|
||||
|
||||
from settings import PORT
|
||||
|
||||
log_settings = {
|
||||
"version": 1,
|
||||
"disable_existing_loggers": True,
|
||||
"formatters": {
|
||||
"default": {
|
||||
"()": "uvicorn.logging.DefaultFormatter",
|
||||
"fmt": "%(levelprefix)s %(message)s",
|
||||
"use_colors": None,
|
||||
},
|
||||
"access": {
|
||||
"()": "uvicorn.logging.AccessFormatter",
|
||||
"fmt": '%(levelprefix)s %(client_addr)s - "%(request_line)s" %(status_code)s',
|
||||
},
|
||||
},
|
||||
"handlers": {
|
||||
"default": {
|
||||
"formatter": "default",
|
||||
"class": "logging.StreamHandler",
|
||||
"stream": "ext://sys.stderr",
|
||||
},
|
||||
"access": {
|
||||
"formatter": "access",
|
||||
"class": "logging.StreamHandler",
|
||||
"stream": "ext://sys.stdout",
|
||||
},
|
||||
},
|
||||
"loggers": {
|
||||
"uvicorn": {"handlers": ["default"], "level": "INFO"},
|
||||
"uvicorn.error": {"level": "INFO", "handlers": ["default"], "propagate": True},
|
||||
"uvicorn.access": {"handlers": ["access"], "level": "INFO", "propagate": False},
|
||||
},
|
||||
}
|
||||
|
||||
local_headers = [
|
||||
("Access-Control-Allow-Methods", "GET, POST, OPTIONS, HEAD"),
|
||||
("Access-Control-Allow-Origin", "https://localhost:3000"),
|
||||
(
|
||||
"Access-Control-Allow-Headers",
|
||||
"DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization",
|
||||
),
|
||||
("Access-Control-Expose-Headers", "Content-Length,Content-Range"),
|
||||
("Access-Control-Allow-Credentials", "true"),
|
||||
]
|
||||
|
||||
|
||||
def exception_handler(_et, exc, _tb):
|
||||
logger.error(..., exc_info=(type(exc), exc, exc.__traceback__))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
sys.excepthook = exception_handler
|
||||
if "dev" in sys.argv:
|
||||
import os
|
||||
os.environ.set("MODE", "development")
|
||||
uvicorn.run(
|
||||
"main:app",
|
||||
host="0.0.0.0",
|
||||
port=PORT,
|
||||
proxy_headers=True,
|
||||
server_header=True
|
||||
)
|
14
services/settings.py
Normal file
14
services/settings.py
Normal file
@@ -0,0 +1,14 @@
|
||||
from os import environ
|
||||
|
||||
PORT = 8080
|
||||
DB_URL = (
|
||||
environ.get("DATABASE_URL")
|
||||
or environ.get("DB_URL")
|
||||
or "postgresql://postgres@localhost:5432/discoursio"
|
||||
)
|
||||
REDIS_URL = environ.get("REDIS_URL") or "redis://127.0.0.1"
|
||||
API_BASE = environ.get("API_BASE") or ""
|
||||
AUTH_URL = environ.get("AUTH_URL") or ""
|
||||
MODE = environ.get("MODE") or "production"
|
||||
SENTRY_DSN = environ.get("SENTRY_DSN")
|
||||
DEV_SERVER_PID_FILE_NAME = "dev-server.pid"
|
@@ -1,6 +1,4 @@
|
||||
import json
|
||||
|
||||
from services.redis import redis
|
||||
from services.rediscache import redis
|
||||
|
||||
|
||||
async def get_unread_counter(chat_id: str, author_id: int) -> int:
|
||||
|
Reference in New Issue
Block a user