noita leaderboard + view + management commands
This commit is contained in:
@@ -5,6 +5,7 @@ from django.db.models import (
|
||||
Case,
|
||||
When,
|
||||
Sum,
|
||||
Count,
|
||||
IntegerField,
|
||||
Subquery,
|
||||
OuterRef,
|
||||
@@ -154,7 +155,6 @@ def get_leaderboard(request: HttpRequest):
|
||||
|
||||
# Get unique users and their scores, then apply ranking
|
||||
leaderboard = (
|
||||
# User.objects.filter(objectiv_set__isnull=False)
|
||||
User.objects.filter(objectiv__isnull=False)
|
||||
.distinct()
|
||||
.annotate(
|
||||
@@ -163,13 +163,14 @@ def get_leaderboard(request: HttpRequest):
|
||||
output_field=IntegerField(),
|
||||
)
|
||||
)
|
||||
.annotate(objectives_count=Count("objectiv", distinct=True))
|
||||
.annotate(
|
||||
rank=Window(
|
||||
expression=Rank(),
|
||||
order_by=F("total_score").desc(),
|
||||
)
|
||||
)
|
||||
.values("rank", "username", "total_score")
|
||||
.values("rank", "username", "total_score", "objectives_count")
|
||||
.order_by("rank")
|
||||
)
|
||||
|
||||
@@ -179,13 +180,14 @@ def get_leaderboard(request: HttpRequest):
|
||||
"rank": entry["rank"],
|
||||
"username": entry["username"],
|
||||
"total_score": entry["total_score"] or 0,
|
||||
"objectives_count": entry["objectives_count"],
|
||||
}
|
||||
for entry in leaderboard
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
@router.post("submit", response=NoitaSubmissionOut)
|
||||
@router.post("submit", response={200: NoitaSubmissionOut, 400: dict})
|
||||
def submit_log_file(request: HttpRequest, file: UploadedFile = File(...)):
|
||||
"""
|
||||
Submit a Noita run file (log file, screenshot, or video).
|
||||
@@ -200,6 +202,7 @@ def submit_log_file(request: HttpRequest, file: UploadedFile = File(...)):
|
||||
# Validate file type
|
||||
allowed_types = [
|
||||
"text/plain",
|
||||
"text/x-log",
|
||||
"image/jpeg",
|
||||
"image/jpg",
|
||||
"image/png",
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from noita.models import ObjectivPoint
|
||||
from noita.services.decode import POINTS
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = "Load ObjectivPoints from the POINTS dictionary in services.decode"
|
||||
|
||||
def add_arguments(self, parser):
|
||||
parser.add_argument(
|
||||
"--clear",
|
||||
action="store_true",
|
||||
help="Clear all existing ObjectivPoints before loading",
|
||||
)
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if options["clear"]:
|
||||
ObjectivPoint.objects.all().delete()
|
||||
self.stdout.write(self.style.SUCCESS("Cleared existing ObjectivPoints"))
|
||||
|
||||
created_count = 0
|
||||
updated_count = 0
|
||||
|
||||
for objectiv_id, point_value in POINTS.items():
|
||||
# Skip special entries
|
||||
if objectiv_id in {"-", "DEBUG"}:
|
||||
continue
|
||||
|
||||
# Get display string from objectiv_id (convert to title case)
|
||||
display_string = objectiv_id.replace("_", " ").title()
|
||||
|
||||
# Create or update ObjectivPoint
|
||||
obj, created = ObjectivPoint.objects.get_or_create(
|
||||
objectiv_id=objectiv_id,
|
||||
defaults={
|
||||
"display_string": display_string,
|
||||
"point": point_value,
|
||||
"max_count": 1, # Default max_count is 1
|
||||
},
|
||||
)
|
||||
|
||||
if created:
|
||||
created_count += 1
|
||||
self.stdout.write(f"✓ Created: {objectiv_id} - {point_value} points")
|
||||
else:
|
||||
# Update if points changed
|
||||
if obj.point != point_value or obj.display_string != display_string:
|
||||
obj.point = point_value
|
||||
obj.display_string = display_string
|
||||
obj.save()
|
||||
updated_count += 1
|
||||
self.stdout.write(
|
||||
self.style.WARNING(
|
||||
f"↻ Updated: {objectiv_id} - {point_value} points"
|
||||
)
|
||||
)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(f"\nCreated: {created_count}"))
|
||||
self.stdout.write(self.style.SUCCESS(f"Updated: {updated_count}"))
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f"Total ObjectivPoints: {ObjectivPoint.objects.count()}")
|
||||
)
|
||||
@@ -37,6 +37,7 @@ class LeaderboardEntryOut(Schema):
|
||||
rank: int
|
||||
username: str
|
||||
total_score: int
|
||||
objectives_count: int
|
||||
|
||||
|
||||
class LeaderboardOut(Schema):
|
||||
|
||||
Reference in New Issue
Block a user