feat(backend): added auth, reviews, users modules

also provided tests
This commit is contained in:
ITQ
2026-02-12 20:48:29 +03:00
parent cb9692089f
commit 613c99dce2
60 changed files with 5101 additions and 127 deletions
+166
View File
@@ -0,0 +1,166 @@
from datetime import datetime
from typing import ClassVar
from ninja import ModelSchema, Schema
from pydantic import Field
from apps.reviews.models import ApproverGroup, ReviewSettings
from apps.users.models import User
class ApproverOut(ModelSchema):
first_name: str = Field("", alias="firstName")
last_name: str = Field("", alias="lastName")
class Meta:
model = User
fields: ClassVar[tuple[str, ...]] = (
User.id.field.name,
User.username.field.name,
User.email.field.name,
User.first_name.field.name,
User.last_name.field.name,
)
class ExperimenterOut(ModelSchema):
class Meta:
model = User
fields: ClassVar[tuple[str, ...]] = (
User.id.field.name,
User.username.field.name,
User.email.field.name,
)
class ApproverGroupOut(ModelSchema):
experimenter: ExperimenterOut
approvers: list[ApproverOut]
min_approvals: int
created_at: datetime
updated_at: datetime
class Meta:
model = ApproverGroup
fields: ClassVar[tuple[str, ...]] = (
ApproverGroup.id.field.name,
ApproverGroup.experimenter.field.name,
ApproverGroup.approvers.field.name,
ApproverGroup.min_approvals.field.name,
ApproverGroup.created_at.field.name,
ApproverGroup.updated_at.field.name,
)
class ApproverGroupCreateIn(Schema):
experimenter_id: str = Field(
...,
alias="experimenterId",
description="UUID of the experimenter user this group belongs to.",
)
approver_ids: list[str] = Field(
default_factory=list,
alias="approverIds",
description=(
"List of user UUIDs to add as approvers. "
"Each user must have the 'approver' role."
),
)
min_approvals: int = Field(
1,
alias="minApprovals",
ge=1,
description=(
"Number of distinct approvals required. "
"Must be >= 1 and <= number of approvers (if any are provided)."
),
)
class ApproverGroupUpdateIn(Schema):
approver_ids: list[str] | None = Field(
None,
alias="approverIds",
description=(
"If provided, replaces the current set of approvers. "
"Each user must have the 'approver' role."
),
)
min_approvals: int | None = Field(
None,
alias="minApprovals",
ge=1,
description="New minimum approval threshold.",
)
class ApproverGroupListOut(Schema):
count: int
items: list[ApproverGroupOut]
class ApproverGroupAddApproverIn(Schema):
approver_id: str = Field(
...,
alias="approverId",
description="UUID of the user to add as an approver.",
)
class ApproverGroupRemoveApproverIn(Schema):
approver_id: str = Field(
...,
alias="approverId",
description="UUID of the approver to remove.",
)
class ReviewSettingsOut(ModelSchema):
default_min_approvals: int
allow_any_approver: bool
updated_at: datetime
class Meta:
model = ReviewSettings
fields: ClassVar[tuple[str, ...]] = (
ReviewSettings.id.field.name,
ReviewSettings.default_min_approvals.field.name,
ReviewSettings.allow_any_approver.field.name,
ReviewSettings.updated_at.field.name,
)
class ReviewSettingsUpdateIn(Schema):
default_min_approvals: int | None = Field(
None,
alias="defaultMinApprovals",
ge=1,
description="New default minimum approval threshold.",
)
allow_any_approver: bool | None = Field(
None,
alias="allowAnyApprover",
description="New fallback policy for approver eligibility.",
)
class EffectiveReviewPolicyOut(Schema):
experimenter_id: str = Field(..., description="UUID of the experimenter.")
min_approvals: int = Field(
..., description="Effective number of approvals required."
)
approvers: list[ApproverOut] = Field(
...,
description="List of users who are eligible to approve.",
)
source: str = Field(
...,
description=(
"Where the policy comes from: "
"'approver_group' or 'global_fallback'."
),
)
has_explicit_group: bool = Field(
...,
description="Whether the experimenter has an explicit approver group.",
)