diora-web/books/models.py
marwin 1af07c7952
All checks were successful
Build and push Docker image / build (push) Successful in 12s
Test / test (push) Successful in 15s
Add anchor-based reading position tracking
Replaces scroll_fraction-only position tracking with element-based
anchors ("{index}:{innerFraction}"). Position is now stable across
font size changes and different screen sizes. A ResizeObserver
restores the anchor on viewport/orientation changes.

Falls back to scroll_fraction for books without a saved anchor.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 15:41:30 +02:00

59 lines
2.3 KiB
Python

from django.db import models
from django.contrib.auth.models import User
class EBook(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='ebooks')
meta_ct = models.TextField() # base64 AES-GCM ciphertext of {title, author, filename}
meta_iv = models.CharField(max_length=32) # hex IV for metadata
data_ct = models.TextField() # base64 AES-GCM ciphertext of raw EPUB bytes
data_iv = models.CharField(max_length=32) # hex IV for EPUB data
uploaded_at = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ['uploaded_at']
def __str__(self):
return f"EBook #{self.pk} (user={self.user_id})"
class EBookProgress(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='ebook_progress')
book = models.ForeignKey(EBook, on_delete=models.CASCADE, related_name='progress')
scroll_fraction = models.FloatField(default=0.0)
position_anchor = models.CharField(max_length=30, blank=True, default='')
updated_at = models.DateTimeField(auto_now=True)
class Meta:
unique_together = ('user', 'book')
def __str__(self):
return f"Progress book={self.book_id} user={self.user_id} {self.scroll_fraction:.2f}"
class EBookHighlights(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='ebook_highlights')
book = models.ForeignKey(EBook, on_delete=models.CASCADE, related_name='highlights')
ct = models.TextField() # base64 AES-GCM ciphertext of JSON array
iv = models.CharField(max_length=32) # hex IV
updated_at = models.DateTimeField(auto_now=True)
class Meta:
unique_together = ('user', 'book')
def __str__(self):
return f"Highlights book={self.book_id} user={self.user_id}"
class EBookBookmarks(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='ebook_bookmarks')
book = models.ForeignKey(EBook, on_delete=models.CASCADE, related_name='bookmarks')
ct = models.TextField()
iv = models.CharField(max_length=32)
updated_at = models.DateTimeField(auto_now=True)
class Meta:
unique_together = ('user', 'book')
def __str__(self):
return f"Bookmarks book={self.book_id} user={self.user_id}"