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',
'openlibrary_key',
'librarything_key',
'fedireads_key',
'lccn',
'oclc_number',
'pages',

View file

@ -5,18 +5,17 @@ from fedireads import models
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 '''
try:
book = models.Book.objects.select_subclasses().get(
fedireads_key=key
)
book = models.Book.objects.select_subclasses().get(**{key: value})
return book
except models.Book.DoesNotExist:
pass
connector = get_connector()
book = connector.get_or_create_book(key)
connector_info = models.Connector.objects.get(id=connector_id)
connector = load_connector(connector_info)
book = connector.get_or_create_book(value)
load_more_data.delay(book.id)
return book
@ -25,7 +24,7 @@ def get_or_create_book(key):
def load_more_data(book_id):
''' background the work of getting all 10,000 editions of LoTR '''
book = models.Book.objects.select_subclasses().get(id=book_id)
connector = get_connector(book)
connector = load_connector(book.connector)
connector.expand_book_data(book)
@ -60,7 +59,7 @@ def first_search_result(query):
def update_book(book):
''' re-sync with the original data source '''
connector = get_connector(book)
connector = load_connector(book.connector)
connector.update_book(book)
@ -70,18 +69,6 @@ def get_connectors():
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):
''' instantiate the connector class '''
connector = importlib.import_module(

View file

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

View file

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

View file

@ -36,7 +36,7 @@ class Connector(AbstractConnector):
search_results.append(
SearchResult(
book.title,
book.fedireads_key,
book.id,
book.author_text,
book.published_date.year if book.published_date else None,
None
@ -45,21 +45,21 @@ class Connector(AbstractConnector):
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
get a book, not load one from an external source '''
try:
return models.Book.objects.select_subclasses().get(
fedireads_key=fedireads_key
id=book_id
)
except ObjectDoesNotExist:
return None
def get_or_create_author(self, fedireads_key):
def get_or_create_author(self, author_id):
''' load that author '''
try:
return models.Author.objects.get(fedreads_key=fedireads_key)
return models.Author.objects.get(id=author_id)
except ObjectDoesNotExist:
pass

View file

@ -51,7 +51,6 @@ class Connector(FedireadsModel):
class Book(FedireadsModel):
''' a generic book, which can mean either an edition or a work '''
# 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)
librarything_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):
''' 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)
wikipedia_link = models.CharField(max_length=255, blank=True, null=True)
# 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):
''' 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_activity = activitypub.get_remove_tag(tag)
tag.delete()

View file

@ -6,7 +6,7 @@
{% include 'snippets/book_titleby.html' with book=book %}
{% 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="hidden-text">Edit Book</span>
</span>
@ -22,7 +22,7 @@
{% include 'snippets/shelve_button.html' %}
{% 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 %}
{{ cover_form.as_p }}
<button type="submit">Add cover</button>
@ -57,7 +57,7 @@
<h3>Tags</h3>
<form name="tag" action="/tag/" method="post">
{% csrf_token %}
<input type="hidden" name="book" value="{{ book.fedireads_key }}">
<input type="hidden" name="book" value="{{ book.id }}">
<input type="text" name="name">
<button type="submit">Add tag</button>
</form>

View file

@ -12,7 +12,7 @@
{% for result in result_set.results %}
<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>
{% endfor %}
</section>

View file

@ -4,7 +4,7 @@
<div class="content-container">
<h2>
Edit "{{ book.title }}"
<a href="/book/{{ book.fedireads_key }}">
<a href="/book/{{ book.id }}">
<span class="edit-link icon icon-close">
<span class="hidden-text">Close</span>
</span>
@ -40,8 +40,8 @@
<h3>Book Identifiers</h2>
<div>
<p><label for="id_isbn">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_13">ISBN 13:</label> {{ form.isbn_13 }} </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_librarything_key">Librarything key:</label> {{ form.librarything_key }} </p>
<p><label for="id_goodreads_key">Goodreads key:</label> {{ form.goodreads_key }} </p>

View file

@ -2,7 +2,7 @@
{% load fr_display %}
{% block content %}
<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">
{% for book in editions %}
<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">
<a href="/book/{{ book.fedireads_key }}">{{ book.title }}</a>
<a href="/book/{{ book.id }}">{{ book.title }}</a>
</span>
{% if book.authors %}
<span class="author">

View file

@ -37,7 +37,7 @@
<h2>
{% include 'snippets/avatar.html' with user=user %}
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 %}
</h2>

View file

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

View file

@ -4,7 +4,7 @@
{% for i in '12345'|make_list %}
<form name="rate" action="/rate/" method="POST" onsubmit="return rate_stars(event)">
{% 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 }}">
<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>

View file

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

View file

@ -3,14 +3,14 @@
{% if tag.identifier in user_tags %}
<form class="tag-form" name="tag" action="/untag/" method="post">
{% 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 }}">
<button type="submit">x</button>
</form>
{% else %}
<form class="tag-form" name="tag" action="/tag/" method="post">
{% 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 }}">
<button type="submit">+</button>
</form>

View file

@ -11,7 +11,7 @@ localname_regex = r'(?P<username>[\w\-_]+)'
user_path = r'^user/%s' % username_regex
local_user_path = r'^user/%s' % localname_regex
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'
handler500 = 'fedireads.views.server_error_page'
@ -58,7 +58,7 @@ urlpatterns = [
re_path(r'%s/replies(.json)?/?$' % status_path, views.replies_page),
# 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/edit/?$' % book_path, views.edit_book_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()
outgoing.handle_update_book(request.user, book)
return redirect('/book/%s' % book.fedireads_key)
return redirect('/book/%s' % book.id)
@login_required
@ -157,7 +157,7 @@ def upload_cover(request, book_id):
book.save()
outgoing.handle_update_book(request.user, book)
return redirect('/book/%s' % book.fedireads_key)
return redirect('/book/%s' % book.id)
@login_required

View file

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