Remove fedireads_key field

we have ID
This commit is contained in:
Mouse Reeve 2020-05-03 17:53:14 -07:00
parent fba1397444
commit 2fd7792f34
21 changed files with 65 additions and 70 deletions

View file

@ -11,7 +11,6 @@ def get_book(book):
'oclc_number', 'oclc_number',
'openlibrary_key', 'openlibrary_key',
'librarything_key', 'librarything_key',
'fedireads_key',
'lccn', 'lccn',
'oclc_number', 'oclc_number',
'pages', 'pages',

View file

@ -5,18 +5,17 @@ from fedireads import models
from fedireads.tasks import app from fedireads.tasks import app
def get_or_create_book(key): def get_or_create_book(value, key='id', connector_id=None):
''' 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(**{key: value})
fedireads_key=key
)
return book return book
except models.Book.DoesNotExist: except models.Book.DoesNotExist:
pass pass
connector = get_connector() connector_info = models.Connector.objects.get(id=connector_id)
book = connector.get_or_create_book(key) connector = load_connector(connector_info)
book = connector.get_or_create_book(value)
load_more_data.delay(book.id) load_more_data.delay(book.id)
return book return book
@ -25,7 +24,7 @@ def get_or_create_book(key):
def load_more_data(book_id): def load_more_data(book_id):
''' background the work of getting all 10,000 editions of LoTR ''' ''' background the work of getting all 10,000 editions of LoTR '''
book = models.Book.objects.select_subclasses().get(id=book_id) book = models.Book.objects.select_subclasses().get(id=book_id)
connector = get_connector(book) connector = load_connector(book.connector)
connector.expand_book_data(book) connector.expand_book_data(book)
@ -60,7 +59,7 @@ def first_search_result(query):
def update_book(book): def update_book(book):
''' re-sync with the original data source ''' ''' re-sync with the original data source '''
connector = get_connector(book) connector = load_connector(book.connector)
connector.update_book(book) connector.update_book(book)
@ -70,18 +69,6 @@ def get_connectors():
return [load_connector(c) for c in connectors_info] return [load_connector(c) for c in connectors_info]
def get_connector(book=None):
''' pick a book data connector '''
if book and book.connector:
connector_info = book.connector
else:
# only select from external connectors
connector_info = models.Connector.objects.filter(
local=False
).order_by('priority').first()
return load_connector(connector_info)
def load_connector(connector_info): def load_connector(connector_info):
''' instantiate the connector class ''' ''' instantiate the connector class '''
connector = importlib.import_module( connector = importlib.import_module(

View file

@ -22,12 +22,13 @@ class AbstractConnector(ABC):
self.max_query_count = info.max_query_count self.max_query_count = info.max_query_count
self.name = info.name self.name = info.name
self.local = info.local self.local = info.local
self.id = info.id
def is_available(self): def is_available(self):
''' check if you're allowed to use this connector ''' ''' check if you're allowed to use this connector '''
if self.connector.max_query_count is not None: if self.max_query_count is not None:
if self.connector.query_count >= self.connector.max_query_count: if self.connector.query_count >= self.max_query_count:
return False return False
return True return True

View file

