mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2025-06-06 15:58:48 +00:00
Merge branch 'main' into production
This commit is contained in:
commit
7dd1deb438
12 changed files with 78 additions and 25 deletions
|
@ -44,10 +44,9 @@ class ActivityObject:
|
||||||
type: str
|
type: str
|
||||||
|
|
||||||
def __init__(self, **kwargs):
|
def __init__(self, **kwargs):
|
||||||
''' this lets you pass in an object with fields
|
''' this lets you pass in an object with fields that aren't in the
|
||||||
that aren't in the dataclass, which it ignores.
|
dataclass, which it ignores. Any field in the dataclass is required or
|
||||||
Any field in the dataclass is required or has a
|
has a default value '''
|
||||||
default value '''
|
|
||||||
for field in fields(self):
|
for field in fields(self):
|
||||||
try:
|
try:
|
||||||
value = kwargs[field.name]
|
value = kwargs[field.name]
|
||||||
|
@ -59,7 +58,7 @@ class ActivityObject:
|
||||||
|
|
||||||
|
|
||||||
def to_model(self, model, instance=None):
|
def to_model(self, model, instance=None):
|
||||||
''' convert from an activity to a model '''
|
''' convert from an activity to a model instance '''
|
||||||
if not isinstance(self, model.activity_serializer):
|
if not isinstance(self, model.activity_serializer):
|
||||||
raise TypeError('Wrong activity type for model')
|
raise TypeError('Wrong activity type for model')
|
||||||
|
|
||||||
|
|
|
@ -52,7 +52,6 @@ class Work(Book):
|
||||||
type: str = 'Work'
|
type: str = 'Work'
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(init=False)
|
@dataclass(init=False)
|
||||||
class Author(ActivityObject):
|
class Author(ActivityObject):
|
||||||
''' author of a book '''
|
''' author of a book '''
|
||||||
|
|
|
@ -6,6 +6,7 @@ from .base_activity import ActivityObject, Image
|
||||||
|
|
||||||
@dataclass(init=False)
|
@dataclass(init=False)
|
||||||
class Tombstone(ActivityObject):
|
class Tombstone(ActivityObject):
|
||||||
|
''' the placeholder for a deleted status '''
|
||||||
url: str
|
url: str
|
||||||
published: str
|
published: str
|
||||||
deleted: str
|
deleted: str
|
||||||
|
@ -23,7 +24,6 @@ class Note(ActivityObject):
|
||||||
cc: List[str]
|
cc: List[str]
|
||||||
content: str
|
content: str
|
||||||
replies: Dict
|
replies: Dict
|
||||||
# TODO: this is wrong???
|
|
||||||
attachment: List[Image] = field(default=lambda: [])
|
attachment: List[Image] = field(default=lambda: [])
|
||||||
sensitive: bool = False
|
sensitive: bool = False
|
||||||
type: str = 'Note'
|
type: str = 'Note'
|
||||||
|
|
|
@ -13,7 +13,6 @@ def get_public_recipients(user, software=None):
|
||||||
''' everybody and their public inboxes '''
|
''' everybody and their public inboxes '''
|
||||||
followers = user.followers.filter(local=False)
|
followers = user.followers.filter(local=False)
|
||||||
if software:
|
if software:
|
||||||
# TODO: eventually we may want to handle particular software differently
|
|
||||||
followers = followers.filter(bookwyrm_user=(software == 'bookwyrm'))
|
followers = followers.filter(bookwyrm_user=(software == 'bookwyrm'))
|
||||||
|
|
||||||
# we want shared inboxes when available
|
# we want shared inboxes when available
|
||||||
|
@ -36,7 +35,6 @@ def broadcast(sender, activity, software=None, \
|
||||||
# start with parsing the direct recipients
|
# start with parsing the direct recipients
|
||||||
recipients = [u.inbox for u in direct_recipients or []]
|
recipients = [u.inbox for u in direct_recipients or []]
|
||||||
# and then add any other recipients
|
# and then add any other recipients
|
||||||
# TODO: other kinds of privacy
|
|
||||||
if privacy == 'public':
|
if privacy == 'public':
|
||||||
recipients += get_public_recipients(sender, software=software)
|
recipients += get_public_recipients(sender, software=software)
|
||||||
broadcast_task.delay(
|
broadcast_task.delay(
|
||||||
|
@ -55,7 +53,6 @@ def broadcast_task(sender_id, activity, recipients):
|
||||||
try:
|
try:
|
||||||
sign_and_send(sender, activity, recipient)
|
sign_and_send(sender, activity, recipient)
|
||||||
except requests.exceptions.HTTPError as e:
|
except requests.exceptions.HTTPError as e:
|
||||||
# TODO: maybe keep track of users who cause errors
|
|
||||||
errors.append({
|
errors.append({
|
||||||
'error': str(e),
|
'error': str(e),
|
||||||
'recipient': recipient,
|
'recipient': recipient,
|
||||||
|
|
|
@ -6,7 +6,6 @@ from bookwyrm.tasks import app
|
||||||
|
|
||||||
def password_reset_email(reset_code):
|
def password_reset_email(reset_code):
|
||||||
''' generate a password reset email '''
|
''' generate a password reset email '''
|
||||||
# TODO; this should be tempalted
|
|
||||||
site = models.SiteSettings.get()
|
site = models.SiteSettings.get()
|
||||||
send_email.delay(
|
send_email.delay(
|
||||||
reset_code.user.email,
|
reset_code.user.email,
|
||||||
|
|
|
@ -68,7 +68,7 @@ def shared_inbox(request):
|
||||||
'Like': handle_unfavorite,
|
'Like': handle_unfavorite,
|
||||||
},
|
},
|
||||||
'Update': {
|
'Update': {
|
||||||
'Person': None,# TODO: handle_update_user
|
'Person': handle_update_user,
|
||||||
'Document': handle_update_book,
|
'Document': handle_update_book,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -308,6 +308,20 @@ def handle_tag(activity):
|
||||||
status_builder.create_tag(user, book, activity['object']['name'])
|
status_builder.create_tag(user, book, activity['object']['name'])
|
||||||
|
|
||||||
|
|
||||||
|
@app.task
|
||||||
|
def handle_update_user(activity):
|
||||||
|
''' receive an updated user Person activity object '''
|
||||||
|
try:
|
||||||
|
user = models.User.objects.get(remote_id=activity['object']['id'])
|
||||||
|
except models.User.DoesNotExist:
|
||||||
|
# who is this person? who cares
|
||||||
|
return
|
||||||
|
activitypub.Person(
|
||||||
|
**activity['object']
|
||||||
|
).to_model(models.User, instance=user)
|
||||||
|
# model save() happens in the to_model function
|
||||||
|
|
||||||
|
|
||||||
@app.task
|
@app.task
|
||||||
def handle_update_book(activity):
|
def handle_update_book(activity):
|
||||||
''' a remote instance changed a book (Document) '''
|
''' a remote instance changed a book (Document) '''
|
||||||
|
|
18
bookwyrm/migrations/0056_auto_20201021_0150.py
Normal file
18
bookwyrm/migrations/0056_auto_20201021_0150.py
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
# Generated by Django 3.0.7 on 2020-10-21 01:50
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
('bookwyrm', '0055_merge_20201017_0011'),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name='status',
|
||||||
|
name='deleted_date',
|
||||||
|
field=models.DateTimeField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
]
|
|
@ -23,7 +23,7 @@ class Status(OrderedCollectionPageMixin, BookWyrmModel):
|
||||||
# the created date can't be this, because of receiving federated posts
|
# the created date can't be this, because of receiving federated posts
|
||||||
published_date = models.DateTimeField(default=timezone.now)
|
published_date = models.DateTimeField(default=timezone.now)
|
||||||
deleted = models.BooleanField(default=False)
|
deleted = models.BooleanField(default=False)
|
||||||
deleted_date = models.DateTimeField()
|
deleted_date = models.DateTimeField(blank=True, null=True)
|
||||||
favorites = models.ManyToManyField(
|
favorites = models.ManyToManyField(
|
||||||
'User',
|
'User',
|
||||||
symmetrical=False,
|
symmetrical=False,
|
||||||
|
|
|
@ -15,9 +15,6 @@
|
||||||
<div class="control">
|
<div class="control">
|
||||||
{{ login_form.username }}
|
{{ login_form.username }}
|
||||||
</div>
|
</div>
|
||||||
{% for error in login_form.username.errors %}
|
|
||||||
<p class="help is-danger">{{ error | escape }}</p>
|
|
||||||
{% endfor %}
|
|
||||||
</div>
|
</div>
|
||||||
<div class="field">
|
<div class="field">
|
||||||
<label class="label" for="id_password">Password:</label>
|
<label class="label" for="id_password">Password:</label>
|
||||||
|
|
30
bookwyrm/tests/incoming/test_update_user.py
Normal file
30
bookwyrm/tests/incoming/test_update_user.py
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
import json
|
||||||
|
import pathlib
|
||||||
|
from django.test import TestCase
|
||||||
|
|
||||||
|
from bookwyrm import models, incoming
|
||||||
|
|
||||||
|
|
||||||
|
class UpdateUser(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.user = models.User.objects.create_user(
|
||||||
|
'mouse', 'mouse@mouse.com', 'mouseword',
|
||||||
|
remote_id='https://example.com/user/mouse',
|
||||||
|
local=False,
|
||||||
|
localname='mouse'
|
||||||
|
)
|
||||||
|
|
||||||
|
datafile = pathlib.Path(__file__).parent.joinpath(
|
||||||
|
'../data/ap_user.json'
|
||||||
|
)
|
||||||
|
self.user_data = json.loads(datafile.read_bytes())
|
||||||
|
|
||||||
|
def test_handle_update_user(self):
|
||||||
|
self.assertIsNone(self.user.name)
|
||||||
|
self.assertEqual(self.user.localname, 'mouse')
|
||||||
|
|
||||||
|
incoming.handle_update_user({'object': self.user_data})
|
||||||
|
self.user = models.User.objects.get(id=self.user.id)
|
||||||
|
|
||||||
|
self.assertEqual(self.user.name, 'MOUSE?? MOUSE!!')
|
||||||
|
self.assertEqual(self.user.localname, 'mouse')
|
|
@ -11,7 +11,14 @@ 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_types = ['status', 'review', 'comment', 'quotation', 'boost', 'generatedstatus']
|
status_types = [
|
||||||
|
'status',
|
||||||
|
'review',
|
||||||
|
'comment',
|
||||||
|
'quotation',
|
||||||
|
'boost',
|
||||||
|
'generatedstatus'
|
||||||
|
]
|
||||||
status_path = r'%s/(%s)/(?P<status_id>\d+)' % \
|
status_path = r'%s/(%s)/(?P<status_id>\d+)' % \
|
||||||
(local_user_path, '|'.join(status_types))
|
(local_user_path, '|'.join(status_types))
|
||||||
|
|
||||||
|
|
|
@ -24,14 +24,6 @@ def user_login(request):
|
||||||
return redirect('/login')
|
return redirect('/login')
|
||||||
|
|
||||||
login_form = forms.LoginForm(request.POST)
|
login_form = forms.LoginForm(request.POST)
|
||||||
register_form = forms.RegisterForm()
|
|
||||||
if not login_form.is_valid():
|
|
||||||
data = {
|
|
||||||
'site_settings': models.SiteSettings.get(),
|
|
||||||
'login_form': login_form,
|
|
||||||
'register_form': register_form
|
|
||||||
}
|
|
||||||
return TemplateResponse(request, 'login.html', data)
|
|
||||||
|
|
||||||
username = login_form.data['username']
|
username = login_form.data['username']
|
||||||
username = '%s@%s' % (username, DOMAIN)
|
username = '%s@%s' % (username, DOMAIN)
|
||||||
|
@ -42,6 +34,7 @@ def user_login(request):
|
||||||
return redirect(request.GET.get('next', '/'))
|
return redirect(request.GET.get('next', '/'))
|
||||||
|
|
||||||
login_form.non_field_errors = 'Username or password are incorrect'
|
login_form.non_field_errors = 'Username or password are incorrect'
|
||||||
|
register_form = forms.RegisterForm()
|
||||||
data = {
|
data = {
|
||||||
'site_settings': models.SiteSettings.get(),
|
'site_settings': models.SiteSettings.get(),
|
||||||
'login_form': login_form,
|
'login_form': login_form,
|
||||||
|
|
Loading…
Reference in a new issue