From 8494719512ad371e63a1800494df52bcb38631fd Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Mar 2020 14:14:28 -0700 Subject: [PATCH 1/5] Adds book data source connector database table --- fedireads/books_manager.py | 4 ++ fedireads/connectors/abstract_connector.py | 3 +- .../migrations/0020_auto_20200327_2114.py | 49 +++++++++++++++++++ fedireads/models/__init__.py | 2 +- fedireads/models/book.py | 35 +++++++++++-- init_db.py | 17 ++++++- 6 files changed, 102 insertions(+), 8 deletions(-) create mode 100644 fedireads/migrations/0020_auto_20200327_2114.py diff --git a/fedireads/books_manager.py b/fedireads/books_manager.py index 90bc6d86..15a0517f 100644 --- a/fedireads/books_manager.py +++ b/fedireads/books_manager.py @@ -9,3 +9,7 @@ def get_or_create_book(key): def search(query): ''' ya ''' return openlibrary.search(query) + + +def update_book(key): + return openlibrary.update_book(key) diff --git a/fedireads/connectors/abstract_connector.py b/fedireads/connectors/abstract_connector.py index 045e655e..6f378a78 100644 --- a/fedireads/connectors/abstract_connector.py +++ b/fedireads/connectors/abstract_connector.py @@ -61,4 +61,5 @@ class SearchResult(object): self.raw_data = raw_data def __repr__(self): - return "".format(self.key, self.title, self.author) + return "".format( + self.key, self.title, self.author) diff --git a/fedireads/migrations/0020_auto_20200327_2114.py b/fedireads/migrations/0020_auto_20200327_2114.py new file mode 100644 index 00000000..b21a2064 --- /dev/null +++ b/fedireads/migrations/0020_auto_20200327_2114.py @@ -0,0 +1,49 @@ +# Generated by Django 3.0.3 on 2020-03-27 21:14 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('fedireads', '0019_comment'), + ] + + operations = [ + migrations.CreateModel( + name='Connector', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created_date', models.DateTimeField(auto_now_add=True)), + ('updated_date', models.DateTimeField(auto_now=True)), + ('name', models.CharField(max_length=255)), + ('api_key', models.CharField(max_length=255, null=True)), + ('base_url', models.CharField(max_length=255)), + ('covers_url', models.CharField(max_length=255)), + ('search_url', models.CharField(max_length=255, null=True)), + ('key_name', models.CharField(max_length=255)), + ('politeness_delay', models.IntegerField(null=True)), + ('max_query_count', models.IntegerField(null=True)), + ('query_count', models.IntegerField(default=0)), + ('query_count_expiry', models.DateTimeField(auto_now_add=True)), + ], + options={ + 'abstract': False, + }, + ), + migrations.RenameField( + model_name='book', + old_name='origin', + new_name='source_url', + ), + migrations.RemoveField( + model_name='book', + name='local_edits', + ), + migrations.AddField( + model_name='book', + name='connector', + field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.PROTECT, to='fedireads.Connector'), + ), + ] diff --git a/fedireads/models/__init__.py b/fedireads/models/__init__.py index 0902e38b..c201383d 100644 --- a/fedireads/models/__init__.py +++ b/fedireads/models/__init__.py @@ -1,5 +1,5 @@ ''' bring all the models into the app namespace ''' -from .book import Book, Work, Edition, Author +from .book import Connector, Book, Work, Edition, Author from .shelf import Shelf, ShelfBook from .status import Status, Review, Comment, Favorite, Tag, Notification from .user import User, FederatedServer, UserFollows, UserFollowRequest, \ diff --git a/fedireads/models/book.py b/fedireads/models/book.py index 6cdedfe2..42f8742a 100644 --- a/fedireads/models/book.py +++ b/fedireads/models/book.py @@ -8,6 +8,25 @@ from fedireads.utils.fields import JSONField, ArrayField from fedireads.utils.models import FedireadsModel +class Connector(FedireadsModel): + ''' book data source connectors ''' + name = models.CharField(max_length=255) + api_key = models.CharField(max_length=255, null=True) + + base_url = models.CharField(max_length=255) + covers_url = models.CharField(max_length=255) + search_url = models.CharField(max_length=255, null=True) + + key_name = models.CharField(max_length=255) + + politeness_delay = models.IntegerField(null=True) #seconds + max_query_count = models.IntegerField(null=True) + # how many queries executed in a unit of time, like a day + query_count = models.IntegerField(default=0) + # when to reset the query count back to 0 (ie, after 1 day) + query_count_expiry = models.DateTimeField(auto_now_add=True) + + class Book(FedireadsModel): ''' a generic book, which can mean either an edition or a work ''' # these identifiers apply to both works and editions @@ -17,10 +36,11 @@ class Book(FedireadsModel): misc_identifiers = JSONField(null=True) # info about where the data comes from and where/if to sync - origin = models.CharField(max_length=255, unique=True, null=True) - local_edits = models.BooleanField(default=False) + source_url = models.CharField(max_length=255, unique=True, null=True) sync = models.BooleanField(default=True) last_sync_date = models.DateTimeField(default=datetime.now) + connector = models.ForeignKey( + 'Connector', on_delete=models.PROTECT, null=True) # TODO: edit history @@ -55,7 +75,12 @@ class Book(FedireadsModel): return '%s/%s/%s' % (base_path, model_name, self.openlibrary_key) def __repr__(self): - return "<{} key={!r} title={!r} author={!r}>".format(self.__class__, self.openlibrary_key, self.title, self.author) + return "<{} key={!r} title={!r} author={!r}>".format( + self.__class__, + self.openlibrary_key, + self.title, + self.author + ) class Work(Book): @@ -82,6 +107,8 @@ class Author(FedireadsModel): name = models.CharField(max_length=255) last_name = models.CharField(max_length=255, null=True) first_name = models.CharField(max_length=255, null=True) - aliases = ArrayField(models.CharField(max_length=255), blank=True, default=list) + aliases = ArrayField( + models.CharField(max_length=255), blank=True, default=list + ) bio = models.TextField(null=True, blank=True) diff --git a/init_db.py b/init_db.py index f659603d..d7e3c3b1 100644 --- a/init_db.py +++ b/init_db.py @@ -1,10 +1,23 @@ -from fedireads.models import User +''' starter data ''' +from fedireads.models import Connector, User from fedireads.books_manager import get_or_create_book User.objects.create_user('mouse', 'mouse.reeve@gmail.com', 'password123') -User.objects.create_user('rat', 'rat@rat.com', 'ratword', manually_approves_followers=True) +User.objects.create_user( + 'rat', 'rat@rat.com', 'ratword', + manually_approves_followers=True +) User.objects.get(id=1).followers.add(User.objects.get(id=2)) +Connector.objects.create( + name='OpenLibrary', + base_url='https://openlibrary.org', + covers_url='https://covers.openlibrary.org', + search_url='https://openlibrary.org/search?q=', + key_name='olkey', +) + + get_or_create_book('OL1715344W') get_or_create_book('OL102749W') From 5d2fbb85003e69f6b23063815937b0b2014514da Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Mar 2020 15:25:08 -0700 Subject: [PATCH 2/5] Use database as source for initializing connector --- fedireads/books_manager.py | 34 +++++++++++++++---- fedireads/connectors/__init__.py | 1 - fedireads/connectors/abstract_connector.py | 24 ++++++++----- fedireads/connectors/openlibrary.py | 6 ++-- fedireads/connectors/settings.py | 27 ++------------- ...327_2114.py => 0020_auto_20200327_2201.py} | 6 ++-- fedireads/models/book.py | 4 +-- 7 files changed, 56 insertions(+), 46 deletions(-) rename fedireads/migrations/{0020_auto_20200327_2114.py => 0020_auto_20200327_2201.py} (89%) diff --git a/fedireads/books_manager.py b/fedireads/books_manager.py index 15a0517f..fcaf6570 100644 --- a/fedireads/books_manager.py +++ b/fedireads/books_manager.py @@ -1,15 +1,37 @@ ''' select and call a connector for whatever book task needs doing ''' -from fedireads.connectors import OpenLibraryConnector +import importlib + +from fedireads import models +from fedireads.connectors.settings import CONNECTORS + -openlibrary = OpenLibraryConnector() def get_or_create_book(key): ''' pull up a book record by whatever means possible ''' - return openlibrary.get_or_create_book(key) + try: + book = models.Book.objects.get( + openlibrary_key=key + ).select_subclasses() + return book + except models.Book.DoesNotExist: + pass + + connector = get_connector() + return connector.get_or_create_book(key) + def search(query): ''' ya ''' - return openlibrary.search(query) + connector = get_connector() + return connector.search(query) -def update_book(key): - return openlibrary.update_book(key) +def get_connector(book=None): + ''' pick a book data connector ''' + if book and book.connector: + connector_info = book.connector + else: + connector_info = models.Connector.objects.first() + + classname = CONNECTORS[connector_info.name]['classname'] + connector = importlib.import_module(classname) + return connector.Connector() diff --git a/fedireads/connectors/__init__.py b/fedireads/connectors/__init__.py index 8cee368c..b525f65f 100644 --- a/fedireads/connectors/__init__.py +++ b/fedireads/connectors/__init__.py @@ -1,3 +1,2 @@ ''' bring connectors into the namespace ''' from .settings import CONNECTORS -from .openlibrary import OpenLibraryConnector diff --git a/fedireads/connectors/abstract_connector.py b/fedireads/connectors/abstract_connector.py index 6f378a78..7e83b734 100644 --- a/fedireads/connectors/abstract_connector.py +++ b/fedireads/connectors/abstract_connector.py @@ -1,6 +1,7 @@ ''' functionality outline for a book data connector ''' from abc import ABC, abstractmethod +from fedireads import models from fedireads.connectors import CONNECTORS @@ -13,15 +14,22 @@ class AbstractConnector(ABC): if not settings: raise ValueError('No connector with name "%s"' % connector_name) - try: - self.url = settings['BASE_URL'] - self.covers_url = settings['COVERS_URL'] - self.db_field = settings['DB_KEY_FIELD'] - self.key_name = settings['KEY_NAME'] - except KeyError: - raise KeyError('Invalid connector settings') - # TODO: politeness settings + info = models.Connector.objects.get(name=settings['db_name']) + self.model = info + self.url = info.base_url + self.covers_url = info.covers_url + self.search_url = info.search_url + self.key_name = info.key_name + self.max_query_count = info.max_query_count + + + def is_available(self): + ''' check if you're allowed to use this connector ''' + if self.model.max_query_count is not None: + if self.model.query_count >= self.model.max_query_count: + return False + return True @abstractmethod def search(self, query): diff --git a/fedireads/connectors/openlibrary.py b/fedireads/connectors/openlibrary.py index 1beedb08..a83a7d63 100644 --- a/fedireads/connectors/openlibrary.py +++ b/fedireads/connectors/openlibrary.py @@ -8,10 +8,10 @@ from fedireads import models from .abstract_connector import AbstractConnector, SearchResult -class OpenLibraryConnector(AbstractConnector): +class Connector(AbstractConnector): ''' instantiate a connector for OL ''' def __init__(self): - super().__init__('openlibrary') + super().__init__('OpenLibrary') def search(self, query): @@ -76,6 +76,8 @@ class OpenLibraryConnector(AbstractConnector): key = data.get('works')[0]['key'] key = key.split('/')[-1] work = self.get_or_create_book(key) + h + book.parent_work = work # we also need to know the author get the cover diff --git a/fedireads/connectors/settings.py b/fedireads/connectors/settings.py index 0b34a22e..9a0103f0 100644 --- a/fedireads/connectors/settings.py +++ b/fedireads/connectors/settings.py @@ -1,28 +1,7 @@ ''' settings book data connectors ''' CONNECTORS = { - 'openlibrary': { - 'KEY_NAME': 'olkey', - 'DB_KEY_FIELD': 'openlibrary_key', - 'POLITENESS_DELAY': 0, - 'MAX_DAILY_QUERIES': -1, - 'BASE_URL': 'https://openlibrary.org', - 'COVERS_URL': 'https://covers.openlibrary.org', + 'OpenLibrary': { + 'db_name': 'OpenLibrary', + 'classname': 'fedireads.connectors.openlibrary', }, } - -''' not implemented yet: - 'librarything': { - 'KEY_NAME': 'ltkey', - 'DB_KEY_FIELD': 'librarything_key', - 'POLITENESS_DELAY': 1, - 'MAX_DAILY_QUERIES': 1000, - 'BASE_URL': 'https://librarything.com', - }, - 'worldcat': { - 'KEY_NAME': 'ocn', - 'DB_KEY_FIELD': 'oclc_number', - 'POLITENESS_DELAY': 0, - 'MAX_DAILY_QUERIES': -1, - 'BASE_URL': 'https://worldcat.org', - }, -''' diff --git a/fedireads/migrations/0020_auto_20200327_2114.py b/fedireads/migrations/0020_auto_20200327_2201.py similarity index 89% rename from fedireads/migrations/0020_auto_20200327_2114.py rename to fedireads/migrations/0020_auto_20200327_2201.py index b21a2064..89f45fbe 100644 --- a/fedireads/migrations/0020_auto_20200327_2114.py +++ b/fedireads/migrations/0020_auto_20200327_2201.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.3 on 2020-03-27 21:14 +# Generated by Django 3.0.3 on 2020-03-27 22:01 from django.db import migrations, models import django.db.models.deletion @@ -17,12 +17,12 @@ class Migration(migrations.Migration): ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created_date', models.DateTimeField(auto_now_add=True)), ('updated_date', models.DateTimeField(auto_now=True)), - ('name', models.CharField(max_length=255)), + ('name', models.CharField(max_length=255, unique=True)), ('api_key', models.CharField(max_length=255, null=True)), ('base_url', models.CharField(max_length=255)), ('covers_url', models.CharField(max_length=255)), ('search_url', models.CharField(max_length=255, null=True)), - ('key_name', models.CharField(max_length=255)), + ('key_name', models.CharField(max_length=255, unique=True)), ('politeness_delay', models.IntegerField(null=True)), ('max_query_count', models.IntegerField(null=True)), ('query_count', models.IntegerField(default=0)), diff --git a/fedireads/models/book.py b/fedireads/models/book.py index 42f8742a..94e522b2 100644 --- a/fedireads/models/book.py +++ b/fedireads/models/book.py @@ -10,14 +10,14 @@ from fedireads.utils.models import FedireadsModel class Connector(FedireadsModel): ''' book data source connectors ''' - name = models.CharField(max_length=255) + name = models.CharField(max_length=255, unique=True) api_key = models.CharField(max_length=255, null=True) base_url = models.CharField(max_length=255) covers_url = models.CharField(max_length=255) search_url = models.CharField(max_length=255, null=True) - key_name = models.CharField(max_length=255) + key_name = models.CharField(max_length=255, unique=True) politeness_delay = models.IntegerField(null=True) #seconds max_query_count = models.IntegerField(null=True) From 0f986106294d0becd523c54a9cb82d9bee317ed9 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Mar 2020 15:42:44 -0700 Subject: [PATCH 3/5] Use local key instead of openlibrary key in urls but uh maybe the local key shouldn't look so gnarly? --- fedireads/books_manager.py | 6 +++--- ...0_auto_20200327_2201.py => 0020_auto_20200327_2236.py} | 2 +- fedireads/models/book.py | 2 ++ fedireads/outgoing.py | 2 +- fedireads/templates/book.html | 4 ++-- fedireads/templates/snippets/authors.html | 2 +- fedireads/templates/snippets/book.html | 2 +- fedireads/templates/snippets/create_status.html | 8 +++----- fedireads/templates/snippets/shelf.html | 4 ++-- fedireads/templates/snippets/tag.html | 4 ++-- fedireads/urls.py | 4 ++-- fedireads/views.py | 4 +++- init_db.py | 2 +- 13 files changed, 24 insertions(+), 22 deletions(-) rename fedireads/migrations/{0020_auto_20200327_2201.py => 0020_auto_20200327_2236.py} (97%) diff --git a/fedireads/books_manager.py b/fedireads/books_manager.py index fcaf6570..915d95cc 100644 --- a/fedireads/books_manager.py +++ b/fedireads/books_manager.py @@ -8,9 +8,9 @@ from fedireads.connectors.settings import CONNECTORS def get_or_create_book(key): ''' pull up a book record by whatever means possible ''' try: - book = models.Book.objects.get( - openlibrary_key=key - ).select_subclasses() + book = models.Book.objects.select_subclasses().get( + local_key=key + ) return book except models.Book.DoesNotExist: pass diff --git a/fedireads/migrations/0020_auto_20200327_2201.py b/fedireads/migrations/0020_auto_20200327_2236.py similarity index 97% rename from fedireads/migrations/0020_auto_20200327_2201.py rename to fedireads/migrations/0020_auto_20200327_2236.py index 89f45fbe..7292e34c 100644 --- a/fedireads/migrations/0020_auto_20200327_2201.py +++ b/fedireads/migrations/0020_auto_20200327_2236.py @@ -1,4 +1,4 @@ -# Generated by Django 3.0.3 on 2020-03-27 22:01 +# Generated by Django 3.0.3 on 2020-03-27 22:36 from django.db import migrations, models import django.db.models.deletion diff --git a/fedireads/models/book.py b/fedireads/models/book.py index 94e522b2..9edf5933 100644 --- a/fedireads/models/book.py +++ b/fedireads/models/book.py @@ -1,6 +1,7 @@ ''' database schema for books and shelves ''' from datetime import datetime from django.db import models +from model_utils.managers import InheritanceManager from uuid import uuid4 from fedireads.settings import DOMAIN @@ -66,6 +67,7 @@ class Book(FedireadsModel): ) # TODO: why can't I just call this work???? parent_work = models.ForeignKey('Work', on_delete=models.PROTECT, null=True) + objects = InheritanceManager() @property def absolute_id(self): diff --git a/fedireads/outgoing.py b/fedireads/outgoing.py index 9817c4bc..f204888b 100644 --- a/fedireads/outgoing.py +++ b/fedireads/outgoing.py @@ -232,7 +232,7 @@ def handle_tag(user, book, name): def handle_untag(user, book, name): ''' tag a book ''' - book = models.Book.objects.get(openlibrary_key=book) + book = models.Book.objects.get(local_key=book) tag = models.Tag.objects.get(name=name, book=book, user=user) tag_activity = activitypub.get_remove_tag(tag) tag.delete() diff --git a/fedireads/templates/book.html b/fedireads/templates/book.html index 25776181..74777a19 100644 --- a/fedireads/templates/book.html +++ b/fedireads/templates/book.html @@ -5,7 +5,7 @@

