forked from mirrors/bookwyrm
Adds create_book functionality for fedireads conn
This commit is contained in:
parent
1b91fb375f
commit
0edb9688cb
5 changed files with 95 additions and 29 deletions
|
@ -5,6 +5,7 @@ def get_book(book):
|
||||||
''' activitypub serialize a book '''
|
''' activitypub serialize a book '''
|
||||||
|
|
||||||
fields = [
|
fields = [
|
||||||
|
'title',
|
||||||
'sort_title',
|
'sort_title',
|
||||||
'subtitle',
|
'subtitle',
|
||||||
'isbn_13',
|
'isbn_13',
|
||||||
|
@ -27,10 +28,11 @@ def get_book(book):
|
||||||
'physical_format',
|
'physical_format',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
book_type = type(book).__name__
|
||||||
activity = {
|
activity = {
|
||||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||||
'type': 'Document',
|
'type': 'Document',
|
||||||
'book_type': type(book).__name__,
|
'book_type': book_type,
|
||||||
'name': book.title,
|
'name': book.title,
|
||||||
'url': book.absolute_id,
|
'url': book.absolute_id,
|
||||||
|
|
||||||
|
@ -39,9 +41,13 @@ def get_book(book):
|
||||||
book.first_published_date else None,
|
book.first_published_date else None,
|
||||||
'published_date': book.published_date.isoformat() if \
|
'published_date': book.published_date.isoformat() if \
|
||||||
book.published_date else None,
|
book.published_date else None,
|
||||||
'parent_work': book.parent_work.absolute_id if \
|
|
||||||
hasattr(book, 'parent_work') else None,
|
|
||||||
}
|
}
|
||||||
|
if book_type == 'Edition':
|
||||||
|
activity['work'] = book.parent_work.absolute_id
|
||||||
|
else:
|
||||||
|
editions = book.edition_set.order_by('default')
|
||||||
|
activity['editions'] = [get_book(b) for b in editions]
|
||||||
|
|
||||||
for field in fields:
|
for field in fields:
|
||||||
if hasattr(book, field):
|
if hasattr(book, field):
|
||||||
activity[field] = book.__getattribute__(field)
|
activity[field] = book.__getattribute__(field)
|
||||||
|
|
|
@ -18,11 +18,13 @@ def get_or_create_book(value, key='id', connector_id=None):
|
||||||
book = get_by_absolute_id(value, models.Book)
|
book = get_by_absolute_id(value, models.Book)
|
||||||
if book:
|
if book:
|
||||||
return book
|
return book
|
||||||
connector = get_or_create_connector(value)
|
|
||||||
return connector.get_or_create_book(value)
|
|
||||||
|
|
||||||
|
if connector_id:
|
||||||
connector_info = models.Connector.objects.get(id=connector_id)
|
connector_info = models.Connector.objects.get(id=connector_id)
|
||||||
connector = load_connector(connector_info)
|
connector = load_connector(connector_info)
|
||||||
|
else:
|
||||||
|
connector = get_or_create_connector(value)
|
||||||
|
|
||||||
book = connector.get_or_create_book(value)
|
book = connector.get_or_create_book(value)
|
||||||
load_more_data.delay(book.id)
|
load_more_data.delay(book.id)
|
||||||
return book
|
return book
|
||||||
|
@ -33,7 +35,7 @@ def get_or_create_connector(remote_id):
|
||||||
url = urlparse(remote_id)
|
url = urlparse(remote_id)
|
||||||
identifier = url.netloc
|
identifier = url.netloc
|
||||||
if not identifier:
|
if not identifier:
|
||||||
raise(ValueError)
|
raise ValueError('Invalid remote id')
|
||||||
|
|
||||||
try:
|
try:
|
||||||
connector_info = models.Connector.objects.get(identifier=identifier)
|
connector_info = models.Connector.objects.get(identifier=identifier)
|
||||||
|
|
|
@ -52,6 +52,33 @@ class AbstractConnector(ABC):
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
|
def create_book(self, key, data, model):
|
||||||
|
''' create a work or edition from data '''
|
||||||
|
# we really would rather use an existing book than make a new one
|
||||||
|
match = match_from_mappings(data, self.key_mappings)
|
||||||
|
if match:
|
||||||
|
if not isinstance(match, model):
|
||||||
|
if type(match).__name__ == 'Edition':
|
||||||
|
return match.parent_work
|
||||||
|
else:
|
||||||
|
return match.default_edition
|
||||||
|
return match
|
||||||
|
|
||||||
|
kwargs = {
|
||||||
|
self.key_name: key,
|
||||||
|
'title': data['title'],
|
||||||
|
'connector': self.connector
|
||||||
|
}
|
||||||
|
book = model.objects.create(**kwargs)
|
||||||
|
return self.update_book_from_data(book, data)
|
||||||
|
|
||||||
|
|
||||||
|
def update_book_from_data(self, book, data):
|
||||||
|
''' simple function to save data to a book '''
|
||||||
|
update_from_mappings(book, data, self.book_mappings)
|
||||||
|
book.save()
|
||||||
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def format_search_result(self, search_result):
|
def format_search_result(self, search_result):
|
||||||
''' create a SearchResult obj from json '''
|
''' create a SearchResult obj from json '''
|
||||||
|
|
|
@ -1,7 +1,9 @@
|
||||||
''' using another fedireads instance as a source of book data '''
|
''' using another fedireads instance as a source of book data '''
|
||||||
|
import requests
|
||||||
|
|
||||||
from django.core.exceptions import ObjectDoesNotExist
|
from django.core.exceptions import ObjectDoesNotExist
|
||||||
from django.core.files.base import ContentFile
|
from django.core.files.base import ContentFile
|
||||||
import requests
|
from django.db import transaction
|
||||||
|
|
||||||
from fedireads import models
|
from fedireads import models
|
||||||
from .abstract_connector import AbstractConnector, SearchResult, get_date
|
from .abstract_connector import AbstractConnector, SearchResult, get_date
|
||||||
|
@ -10,6 +12,15 @@ from .abstract_connector import match_from_mappings, update_from_mappings
|
||||||
|
|
||||||
class Connector(AbstractConnector):
|
class Connector(AbstractConnector):
|
||||||
''' interact with other instances '''
|
''' interact with other instances '''
|
||||||
|
def __init__(self, identifier):
|
||||||
|
self.key_mappings = {
|
||||||
|
'isbn_13': ('isbn_13', None),
|
||||||
|
'isbn_10': ('isbn_10', None),
|
||||||
|
'oclc_numbers': ('oclc_number', None),
|
||||||
|
'lccn': ('lccn', None),
|
||||||
|
}
|
||||||
|
super().__init__(identifier)
|
||||||
|
|
||||||
|
|
||||||
def format_search_result(self, search_result):
|
def format_search_result(self, search_result):
|
||||||
return SearchResult(**search_result)
|
return SearchResult(**search_result)
|
||||||
|
@ -26,8 +37,44 @@ class Connector(AbstractConnector):
|
||||||
return book
|
return book
|
||||||
|
|
||||||
# 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(remote_id=remote_id)
|
response = requests.get(
|
||||||
self.update_book(book)
|
remote_id,
|
||||||
|
headers={
|
||||||
|
'Accept': 'application/activity+json; charset=utf-8',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
if not response.ok:
|
||||||
|
response.raise_for_status()
|
||||||
|
data = response.json()
|
||||||
|
|
||||||
|
if data['book_type'] == 'work':
|
||||||
|
work_data = data
|
||||||
|
try:
|
||||||
|
edition_data = data['editions'][0]
|
||||||
|
except KeyError:
|
||||||
|
# hack: re-use the work data as the edition data
|
||||||
|
edition_data = data
|
||||||
|
else:
|
||||||
|
edition_data = data
|
||||||
|
try:
|
||||||
|
work_data = data['work']
|
||||||
|
except KeyError:
|
||||||
|
# hack: re-use the work data as the edition data
|
||||||
|
work_data = data
|
||||||
|
|
||||||
|
with transaction.atomic():
|
||||||
|
# create both work and a default edition
|
||||||
|
work_key = edition_data.get('url')
|
||||||
|
work = self.create_book(work_key, work_data, models.Work)
|
||||||
|
|
||||||
|
ed_key = edition_data.get('url')
|
||||||
|
edition = self.create_book(ed_key, edition_data, models.Edition)
|
||||||
|
edition.default = True
|
||||||
|
edition.parent_work = work
|
||||||
|
edition.save()
|
||||||
|
|
||||||
|
print(work, edition)
|
||||||
|
return edition
|
||||||
|
|
||||||
|
|
||||||
def update_book(self, book, data=None):
|
def update_book(self, book, data=None):
|
||||||
|
|
|
@ -7,7 +7,7 @@ from django.db import transaction
|
||||||
|
|
||||||
from fedireads import models
|
from fedireads import models
|
||||||
from .abstract_connector import AbstractConnector, SearchResult
|
from .abstract_connector import AbstractConnector, SearchResult
|
||||||
from .abstract_connector import match_from_mappings, update_from_mappings
|
from .abstract_connector import update_from_mappings
|
||||||
from .abstract_connector import get_date
|
from .abstract_connector import get_date
|
||||||
from .openlibrary_languages import languages
|
from .openlibrary_languages import languages
|
||||||
|
|
||||||
|
@ -104,26 +104,10 @@ class Connector(AbstractConnector):
|
||||||
return edition
|
return edition
|
||||||
|
|
||||||
|
|
||||||
def create_book(self, key, data, model):
|
|
||||||
''' create a work or edition from data '''
|
|
||||||
# we really would rather use an existing book than make a new one
|
|
||||||
match = match_from_mappings(data, self.key_mappings)
|
|
||||||
if match:
|
|
||||||
return match
|
|
||||||
|
|
||||||
book = model.objects.create(
|
|
||||||
openlibrary_key=key,
|
|
||||||
title=data['title'],
|
|
||||||
connector=self.connector,
|
|
||||||
)
|
|
||||||
return self.update_book_from_data(book, data)
|
|
||||||
|
|
||||||
|
|
||||||
def update_book_from_data(self, book, data):
|
def update_book_from_data(self, book, data):
|
||||||
''' updaet a book model instance from ol data '''
|
''' updaet a book model instance from ol data '''
|
||||||
# populate the simple data fields
|
# populate the simple data fields
|
||||||
update_from_mappings(book, data, self.book_mappings)
|
super().update_book_from_data(book, data)
|
||||||
book.save()
|
|
||||||
|
|
||||||
authors = self.get_authors_from_data(data)
|
authors = self.get_authors_from_data(data)
|
||||||
for author in authors:
|
for author in authors:
|
||||||
|
|
Loading…
Reference in a new issue