diff --git a/fedireads/activitystream.py b/fedireads/activitystream.py new file mode 100644 index 000000000..06c8425be --- /dev/null +++ b/fedireads/activitystream.py @@ -0,0 +1,4 @@ +''' activitystream api ''' + +def webfinger(request): + return 'hi' diff --git a/fedireads/migrations/0001_initial.py b/fedireads/migrations/0001_initial.py index 266f12b07..f647d8866 100644 --- a/fedireads/migrations/0001_initial.py +++ b/fedireads/migrations/0001_initial.py @@ -1,4 +1,4 @@ -# Generated by Django 2.0.13 on 2020-01-25 06:23 +# Generated by Django 2.0.13 on 2020-01-25 21:32 from django.conf import settings import django.contrib.auth.models @@ -34,13 +34,10 @@ class Migration(migrations.Migration): ('date_joined', models.DateTimeField(default=django.utils.timezone.now, verbose_name='date joined')), ('private_key', models.CharField(max_length=255)), ('public_key', models.CharField(max_length=255)), - ('webfinger', django.contrib.postgres.fields.jsonb.JSONField(max_length=255)), - ('actor', django.contrib.postgres.fields.jsonb.JSONField(max_length=255)), - ('apikey', models.CharField(max_length=255)), - ('followers', models.CharField(max_length=255)), - ('messages', models.CharField(max_length=255)), - ('created_date', models.DateTimeField()), - ('updated_date', models.DateTimeField(blank=True, null=True)), + ('api_key', models.CharField(blank=True, max_length=255, null=True)), + ('created_date', models.DateTimeField(auto_now_add=True)), + ('updated_date', models.DateTimeField(auto_now=True)), + ('followers', models.ManyToManyField(to=settings.AUTH_USER_MODEL)), ('groups', models.ManyToManyField(blank=True, help_text='The groups this user belongs to. A user will get all permissions granted to each of their groups.', related_name='user_set', related_query_name='user', to='auth.Group', verbose_name='groups')), ('user_permissions', models.ManyToManyField(blank=True, help_text='Specific permissions for this user.', related_name='user_set', related_query_name='user', to='auth.Permission', verbose_name='user permissions')), ], @@ -59,8 +56,9 @@ class Migration(migrations.Migration): ('id', models.AutoField(primary_key=True, serialize=False)), ('openlibary_key', models.CharField(max_length=255)), ('data', django.contrib.postgres.fields.jsonb.JSONField()), - ('added_date', models.DateTimeField()), - ('updated_date', models.DateTimeField(blank=True, null=True)), + ('added_date', models.DateTimeField(auto_now_add=True)), + ('updated_date', models.DateTimeField(auto_now=True)), + ('added_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), ], ), migrations.CreateModel( @@ -68,6 +66,8 @@ class Migration(migrations.Migration): fields=[ ('name', models.CharField(max_length=255)), ('content', django.contrib.postgres.fields.jsonb.JSONField(max_length=5000)), + ('created_date', models.DateTimeField(auto_now_add=True)), + ('updated_date', models.DateTimeField(auto_now=True)), ('id', models.AutoField(primary_key=True, serialize=False)), ('star_rating', models.IntegerField(default=0)), ('author', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), @@ -83,15 +83,26 @@ class Migration(migrations.Migration): ('id', models.AutoField(primary_key=True, serialize=False)), ('name', models.CharField(max_length=100)), ('editable', models.BooleanField(default=True)), + ('created_date', models.DateTimeField(auto_now_add=True)), + ('updated_date', models.DateTimeField(auto_now=True)), + ('books', models.ManyToManyField(to='fedireads.Book')), ('user', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), ], ), migrations.CreateModel( - name='ShelfBooks', + name='Work', fields=[ ('id', models.AutoField(primary_key=True, serialize=False)), - ('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')), + ('openlibary_key', models.CharField(max_length=255)), + ('data', django.contrib.postgres.fields.jsonb.JSONField()), + ('added_date', models.DateTimeField(auto_now_add=True)), + ('updated_date', models.DateTimeField(auto_now=True)), + ('added_by', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL)), ], ), + migrations.AddField( + model_name='book', + name='works', + field=models.ManyToManyField(to='fedireads.Work'), + ), ] diff --git a/fedireads/models.py b/fedireads/models.py index e00ec1ea1..76d9630e6 100644 --- a/fedireads/models.py +++ b/fedireads/models.py @@ -2,18 +2,31 @@ from django.db import models from django.contrib.auth.models import AbstractUser from django.contrib.postgres.fields import JSONField +from Crypto.PublicKey import RSA +from Crypto import Random +from datetime import datetime class User(AbstractUser): ''' a user who wants to read books ''' private_key = models.CharField(max_length=255) public_key = models.CharField(max_length=255) - webfinger = JSONField(max_length=255) - actor = JSONField(max_length=255, blank=True, null=True) api_key = models.CharField(max_length=255, blank=True, null=True) - followers = models.CharField(max_length=255, blank=True, null=True) - messages = models.CharField(max_length=255, blank=True, null=True) - created_date = models.DateTimeField() - updated_date = models.DateTimeField(blank=True, null=True) + created_date = models.DateTimeField(auto_now_add=True) + updated_date = models.DateTimeField(auto_now=True) + followers = models.ManyToManyField('self', symmetrical=False) + + def save(self, *args, **kwargs): + # give a new user keys + if not self.private_key: + random_generator = Random.new().read + key = RSA.generate(1024, random_generator) + self.private_key = key + self.public_key = key.publickey() + if not self.id: + self.created_date = datetime.now() + self.updated_date = datetime.now() + + super().save(*args, **kwargs) class Message(models.Model): @@ -22,6 +35,8 @@ class Message(models.Model): author = models.ForeignKey('User', on_delete=models.PROTECT) name = models.CharField(max_length=255) content = JSONField(max_length=5000) + created_date = models.DateTimeField(auto_now_add=True) + updated_date = models.DateTimeField(auto_now=True) class Meta: abstract = True @@ -38,6 +53,9 @@ class Shelf(models.Model): name = models.CharField(max_length=100) user = models.ForeignKey('User', on_delete=models.PROTECT) editable = models.BooleanField(default=True) + books = models.ManyToManyField('Book', symmetrical=False) + created_date = models.DateTimeField(auto_now_add=True) + updated_date = models.DateTimeField(auto_now=True) class Book(models.Model): @@ -45,12 +63,15 @@ class Book(models.Model): id = models.AutoField(primary_key=True) openlibary_key = models.CharField(max_length=255) data = JSONField() - added_date = models.DateTimeField() - updated_date = models.DateTimeField(blank=True, null=True) + works = models.ManyToManyField('Work') + added_by = models.ForeignKey('User', on_delete=models.PROTECT, blank=True, null=True) + added_date = models.DateTimeField(auto_now_add=True) + updated_date = models.DateTimeField(auto_now=True) - -class ShelfBooks(models.Model): - ''' many to many join table ''' +class Work(models.Model): id = models.AutoField(primary_key=True) - shelf = models.ForeignKey('Shelf', on_delete=models.PROTECT) - book = models.ForeignKey('Book', on_delete=models.PROTECT) + openlibary_key = models.CharField(max_length=255) + data = JSONField() + added_by = models.ForeignKey('User', on_delete=models.PROTECT, blank=True, null=True) + added_date = models.DateTimeField(auto_now_add=True) + updated_date = models.DateTimeField(auto_now=True) diff --git a/fedireads/openlibrary.py b/fedireads/openlibrary.py new file mode 100644 index 000000000..3953da2d4 --- /dev/null +++ b/fedireads/openlibrary.py @@ -0,0 +1,36 @@ +''' activitystream api and books ''' +from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest +from django.core.exceptions import ObjectDoesNotExist +from django.core import serializers +from fedireads.models import Book, Work +import requests + +openlibrary_url = 'https://openlibrary.org' + +def get_book(request, olkey): + # check if this is a valid open library key, and a book + response = requests.get(openlibrary_url + '/book/' + olkey + '.json') + + # get the existing entry from our db, if it exists + try: + book = Book.objects.get(openlibary_key=olkey) + except ObjectDoesNotExist: + book = Book(openlibary_key=olkey) + data = response.json() + book.data = data + book.save() + for work_id in data['works']: + work_id = work_id['key'] + book.works.add(get_or_create_work(work_id)) + return HttpResponse(serializers.serialize('json', [book])) + +def get_or_create_work(olkey): + try: + work = Work.objects.get(openlibary_key=olkey) + except ObjectDoesNotExist: + response = requests.get(openlibrary_url + '/work/' + olkey +'.json') + data = response.json() + work = Work(openlibary_key=olkey, data=data) + work.save() + return work + diff --git a/fedireads/urls.py b/fedireads/urls.py index 660dfc8b3..e4a94ebda 100644 --- a/fedireads/urls.py +++ b/fedireads/urls.py @@ -15,10 +15,10 @@ Including another URLconf """ from django.contrib import admin from django.urls import path -from fedireads import views +from fedireads import activitystream, openlibrary, views urlpatterns = [ path('admin/', admin.site.urls), - path('api/', views.api), - path('webfinger/', views.webfinger), + path('api/book/', openlibrary.get_book), + path('webfinger/', activitystream.webfinger), ]