{{ book.title }} by {% include 'snippets/authors.html' with book=book %}

- {% if book.parent_work %}

Edition of {{ book.parent_work.title }}

{% endif %} + {% if book.parent_work %}

Edition of {{ book.parent_work.title }}

{% endif %}
{% include 'snippets/book_cover.html' with book=book size=large %} @@ -32,7 +32,7 @@

Leave a review

{% csrf_token %} - + {{ review_form.as_p }}
diff --git a/fedireads/templates/snippets/authors.html b/fedireads/templates/snippets/authors.html index 1d619153..e45a19a5 100644 --- a/fedireads/templates/snippets/authors.html +++ b/fedireads/templates/snippets/authors.html @@ -1 +1 @@ -{{ book.authors.first.name }} +{{ book.authors.first.name }} diff --git a/fedireads/templates/snippets/book.html b/fedireads/templates/snippets/book.html index ce960a8e..dad89603 100644 --- a/fedireads/templates/snippets/book.html +++ b/fedireads/templates/snippets/book.html @@ -1,7 +1,7 @@ {% load fr_display %} {% include 'snippets/book_cover.html' with book=book %}

- {{ book.title }} + {{ book.title }}

by {% include 'snippets/authors.html' with book=book %} diff --git a/fedireads/templates/snippets/create_status.html b/fedireads/templates/snippets/create_status.html index 8206e768..bd3efbcf 100644 --- a/fedireads/templates/snippets/create_status.html +++ b/fedireads/templates/snippets/create_status.html @@ -4,7 +4,7 @@

