Merge branch 'main' of github.com:Discours/discours-backend into viewed
This commit is contained in:
commit
3f51515c5c
|
@ -7,7 +7,7 @@ Tech stack:
|
||||||
- ariadne
|
- ariadne
|
||||||
- starlette
|
- starlette
|
||||||
|
|
||||||
# Local development
|
# Local development
|
||||||
|
|
||||||
Install deps first
|
Install deps first
|
||||||
|
|
||||||
|
@ -40,5 +40,5 @@ python3 server.py dev
|
||||||
|
|
||||||
# How to do an authorized request
|
# How to do an authorized request
|
||||||
|
|
||||||
Put the header 'Auth' with token from signInQuery or registerQuery.
|
Put the header 'Authorization' with token from signInQuery or registerQuery.
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ from auth.jwtcodec import JWTCodec
|
||||||
from auth.tokenstorage import TokenStorage
|
from auth.tokenstorage import TokenStorage
|
||||||
from base.exceptions import InvalidToken
|
from base.exceptions import InvalidToken
|
||||||
from services.auth.users import UserStorage
|
from services.auth.users import UserStorage
|
||||||
|
from settings import SESSION_TOKEN_HEADER
|
||||||
|
|
||||||
|
|
||||||
class SessionToken:
|
class SessionToken:
|
||||||
|
@ -48,10 +49,12 @@ class JWTAuthenticate(AuthenticationBackend):
|
||||||
async def authenticate(
|
async def authenticate(
|
||||||
self, request: HTTPConnection
|
self, request: HTTPConnection
|
||||||
) -> Optional[Tuple[AuthCredentials, AuthUser]]:
|
) -> Optional[Tuple[AuthCredentials, AuthUser]]:
|
||||||
if "Auth" not in request.headers:
|
|
||||||
|
if SESSION_TOKEN_HEADER not in request.headers:
|
||||||
return AuthCredentials(scopes=[]), AuthUser(user_id=None)
|
return AuthCredentials(scopes=[]), AuthUser(user_id=None)
|
||||||
|
|
||||||
token = request.headers.get("Auth", "")
|
token = request.headers.get(SESSION_TOKEN_HEADER, "")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
payload = await SessionToken.verify(token)
|
payload = await SessionToken.verify(token)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
|
|
|
@ -25,6 +25,8 @@ async def send_auth_email(user, token, lang="ru"):
|
||||||
"h:X-Mailgun-Variables": "{ \"token\": \"%s\" }" % token
|
"h:X-Mailgun-Variables": "{ \"token\": \"%s\" }" % token
|
||||||
}
|
}
|
||||||
print('[auth.email] payload: %r' % payload)
|
print('[auth.email] payload: %r' % payload)
|
||||||
|
# debug
|
||||||
|
# print('http://localhost:3000/?modal=auth&mode=confirm-email&token=%s' % token)
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
api_url,
|
api_url,
|
||||||
auth=("api", MAILGUN_API_KEY),
|
auth=("api", MAILGUN_API_KEY),
|
||||||
|
|
|
@ -119,7 +119,7 @@ server {
|
||||||
#
|
#
|
||||||
# Custom headers and headers various browsers *should* be OK with but aren't
|
# Custom headers and headers various browsers *should* be OK with but aren't
|
||||||
#
|
#
|
||||||
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Auth';
|
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization';
|
||||||
add_header 'Access-Control-Allow-Credentials' 'true';
|
add_header 'Access-Control-Allow-Credentials' 'true';
|
||||||
#
|
#
|
||||||
# Tell client that this pre-flight info is valid for 20 days
|
# Tell client that this pre-flight info is valid for 20 days
|
||||||
|
@ -133,7 +133,7 @@ server {
|
||||||
if ($request_method = 'POST') {
|
if ($request_method = 'POST') {
|
||||||
add_header 'Access-Control-Allow-Origin' '$allow_origin' always;
|
add_header 'Access-Control-Allow-Origin' '$allow_origin' always;
|
||||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
|
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
|
||||||
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Auth' always;
|
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
|
||||||
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
|
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
|
||||||
add_header 'Access-Control-Allow-Credentials' 'true' always;
|
add_header 'Access-Control-Allow-Credentials' 'true' always;
|
||||||
}
|
}
|
||||||
|
@ -141,7 +141,7 @@ server {
|
||||||
if ($request_method = 'GET') {
|
if ($request_method = 'GET') {
|
||||||
add_header 'Access-Control-Allow-Origin' '$allow_origin' always;
|
add_header 'Access-Control-Allow-Origin' '$allow_origin' always;
|
||||||
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
|
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always;
|
||||||
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Auth' always;
|
add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Authorization' always;
|
||||||
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
|
add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range' always;
|
||||||
add_header 'Access-Control-Allow-Credentials' 'true' always;
|
add_header 'Access-Control-Allow-Credentials' 'true' always;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ from base.orm import local_session
|
||||||
from base.resolvers import mutation, query
|
from base.resolvers import mutation, query
|
||||||
from orm import Role, User
|
from orm import Role, User
|
||||||
from resolvers.zine.profile import user_subscriptions
|
from resolvers.zine.profile import user_subscriptions
|
||||||
|
from settings import SESSION_TOKEN_HEADER
|
||||||
|
|
||||||
|
|
||||||
@mutation.field("refreshSession")
|
@mutation.field("refreshSession")
|
||||||
|
@ -143,7 +144,6 @@ async def auth_send_link(_, _info, email, lang="ru"):
|
||||||
|
|
||||||
@query.field("signIn")
|
@query.field("signIn")
|
||||||
async def login(_, info, email: str, password: str = "", lang: str = "ru"):
|
async def login(_, info, email: str, password: str = "", lang: str = "ru"):
|
||||||
|
|
||||||
with local_session() as session:
|
with local_session() as session:
|
||||||
orm_user = session.query(User).filter(User.email == email).first()
|
orm_user = session.query(User).filter(User.email == email).first()
|
||||||
if orm_user is None:
|
if orm_user is None:
|
||||||
|
@ -182,7 +182,7 @@ async def login(_, info, email: str, password: str = "", lang: str = "ru"):
|
||||||
@query.field("signOut")
|
@query.field("signOut")
|
||||||
@login_required
|
@login_required
|
||||||
async def sign_out(_, info: GraphQLResolveInfo):
|
async def sign_out(_, info: GraphQLResolveInfo):
|
||||||
token = info.context["request"].headers.get("Auth", "")
|
token = info.context["request"].headers.get(SESSION_TOKEN_HEADER, "")
|
||||||
status = await TokenStorage.revoke(token)
|
status = await TokenStorage.revoke(token)
|
||||||
return status
|
return status
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,8 @@ from services.zine.shoutauthor import ShoutAuthorStorage
|
||||||
from services.stat.reacted import ReactedStorage
|
from services.stat.reacted import ReactedStorage
|
||||||
|
|
||||||
|
|
||||||
def apply_filters(filters, q, user=None):
|
def apply_filters(q, filters, user=None):
|
||||||
|
filters = {} if filters is None else filters
|
||||||
if filters.get("reacted") and user:
|
if filters.get("reacted") and user:
|
||||||
q.join(Reaction, Reaction.createdBy == user.slug)
|
q.join(Reaction, Reaction.createdBy == user.slug)
|
||||||
if filters.get("visibility"):
|
if filters.get("visibility"):
|
||||||
|
@ -106,7 +107,7 @@ async def load_shouts_by(_, info, options):
|
||||||
Shout.deletedAt.is_(None)
|
Shout.deletedAt.is_(None)
|
||||||
)
|
)
|
||||||
user = info.context["request"].user
|
user = info.context["request"].user
|
||||||
q = apply_filters(options.get("filters"), q, user)
|
q = apply_filters(q, options.get("filters"), user)
|
||||||
|
|
||||||
order_by = extract_order(options.get("order_by"), q)
|
order_by = extract_order(options.get("order_by"), q)
|
||||||
|
|
||||||
|
|
|
@ -59,7 +59,7 @@ if __name__ == "__main__":
|
||||||
("Access-Control-Allow-Origin", "http://localhost:3000"),
|
("Access-Control-Allow-Origin", "http://localhost:3000"),
|
||||||
(
|
(
|
||||||
"Access-Control-Allow-Headers",
|
"Access-Control-Allow-Headers",
|
||||||
"DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,Auth",
|
"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-Expose-Headers", "Content-Length,Content-Range"),
|
||||||
("Access-Control-Allow-Credentials", "true"),
|
("Access-Control-Allow-Credentials", "true"),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import asyncio
|
import asyncio
|
||||||
from sqlalchemy.orm import selectinload
|
from sqlalchemy.orm import selectinload
|
||||||
from orm.user import User
|
from orm.user import User
|
||||||
|
from base.orm import local_session
|
||||||
|
|
||||||
|
|
||||||
class UserStorage:
|
class UserStorage:
|
||||||
|
@ -20,9 +21,15 @@ class UserStorage:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get_user(id):
|
async def get_user(id):
|
||||||
self = UserStorage
|
with local_session() as session:
|
||||||
async with self.lock:
|
user = (
|
||||||
return self.users.get(id)
|
session.query(User)
|
||||||
|
.options(selectinload(User.roles), selectinload(User.ratings))
|
||||||
|
.filter(User.id == id)
|
||||||
|
.one()
|
||||||
|
)
|
||||||
|
|
||||||
|
return user
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get_all_users():
|
async def get_all_users():
|
||||||
|
|
|
@ -36,7 +36,8 @@ class ReactedStorage:
|
||||||
@staticmethod
|
@staticmethod
|
||||||
async def get_shout_stat(slug):
|
async def get_shout_stat(slug):
|
||||||
return {
|
return {
|
||||||
"viewed": await ViewedStorage.get_shout(slug),
|
# TODO
|
||||||
|
"viewed": 0, # await ViewedStorage.get_shout(slug),
|
||||||
"reacted": len(await ReactedStorage.get_shout(slug)),
|
"reacted": len(await ReactedStorage.get_shout(slug)),
|
||||||
"commented": len(await ReactedStorage.get_comments(slug)),
|
"commented": len(await ReactedStorage.get_comments(slug)),
|
||||||
"rating": await ReactedStorage.get_rating(slug),
|
"rating": await ReactedStorage.get_rating(slug),
|
||||||
|
|
|
@ -24,3 +24,4 @@ for provider in OAUTH_PROVIDERS:
|
||||||
}
|
}
|
||||||
|
|
||||||
SHOUTS_REPO = "content"
|
SHOUTS_REPO = "content"
|
||||||
|
SESSION_TOKEN_HEADER = "Authorization"
|
||||||
|
|
Loading…
Reference in New Issue
Block a user