Fix following past 48 entries and make the e621 page size configurable
Follow lists were paginated at the API default of 48, but the SPA treats them as complete sets: the tag/pool toggles read their state from page one (so the 49th follow looked unfollowed and its spinner waited for a page that could never contain it) and the Followed page rendered only 48 cards while showing that as the count. Both follow endpoints are now unpaginated — they are per-user sets and still restricted to the caller's rows — and the three consumers take plain arrays. Post visibility: the old J621-Django online view fetched limit=320 (e621's maximum) while ours hard-coded 48, and fetchPostsByIds capped id batches at 100. The Online browser now has a 'Posts per page' setting (48/100/200/320) in its sidebar, mirrored in Account -> Browsing preferences, stored per user as e621_per_page and also used for pool loading; the id-batch cap is raised to 320. Tests: follow list shape/isolation (4) and preference validation/merge (3) added; the full backend suite is 46 green. Live-checked the array response shape and the preference bounds (200 accepted, 500 rejected).
This commit is contained in:
@@ -134,5 +134,7 @@ class PreferencesSerializer(serializers.Serializer):
|
||||
ordering = serializers.CharField(max_length=30, required=False)
|
||||
per_page = serializers.IntegerField(min_value=12, max_value=200, required=False)
|
||||
zoom = serializers.IntegerField(min_value=120, max_value=400, required=False)
|
||||
# e621 renders at most 320 posts per request.
|
||||
e621_per_page = serializers.IntegerField(min_value=12, max_value=320, required=False)
|
||||
# Open Online with the order:hot metatag when no search is given.
|
||||
online_hot_default = serializers.BooleanField(required=False)
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
"""Per-user browse preferences: validation and merge semantics."""
|
||||
|
||||
import json
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.test import Client, TestCase
|
||||
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
User = get_user_model()
|
||||
|
||||
|
||||
class PreferenceTests(TestCase):
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_user(
|
||||
username="prefs-user", password="prefs-pass-123456"
|
||||
)
|
||||
self.client = Client()
|
||||
self.client.defaults["HTTP_AUTHORIZATION"] = (
|
||||
f"Token {Token.objects.create(user=self.user).key}"
|
||||
)
|
||||
|
||||
def post(self, payload):
|
||||
return self.client.post(
|
||||
"/api/auth/preferences/",
|
||||
data=json.dumps(payload),
|
||||
content_type="application/json",
|
||||
)
|
||||
|
||||
def test_e621_per_page_round_trips_within_range(self):
|
||||
response = self.post({"e621_per_page": 320})
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.json()["e621_per_page"], 320)
|
||||
self.assertEqual(
|
||||
self.client.get("/api/auth/me/").json()["preferences"]["e621_per_page"],
|
||||
320,
|
||||
)
|
||||
|
||||
def test_e621_per_page_rejects_out_of_range(self):
|
||||
for value in (0, 8, 321, 1000):
|
||||
self.assertEqual(self.post({"e621_per_page": value}).status_code, 400, value)
|
||||
|
||||
def test_merge_keeps_other_keys(self):
|
||||
self.post({"ratings": ["s"], "e621_per_page": 100})
|
||||
response = self.post({"per_page": 24})
|
||||
data = response.json()
|
||||
self.assertEqual(data["ratings"], ["s"])
|
||||
self.assertEqual(data["e621_per_page"], 100)
|
||||
self.assertEqual(data["per_page"], 24)
|
||||
Reference in New Issue
Block a user