From 5cd43d53ba99e82e7b35386cca9970987b0bbab4 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Sat, 15 Feb 2020 14:38:46 -0800 Subject: [PATCH] Cleaning up model fields --- fedireads/migrations/0001_initial.py | 15 +++++------ fedireads/models/activity.py | 7 +++++- fedireads/models/book.py | 37 +++++----------------------- fedireads/models/user.py | 13 ++++------ fedireads/outgoing.py | 6 +++-- fedireads/templates/feed.html | 12 ++++----- fedireads/urls.py | 5 +++- fedireads/views.py | 17 ++++++++++--- 8 files changed, 50 insertions(+), 62 deletions(-) diff --git a/fedireads/migrations/0001_initial.py b/fedireads/migrations/0001_initial.py index 214204e3..4b9ee2e1 100644 --- a/fedireads/migrations/0001_initial.py +++ b/fedireads/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.3 on 2020-02-15 22:15 +# Generated by Django 3.0.3 on 2020-02-15 22:50 from django.conf import settings import django.contrib.auth.models @@ -35,7 +35,6 @@ class Migration(migrations.Migration): ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), ('private_key', models.TextField(blank=True, null=True)), ('public_key', models.TextField(blank=True, null=True)), - ('api_key', models.CharField(blank=True, max_length=255, null=True)), ('actor', models.CharField(max_length=255, unique=True)), ('inbox', models.CharField(max_length=255, unique=True)), ('shared_inbox', models.CharField(blank=True, max_length=255, null=True)), @@ -65,6 +64,7 @@ class Migration(migrations.Migration): ('content', fedireads.utils.fields.JSONField(max_length=5000)), ('activity_type', models.CharField(max_length=255)), ('fedireads_type', models.CharField(blank=True, max_length=255, null=True)), + ('local', models.BooleanField(default=True)), ('created_date', models.DateTimeField(auto_now_add=True)), ('updated_date', models.DateTimeField(auto_now=True)), ('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), @@ -84,7 +84,6 @@ class Migration(migrations.Migration): name='Book', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('activitypub_id', models.CharField(max_length=255)), ('openlibrary_key', models.CharField(max_length=255, unique=True)), ('data', fedireads.utils.fields.JSONField()), ('cover', models.ImageField(blank=True, null=True, upload_to='covers/')), @@ -99,7 +98,6 @@ class Migration(migrations.Migration): fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('server_name', models.CharField(max_length=255, unique=True)), - ('shared_inbox', models.CharField(max_length=255, unique=True)), ('status', models.CharField(default='federated', max_length=255)), ('application_type', models.CharField(max_length=255, null=True)), ], @@ -108,11 +106,9 @@ class Migration(migrations.Migration): name='Shelf', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('activitypub_id', models.CharField(max_length=255)), - ('identifier', models.CharField(max_length=255, unique=True)), ('name', models.CharField(max_length=100)), + ('identifier', models.CharField(max_length=100)), ('editable', models.BooleanField(default=True)), - ('shelf_type', models.CharField(default='custom', max_length=100)), ('created_date', models.DateTimeField(auto_now_add=True)), ('updated_date', models.DateTimeField(auto_now=True)), ], @@ -123,6 +119,7 @@ class Migration(migrations.Migration): ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('status_type', models.CharField(default='Note', max_length=255)), ('activity', fedireads.utils.fields.JSONField(max_length=5000, null=True)), + ('local', models.BooleanField(default=True)), ('content', models.TextField(blank=True, null=True)), ('created_date', models.DateTimeField(auto_now_add=True)), ('updated_date', models.DateTimeField(auto_now=True)), @@ -134,7 +131,7 @@ class Migration(migrations.Migration): name='ShelfBook', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), - ('added_date', models.DateTimeField(auto_now_add=True)), + ('created_date', models.DateTimeField(auto_now_add=True)), ('added_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), ('book', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='fedireads.Book')), ('shelf', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='fedireads.Shelf')), @@ -189,7 +186,7 @@ class Migration(migrations.Migration): ), migrations.AlterUniqueTogether( name='shelf', - unique_together={('user', 'name')}, + unique_together={('user', 'identifier')}, ), migrations.CreateModel( name='ReviewActivity', diff --git a/fedireads/models/activity.py b/fedireads/models/activity.py index e922f1f9..67d35cf0 100644 --- a/fedireads/models/activity.py +++ b/fedireads/models/activity.py @@ -5,6 +5,9 @@ from model_utils.managers import InheritanceManager from fedireads.utils.fields import JSONField +# TODO: I don't know that these Activity models should exist, at least in this way +# but I'm not sure what the right approach is for now. + class Activity(models.Model): ''' basic fields for storing activities ''' uuid = models.CharField(max_length=255, unique=True) @@ -14,6 +17,7 @@ class Activity(models.Model): activity_type = models.CharField(max_length=255) # custom types internal to fedireads (Review, Shelve, ...) fedireads_type = models.CharField(max_length=255, blank=True, null=True) + local = models.BooleanField(default=True) created_date = models.DateTimeField(auto_now_add=True) updated_date = models.DateTimeField(auto_now=True) objects = InheritanceManager() @@ -48,7 +52,7 @@ class ReviewActivity(Activity): book = models.ForeignKey('Book', on_delete=models.PROTECT) def save(self, *args, **kwargs): - self.activity_type = 'Article' + self.activity_type = 'Note' self.fedireads_type = 'Review' super().save(*args, **kwargs) @@ -58,6 +62,7 @@ class Status(models.Model): user = models.ForeignKey('User', on_delete=models.PROTECT) status_type = models.CharField(max_length=255, default='Note') activity = JSONField(max_length=5000, null=True) + local = models.BooleanField(default=True) reply_parent = models.ForeignKey( 'self', null=True, diff --git a/fedireads/models/book.py b/fedireads/models/book.py index 1cd9952c..e4b73dbe 100644 --- a/fedireads/models/book.py +++ b/fedireads/models/book.py @@ -1,23 +1,13 @@ -''' database schema for the whole dang thing ''' +''' database schema for books and shelves ''' from django.db import models -from model_utils.managers import InheritanceManager -from django.dispatch import receiver -from django.contrib.auth.models import AbstractUser -from django.core.exceptions import ValidationError -from Crypto import Random -from Crypto.PublicKey import RSA -import re - -from fedireads.settings import DOMAIN, OL_URL from fedireads.utils.fields import JSONField + class Shelf(models.Model): - activitypub_id = models.CharField(max_length=255) - identifier = models.CharField(max_length=255, unique=True) name = models.CharField(max_length=100) + identifier = models.CharField(max_length=100) user = models.ForeignKey('User', on_delete=models.PROTECT) editable = models.BooleanField(default=True) - shelf_type = models.CharField(default='custom', max_length=100) books = models.ManyToManyField( 'Book', symmetrical=False, @@ -28,18 +18,7 @@ class Shelf(models.Model): updated_date = models.DateTimeField(auto_now=True) class Meta: - unique_together = ('user', 'name') - - def save(self, *args, **kwargs): - if not self.identifier: - self.identifier = '%s_%s' % ( - self.user.localname, - re.sub(r'\W', '-', self.name).lower() - ) - if not self.activitypub_id: - self.activitypub_id = 'https://%s/shelf/%s' % \ - (DOMAIN, self.identifier) - super().save(*args, **kwargs) + unique_together = ('user', 'identifier') class ShelfBook(models.Model): @@ -52,7 +31,7 @@ class ShelfBook(models.Model): null=True, on_delete=models.PROTECT ) - added_date = models.DateTimeField(auto_now_add=True) + created_date = models.DateTimeField(auto_now_add=True) class Meta: unique_together = ('book', 'shelf') @@ -60,7 +39,6 @@ class ShelfBook(models.Model): class Book(models.Model): ''' a non-canonical copy of a work (not book) from open library ''' - activitypub_id = models.CharField(max_length=255) openlibrary_key = models.CharField(max_length=255, unique=True) data = JSONField() authors = models.ManyToManyField('Author') @@ -81,12 +59,9 @@ class Book(models.Model): added_date = models.DateTimeField(auto_now_add=True) updated_date = models.DateTimeField(auto_now=True) - def save(self, *args, **kwargs): - self.activitypub_id = '%s%s' % (OL_URL, self.openlibrary_key) - super().save(*args, **kwargs) - class Author(models.Model): + ''' copy of an author from OL ''' openlibrary_key = models.CharField(max_length=255) data = JSONField() added_date = models.DateTimeField(auto_now_add=True) diff --git a/fedireads/models/user.py b/fedireads/models/user.py index 908fa790..d396d38a 100644 --- a/fedireads/models/user.py +++ b/fedireads/models/user.py @@ -13,7 +13,6 @@ class User(AbstractUser): ''' a user who wants to read books ''' private_key = models.TextField(blank=True, null=True) public_key = models.TextField(blank=True, null=True) - api_key = models.CharField(max_length=255, blank=True, null=True) actor = models.CharField(max_length=255, unique=True) inbox = models.CharField(max_length=255, unique=True) shared_inbox = models.CharField(max_length=255, blank=True, null=True) @@ -41,7 +40,6 @@ class User(AbstractUser): class FederatedServer(models.Model): ''' store which server's we federate with ''' server_name = models.CharField(max_length=255, unique=True) - shared_inbox = models.CharField(max_length=255, unique=True) # federated, blocked, whatever else status = models.CharField(max_length=255, default='federated') # is it mastodon, fedireads, etc @@ -50,7 +48,7 @@ class FederatedServer(models.Model): @receiver(models.signals.pre_save, sender=User) def execute_before_save(sender, instance, *args, **kwargs): - ''' create shelves for new users ''' + ''' populate fields for new local users ''' # this user already exists, no need to poplate fields if instance.id or not instance.local: return @@ -72,25 +70,24 @@ def execute_before_save(sender, instance, *args, **kwargs): @receiver(models.signals.post_save, sender=User) def execute_after_save(sender, instance, created, *args, **kwargs): ''' create shelves for new users ''' - # TODO: how are remote users handled? what if they aren't readers? if not instance.local or not created: return shelves = [{ 'name': 'To Read', - 'type': 'to-read', + 'identifier': 'to-read', }, { 'name': 'Currently Reading', - 'type': 'reading', + 'identifier': 'reading', }, { 'name': 'Read', - 'type': 'read', + 'identifier': 'read', }] for shelf in shelves: Shelf( name=shelf['name'], - shelf_type=shelf['type'], + identifier=shelf['identifier'], user=instance, editable=False ).save() diff --git a/fedireads/outgoing.py b/fedireads/outgoing.py index 72e906f5..38c82be0 100644 --- a/fedireads/outgoing.py +++ b/fedireads/outgoing.py @@ -158,7 +158,8 @@ def handle_shelve(user, book, shelf): 'target': { 'type': 'Collection', 'name': shelf.name, - 'id': shelf.activitypub_id + 'id': 'https://%s/user/%s/shelf/%s' % \ + (DOMAIN, user.localname, shelf.identifier) } } recipients = get_recipients(user, 'public') @@ -202,7 +203,8 @@ def handle_unshelve(user, book, shelf): 'target': { 'type': 'Collection', 'name': shelf.name, - 'id': shelf.activitypub_id + 'id': 'https://%s/user/%s/shelf/%s' % \ + (DOMAIN, user.localname, shelf.identifier) } } recipients = get_recipients(user, 'public') diff --git a/fedireads/templates/feed.html b/fedireads/templates/feed.html index 6b8f2689..6ecb6536 100644 --- a/fedireads/templates/feed.html +++ b/fedireads/templates/feed.html @@ -10,7 +10,7 @@ {% for book in to_read.books.all %}
{% include 'snippets/book.html' with book=book size="small" %} -
+ {% csrf_token %} @@ -22,7 +22,7 @@ {% for book in reading.books.all %}
{% include 'snippets/book.html' with book=book size="small" %} - + {% csrf_token %} @@ -37,7 +37,7 @@
{% include 'snippets/book.html' with book=book size="small" %} {% if not book in user_books.all %} - + {% csrf_token %} @@ -57,11 +57,11 @@ {% include 'snippets/username.html' with user=activity.user %} {% if activity.fedireads_type == 'Shelve' %} {# display a reading/shelving activity #} - {% if activity.shelf.shelf_type == 'to-read' %} + {% if activity.shelf.identifier == 'to-read' %} wants to read - {% elif activity.shelf.shelf_type == 'read' %} + {% elif activity.shelf.identifier == 'read' %} finished reading - {% elif activity.shelf.shelf_type == 'reading' %} + {% elif activity.shelf.identifier == 'reading' %} started reading {% else %} shelved in "{{ activity.shelf.name }}" diff --git a/fedireads/urls.py b/fedireads/urls.py index 97177928..b7312d0d 100644 --- a/fedireads/urls.py +++ b/fedireads/urls.py @@ -47,7 +47,10 @@ urlpatterns = [ # internal action endpoints re_path(r'^review/?$', views.review), - re_path(r'^shelve/(?P[\w_-]+)/(?P\d+)/?$', views.shelve), + re_path( + r'^shelve/(?P\w+)/(?P[\w-]+)/(?P\d+)/?$', + views.shelve + ), re_path(r'^follow/?$', views.follow), re_path(r'^unfollow/?$', views.unfollow), re_path(r'^search/?$', views.search), diff --git a/fedireads/views.py b/fedireads/views.py index e40c4dc5..8292f6ec 100644 --- a/fedireads/views.py +++ b/fedireads/views.py @@ -17,11 +17,11 @@ def home(request): # user's shelves for display reading = models.Shelf.objects.get( user=request.user, - shelf_type='reading' + identifier='reading' ) to_read = models.Shelf.objects.get( user=request.user, - shelf_type='to-read' + identifier='to-read' ) # allows us to check if a user has shelved a book @@ -208,10 +208,18 @@ def author_page(request, author_identifier): @login_required -def shelve(request, shelf_id, book_id, reshelve=True): +def shelve(request, username, shelf_id, book_id, reshelve=True): ''' put a book on a user's shelf ''' + if request.user.localname != username: + # don't let people put books on other people's shelves + return HttpResponseNotFound() + book = models.Book.objects.get(id=book_id) - desired_shelf = models.Shelf.objects.get(identifier=shelf_id) + desired_shelf = models.Shelf.objects.filter( + identifier=shelf_id, + user=request.user + ).first() + if reshelve: try: current_shelf = models.Shelf.objects.get( @@ -220,6 +228,7 @@ def shelve(request, shelf_id, book_id, reshelve=True): ) outgoing.handle_unshelve(request.user, book, current_shelf) except models.Shelf.DoesNotExist: + # this just means it isn't currently on the user's shelves pass outgoing.handle_shelve(request.user, book, desired_shelf) return redirect('/')