Rename local key and suggest fedireads connectors

This commit is contained in:
Mouse Reeve 2020-03-27 16:36:52 -07:00
parent 0f98610629
commit ed6fd6d48e
14 changed files with 74 additions and 42 deletions

View file

@ -2,14 +2,13 @@
import importlib import importlib
from fedireads import models from fedireads import models
from fedireads.connectors.settings import CONNECTORS
def get_or_create_book(key): def get_or_create_book(key):
''' pull up a book record by whatever means possible ''' ''' pull up a book record by whatever means possible '''
try: try:
book = models.Book.objects.select_subclasses().get( book = models.Book.objects.select_subclasses().get(
local_key=key fedireads_key=key
) )
return book return book
except models.Book.DoesNotExist: except models.Book.DoesNotExist:
@ -32,6 +31,7 @@ def get_connector(book=None):
else: else:
connector_info = models.Connector.objects.first() connector_info = models.Connector.objects.first()
classname = CONNECTORS[connector_info.name]['classname'] connector = importlib.import_module(
connector = importlib.import_module(classname) 'fedireads.connectors.%s' % connector_info.connector_file
return connector.Connector() )
return connector.Connector(connector_info.identifier)

View file

@ -2,19 +2,14 @@
from abc import ABC, abstractmethod from abc import ABC, abstractmethod
from fedireads import models from fedireads import models
from fedireads.connectors import CONNECTORS
class AbstractConnector(ABC): class AbstractConnector(ABC):
''' generic book data connector ''' ''' generic book data connector '''
def __init__(self, connector_name): def __init__(self, identifier):
# load connector settings # load connector settings
settings = CONNECTORS.get(connector_name) info = models.Connector.objects.get(identifier=identifier)
if not settings:
raise ValueError('No connector with name "%s"' % connector_name)
info = models.Connector.objects.get(name=settings['db_name'])
self.model = info self.model = info
self.url = info.base_url self.url = info.base_url

View file

@ -10,8 +10,8 @@ from .abstract_connector import AbstractConnector, SearchResult
class Connector(AbstractConnector): class Connector(AbstractConnector):
''' instantiate a connector for OL ''' ''' instantiate a connector for OL '''
def __init__(self): def __init__(self, identifier):
super().__init__('OpenLibrary') super().__init__(identifier)
def search(self, query): def search(self, query):
@ -140,3 +140,4 @@ class Connector(AbstractConnector):
def update_book(self, book_obj): def update_book(self, book_obj):
pass pass

View file

@ -1,7 +1,3 @@
''' settings book data connectors ''' ''' settings book data connectors '''
CONNECTORS = {
'OpenLibrary': { CONNECTORS = ['openlibrary', 'fedireads']
'db_name': 'OpenLibrary',
'classname': 'fedireads.connectors.openlibrary',
},
}

View file

