diora-web/books/migrations/0005_progress_last_read_wins.py
mrwnslz 60dd4926cf
All checks were successful
Build and push Docker image / build (push) Successful in 15s
Test / test (push) Successful in 8m21s
Lesestand: die zuletzt gelesene Stelle gewinnt, nicht mehr die weiteste; sw v100
docs/progress-sync.md ist der Vertrag für Server, Web, Android und Desktop.

- Server: read_at (Zeit, zu der dort gelesen wurde, Uhrfehler des Geräts per
  sent_at herausgerechnet, nie nach "jetzt"), Gerät, weiteste Stelle. Ältere
  Schreibvorgänge (offline nachgereicht, liegengelassener Tab) gewinnen nicht.
  Apps ohne read_at: nur strikt vorwärts. Antwort = Zustand nach dem Schreiben.
  /books/ mit X-Server-Now, /api/sync/ mit server_now.
- Web-Reader: Zeit einer Stelle ist der Moment, in dem man durch eigenes Tun
  hinkam (Scrollen, Blättern, Tasten, Vorlesen); unverändert Liegendes
  schickt nichts bzw. nur seine alte Zeit. Vor dem Wiederherstellen und
  während eines Blicks (Fußnote, "Weit gescrollt") wird nicht gespeichert.
  Eigene Stellen in einem Ausgang (localStorage) bis der Server sie hat.
  Angebote "Auf <Gerät> weitergelesen" und "Weiteste Stelle".
- Tests: books/tests.py (Reihenfolge, Uhrfehler, Zukunft, alte Apps, weiteste
  Stelle, Liste und Snapshot).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-12 19:31:36 +02:00

43 lines
1.4 KiB
Python

from django.db import migrations, models
def keep_what_we_know(apps, schema_editor):
"""The continue point so far was the furthest place: it is that, and it was
last saved at updated_at."""
EBookProgress = apps.get_model('books', 'EBookProgress')
for p in EBookProgress.objects.all().iterator():
p.furthest_fraction = p.scroll_fraction
p.furthest_anchor = p.position_anchor
p.read_at = int(p.updated_at.timestamp() * 1000)
p.save(update_fields=['furthest_fraction', 'furthest_anchor', 'read_at'])
class Migration(migrations.Migration):
dependencies = [
('books', '0004_ebook_is_read'),
]
operations = [
migrations.AddField(
model_name='ebookprogress',
name='read_at',
field=models.BigIntegerField(blank=True, null=True),
),
migrations.AddField(
model_name='ebookprogress',
name='device',
field=models.CharField(blank=True, default='', max_length=40),
),
migrations.AddField(
model_name='ebookprogress',
name='furthest_fraction',
field=models.FloatField(default=0.0),
),
migrations.AddField(
model_name='ebookprogress',
name='furthest_anchor',
field=models.CharField(blank=True, default='', max_length=30),
),
migrations.RunPython(keep_what_we_know, migrations.RunPython.noop),
]