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

This commit is contained in:
ITQ
2025-03-01 01:22:14 +03:00
20 changed files with 170 additions and 52 deletions
+6 -4
View File
@@ -1,5 +1,5 @@
import datetime
from typing import Optional, Any
from typing import Any
import jwt
from django.conf import settings
@@ -10,7 +10,7 @@ from apps.user.models import User
class BearerAuth(HttpBearer):
def authenticate(self, request: HttpRequest, token: str) -> Optional[Any]:
def authenticate(self, request: HttpRequest, token: str) -> Any | None:
data = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
if data["exp"] < datetime.datetime.now().timestamp():
return None
@@ -21,7 +21,9 @@ class BearerAuth(HttpBearer):
@staticmethod
def generate_jwt(user: User) -> str:
data = {
"exp": (datetime.datetime.now() + datetime.timedelta(days=365)).timestamp(),
"id": str(user.id)
"exp": (
datetime.datetime.now() + datetime.timedelta(days=365)
).timestamp(),
"id": str(user.id),
}
return jwt.encode(data, settings.SECRET_KEY, algorithm="HS256")
@@ -0,0 +1,30 @@
from uuid import UUID
from ninja import ModelSchema
from apps.competition.models import Competition
class CompetitionOut(ModelSchema):
id: UUID
class Meta:
model = Competition
fields = "__all__"
class CompetitionListInstanceOut(ModelSchema):
id: UUID
is_participating: bool
completed: bool
class Meta:
model = Competition
fields = (
"id",
"title",
"description",
"start_date",
"end_date",
"image_url",
)
@@ -0,0 +1,39 @@
from http import HTTPStatus as status
from uuid import UUID
from django.http import HttpRequest
from ninja import Router
import api.v1.schemas as global_schemas
from api.v1.auth import BearerAuth
from api.v1.competition import schemas
router = Router(tags=["competition"])
@router.get(
"competition/{competition_id}",
response={
status.OK: schemas.CompetitionOut,
status.BAD_REQUEST: global_schemas.BadRequestError,
status.UNAUTHORIZED: global_schemas.UnauthorizedError,
},
auth=BearerAuth(),
)
def get_competition(
request: HttpRequest, competition_id: UUID
) -> tuple[status, schemas.CompetitionOut]: ...
@router.get(
"competitions",
response={
status.OK: list[schemas.CompetitionListInstanceOut],
status.BAD_REQUEST: global_schemas.BadRequestError,
status.UNAUTHORIZED: global_schemas.UnauthorizedError,
},
auth=BearerAuth(),
)
def list_competitions(
request: HttpRequest, is_participating: bool
) -> tuple[status, list[schemas.CompetitionListInstanceOut]]: ...
+1 -1
View File
@@ -15,4 +15,4 @@ router = Router(tags=["ping"])
},
)
def ping(request: HttpRequest) -> tuple[status, schemas.PingOut]:
return status.OK, schemas.PingOut
return status.OK, schemas.PingOut()
+9 -6
View File
@@ -3,14 +3,14 @@ from functools import partial
from ninja import NinjaAPI
from api.v1 import handlers
from api.v1.auth import BearerAuth
from api.v1.competition.views import router as competition_router
from api.v1.ping.views import router as ping_router
from api.v1.users.views import router as users_router
from api.v1.user.views import router as user_router
router = NinjaAPI(
title="DataRush API",
title="project_name API",
version="1",
description="API docs for DataRush",
description="API docs for project_name",
openapi_url="/docs/openapi.json",
)
@@ -21,8 +21,11 @@ router.add_router(
)
router.add_router(
"",
users_router,
auth=BearerAuth(),
user_router,
)
router.add_router(
"",
competition_router,
)
@@ -1,5 +1,4 @@
from ninja import Schema, ModelSchema
from ninja import ModelSchema, Schema
from apps.user.models import User
@@ -3,7 +3,7 @@ from http import HTTPStatus as status
from ninja import Router
from ninja.errors import AuthenticationError
from api.v1.users.schemas import LoginSchema, RegisterSchema, TokenSchema, UserSchema
from api.v1.user.schemas import LoginSchema, RegisterSchema, TokenSchema, UserSchema
from api.v1.auth import BearerAuth
from api.v1.schemas import BadRequestError, ForbiddenError, NotFoundError
from apps.user.models import User
@@ -0,0 +1,7 @@
from django.apps import AppConfig
class CompetitionsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "apps.competition"
label = "competition"
@@ -0,0 +1,32 @@
# Generated by Django 5.1.6 on 2025-02-28 21:27
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
]
operations = [
migrations.CreateModel(
name='Competition',
fields=[
('id', models.UUIDField(default=uuid.uuid4, editable=False, primary_key=True, serialize=False)),
('title', models.CharField(max_length=100, verbose_name='Название')),
('description', models.TextField(verbose_name='Описание')),
('image_url', models.FileField(blank=True, null=True, upload_to='', verbose_name='Изображение соревнования')),
('end_date', models.DateTimeField(blank=True, null=True, verbose_name='Дедлайн участия')),
('start_date', models.DateTimeField(blank=True, null=True, verbose_name='Дедлайн участия')),
('type', models.CharField(choices=[('solo', 'Solo')], max_length=10, verbose_name='Тип участия')),
('participation_type', models.CharField(choices=[('edu', 'Edu'), ('competitive', 'Competitive')], max_length=11, verbose_name='Тип соревнования')),
],
options={
'verbose_name': 'соревнование',
'verbose_name_plural': 'соревнования',
},
),
]
@@ -0,0 +1,40 @@
from django.db import models
from apps.core.models import BaseModel
class CompetitionType(models.TextChoices):
SOLO = "solo"
class CompetitionParticipationType(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="Изображение соревнования", null=True, blank=True
)
end_date = models.DateTimeField(
verbose_name="Дедлайн участия", null=True, blank=True
)
start_date = models.DateTimeField(
verbose_name="Дедлайн участия", null=True, blank=True
)
type = models.CharField(
max_length=10,
choices=CompetitionType.choices,
verbose_name="Тип участия",
)
participation_type = models.CharField(
max_length=11,
choices=CompetitionParticipationType.choices,
verbose_name="Тип соревнования",
)
class Meta:
verbose_name = "соревнование"
verbose_name_plural = "соревнования"
@@ -1,7 +0,0 @@
from django.apps import AppConfig
class CompetitionsConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.competitions'
label = 'competitions'
@@ -1,28 +0,0 @@
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 = "соревнования"
+3 -3
View File
@@ -2,6 +2,6 @@ from django.apps import AppConfig
class UsersConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'apps.user'
label = 'user'
default_auto_field = "django.db.models.BigAutoField"
name = "apps.user"
label = "user"
+1
View File
@@ -444,6 +444,7 @@ INSTALLED_APPS = [
# Internal apps
"apps.core",
"apps.user",
"apps.competition",
]
# GUID