@ -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 from django.db import migrations, models
import django.db.models.deletion import django.db.models.deletion
import fedireads.models.book
class Migration(migrations.Migration): 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')), ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_date', models.DateTimeField(auto_now_add=True)), ('created_date', models.DateTimeField(auto_now_add=True)),
('updated_date', models.DateTimeField(auto_now=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)), ('api_key', models.CharField(max_length=255, null=True)),
('base_url', models.CharField(max_length=255)), ('base_url', models.CharField(max_length=255)),
('covers_url', models.CharField(max_length=255)), ('covers_url', models.CharField(max_length=255)),
('search_url', models.CharField(max_length=255, null=True)), ('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)), ('politeness_delay', models.IntegerField(null=True)),
('max_query_count', models.IntegerField(null=True)), ('max_query_count', models.IntegerField(null=True)),
('query_count', models.IntegerField(default=0)), ('query_count', models.IntegerField(default=0)),
('query_count_expiry', models.DateTimeField(auto_now_add=True)), ('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( migrations.RenameField(
model_name='book', model_name='book',
@ -41,6 +46,10 @@ class Migration(migrations.Migration):
model_name='book', model_name='book',
name='local_edits', 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( migrations.AddField(
model_name='book', model_name='book',
name='connector', name='connector',

View file

@ -8,17 +8,28 @@ from fedireads.settings import DOMAIN
from fedireads.utils.fields import JSONField, ArrayField from fedireads.utils.fields import JSONField, ArrayField
from fedireads.utils.models import FedireadsModel from fedireads.utils.models import FedireadsModel
from fedireads.connectors.settings import CONNECTORS
ConnectorFiles = models.TextChoices('ConnectorFiles', CONNECTORS)
class Connector(FedireadsModel): class Connector(FedireadsModel):
''' book data source connectors ''' ''' 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) api_key = models.CharField(max_length=255, null=True)
base_url = models.CharField(max_length=255) base_url = models.CharField(max_length=255)
covers_url = models.CharField(max_length=255) covers_url = models.CharField(max_length=255)
search_url = models.CharField(max_length=255, null=True) 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 politeness_delay = models.IntegerField(null=True) #seconds
max_query_count = models.IntegerField(null=True) 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) # when to reset the query count back to 0 (ie, after 1 day)
query_count_expiry = models.DateTimeField(auto_now_add=True) 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): class Book(FedireadsModel):
''' a generic book, which can mean either an edition or a work ''' ''' a generic book, which can mean either an edition or a work '''
# these identifiers apply to both works and editions # these identifiers apply to both works and editions
openlibrary_key = models.CharField(max_length=255, unique=True, null=True) openlibrary_key = models.CharField(max_length=255, unique=True, null=True)
librarything_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) misc_identifiers = JSONField(null=True)
# info about where the data comes from and where/if to sync # info about where the data comes from and where/if to sync

View file

@ -232,7 +232,7 @@ def handle_tag(user, book, name):
def handle_untag(user, book, name): def handle_untag(user, book, name):
''' tag a book ''' ''' 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 = models.Tag.objects.get(name=name, book=book, user=user)
tag_activity = activitypub.get_remove_tag(tag) tag_activity = activitypub.get_remove_tag(tag)
tag.delete() tag.delete()

View file

@ -5,7 +5,7 @@
<h2><q>{{ book.title }}</q> by <h2><q>{{ book.title }}</q> by
{% include 'snippets/authors.html' with book=book %}</h2> {% include 'snippets/authors.html' with book=book %}</h2>
<div> <div>
{% if book.parent_work %}<p>Edition of <a href="/book/{{ book.parent_work.local_key }}">{{ book.parent_work.title }}</a></p>{% endif %} {% if book.parent_work %}<p>Edition of <a href="/book/{{ book.parent_work.fedireads_key }}">{{ book.parent_work.title }}</a></p>{% endif %}
<div class="book-preview"> <div class="book-preview">
{% include 'snippets/book_cover.html' with book=book size=large %} {% include 'snippets/book_cover.html' with book=book size=large %}
@ -32,7 +32,7 @@
<h2>Leave a review</h2> <h2>Leave a review</h2>
<form class="review-form" name="review" action="/review/" method="post"> <form class="review-form" name="review" action="/review/" method="post">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="book" value="{{ book.local_key }}"></input> <input type="hidden" name="book" value="{{ book.fedireads_key }}"></input>
{{ review_form.as_p }} {{ review_form.as_p }}
<button type="submit">Post review</button> <button type="submit">Post review</button>
</form> </form>

View file

@ -1 +1 @@
<a href="/author/{{ book.authors.first.local_key }}" class="author">{{ book.authors.first.name }}</a> <a href="/author/{{ book.authors.first.fedireads_key }}" class="author">{{ book.authors.first.name }}</a>

View file

@ -1,7 +1,7 @@
{% load fr_display %} {% load fr_display %}
{% include 'snippets/book_cover.html' with book=book %} {% include 'snippets/book_cover.html' with book=book %}
<p class="title"> <p class="title">
<a href="/book/{{ book.local_key }}">{{ book.title }}</a> <a href="/book/{{ book.fedireads_key }}">{{ book.title }}</a>
</p> </p>
<p> <p>
by {% include 'snippets/authors.html' with book=book %} by {% include 'snippets/authors.html' with book=book %}

View file

@ -4,7 +4,7 @@
<h2> <h2>
{% include 'snippets/avatar.html' with user=user %} {% include 'snippets/avatar.html' with user=user %}
Your thoughts on Your thoughts on
<a href="/book/{{ book.local_key }}">{{ book.title }}</a> <a href="/book/{{ book.fedireads_key }}">{{ book.title }}</a>
by {% include 'snippets/authors.html' with book=book %} by {% include 'snippets/authors.html' with book=book %}
</h2> </h2>
@ -24,14 +24,14 @@
{% include 'snippets/book_cover.html' with book=book %} {% include 'snippets/book_cover.html' with book=book %}
<form class="tab-option-{{ book.id }} review-form" name="review" action="/review/" method="post" id="tab-review-{{ book.id }}"> <form class="tab-option-{{ book.id }} review-form" name="review" action="/review/" method="post" id="tab-review-{{ book.id }}">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="book" value="{{ book.local_key }}"></input> <input type="hidden" name="book" value="{{ book.fedireads_key }}"></input>
{{ review_form.as_p }} {{ review_form.as_p }}
<button type="submit">post review</button> <button type="submit">post review</button>
</form> </form>
<form class="hidden tab-option-{{ book.id }} review-form" name="comment" action="/comment/" method="post" id="tab-comment-{{ book.id }}"> <form class="hidden tab-option-{{ book.id }} review-form" name="comment" action="/comment/" method="post" id="tab-comment-{{ book.id }}">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="book" value="{{ book.local_key }}"></input> <input type="hidden" name="book" value="{{ book.fedireads_key }}"></input>
{{ comment_form.as_p }} {{ comment_form.as_p }}
<button type="submit">post comment</button> <button type="submit">post comment</button>
</form> </form>

View file

@ -33,7 +33,7 @@
{% include 'snippets/book_cover.html' with book=book size="small" %} {% include 'snippets/book_cover.html' with book=book size="small" %}
</td> </td>
<td> <td>
<a href="/book/{{ book.local_key }}">{{ book.title }}</a> <a href="/book/{{ book.fedireads_key }}">{{ book.title }}</a>
</td> </td>
<td> <td>
{{ book.authors.first.name }} {{ book.authors.first.name }}

View file

@ -3,14 +3,14 @@
{% if tag.identifier in user_tags %} {% if tag.identifier in user_tags %}
<form class="tag-form" name="tag" action="/untag/" method="post"> <form class="tag-form" name="tag" action="/untag/" method="post">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="book" value="{{ book.local_key }}"></input> <input type="hidden" name="book" value="{{ book.fedireads_key }}"></input>
<input type="hidden" name="name" value="{{ tag.name }}"></input> <input type="hidden" name="name" value="{{ tag.name }}"></input>
<button type="submit">x</button> <button type="submit">x</button>
</form> </form>
{% else %} {% else %}
<form class="tag-form" name="tag" action="/tag/" method="post"> <form class="tag-form" name="tag" action="/tag/" method="post">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="book" value="{{ book.local_key }}"></input> <input type="hidden" name="book" value="{{ book.fedireads_key }}"></input>
<input type="hidden" name="name" value="{{ tag.name }}"></input> <input type="hidden" name="name" value="{{ tag.name }}"></input>
<button type="submit">+</button> <button type="submit">+</button>
</form> </form>

View file

@ -1,6 +1,7 @@
''' starter data ''' ''' starter data '''
from fedireads.models import Connector, User
from fedireads.books_manager import get_or_create_book 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('mouse', 'mouse.reeve@gmail.com', 'password123')
User.objects.create_user( User.objects.create_user(
@ -11,13 +12,24 @@ User.objects.create_user(
User.objects.get(id=1).followers.add(User.objects.get(id=2)) User.objects.get(id=1).followers.add(User.objects.get(id=2))
Connector.objects.create( Connector.objects.create(
name='OpenLibrary', identifier='openlibrary.org',
connector_file='openlibrary',
base_url='https://openlibrary.org', base_url='https://openlibrary.org',
covers_url='https://covers.openlibrary.org', covers_url='https://covers.openlibrary.org',
search_url='https://openlibrary.org/search?q=', search_url='https://openlibrary.org/search?q=',
key_name='openlibrary_key', 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('OL1715344W')
get_or_create_book('OL102749W') get_or_create_book('OL102749W')