Compare commits

..
1 Commits
Author SHA1 Message Date
Marko (Hermes Implementer) 45d16d00ed refactor: consolidate backend/frontend, remove api/web duplicates
- backend/ kept as canonical, api/ features merged (EBook, ReadingProgress, ReadingSettings)
- frontend/ kept as canonical, web/ pages merged (Library, Reader, AddBook, Auth, Settings)
- Added Dockerfiles for backend/ and frontend/
- Updated docker-compose.yml for consolidated services
- Updated README, package.json workspaces
- api/ and web/ directories removed
2026-05-26 02:58:24 +00:00
3 changed files with 2 additions and 98 deletions
@@ -1,96 +0,0 @@
# Generated by Django 5.1.7 on 2026-05-26 03:33
import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models
class Migration(migrations.Migration):
initial = True
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]
operations = [
migrations.CreateModel(
name='Book',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(db_index=True, max_length=512)),
('author', models.CharField(blank=True, db_index=True, default='', max_length=256)),
('genre', models.CharField(blank=True, db_index=True, default='', max_length=128)),
('description', models.TextField(blank=True, default='')),
('reading_status', models.CharField(choices=[('want_to_read', 'Want to Read'), ('reading', 'Reading'), ('finished', 'Finished'), ('dnf', 'Did Not Finish')], db_index=True, default='want_to_read', max_length=20)),
('total_pages', models.PositiveIntegerField(default=0)),
('cover_image', models.URLField(blank=True, default='')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
],
options={
'verbose_name': 'Book',
'verbose_name_plural': 'Books',
'db_table': 'books_book',
'ordering': ['title'],
'indexes': [models.Index(fields=['title', 'author', 'genre'], name='books_book_title_9fddc2_idx')],
},
),
migrations.CreateModel(
name='EBook',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('title', models.CharField(max_length=512)),
('author', models.CharField(blank=True, default='', max_length=256)),
('file', models.FileField(upload_to='ebooks/%Y/%m/%d/')),
('cover_image', models.ImageField(blank=True, null=True, upload_to='ebook_covers/%Y/%m/%d/')),
('created_at', models.DateTimeField(auto_now_add=True)),
('updated_at', models.DateTimeField(auto_now=True)),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='ebooks', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'E-Book',
'verbose_name_plural': 'E-Books',
'db_table': 'books_ebook',
'ordering': ['-created_at'],
},
),
migrations.CreateModel(
name='ReadingProgress',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('current_position', models.FloatField(default=0.0)),
('last_page', models.IntegerField(default=0)),
('updated_at', models.DateTimeField(auto_now=True)),
('ebook', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='reading_progress', to='books.ebook')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='reading_progress', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name_plural': 'reading progress',
'db_table': 'books_reading_progress',
},
),
migrations.CreateModel(
name='ReadingSettings',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('font_size', models.IntegerField(default=18)),
('font_style', models.CharField(choices=[('sans-serif', 'Sans Serif'), ('serif', 'Serif'), ('monospace', 'Monospace')], default='sans-serif', max_length=20)),
('background_color', models.CharField(choices=[('#ffffff', 'White'), ('#f4e4c1', 'Sepia'), ('#1a1a2e', 'Dark'), ('#c7edcc', 'Green')], default='#ffffff', max_length=7)),
('updated_at', models.DateTimeField(auto_now=True)),
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, related_name='reading_settings', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name_plural': 'reading settings',
'db_table': 'books_reading_settings',
},
),
migrations.AddIndex(
model_name='ebook',
index=models.Index(fields=['user', '-created_at'], name='books_ebook_user_id_0b6bdb_idx'),
),
migrations.AlterUniqueTogether(
name='readingprogress',
unique_together={('user', 'ebook')},
),
]
+2 -2
View File
@@ -2,7 +2,7 @@ from typing import Any
from django.db.models import QuerySet, Q from django.db.models import QuerySet, Q
from django_filters.rest_framework import DjangoFilterBackend from django_filters.rest_framework import DjangoFilterBackend
from rest_framework import parsers, permissions, status, viewsets from rest_framework import parsers, status, viewsets
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.filters import OrderingFilter, SearchFilter from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.permissions import AllowAny, IsAuthenticated from rest_framework.permissions import AllowAny, IsAuthenticated
@@ -51,7 +51,7 @@ class BookViewSet(viewsets.ModelViewSet):
return Response([a for a in author_list if a]) return Response([a for a in author_list if a])
class IsEBookOwner(permissions.BasePermission): class IsEBookOwner(AllowAny):
def has_object_permission(self, request: Request, view: object, obj: EBook) -> bool: def has_object_permission(self, request: Request, view: object, obj: EBook) -> bool:
return obj.user == request.user return obj.user == request.user