mirror of
https://gitlab.com/megazordpobeda/DataRush.git
synced 2026-05-23 00:27:11 +00:00
Merge branch 'master' of gitlab.prodcontest.ru:team-15/project
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from typing import Optional, Any
|
from typing import Any
|
||||||
|
|
||||||
import jwt
|
import jwt
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@@ -10,7 +10,7 @@ from apps.user.models import User
|
|||||||
|
|
||||||
|
|
||||||
class BearerAuth(HttpBearer):
|
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"])
|
data = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
|
||||||
if data["exp"] < datetime.datetime.now().timestamp():
|
if data["exp"] < datetime.datetime.now().timestamp():
|
||||||
return None
|
return None
|
||||||
@@ -21,7 +21,9 @@ class BearerAuth(HttpBearer):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def generate_jwt(user: User) -> str:
|
def generate_jwt(user: User) -> str:
|
||||||
data = {
|
data = {
|
||||||
"exp": (datetime.datetime.now() + datetime.timedelta(days=365)).timestamp(),
|
"exp": (
|
||||||
"id": str(user.id)
|
datetime.datetime.now() + datetime.timedelta(days=365)
|
||||||
|
).timestamp(),
|
||||||
|
"id": str(user.id),
|
||||||
}
|
}
|
||||||
return jwt.encode(data, settings.SECRET_KEY, algorithm="HS256")
|
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]]: ...
|
||||||
@@ -15,4 +15,4 @@ router = Router(tags=["ping"])
|
|||||||
},
|
},
|
||||||
)
|
)
|
||||||
def ping(request: HttpRequest) -> tuple[status, schemas.PingOut]:
|
def ping(request: HttpRequest) -> tuple[status, schemas.PingOut]:
|
||||||
return status.OK, schemas.PingOut
|
return status.OK, schemas.PingOut()
|
||||||
|
|||||||
@@ -3,14 +3,14 @@ from functools import partial
|
|||||||
from ninja import NinjaAPI
|
from ninja import NinjaAPI
|
||||||
|
|
||||||
from api.v1 import handlers
|
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.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(
|
router = NinjaAPI(
|
||||||
title="DataRush API",
|
title="project_name API",
|
||||||
version="1",
|
version="1",
|
||||||
description="API docs for DataRush",
|
description="API docs for project_name",
|
||||||
openapi_url="/docs/openapi.json",
|
openapi_url="/docs/openapi.json",
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -21,8 +21,11 @@ router.add_router(
|
|||||||
)
|
)
|
||||||
router.add_router(
|
router.add_router(
|
||||||
"",
|
"",
|
||||||
users_router,
|
user_router,
|
||||||
auth=BearerAuth(),
|
)
|
||||||
|
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
|
from apps.user.models import User
|
||||||
|
|
||||||
@@ -3,7 +3,7 @@ from http import HTTPStatus as status
|
|||||||
from ninja import Router
|
from ninja import Router
|
||||||
from ninja.errors import AuthenticationError
|
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.auth import BearerAuth
|
||||||
from api.v1.schemas import BadRequestError, ForbiddenError, NotFoundError
|
from api.v1.schemas import BadRequestError, ForbiddenError, NotFoundError
|
||||||
from apps.user.models import User
|
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 = "соревнования"
|
|
||||||
@@ -2,6 +2,6 @@ from django.apps import AppConfig
|
|||||||
|
|
||||||
|
|
||||||
class UsersConfig(AppConfig):
|
class UsersConfig(AppConfig):
|
||||||
default_auto_field = 'django.db.models.BigAutoField'
|
default_auto_field = "django.db.models.BigAutoField"
|
||||||
name = 'apps.user'
|
name = "apps.user"
|
||||||
label = 'user'
|
label = "user"
|
||||||
|
|||||||
@@ -444,6 +444,7 @@ INSTALLED_APPS = [
|
|||||||
# Internal apps
|
# Internal apps
|
||||||
"apps.core",
|
"apps.core",
|
||||||
"apps.user",
|
"apps.user",
|
||||||
|
"apps.competition",
|
||||||
]
|
]
|
||||||
|
|
||||||
# GUID
|
# GUID
|
||||||
|
|||||||
Reference in New Issue
Block a user