basic noita submissions
This commit is contained in:
@@ -0,0 +1 @@
|
||||
# Register your models here.
|
||||
@@ -0,0 +1,67 @@
|
||||
from django.http import HttpRequest
|
||||
from django.core.files.base import ContentFile
|
||||
from ninja import Router, File
|
||||
from ninja.files import UploadedFile
|
||||
|
||||
from .models import LogfileSubmission
|
||||
from .schemas import NoitaSubmissionOut
|
||||
|
||||
|
||||
router = Router()
|
||||
|
||||
|
||||
@router.post("submit", response=NoitaSubmissionOut)
|
||||
def submit_log_file(request: HttpRequest, file: UploadedFile = File(...)):
|
||||
"""
|
||||
Submit a Noita run file (log file, screenshot, or video).
|
||||
|
||||
Accepts:
|
||||
- Text files (.txt) for polylan_mod_log.txt
|
||||
- Images (.png, .jpg, .gif)
|
||||
- Videos (.mp4, .webm)
|
||||
|
||||
Max file size: 256 MB
|
||||
"""
|
||||
# Validate file type
|
||||
allowed_types = [
|
||||
"text/plain",
|
||||
"image/jpeg",
|
||||
"image/jpg",
|
||||
"image/png",
|
||||
"image/gif",
|
||||
"video/mp4",
|
||||
"video/webm",
|
||||
]
|
||||
|
||||
if file.content_type not in allowed_types:
|
||||
return 400, {
|
||||
"detail": f"Invalid file type: {file.content_type}. Allowed types: {', '.join(allowed_types)}"
|
||||
}
|
||||
|
||||
# Validate file size (256MB limit)
|
||||
if file.size > 256 * 1024 * 1024:
|
||||
return 400, {"detail": "File too large (max 256MB)"}
|
||||
|
||||
try:
|
||||
# Create submission
|
||||
submission = LogfileSubmission.objects.create(
|
||||
user=request.user if request.user.is_authenticated else None,
|
||||
content_type=file.content_type,
|
||||
file_size=file.size,
|
||||
)
|
||||
|
||||
# Save the file
|
||||
submission.file.save(file.name, ContentFile(file.read()), save=True)
|
||||
|
||||
return {
|
||||
"id": str(submission.id),
|
||||
"user_id": submission.user_id,
|
||||
"username": submission.user.username if submission.user else None,
|
||||
"file_size": submission.file_size,
|
||||
"content_type": submission.content_type,
|
||||
"created_at": submission.created_at,
|
||||
"processed": submission.processed,
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
return 500, {"detail": f"Error creating submission: {str(e)}"}
|
||||
@@ -0,0 +1,6 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class NoitaConfig(AppConfig):
|
||||
default_auto_field = "django.db.models.BigAutoField"
|
||||
name = "noita"
|
||||
@@ -0,0 +1,61 @@
|
||||
# Generated by Django 5.2.7 on 2026-05-09 22:53
|
||||
|
||||
import django.db.models.deletion
|
||||
import noita.models
|
||||
import uuid
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
initial = True
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="Submission",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid4,
|
||||
editable=False,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
),
|
||||
),
|
||||
(
|
||||
"content_type",
|
||||
models.CharField(help_text="MIME type of the file", max_length=100),
|
||||
),
|
||||
(
|
||||
"file_size",
|
||||
models.PositiveIntegerField(help_text="File size in bytes"),
|
||||
),
|
||||
(
|
||||
"file",
|
||||
models.FileField(
|
||||
help_text="Uploaded file (image/gif)",
|
||||
upload_to=noita.models.submission_file_upload_path,
|
||||
),
|
||||
),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("processed", models.BooleanField(default=False)),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="User who made the submission (null for anonymous)",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="noita_submissions",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 5.2.7 on 2026-05-09 22:55
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("noita", "0001_initial"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RenameModel(
|
||||
old_name="Submission",
|
||||
new_name="LogfileSubmission",
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,44 @@
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.db import models
|
||||
|
||||
import uuid
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
def submission_file_upload_path(instance, filename):
|
||||
"""Generate upload path for submission files"""
|
||||
# Create path: submissions/{submission_id}/{uuid}_{filename}
|
||||
ext = filename.split(".")[-1] if "." in filename else ""
|
||||
new_filename = f"{uuid.uuid4()}_{filename}" if ext else str(uuid.uuid4())
|
||||
return f"noita-submissions/{instance.id}/{new_filename}"
|
||||
|
||||
|
||||
class LogfileSubmission(models.Model):
|
||||
"""Model representing a submission containing multiple puzzle responses"""
|
||||
|
||||
# Identification
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
|
||||
content_type = models.CharField(max_length=100, help_text="MIME type of the file")
|
||||
file_size = models.PositiveIntegerField(help_text="File size in bytes")
|
||||
file = models.FileField(
|
||||
upload_to=submission_file_upload_path,
|
||||
help_text="Uploaded file (image/gif)",
|
||||
)
|
||||
|
||||
# User information (optional for anonymous submissions)
|
||||
user = models.ForeignKey(
|
||||
User,
|
||||
on_delete=models.CASCADE,
|
||||
null=True,
|
||||
blank=True,
|
||||
help_text="User who made the submission (null for anonymous)",
|
||||
related_name="noita_submissions",
|
||||
)
|
||||
|
||||
# Timestamps
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
processed = models.BooleanField(default=False)
|
||||
@@ -0,0 +1,16 @@
|
||||
from typing import Optional
|
||||
from pydantic import BaseModel
|
||||
from datetime import datetime
|
||||
|
||||
|
||||
class NoitaSubmissionOut(BaseModel):
|
||||
id: str
|
||||
user_id: Optional[int]
|
||||
username: Optional[str]
|
||||
file_size: int
|
||||
content_type: str
|
||||
created_at: datetime
|
||||
processed: bool
|
||||
|
||||
class Config:
|
||||
from_attributes = True
|
||||
@@ -0,0 +1 @@
|
||||
# Create your tests here.
|
||||
@@ -0,0 +1 @@
|
||||
# Create your views here.
|
||||
Reference in New Issue
Block a user