feat(submissions): show all submissions for admin

This commit is contained in:
2026-10-16 02:11:04 +02:00
parent bfaef2e402
commit a110575e0a
6 changed files with 69 additions and 7 deletions
+5 -2
View File
@@ -8,6 +8,7 @@ import { useUser } from "@/composables/useUser";
import { eventGamesQuery } from "@/queries";
import { usePageHeaderStore } from "@/stores/pageHeader";
import { submissionsApiListAvailableScopes, submissionsApiCreateSubmission, submissionsApiListUserSubmissions, submissionsApiCreateImageCrop, submissionsApiDeleteImageCrop, submissionsApiProcessFileOcr, submissionsApiProcessCropOcr } from "@/api";
import type { SubmissionOut } from "@/api";
import { useSubmissionsWebSocket } from "@/composables/useSubmissionsWebSocket";
import { provideEventPath } from "@/composables/useEventPath";
@@ -42,7 +43,7 @@ const notes = ref("");
const selectedFile = ref<File | null>(null);
const filePreviewUrl = ref<string>("");
const isModalOpen = ref(false);
const userSubmissions = ref<any[]>([]);
const userSubmissions = ref<SubmissionOut[]>([]);
const isLoadingSubmissions = ref(false);
const selectedSubmissionFile = ref<any>(null);
const isSubmissionFileModalOpen = ref(false);
@@ -728,7 +729,7 @@ onUnmounted(() => {
<div class="card-body">
<h2 class="card-title text-2xl mb-6">
<i class="mdi mdi-history text-primary mr-2"></i>
{{ t("submissions.yourSubmissions") }}
{{ userInfo.isStaff ? t("submissions.allSubmissions") : t("submissions.yourSubmissions") }}
</h2>
<div v-if="isLoadingSubmissions" class="flex justify-center py-8">
@@ -745,6 +746,7 @@ onUnmounted(() => {
<thead>
<tr>
<th>{{ t("common.date") }}</th>
<th v-if="userInfo.isStaff">{{ t("common.user") }}</th>
<th>{{ t("common.files") }}</th>
<th>{{ t("submissions.fileStatus") }}</th>
<th>{{ t("submissions.ocrStatus") }}</th>
@@ -754,6 +756,7 @@ onUnmounted(() => {
<tbody>
<tr v-for="submission in userSubmissions" :key="submission.id" class="hover">
<td class="text-sm">{{ formatDate(submission.created_at) }}</td>
<td v-if="userInfo.isStaff" class="text-sm">{{ submission.username ?? "-" }}</td>
<td class="text-sm">
<div class="flex flex-col gap-1">
<div v-for="file in submission.files" :key="file.id" class="flex items-center gap-2">
+4
View File
@@ -423,6 +423,10 @@ export type SubmissionOut = {
* Scope Id
*/
scope_id: string;
/**
* Username
*/
username?: string | null;
/**
* Notes
*/
+2
View File
@@ -24,6 +24,7 @@
"puzzle": "Puzzle",
"files": "Files",
"date": "Date",
"user": "User",
"notes": "Notes",
"actions": "Actions",
"noRankYet": "No rank yet",
@@ -168,6 +169,7 @@
}
},
"yourSubmissions": "Your Submissions",
"allSubmissions": "All Submissions",
"noSubmissionsHint": "Upload your first submission above to get started",
"fileStatus": "File Status",
"ocrStatus": "OCR Status",
+6 -4
View File
@@ -202,10 +202,12 @@ def list_user_submissions(request: HttpRequest, event_path: str, scope_id: UUID)
if not request.user.is_authenticated:
return 403, {"detail": "Authentication required"}
submissions = Submission.for_event.filter(
scope_id=scope_id, user=request.user
).order_by("-created_at")
return submissions
submissions = Submission.for_event.filter(scope_id=scope_id)
# Admins see every player's submissions for the scope
if not request.user.is_staff:
submissions = submissions.filter(user=request.user)
return submissions.select_related("user").order_by("-created_at")
@router.get(f"{PREFIX}/submission/by/game", response=list[SubmissionOut])
+5
View File
@@ -71,7 +71,12 @@ class SubmissionFileOut(Schema):
class SubmissionOut(Schema):
id: UUID
scope_id: UUID
username: str | None = None
notes: str | None = None
files: list[SubmissionFileOut] = []
created_at: datetime
updated_at: datetime
@staticmethod
def resolve_username(obj) -> str | None:
return obj.user.username if obj.user else None
+47 -1
View File
@@ -11,7 +11,7 @@ from events.models import Event
from games.models import EventGame, Game
from . import tasks
from .models import Scope
from .models import Scope, Submission
from .services.aandt_client.models import (
AandtApiInfosResponse200,
AandtApiMatchesResponse200,
@@ -388,3 +388,49 @@ class SubmissionHomeViewTests(TestCase):
response = self.client.get("/nope/submissions/unknown-game")
self.assertEqual(response.status_code, 404)
class ListUserSubmissionsApiTests(TestCase):
def setUp(self):
self.event = Event.objects.create(name="Event", path="event")
game = Game.objects.create(name="Game", path="game")
event_game = EventGame.objects.create(event=self.event, game=game)
self.scope = Scope.objects.create(event_game=event_game, name="M1")
other_scope = Scope.objects.create(event_game=event_game, name="M2")
self.player = CustomUser.objects.create_user(username="player", password="x")
other = CustomUser.objects.create_user(username="other", password="x")
self.mine = Submission.objects.create(
event=self.event, scope=self.scope, user=self.player
)
self.theirs = Submission.objects.create(
event=self.event, scope=self.scope, user=other
)
Submission.objects.create(event=self.event, scope=other_scope, user=other)
self.url = f"/api/events/{self.event.path}/submissions/submission/by/user"
def _list(self):
response = self.client.get(self.url, {"scope_id": self.scope.id})
self.assertEqual(response.status_code, 200)
return response.json()
def test_player_sees_only_own_submissions(self):
self.client.force_login(self.player)
data = self._list()
self.assertEqual([s["id"] for s in data], [str(self.mine.id)])
self.assertEqual(data[0]["username"], "player")
def test_staff_sees_all_submissions_of_scope(self):
staff = CustomUser.objects.create_user(
username="staff", password="x", is_staff=True
)
self.client.force_login(staff)
data = self._list()
self.assertEqual(
{s["id"] for s in data}, {str(self.mine.id), str(self.theirs.id)}
)