{% include 'snippets/avatar.html' with user=user %} Your thoughts on - {{ book.title }} + {{ book.title }} by {% include 'snippets/authors.html' with book=book %}

@@ -24,16 +24,14 @@ {% include 'snippets/book_cover.html' with book=book %}
{% csrf_token %} - {# todo: this shouldn't use the openlibrary key #} - + {{ review_form.as_p }}
diff --git a/fedireads/templates/snippets/shelf.html b/fedireads/templates/snippets/shelf.html index b18967e7..e0975a48 100644 --- a/fedireads/templates/snippets/shelf.html +++ b/fedireads/templates/snippets/shelf.html @@ -33,7 +33,7 @@ {% include 'snippets/book_cover.html' with book=book size="small" %} - {{ book.title }} + {{ book.title }} {{ book.authors.first.name }} @@ -45,7 +45,7 @@ {{ book.created_date | naturalday }} - OpenLibrary + OpenLibrary {% if ratings %} diff --git a/fedireads/templates/snippets/tag.html b/fedireads/templates/snippets/tag.html index 48822a92..14d6f102 100644 --- a/fedireads/templates/snippets/tag.html +++ b/fedireads/templates/snippets/tag.html @@ -3,14 +3,14 @@ {% if tag.identifier in user_tags %}
{% csrf_token %} - +
{% else %}
{% csrf_token %} - +
diff --git a/fedireads/urls.py b/fedireads/urls.py index 10761e86..fc054ed2 100644 --- a/fedireads/urls.py +++ b/fedireads/urls.py @@ -56,8 +56,8 @@ urlpatterns = [ re_path(r'%s/replies\.json$' % status_path, views.replies_page), # books - re_path(r'^book/(?P\w+)/?$', views.book_page), - re_path(r'^book/(?P\w+)/(?Pfriends|local|federated)?$', views.book_page), + re_path(r'^book/(?P[\w\-]+)/?$', views.book_page), + re_path(r'^book/(?P[\w\-]+)/(?Pfriends|local|federated)?$', views.book_page), re_path(r'^author/(?P\w+)/?$', views.author_page), re_path(r'^tag/(?P.+)/?$', views.tag_page), re_path(r'^shelf/%s/(?P[\w-]+)/?$' % username_regex, views.shelf_page), diff --git a/fedireads/views.py b/fedireads/views.py index 7d9d6e99..f94c3df1 100644 --- a/fedireads/views.py +++ b/fedireads/views.py @@ -100,7 +100,9 @@ def books_page(request): ''' discover books ''' recent_books = models.Book.objects if request.user.is_authenticated: - recent_books = recent_books.filter(~Q(shelfbook__shelf__user=request.user)) + recent_books = recent_books.filter( + ~Q(shelfbook__shelf__user=request.user) + ) recent_books = recent_books.order_by('-created_date')[:50] data = { diff --git a/init_db.py b/init_db.py index d7e3c3b1..2d6f2d94 100644 --- a/init_db.py +++ b/init_db.py @@ -15,7 +15,7 @@ Connector.objects.create( base_url='https://openlibrary.org', covers_url='https://covers.openlibrary.org', search_url='https://openlibrary.org/search?q=', - key_name='olkey', + key_name='openlibrary_key', ) From ed6fd6d48ec015880a30665c0bd2c2a1f68abf03 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Mar 2020 16:36:52 -0700 Subject: [PATCH 4/5] Rename local key and suggest fedireads connectors --- fedireads/books_manager.py | 10 ++++---- fedireads/connectors/abstract_connector.py | 9 ++----- fedireads/connectors/openlibrary.py | 5 ++-- fedireads/connectors/settings.py | 8 ++---- ...327_2236.py => 0020_auto_20200327_2335.py} | 21 +++++++++++----- fedireads/models/book.py | 25 ++++++++++++++++--- fedireads/outgoing.py | 2 +- fedireads/templates/book.html | 4 +-- fedireads/templates/snippets/authors.html | 2 +- fedireads/templates/snippets/book.html | 2 +- .../templates/snippets/create_status.html | 6 ++--- fedireads/templates/snippets/shelf.html | 2 +- fedireads/templates/snippets/tag.html | 4 +-- init_db.py | 16 ++++++++++-- 14 files changed, 74 insertions(+), 42 deletions(-) rename fedireads/migrations/{0020_auto_20200327_2236.py => 0020_auto_20200327_2335.py} (66%) diff --git a/fedireads/books_manager.py b/fedireads/books_manager.py index 915d95cc..c476f579 100644 --- a/fedireads/books_manager.py +++ b/fedireads/books_manager.py @@ -2,14 +2,13 @@ import importlib from fedireads import models -from fedireads.connectors.settings import CONNECTORS def get_or_create_book(key): ''' pull up a book record by whatever means possible ''' try: book = models.Book.objects.select_subclasses().get( - local_key=key + fedireads_key=key ) return book except models.Book.DoesNotExist: @@ -32,6 +31,7 @@ def get_connector(book=None): else: connector_info = models.Connector.objects.first() - classname = CONNECTORS[connector_info.name]['classname'] - connector = importlib.import_module(classname) - return connector.Connector() + connector = importlib.import_module( + 'fedireads.connectors.%s' % connector_info.connector_file + ) + return connector.Connector(connector_info.identifier) diff --git a/fedireads/connectors/abstract_connector.py b/fedireads/connectors/abstract_connector.py index 7e83b734..a0f8aa22 100644 --- a/fedireads/connectors/abstract_connector.py +++ b/fedireads/connectors/abstract_connector.py @@ -2,19 +2,14 @@ from abc import ABC, abstractmethod from fedireads import models -from fedireads.connectors import CONNECTORS class AbstractConnector(ABC): ''' generic book data connector ''' - def __init__(self, connector_name): + def __init__(self, identifier): # load connector settings - settings = CONNECTORS.get(connector_name) - if not settings: - raise ValueError('No connector with name "%s"' % connector_name) - - info = models.Connector.objects.get(name=settings['db_name']) + info = models.Connector.objects.get(identifier=identifier) self.model = info self.url = info.base_url diff --git a/fedireads/connectors/openlibrary.py b/fedireads/connectors/openlibrary.py index a83a7d63..0f69a79d 100644 --- a/fedireads/connectors/openlibrary.py +++ b/fedireads/connectors/openlibrary.py @@ -10,8 +10,8 @@ from .abstract_connector import AbstractConnector, SearchResult class Connector(AbstractConnector): ''' instantiate a connector for OL ''' - def __init__(self): - super().__init__('OpenLibrary') + def __init__(self, identifier): + super().__init__(identifier) def search(self, query): @@ -140,3 +140,4 @@ class Connector(AbstractConnector): def update_book(self, book_obj): pass + diff --git a/fedireads/connectors/settings.py b/fedireads/connectors/settings.py index 9a0103f0..a56b2cf2 100644 --- a/fedireads/connectors/settings.py +++ b/fedireads/connectors/settings.py @@ -1,7 +1,3 @@ ''' settings book data connectors ''' -CONNECTORS = { - 'OpenLibrary': { - 'db_name': 'OpenLibrary', - 'classname': 'fedireads.connectors.openlibrary', - }, -} + +CONNECTORS = ['openlibrary', 'fedireads'] diff --git a/fedireads/migrations/0020_auto_20200327_2236.py b/fedireads/migrations/0020_auto_20200327_2335.py similarity index 66% rename from fedireads/migrations/0020_auto_20200327_2236.py rename to fedireads/migrations/0020_auto_20200327_2335.py index 7292e34c..511b1bed 100644 --- a/fedireads/migrations/0020_auto_20200327_2236.py +++ b/fedireads/migrations/0020_auto_20200327_2335.py @@ -1,7 +1,8 @@ -# Generated by Django 3.0.3 on 2020-03-27 22:36 +# Generated by Django 3.0.3 on 2020-03-27 23:35 from django.db import migrations, models import django.db.models.deletion +import fedireads.models.book class Migration(migrations.Migration): @@ -17,20 +18,24 @@ class Migration(migrations.Migration): ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('created_date', models.DateTimeField(auto_now_add=True)), ('updated_date', models.DateTimeField(auto_now=True)), - ('name', models.CharField(max_length=255, unique=True)), + ('identifier', models.CharField(max_length=255, unique=True)), + ('connector_file', models.CharField(choices=[('openlibrary', 'Openlibrary'), ('fedireads', 'Fedireads')], default='openlibrary', max_length=255)), + ('is_self', models.BooleanField(default=False)), ('api_key', models.CharField(max_length=255, null=True)), ('base_url', models.CharField(max_length=255)), ('covers_url', models.CharField(max_length=255)), ('search_url', models.CharField(max_length=255, null=True)), - ('key_name', models.CharField(max_length=255, unique=True)), + ('key_name', models.CharField(max_length=255)), ('politeness_delay', models.IntegerField(null=True)), ('max_query_count', models.IntegerField(null=True)), ('query_count', models.IntegerField(default=0)), ('query_count_expiry', models.DateTimeField(auto_now_add=True)), ], - options={ - 'abstract': False, - }, + ), + migrations.RenameField( + model_name='book', + old_name='local_key', + new_name='fedireads_key', ), migrations.RenameField( model_name='book', @@ -41,6 +46,10 @@ class Migration(migrations.Migration): model_name='book', name='local_edits', ), + migrations.AddConstraint( + model_name='connector', + constraint=models.CheckConstraint(check=models.Q(connector_file__in=fedireads.models.book.ConnectorFiles), name='connector_file_valid'), + ), migrations.AddField( model_name='book', name='connector', diff --git a/fedireads/models/book.py b/fedireads/models/book.py index 9edf5933..9f52a1f1 100644 --- a/fedireads/models/book.py +++ b/fedireads/models/book.py @@ -8,17 +8,28 @@ from fedireads.settings import DOMAIN from fedireads.utils.fields import JSONField, ArrayField from fedireads.utils.models import FedireadsModel +from fedireads.connectors.settings import CONNECTORS + +ConnectorFiles = models.TextChoices('ConnectorFiles', CONNECTORS) class Connector(FedireadsModel): ''' book data source connectors ''' - name = models.CharField(max_length=255, unique=True) + identifier = models.CharField(max_length=255, unique=True) + connector_file = models.CharField( + max_length=255, + default='openlibrary', + choices=ConnectorFiles.choices + ) + # is this a connector to your own database, should only be true if + # the connector_file is `fedireads` + is_self = models.BooleanField(default=False) api_key = models.CharField(max_length=255, null=True) base_url = models.CharField(max_length=255) covers_url = models.CharField(max_length=255) search_url = models.CharField(max_length=255, null=True) - key_name = models.CharField(max_length=255, unique=True) + key_name = models.CharField(max_length=255) politeness_delay = models.IntegerField(null=True) #seconds max_query_count = models.IntegerField(null=True) @@ -27,13 +38,21 @@ class Connector(FedireadsModel): # when to reset the query count back to 0 (ie, after 1 day) query_count_expiry = models.DateTimeField(auto_now_add=True) + class Meta: + constraints = [ + models.CheckConstraint( + check=models.Q(connector_file__in=ConnectorFiles), + name='connector_file_valid' + ) + ] + class Book(FedireadsModel): ''' a generic book, which can mean either an edition or a work ''' # these identifiers apply to both works and editions openlibrary_key = models.CharField(max_length=255, unique=True, null=True) librarything_key = models.CharField(max_length=255, unique=True, null=True) - local_key = models.CharField(max_length=255, unique=True, default=uuid4) + fedireads_key = models.CharField(max_length=255, unique=True, default=uuid4) misc_identifiers = JSONField(null=True) # info about where the data comes from and where/if to sync diff --git a/fedireads/outgoing.py b/fedireads/outgoing.py index f204888b..e2d99563 100644 --- a/fedireads/outgoing.py +++ b/fedireads/outgoing.py @@ -232,7 +232,7 @@ def handle_tag(user, book, name): def handle_untag(user, book, name): ''' tag a book ''' - book = models.Book.objects.get(local_key=book) + book = models.Book.objects.get(fedireads_key=book) tag = models.Tag.objects.get(name=name, book=book, user=user) tag_activity = activitypub.get_remove_tag(tag) tag.delete() diff --git a/fedireads/templates/book.html b/fedireads/templates/book.html index 74777a19..b337f552 100644 --- a/fedireads/templates/book.html +++ b/fedireads/templates/book.html @@ -5,7 +5,7 @@

{{ book.title }} by {% include 'snippets/authors.html' with book=book %}

- {% if book.parent_work %}

Edition of {{ book.parent_work.title }}

{% endif %} + {% if book.parent_work %}

Edition of {{ book.parent_work.title }}

{% endif %}
{% include 'snippets/book_cover.html' with book=book size=large %} @@ -32,7 +32,7 @@

Leave a review

{% csrf_token %} - + {{ review_form.as_p }}
diff --git a/fedireads/templates/snippets/authors.html b/fedireads/templates/snippets/authors.html index e45a19a5..35fe6a03 100644 --- a/fedireads/templates/snippets/authors.html +++ b/fedireads/templates/snippets/authors.html @@ -1 +1 @@ -{{ book.authors.first.name }} +{{ book.authors.first.name }} diff --git a/fedireads/templates/snippets/book.html b/fedireads/templates/snippets/book.html index dad89603..3c5fd377 100644 --- a/fedireads/templates/snippets/book.html +++ b/fedireads/templates/snippets/book.html @@ -1,7 +1,7 @@ {% load fr_display %} {% include 'snippets/book_cover.html' with book=book %}

- {{ book.title }} + {{ book.title }}

by {% include 'snippets/authors.html' with book=book %} diff --git a/fedireads/templates/snippets/create_status.html b/fedireads/templates/snippets/create_status.html index bd3efbcf..70bc9fef 100644 --- a/fedireads/templates/snippets/create_status.html +++ b/fedireads/templates/snippets/create_status.html @@ -4,7 +4,7 @@

{% include 'snippets/avatar.html' with user=user %} Your thoughts on - {{ book.title }} + {{ book.title }} by {% include 'snippets/authors.html' with book=book %}

@@ -24,14 +24,14 @@ {% include 'snippets/book_cover.html' with book=book %}
{% csrf_token %} - + {{ review_form.as_p }}
diff --git a/fedireads/templates/snippets/shelf.html b/fedireads/templates/snippets/shelf.html index e0975a48..2171efb2 100644 --- a/fedireads/templates/snippets/shelf.html +++ b/fedireads/templates/snippets/shelf.html @@ -33,7 +33,7 @@ {% include 'snippets/book_cover.html' with book=book size="small" %} - {{ book.title }} + {{ book.title }} {{ book.authors.first.name }} diff --git a/fedireads/templates/snippets/tag.html b/fedireads/templates/snippets/tag.html index 14d6f102..fdc686dc 100644 --- a/fedireads/templates/snippets/tag.html +++ b/fedireads/templates/snippets/tag.html @@ -3,14 +3,14 @@ {% if tag.identifier in user_tags %}
{% csrf_token %} - +
{% else %}
{% csrf_token %} - +
diff --git a/init_db.py b/init_db.py index 2d6f2d94..e121503b 100644 --- a/init_db.py +++ b/init_db.py @@ -1,6 +1,7 @@ ''' starter data ''' -from fedireads.models import Connector, User from fedireads.books_manager import get_or_create_book +from fedireads.models import Connector, User +from fedireads.settings import DOMAIN User.objects.create_user('mouse', 'mouse.reeve@gmail.com', 'password123') User.objects.create_user( @@ -11,13 +12,24 @@ User.objects.create_user( User.objects.get(id=1).followers.add(User.objects.get(id=2)) Connector.objects.create( - name='OpenLibrary', + identifier='openlibrary.org', + connector_file='openlibrary', base_url='https://openlibrary.org', covers_url='https://covers.openlibrary.org', search_url='https://openlibrary.org/search?q=', key_name='openlibrary_key', ) +Connector.objects.create( + identifier=DOMAIN, + connector_file='fedireads', + base_url='https://%s/book' % DOMAIN, + covers_url='https://%s/images/covers' % DOMAIN, + search_url='https://%s/search?q=' % DOMAIN, + key_name='openlibrary_key', + is_self=True +) + get_or_create_book('OL1715344W') get_or_create_book('OL102749W') From 7f825462301a087ede0b866a381b62c000d2e9f1 Mon Sep 17 00:00:00 2001 From: Mouse Reeve Date: Fri, 27 Mar 2020 18:36:45 -0700 Subject: [PATCH 5/5] Typo fix --- fedireads/connectors/openlibrary.py | 1 - fedireads/connectors/settings.py | 2 +- fedireads/models/book.py | 1 - init_db.py | 2 +- 4 files changed, 2 insertions(+), 4 deletions(-) diff --git a/fedireads/connectors/openlibrary.py b/fedireads/connectors/openlibrary.py index 0f69a79d..64e9bbe3 100644 --- a/fedireads/connectors/openlibrary.py +++ b/fedireads/connectors/openlibrary.py @@ -76,7 +76,6 @@ class Connector(AbstractConnector): key = data.get('works')[0]['key'] key = key.split('/')[-1] work = self.get_or_create_book(key) - h book.parent_work = work diff --git a/fedireads/connectors/settings.py b/fedireads/connectors/settings.py index a56b2cf2..425e56ef 100644 --- a/fedireads/connectors/settings.py +++ b/fedireads/connectors/settings.py @@ -1,3 +1,3 @@ ''' settings book data connectors ''' -CONNECTORS = ['openlibrary', 'fedireads'] +CONNECTORS = ['openlibrary', 'fedireads_connector'] diff --git a/fedireads/models/book.py b/fedireads/models/book.py index 9f52a1f1..ed6423ff 100644 --- a/fedireads/models/book.py +++ b/fedireads/models/book.py @@ -84,7 +84,6 @@ class Book(FedireadsModel): through='ShelfBook', through_fields=('book', 'shelf') ) - # TODO: why can't I just call this work???? parent_work = models.ForeignKey('Work', on_delete=models.PROTECT, null=True) objects = InheritanceManager() diff --git a/init_db.py b/init_db.py index e121503b..1487d356 100644 --- a/init_db.py +++ b/init_db.py @@ -22,7 +22,7 @@ Connector.objects.create( Connector.objects.create( identifier=DOMAIN, - connector_file='fedireads', + connector_file='fedireads_connector', base_url='https://%s/book' % DOMAIN, covers_url='https://%s/images/covers' % DOMAIN, search_url='https://%s/search?q=' % DOMAIN,