@ -9,6 +9,8 @@ from .abstract_connector import update_from_mappings, get_date
class Connector(AbstractConnector): class Connector(AbstractConnector):
''' interact with other instances '''
def search(self, query): def search(self, query):
''' right now you can't search fedireads, but... ''' ''' right now you can't search fedireads, but... '''
resp = requests.get( resp = requests.get(
@ -23,11 +25,11 @@ class Connector(AbstractConnector):
return resp.json() return resp.json()
def get_or_create_book(self, fedireads_key): def get_or_create_book(self, remote_id):
''' 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(
fedireads_key=fedireads_key remote_id=remote_id
) )
return book return book
except ObjectDoesNotExist: except ObjectDoesNotExist:
@ -35,14 +37,14 @@ class Connector(AbstractConnector):
# we can't load a book from a remote server, this is it # we can't load a book from a remote server, this is it
return None return None
# no book was found, so we start creating a new one # no book was found, so we start creating a new one
book = models.Book(fedireads_key=fedireads_key) book = models.Book(remote_id=remote_id)
def update_book(self, book): def update_book(self, book):
''' add remote data to a local book ''' ''' add remote data to a local book '''
fedireads_key = book.fedireads_key remote_id = book.remote_id
response = requests.get( response = requests.get(
'%s/%s' % (self.base_url, fedireads_key), '%s/%s' % (self.base_url, remote_id),
headers={ headers={
'Accept': 'application/activity+json; charset=utf-8', 'Accept': 'application/activity+json; charset=utf-8',
}, },
@ -81,21 +83,21 @@ class Connector(AbstractConnector):
return book return book
def get_or_create_author(self, fedireads_key): def get_or_create_author(self, remote_id):
''' load that author ''' ''' load that author '''
try: try:
return models.Author.objects.get(fedireads_key=fedireads_key) return models.Author.objects.get(remote_id=remote_id)
except ObjectDoesNotExist: except ObjectDoesNotExist:
pass pass
resp = requests.get('%s/authors/%s.json' % (self.url, fedireads_key)) resp = requests.get('%s/authors/%s.json' % (self.url, remote_id))
if not resp.ok: if not resp.ok:
resp.raise_for_status() resp.raise_for_status()
data = resp.json() data = resp.json()
# ingest a new author # ingest a new author
author = models.Author(fedireads_key=fedireads_key) author = models.Author(remote_id=remote_id)
mappings = { mappings = {
'born': ('born', get_date), 'born': ('born', get_date),
'died': ('died', get_date), 'died': ('died', get_date),

View file

@ -36,7 +36,7 @@ class Connector(AbstractConnector):
search_results.append( search_results.append(
SearchResult( SearchResult(
book.title, book.title,
book.fedireads_key, book.id,
book.author_text, book.author_text,
book.published_date.year if book.published_date else None, book.published_date.year if book.published_date else None,
None None
@ -45,21 +45,21 @@ class Connector(AbstractConnector):
return search_results return search_results
def get_or_create_book(self, fedireads_key): def get_or_create_book(self, book_id):
''' since this is querying its own data source, it can only ''' since this is querying its own data source, it can only
get a book, not load one from an external source ''' get a book, not load one from an external source '''
try: try:
return models.Book.objects.select_subclasses().get( return models.Book.objects.select_subclasses().get(
fedireads_key=fedireads_key id=book_id
) )
except ObjectDoesNotExist: except ObjectDoesNotExist:
return None return None
def get_or_create_author(self, fedireads_key): def get_or_create_author(self, author_id):
''' load that author ''' ''' load that author '''
try: try:
return models.Author.objects.get(fedreads_key=fedireads_key) return models.Author.objects.get(id=author_id)
except ObjectDoesNotExist: except ObjectDoesNotExist:
pass pass

View file

@ -51,7 +51,6 @@ class Connector(FedireadsModel):
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
fedireads_key = models.CharField(max_length=255, unique=True, default=uuid4)
openlibrary_key = models.CharField(max_length=255, blank=True, null=True) openlibrary_key = models.CharField(max_length=255, blank=True, null=True)
librarything_key = models.CharField(max_length=255, blank=True, null=True) librarything_key = models.CharField(max_length=255, blank=True, null=True)
goodreads_key = models.CharField(max_length=255, blank=True, null=True) goodreads_key = models.CharField(max_length=255, blank=True, null=True)
@ -151,7 +150,6 @@ class Edition(Book):
class Author(FedireadsModel): class Author(FedireadsModel):
''' copy of an author from OL ''' ''' copy of an author from OL '''
fedireads_key = models.CharField(max_length=255, unique=True, default=uuid4)
openlibrary_key = models.CharField(max_length=255, blank=True, null=True) openlibrary_key = models.CharField(max_length=255, blank=True, null=True)
wikipedia_link = models.CharField(max_length=255, blank=True, null=True) wikipedia_link = models.CharField(max_length=255, blank=True, null=True)
# idk probably other keys would be useful here? # idk probably other keys would be useful here?

View file

@ -286,7 +286,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(fedireads_key=book) book = models.Book.objects.get(id=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

@ -6,7 +6,7 @@
{% include 'snippets/book_titleby.html' with book=book %} {% include 'snippets/book_titleby.html' with book=book %}
{% if request.user.is_authenticated %} {% if request.user.is_authenticated %}
<a href="{{ book.fedireads_key }}/edit" class="edit-link">edit <a href="{{ book.id }}/edit" class="edit-link">edit
<span class="icon icon-pencil"> <span class="icon icon-pencil">
<span class="hidden-text">Edit Book</span> <span class="hidden-text">Edit Book</span>
</span> </span>
@ -22,7 +22,7 @@
{% include 'snippets/shelve_button.html' %} {% include 'snippets/shelve_button.html' %}
{% if request.user.is_authenticated and not book.cover %} {% if request.user.is_authenticated and not book.cover %}
<form name="add-cover" method="POST" action="/upload_cover/{{book.id}}" enctype="multipart/form-data"> <form name="add-cover" method="POST" action="/upload_cover/{{ book.id }}" enctype="multipart/form-data">
{% csrf_token %} {% csrf_token %}
{{ cover_form.as_p }} {{ cover_form.as_p }}
<button type="submit">Add cover</button> <button type="submit">Add cover</button>
@ -57,7 +57,7 @@
<h3>Tags</h3> <h3>Tags</h3>
<form name="tag" action="/tag/" method="post"> <form name="tag" action="/tag/" method="post">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="book" value="{{ book.fedireads_key }}"> <input type="hidden" name="book" value="{{ book.id }}">
<input type="text" name="name"> <input type="text" name="name">
<button type="submit">Add tag</button> <button type="submit">Add tag</button>
</form> </form>

View file

@ -12,7 +12,7 @@
{% for result in result_set.results %} {% for result in result_set.results %}
<div> <div>
<a href="/book/{{ result.key }}">{{ result.title }}</a> by {{ result.author }} ({{ result.year }}) <a href="/book/{% if not result_set.connector.local %}{{ result_set.connector.id }}:{{ result_set.connector.key_name}}:{% endif %}{{ result.key }}">{{ result.title }}</a> by {{ result.author }} ({{ result.year }})
</div> </div>
{% endfor %} {% endfor %}
</section> </section>

View file

@ -4,7 +4,7 @@
<div class="content-container"> <div class="content-container">
<h2> <h2>
Edit "{{ book.title }}" Edit "{{ book.title }}"
<a href="/book/{{ book.fedireads_key }}"> <a href="/book/{{ book.id }}">
<span class="edit-link icon icon-close"> <span class="edit-link icon icon-close">
<span class="hidden-text">Close</span> <span class="hidden-text">Close</span>
</span> </span>
@ -40,8 +40,8 @@
<h3>Book Identifiers</h2> <h3>Book Identifiers</h2>
<div> <div>
<p><label for="id_isbn">ISBN 13:</label> {{ form.isbn_13 }} </p> <p><label for="id_isbn_13">ISBN 13:</label> {{ form.isbn_13 }} </p>
<p><label for="id_fedireads_key">Fedireads key:</label> {{ form.fedireads_key }} </p> <p><label for="id_isbn_10">ISBN 10:</label> {{ form.isbn_10 }} </p>
<p><label for="id_openlibrary_key">Openlibrary key:</label> {{ form.openlibrary_key }} </p> <p><label for="id_openlibrary_key">Openlibrary key:</label> {{ form.openlibrary_key }} </p>
<p><label for="id_librarything_key">Librarything key:</label> {{ form.librarything_key }} </p> <p><label for="id_librarything_key">Librarything key:</label> {{ form.librarything_key }} </p>
<p><label for="id_goodreads_key">Goodreads key:</label> {{ form.goodreads_key }} </p> <p><label for="id_goodreads_key">Goodreads key:</label> {{ form.goodreads_key }} </p>

View file

@ -2,7 +2,7 @@
{% load fr_display %} {% load fr_display %}
{% block content %} {% block content %}
<div class="content-container"> <div class="content-container">
<h2>Editions of <a href="/book/{{ work.fedireads_key }}">"{{ work.title }}"</a></h2> <h2>Editions of <a href="/book/{{ work.id }}">"{{ work.title }}"</a></h2>
<ol class="book-grid row wrap"> <ol class="book-grid row wrap">
{% for book in editions %} {% for book in editions %}
<li class="book-preview"> <li class="book-preview">

View file

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

View file

@ -1,5 +1,5 @@
<span class="title"> <span class="title">
<a href="/book/{{ book.fedireads_key }}">{{ book.title }}</a> <a href="/book/{{ book.id }}">{{ book.title }}</a>
</span> </span>
{% if book.authors %} {% if book.authors %}
<span class="author"> <span class="author">

View file

@ -37,7 +37,7 @@
<h2> <h2>
{% include 'snippets/avatar.html' with user=user %} {% include 'snippets/avatar.html' with user=user %}
Your thoughts on Your thoughts on
a <a href="/book/{{ book.fedireads_key }}">{{ book.title }}</a> a <a href="/book/{{ book.id }}">{{ book.title }}</a>
by {% include 'snippets/authors.html' with book=book %} by {% include 'snippets/authors.html' with book=book %}
</h2> </h2>

View file

@ -21,7 +21,7 @@
{% endif %} {% endif %}
<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.fedireads_key }}"> <input type="hidden" name="book" value="{{ book.id }}">
{% include 'snippets/rate_form.html' with book=book %} {% include 'snippets/rate_form.html' with book=book %}
{{ review_form.as_p }} {{ review_form.as_p }}
<button type="submit">post review</button> <button type="submit">post review</button>
@ -29,14 +29,14 @@
<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.fedireads_key }}"> <input type="hidden" name="book" value="{{ book.id }}">
{{ comment_form.as_p }} {{ comment_form.as_p }}
<button type="submit">post comment</button> <button type="submit">post comment</button>
</form> </form>
<form class="hidden tab-option-{{ book.id }} review-form quote-form" name="quotation" action="/quotate/" method="post" id="tab-quotation-{{ book.id }}"> <form class="hidden tab-option-{{ book.id }} review-form quote-form" name="quotation" action="/quotate/" method="post" id="tab-quotation-{{ book.id }}">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="book" value="{{ book.fedireads_key }}"> <input type="hidden" name="book" value="{{ book.id }}">
{{ quotation_form.as_p }} {{ quotation_form.as_p }}
<button typr="submit">post quote</button> <button typr="submit">post quote</button>
</form> </form>

View file

@ -4,7 +4,7 @@
{% for i in '12345'|make_list %} {% for i in '12345'|make_list %}
<form name="rate" action="/rate/" method="POST" onsubmit="return rate_stars(event)"> <form name="rate" action="/rate/" method="POST" onsubmit="return rate_stars(event)">
{% csrf_token %} {% csrf_token %}
<input type="hidden" name="book" value="{{ book.fedireads_key }}"> <input type="hidden" name="book" value="{{ book.id }}">
<input type="hidden" name="rating" value="{{ forloop.counter }}"> <input type="hidden" name="rating" value="{{ forloop.counter }}">
<button type="submit" class="icon icon-star-{% if book|rating:user < forloop.counter %}empty{% else %}full{% endif %}"> <button type="submit" class="icon icon-star-{% if book|rating:user < forloop.counter %}empty{% else %}full{% endif %}">
<span class="hidden-text">{{ forloop.counter }} star{{ forloop.counter | pluralize }}</span> <span class="hidden-text">{{ forloop.counter }} star{{ forloop.counter | pluralize }}</span>

View file

@ -39,7 +39,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.fedireads_key }}">{{ book.title }}</a> <a href="/book/{{ book.id }}">{{ 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.fedireads_key }}"> <input type="hidden" name="book" value="{{ book.id }}">
<input type="hidden" name="name" value="{{ tag.name }}"> <input type="hidden" name="name" value="{{ tag.name }}">
<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.fedireads_key }}"> <input type="hidden" name="book" value="{{ book.id }}">
<input type="hidden" name="name" value="{{ tag.name }}"> <input type="hidden" name="name" value="{{ tag.name }}">
<button type="submit">+</button> <button type="submit">+</button>
</form> </form>

View file

@ -11,7 +11,7 @@ localname_regex = r'(?P<username>[\w\-_]+)'
user_path = r'^user/%s' % username_regex user_path = r'^user/%s' % username_regex
local_user_path = r'^user/%s' % localname_regex local_user_path = r'^user/%s' % localname_regex
status_path = r'%s/(status|review|comment)/(?P<status_id>\d+)' % local_user_path status_path = r'%s/(status|review|comment)/(?P<status_id>\d+)' % local_user_path
book_path = r'^book/(?P<book_identifier>[\w\-]+)' book_path = r'^book/(?P<book_id>\d+)'
handler404 = 'fedireads.views.not_found_page' handler404 = 'fedireads.views.not_found_page'
handler500 = 'fedireads.views.server_error_page' handler500 = 'fedireads.views.server_error_page'
@ -58,7 +58,7 @@ urlpatterns = [
re_path(r'%s/replies(.json)?/?$' % status_path, views.replies_page), re_path(r'%s/replies(.json)?/?$' % status_path, views.replies_page),
# books # books
re_path(r'%s(.json)?/?$' % book_path, views.book_page), re_path(r'book/(?P<book_id>[\w_:\d]+)(.json)?/?$', views.book_page),
re_path(r'%s/(?P<tab>friends|local|federated)?$' % book_path, views.book_page), re_path(r'%s/(?P<tab>friends|local|federated)?$' % book_path, views.book_page),
re_path(r'%s/edit/?$' % book_path, views.edit_book_page), re_path(r'%s/edit/?$' % book_path, views.edit_book_page),
re_path(r'^editions/(?P<work_id>\d+)/?$', views.editions_page), re_path(r'^editions/(?P<work_id>\d+)/?$', views.editions_page),

View file

@ -133,7 +133,7 @@ def edit_book(request, book_id):
form.save() form.save()
outgoing.handle_update_book(request.user, book) outgoing.handle_update_book(request.user, book)
return redirect('/book/%s' % book.fedireads_key) return redirect('/book/%s' % book.id)
@login_required @login_required
@ -157,7 +157,7 @@ def upload_cover(request, book_id):
book.save() book.save()
outgoing.handle_update_book(request.user, book) outgoing.handle_update_book(request.user, book)
return redirect('/book/%s' % book.fedireads_key) return redirect('/book/%s' % book.id)
@login_required @login_required

View file

@ -8,8 +8,9 @@ from django.template.response import TemplateResponse
from django.views.decorators.csrf import csrf_exempt from django.views.decorators.csrf import csrf_exempt
from fedireads import activitypub from fedireads import activitypub
from fedireads import forms, models, books_manager from fedireads import forms, models
from fedireads import goodreads_import from fedireads import goodreads_import
from fedireads.books_manager import get_or_create_book
from fedireads.tasks import app from fedireads.tasks import app
@ -363,9 +364,16 @@ def edit_profile_page(request):
return TemplateResponse(request, 'edit_user.html', data) return TemplateResponse(request, 'edit_user.html', data)
def book_page(request, book_identifier, tab='friends'): def book_page(request, book_id, tab='friends'):
''' info about a book ''' ''' info about a book '''
book = books_manager.get_or_create_book(book_identifier) key = 'id'
connector_id = None
if ':' in book_id:
try:
connector_id, key, book_id = book_id.split(':')
except ValueError:
return HttpResponseNotFound()
book = get_or_create_book(book_id, key=key, connector_id=connector_id)
if is_api_request(request): if is_api_request(request):
return JsonResponse(activitypub.get_book(book)) return JsonResponse(activitypub.get_book(book))
@ -430,7 +438,7 @@ def book_page(request, book_identifier, tab='friends'):
{'id': 'federated', 'display': 'Federated'} {'id': 'federated', 'display': 'Federated'}
], ],
'active_tab': tab, 'active_tab': tab,
'path': '/book/%s' % book_identifier, 'path': '/book/%s' % book_id,
'cover_form': forms.CoverForm(instance=book), 'cover_form': forms.CoverForm(instance=book),
'info_fields': [ 'info_fields': [
{'name': 'ISBN', 'value': book.isbn_13}, {'name': 'ISBN', 'value': book.isbn_13},
@ -445,9 +453,9 @@ def book_page(request, book_identifier, tab='friends'):
@login_required @login_required
def edit_book_page(request, book_identifier): def edit_book_page(request, book_id):
''' info about a book ''' ''' info about a book '''
book = books_manager.get_or_create_book(book_identifier) book = get_or_create_book(book_id)
if not book.description: if not book.description:
book.description = book.parent_work.description book.description = book.parent_work.description
data = { data = {
@ -468,10 +476,10 @@ def editions_page(request, work_id):
return TemplateResponse(request, 'editions.html', data) return TemplateResponse(request, 'editions.html', data)
def author_page(request, author_identifier): def author_page(request, author_id):
''' landing page for an author ''' ''' landing page for an author '''
try: try:
author = models.Author.objects.get(fedireads_key=author_identifier) author = models.Author.objects.get(id=author_id)
except ValueError: except ValueError:
return HttpResponseNotFound() return HttpResponseNotFound()