Merge branch 'main' into production

This commit is contained in:
Mouse Reeve 2020-11-02 15:40:15 -08:00
commit dd8f91a044
9 changed files with 53 additions and 17 deletions

View file

@ -55,7 +55,6 @@ class Work(Book):
@dataclass(init=False)
class Author(ActivityObject):
''' author of a book '''
url: str
name: str
born: str
died: str

View file

@ -61,7 +61,7 @@ def broadcast_task(sender_id, activity, recipients):
return errors
def sign_and_send(sender, activity, destination):
def sign_and_send(sender, data, destination):
''' crpyto whatever and http junk '''
now = http_date()
@ -69,7 +69,6 @@ def sign_and_send(sender, activity, destination):
# this shouldn't happen. it would be bad if it happened.
raise ValueError('No private key found for sender')
data = json.dumps(activity).encode('utf-8')
digest = make_digest(data)
response = requests.post(

View file

@ -62,6 +62,8 @@ def shared_inbox(request):
'Announce': handle_boost,
'Add': {
'Tag': handle_tag,
'Edition': handle_shelve,
'Work': handle_shelve,
},
'Undo': {
'Follow': handle_unfollow,
@ -318,6 +320,22 @@ def handle_tag(activity):
status_builder.create_tag(user, book, activity['object']['name'])
@app.task
def handle_shelve(activity):
''' putting a book on a shelf '''
user = get_or_create_remote_user(activity['actor'])
book = books_manager.get_or_create_book(activity['object'])
try:
shelf = models.Shelf.objects.get(remote_id=activity['target'])
except models.Shelf.DoesNotExist:
return
if shelf.user != user:
# this doesn't add up.
return
shelf.books.add(book)
shelf.save()
@app.task
def handle_update_user(activity):
''' receive an updated user Person activity object '''

View file

@ -68,7 +68,10 @@ class ActivitypubMixin:
if not hasattr(self, mapping.model_key) or not mapping.activity_key:
continue
value = getattr(self, mapping.model_key)
if hasattr(value, 'remote_id'):
print(value)
if hasattr(value, 'local_id'):
value = value.local_id
elif hasattr(value, 'remote_id'):
value = value.remote_id
if isinstance(value, datetime):
value = value.isoformat()

View file

@ -56,7 +56,7 @@ class Book(ActivitypubMixin, BookWyrmModel):
@property
def ap_authors(self):
''' the activitypub serialization should be a list of author ids '''
return [a.remote_id for a in self.authors.all()]
return [a.local_id for a in self.authors.all()]
@property
def ap_cover(self):
@ -73,7 +73,7 @@ class Book(ActivitypubMixin, BookWyrmModel):
return self.parent_work.local_id
activity_mappings = [
ActivityMapping('id', 'remote_id'),
ActivityMapping('id', 'local_id'),
ActivityMapping('authors', 'ap_authors'),
ActivityMapping('first_published_date', 'first_published_date'),
@ -258,7 +258,7 @@ class Author(ActivitypubMixin, BookWyrmModel):
an instance, so it needs a local url for federation. but it still needs
the remote_id for easier deduplication and, if appropriate, to sync with
the remote canonical copy (ditto here for author)'''
return 'https://%s/book/%d' % (DOMAIN, self.id)
return 'https://%s/author/%d' % (DOMAIN, self.id)
@property
def display_name(self):
@ -271,8 +271,7 @@ class Author(ActivitypubMixin, BookWyrmModel):
return self.last_name or self.first_name
activity_mappings = [
ActivityMapping('id', 'remote_id'),
ActivityMapping('url', 'remote_id'),
ActivityMapping('id', 'local_id'),
ActivityMapping('name', 'display_name'),
ActivityMapping('born', 'born'),
ActivityMapping('died', 'died'),

View file

@ -49,8 +49,8 @@ class ShelfBook(BookWyrmModel):
return activitypub.Add(
id='%s#add' % self.remote_id,
actor=user.remote_id,
object=self.book.to_activity(),
target=self.shelf.to_activity()
object=self.book.local_id,
target=self.shelf.remote_id,
).serialize()
def to_remove_activity(self, user):

View file

@ -44,7 +44,8 @@ def make_signature(sender, destination, date, digest):
def make_digest(data):
''' creates a message digest for signing '''
return 'SHA-256=' + b64encode(hashlib.sha256(data).digest()).decode('utf-8')
return 'SHA-256=' + b64encode(hashlib.sha256(data.encode('utf-8'))\
.digest()).decode('utf-8')
def verify_digest(request):

View file

@ -2,7 +2,7 @@
<!DOCTYPE html>
<html lang="en">
<head>
<title>BookWyrm</title>
<title>{% if title %}{{ title }} | {% endif %}BookWyrm</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link type="text/css" rel="stylesheet" href="/static/css/bulma.min.css">
<link type="text/css" rel="stylesheet" href="/static/css/format.css">

View file

@ -36,12 +36,12 @@ def is_api_request(request):
def server_error_page(request):
''' 500 errors '''
return TemplateResponse(request, 'error.html')
return TemplateResponse(request, 'error.html', {'title': 'Oops!'})
def not_found_page(request, _):
''' 404s '''
return TemplateResponse(request, 'notfound.html')
return TemplateResponse(request, 'notfound.html', {'title': 'Not found'})
@login_required
@ -97,6 +97,7 @@ def home_tab(request, tab):
next_page = '/?page=%d#feed' % (page + 1)
prev_page = '/?page=%d#feed' % (page - 1)
data = {
'title': 'Updates Feed',
'user': request.user,
'suggested_books': set(suggested_books),
'activities': activities,
@ -181,6 +182,7 @@ def search(request):
book_results = books_manager.search(query)
data = {
'title': 'Search Results',
'book_results': book_results,
'user_results': user_results,
'query': query,
@ -192,6 +194,7 @@ def search(request):
def import_page(request):
''' import history from goodreads '''
return TemplateResponse(request, 'import.html', {
'title': 'Import Books',
'import_form': forms.ImportForm(),
'jobs': models.ImportJob.
objects.filter(user=request.user).order_by('-created_date'),
@ -207,6 +210,7 @@ def import_status(request, job_id):
raise PermissionDenied
task = app.AsyncResult(job.task_id)
return TemplateResponse(request, 'import_status.html', {
'title': 'Import Status',
'job': job,
'items': job.items.order_by('index').all(),
'task': task
@ -219,6 +223,7 @@ def login_page(request):
return redirect('/')
# send user to the login page
data = {
'title': 'Login',
'site_settings': models.SiteSettings.get(),
'login_form': forms.LoginForm(),
'register_form': forms.RegisterForm(),
@ -229,6 +234,7 @@ def login_page(request):
def about_page(request):
''' more information about the instance '''
data = {
'title': 'About',
'site_settings': models.SiteSettings.get(),
}
return TemplateResponse(request, 'about.html', data)
@ -236,7 +242,7 @@ def about_page(request):
def password_reset_request(request):
''' invite management page '''
return TemplateResponse(request, 'password_reset_request.html')
return TemplateResponse(request, 'password_reset_request.html', {'title': 'Reset Password'})
def password_reset(request, code):
@ -253,7 +259,7 @@ def password_reset(request, code):
return TemplateResponse(
request,
'password_reset.html',
{'code': reset_code.code}
{'title': 'Reset Password', 'code': reset_code.code}
)
@ -269,6 +275,7 @@ def invite_page(request, code):
raise PermissionDenied
data = {
'title': 'Join',
'site_settings': models.SiteSettings.get(),
'register_form': forms.RegisterForm(),
'invite': invite,
@ -280,6 +287,7 @@ def invite_page(request, code):
def manage_invites(request):
''' invite management page '''
data = {
'title': 'Invitations',
'invites': models.SiteInvite.objects.filter(user=request.user),
'form': forms.CreateInviteForm(),
}
@ -293,6 +301,7 @@ def notifications_page(request):
.order_by('-created_date')
unread = [n.id for n in notifications.filter(read=False)]
data = {
'title': 'Notifications',
'notifications': notifications,
'unread': unread,
}
@ -313,6 +322,7 @@ def user_page(request, username, subpage=None, shelf=None):
# otherwise we're at a UI view
data = {
'title': user.name,
'user': user,
'is_self': request.user.id == user.id,
}
@ -416,6 +426,7 @@ def status_page(request, username, status_id):
return JsonResponse(status.to_activity(), encoder=ActivityEncoder)
data = {
'title': status.type,
'status': status,
}
return TemplateResponse(request, 'status.html', data)
@ -460,6 +471,7 @@ def edit_profile_page(request):
form = forms.EditUserForm(instance=request.user)
data = {
'title': 'Edit profile',
'form': form,
'user': user,
}
@ -506,6 +518,7 @@ def book_page(request, book_id):
).distinct().all()
data = {
'title': book.title,
'book': book,
'reviews': reviews.filter(content__isnull=False),
'ratings': reviews.filter(content__isnull=True),
@ -539,6 +552,7 @@ def edit_book_page(request, book_id):
if not book.description:
book.description = book.parent_work.description
data = {
'title': 'Edit Book',
'book': book,
'form': forms.EditionForm(instance=book)
}
@ -550,6 +564,7 @@ def editions_page(request, work_id):
work = models.Work.objects.get(id=work_id)
editions = models.Edition.objects.filter(parent_work=work).all()
data = {
'title': 'Editions of %s' % work.title,
'editions': editions,
'work': work,
}
@ -568,6 +583,7 @@ def author_page(request, author_id):
books = models.Work.objects.filter(authors=author)
data = {
'title': author.name,
'author': author,
'books': [b.default_edition for b in books],
}
@ -586,6 +602,7 @@ def tag_page(request, tag_id):
books = models.Edition.objects.filter(tag__identifier=tag_id).distinct()
data = {
'title': tag_obj.name,
'books': books,
'tag': tag_obj,
}