Merge branch 'master' of gitlab.prodcontest.ru:team-15/project

This commit is contained in:
ITQ
2025-03-01 00:30:45 +03:00
21 changed files with 562 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
import datetime
from typing import Optional, Any
import jwt
from django.conf import settings
from django.http import HttpRequest
from ninja.security import HttpBearer
from apps.users.models import User
class BearerAuth(HttpBearer):
def authenticate(self, request: HttpRequest, token: str) -> Optional[Any]:
data = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
if data["exp"] < datetime.datetime.now().timestamp():
return None
user = User.objects.get(id=data["id"])
return user
@staticmethod
def generate_jwt(user: User) -> str:
data = {
"exp": (datetime.datetime.now() + datetime.timedelta(days=365)).timestamp(),
"id": str(user.id)
}
return jwt.encode(data, settings.SECRET_KEY, algorithm="HS256")
+4
View File
@@ -17,6 +17,10 @@ router.add_router(
"ping",
ping_router,
)
router.add_router(
"",
users_router,
)
for exception, handler in handlers.exception_handlers:
+26
View File
@@ -0,0 +1,26 @@
from ninja import Schema, ModelSchema
from apps.users.models import User
class TokenSchema(Schema):
token: str
class RegisterSchema(ModelSchema):
class Meta:
model = User
fields = ["email", "username", "password"]
class LoginSchema(ModelSchema):
class Meta:
model = User
fields = ["email", "password"]
class UserSchema(ModelSchema):
class Meta:
model = User
fields = ["email", "username"]
+56
View File
@@ -0,0 +1,56 @@
from ninja import Router
from ninja.errors import AuthenticationError
from api.v1.users.schemas import LoginSchema, RegisterSchema, TokenSchema, UserSchema
from api.v1.auth import BearerAuth
from api.v1.schemas import BadRequestError, ForbiddenError, NotFoundError
from apps.users.models import User
router = Router(tags=["users"])
@router.post(
path="/sign-up",
response={
201: TokenSchema,
400: BadRequestError,
}
)
def sign_up(request, data: RegisterSchema):
user = User(**data.dict())
user.full_clean()
user.save()
token = BearerAuth.generate_jwt(user)
return 201, TokenSchema(token=token)
@router.post(
path="/sign-in",
response={
200: TokenSchema,
400: BadRequestError,
401: ForbiddenError,
}
)
def sign_in(request, data: LoginSchema):
user = User.objects.filter(email=data.email).first()
if not user:
raise AuthenticationError
if user.password != data.password:
raise AuthenticationError
token = BearerAuth.generate_jwt(user)
return 200, TokenSchema(token=token)
@router.get(
path="/user/{user_id}",
response={
200: UserSchema,
400: BadRequestError,
404: NotFoundError,
}
)
def get_user(request, user_id: str):
...
@@ -0,0 +1,7 @@
from django.apps import AppConfig
class CompetitionsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.competitions'
label = 'competitions'
@@ -0,0 +1,28 @@
from django.db import models
from apps.core.models import BaseModel
class CompetitionType(models.TextChoices):
SOLO = "solo"
class CompetitionPartipicationType(models.TextChoices):
EDU = "edu"
COMPETITIVE = "competitive"
class Competition(BaseModel):
title = models.CharField(max_length=100, verbose_name="Название")
description = models.TextField(verbose_name="Описание")
image_url = models.FileField(verbose_name="Изображение соревнования")
due_to = models.DateTimeField(verbose_name="Дедлайн участия")
type = models.CharField(max_length=10, choices=CompetitionType.choices,
verbose_name="Тип участия")
participation_type = models.CharField(max_length=10, choices=CompetitionPartipicationType.choices,
verbose_name="Тип соревнования")
class Meta:
verbose_name = "соревнование"
verbose_name_plural = "соревнования"
+9
View File
@@ -0,0 +1,9 @@
from django.apps import AppConfig
class UsersConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.users'
label = 'users'
@@ -0,0 +1,28 @@
# Generated by Django 5.1.6 on 2025-02-28 20:46
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='User',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('email', models.EmailField(max_length=254, unique=True, verbose_name='Почта')),
('username', models.SlugField(unique=True, verbose_name='Юзернейм')),
('password', models.TextField(verbose_name='Пароль')),
],
options={
'verbose_name': 'пользователь',
'verbose_name_plural': 'пользователи',
},
),
]
+16
View File
@@ -0,0 +1,16 @@
from django.db import models
from apps.core.models import BaseModel
class User(BaseModel):
email = models.EmailField(unique=True, verbose_name="Почта")
username = models.SlugField(unique=True, verbose_name="Юзернейм")
password = models.TextField(verbose_name="Пароль")
def __str__(self):
return self.username
class Meta:
verbose_name = "пользователь"
verbose_name_plural = "пользователи"
+1
View File
@@ -443,6 +443,7 @@ INSTALLED_APPS = [
"minio_storage",
# Internal apps
"apps.core",
"apps.users",
]
# GUID