The upload board partitions /api/uploads/ into Pending / Visual similarity / Auto-uploaded, but the endpoint was paginated at 48 — a 69-file batch silently lost 21 entries, and the similarity sweep (which reads the same list back after uploading) only ever saw the first page. The staged-upload list is now unpaginated: it is a transient per-user set, still limited to the caller's rows and the uploader role. The page takes a plain array. Watching progress with dozens of files was also poor: - the queue uploads three files at a time instead of strictly one at a time; - the Uploads section now shows a batch bar and 'n/m uploaded · x%' next to the count, so the overall progress never scrolls out of sight; - entries are ordered active-first (uploading, queued, failed, done) so the file being uploaded is always at the top of the grid; - tiles are larger (4 columns at lg instead of 5); - the header reads 'Uploading n/m…' and 'Checking n file(s) against IQDB…' instead of a bare spinner. Tests: staged-upload list unpaginated past 48, per-user, uploader-only (3 new; full suite 49 green). Live-checked the bare-array response.
76 lines
2.6 KiB
Python
76 lines
2.6 KiB
Python
"""The staged-upload list is a complete set, not a page.
|
|
|
|
The upload board partitions it into Pending / Visual similarity / Auto-uploaded
|
|
columns; with the standard 48-item pagination a 69-file batch silently lost 21
|
|
entries from the board (and from the similarity sweep that reads it back).
|
|
"""
|
|
|
|
import hashlib
|
|
|
|
from django.contrib.auth import get_user_model
|
|
from django.test import Client, TestCase
|
|
|
|
from rest_framework.authtoken.models import Token
|
|
|
|
from apps.library.models import TempUpload
|
|
|
|
User = get_user_model()
|
|
|
|
|
|
class TempUploadListTests(TestCase):
|
|
def setUp(self):
|
|
self.uploader = User.objects.create_user(
|
|
username="upload-user", password="upload-pass-123456"
|
|
)
|
|
self.uploader.role = "uploader"
|
|
self.uploader.save(update_fields=["role"])
|
|
self.other = User.objects.create_user(
|
|
username="upload-other", password="upload-pass-123456"
|
|
)
|
|
self.other.role = "uploader"
|
|
self.other.save(update_fields=["role"])
|
|
|
|
def api_client(self, user):
|
|
client = Client()
|
|
client.defaults["HTTP_AUTHORIZATION"] = (
|
|
f"Token {Token.objects.create(user=user).key}"
|
|
)
|
|
return client
|
|
|
|
def test_list_is_not_paginated_past_48(self):
|
|
TempUpload.objects.bulk_create(
|
|
[
|
|
TempUpload(
|
|
user=self.uploader,
|
|
original_filename=f"file_{index:03d}.png",
|
|
md5=hashlib.md5(f"file-{index}".encode()).hexdigest(),
|
|
size=index,
|
|
)
|
|
for index in range(69)
|
|
]
|
|
)
|
|
response = self.api_client(self.uploader).get("/api/uploads/")
|
|
self.assertEqual(response.status_code, 200)
|
|
data = response.json()
|
|
self.assertIsInstance(data, list, "the list must not be paginated")
|
|
self.assertEqual(len(data), 69)
|
|
|
|
def test_list_only_contains_the_callers_uploads(self):
|
|
TempUpload.objects.create(
|
|
user=self.uploader,
|
|
original_filename="mine.png",
|
|
md5=hashlib.md5(b"mine").hexdigest(),
|
|
size=1,
|
|
)
|
|
TempUpload.objects.create(
|
|
user=self.other,
|
|
original_filename="theirs.png",
|
|
md5=hashlib.md5(b"theirs").hexdigest(),
|
|
size=1,
|
|
)
|
|
mine = self.api_client(self.uploader).get("/api/uploads/").json()
|
|
self.assertEqual([row["original_filename"] for row in mine], ["mine.png"])
|
|
|
|
def test_anonymous_cannot_list(self):
|
|
self.assertEqual(Client().get("/api/uploads/").status_code, 401)
|