feat: add community contribution ranks

This commit is contained in:
2026-09-29 22:18:57 +03:30
parent 0f6220f72c
commit 77567178ad
46 changed files with 2206 additions and 23 deletions

View File

@@ -330,6 +330,14 @@ class MyEventRegistrationOut(Schema):
status: Literal["pending", "confirmed", "cancelled", "attended"]
event: EventBriefSchema
class PaginatedMyEventRegistrationsSchema(Schema):
count: int
page: int
page_size: int
total_pages: int
results: List[MyEventRegistrationOut]
class RegistrationStatusOut(Schema):
is_registered: bool

View File

@@ -1,13 +1,14 @@
from django.conf import settings
from django.core.files.base import ContentFile
from django.shortcuts import get_object_or_404
from django.db.models import Q, Case, When, IntegerField
from django.db.models import Q, Case, When, IntegerField, F
from django.db.models.functions import Lower
from django.utils.text import slugify
from django.utils import timezone
from ninja import File, Router, Query, UploadedFile
from ninja.errors import HttpError
from typing import List, Optional
from typing import List, Literal, Optional
from uuid import UUID, uuid4
from apps.events.api.schemas import (
@@ -19,6 +20,7 @@ from apps.events.api.schemas import (
EventSchema,
EventUpdateSchema,
MyEventRegistrationOut,
PaginatedMyEventRegistrationsSchema,
PaginatedRegistrationSchema,
RegisterationDetailSchema,
RegistrationCreateSchema,
@@ -485,7 +487,10 @@ def update_registration_status(request, registration_id: int, payload: Registrat
user = request.auth
registration = get_object_or_404(Registration, id=registration_id, user=user, is_deleted=False)
registration.status = payload.dict(exclude_unset=True).get('status')
requested_status = payload.dict(exclude_unset=True).get('status')
if requested_status == Registration.StatusChoices.ATTENDED:
raise HttpError(403, "حضور رویداد فقط توسط برگزارکننده تأیید می‌شود.")
registration.status = requested_status
registration.full_clean()
registration.save()
@@ -518,6 +523,56 @@ def verify_my_registration(request, ticket_id: UUID):
@events_router.get("/my-registrations/paginated", response=PaginatedMyEventRegistrationsSchema, auth=jwt_auth)
def my_registrations_paginated(
request,
status: Literal["all", "pending", "confirmed", "cancelled", "attended"] = Query("confirmed"),
sort_by: Literal["start_time", "title"] = Query("start_time"),
sort_order: Literal["asc", "desc"] = Query("desc"),
page: int = Query(1, ge=1),
):
page_size = 10
queryset = Registration.objects.filter(user=request.auth)
if status != "all":
queryset = queryset.filter(status=status)
ordering_expression = Lower("event__title") if sort_by == "title" else F("event__start_time")
ordering_expression = ordering_expression.desc() if sort_order == "desc" else ordering_expression.asc()
queryset = queryset.select_related("event").order_by(ordering_expression, "id")
count = queryset.count()
total_pages = max(1, (count + page_size - 1) // page_size)
start = (page - 1) * page_size
results = [
MyEventRegistrationOut(
id=registration.id,
created_at=registration.created_at,
status=registration.status,
event=EventBriefSchema(
id=registration.event.id,
title=registration.event.title,
slug=registration.event.slug,
start_date=registration.event.start_time,
end_date=registration.event.end_time,
location=registration.event.location,
price=registration.event.price,
absolute_image_url=(
request.build_absolute_uri(registration.event.featured_image.url)
if registration.event.featured_image
else None
),
),
)
for registration in queryset[start : start + page_size]
]
return {
"count": count,
"page": page,
"page_size": page_size,
"total_pages": total_pages,
"results": results,
}
@events_router.get("/my-registrations", response=List[MyEventRegistrationOut], auth=jwt_auth)
def my_registrations(request):
qs = (