forked from mirrors/bookwyrm
Merge pull request #605 from mouse-reeve/user-creation
User save() override instead of signal to set user fields
This commit is contained in:
commit
2db1409cfb
3 changed files with 82 additions and 76 deletions
|
@ -188,7 +188,7 @@ def handle_block(activity):
|
||||||
''' blocking a user '''
|
''' blocking a user '''
|
||||||
# create "block" databse entry
|
# create "block" databse entry
|
||||||
activitypub.Block(**activity).to_model(models.UserBlocks)
|
activitypub.Block(**activity).to_model(models.UserBlocks)
|
||||||
# the removing relationships is handled in post-save hook in model
|
# the removing relationships is handled in model save
|
||||||
|
|
||||||
|
|
||||||
@app.task
|
@app.task
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
''' defines relationships between users '''
|
''' defines relationships between users '''
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.db import models, transaction
|
from django.db import models, transaction, IntegrityError
|
||||||
from django.db.models import Q
|
from django.db.models import Q
|
||||||
from django.dispatch import receiver
|
|
||||||
|
|
||||||
from bookwyrm import activitypub
|
from bookwyrm import activitypub
|
||||||
from .activitypub_mixin import ActivitypubMixin, ActivityMixin
|
from .activitypub_mixin import ActivitypubMixin, ActivityMixin
|
||||||
|
@ -61,6 +60,20 @@ class UserFollows(ActivitypubMixin, UserRelationship):
|
||||||
status = 'follows'
|
status = 'follows'
|
||||||
activity_serializer = activitypub.Follow
|
activity_serializer = activitypub.Follow
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
''' really really don't let a user follow someone who blocked them '''
|
||||||
|
# blocking in either direction is a no-go
|
||||||
|
if UserBlocks.objects.filter(
|
||||||
|
Q(
|
||||||
|
user_subject=self.user_subject,
|
||||||
|
user_object=self.user_object,
|
||||||
|
) | Q(
|
||||||
|
user_subject=self.user_object,
|
||||||
|
user_object=self.user_subject,
|
||||||
|
)
|
||||||
|
).exists():
|
||||||
|
raise IntegrityError()
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_request(cls, follow_request):
|
def from_request(cls, follow_request):
|
||||||
|
@ -79,23 +92,25 @@ class UserFollowRequest(ActivitypubMixin, UserRelationship):
|
||||||
|
|
||||||
def save(self, *args, broadcast=True, **kwargs):
|
def save(self, *args, broadcast=True, **kwargs):
|
||||||
''' make sure the follow or block relationship doesn't already exist '''
|
''' make sure the follow or block relationship doesn't already exist '''
|
||||||
try:
|
# don't create a request if a follow already exists
|
||||||
UserFollows.objects.get(
|
if UserFollows.objects.filter(
|
||||||
user_subject=self.user_subject,
|
user_subject=self.user_subject,
|
||||||
user_object=self.user_object,
|
user_object=self.user_object,
|
||||||
)
|
).exists():
|
||||||
# blocking in either direction is a no-go
|
raise IntegrityError()
|
||||||
UserBlocks.objects.get(
|
# blocking in either direction is a no-go
|
||||||
user_subject=self.user_subject,
|
if UserBlocks.objects.filter(
|
||||||
user_object=self.user_object,
|
Q(
|
||||||
)
|
user_subject=self.user_subject,
|
||||||
UserBlocks.objects.get(
|
user_object=self.user_object,
|
||||||
user_subject=self.user_object,
|
) | Q(
|
||||||
user_object=self.user_subject,
|
user_subject=self.user_object,
|
||||||
)
|
user_object=self.user_subject,
|
||||||
return None
|
)
|
||||||
except (UserFollows.DoesNotExist, UserBlocks.DoesNotExist):
|
).exists():
|
||||||
super().save(*args, **kwargs)
|
raise IntegrityError()
|
||||||
|
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
if broadcast and self.user_subject.local and not self.user_object.local:
|
if broadcast and self.user_subject.local and not self.user_object.local:
|
||||||
self.broadcast(self.to_activity(), self.user_subject)
|
self.broadcast(self.to_activity(), self.user_subject)
|
||||||
|
@ -143,20 +158,15 @@ class UserBlocks(ActivityMixin, UserRelationship):
|
||||||
status = 'blocks'
|
status = 'blocks'
|
||||||
activity_serializer = activitypub.Block
|
activity_serializer = activitypub.Block
|
||||||
|
|
||||||
|
def save(self, *args, **kwargs):
|
||||||
|
''' remove follow or follow request rels after a block is created '''
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
@receiver(models.signals.post_save, sender=UserBlocks)
|
UserFollows.objects.filter(
|
||||||
#pylint: disable=unused-argument
|
Q(user_subject=self.user_subject, user_object=self.user_object) | \
|
||||||
def execute_after_save(sender, instance, created, *args, **kwargs):
|
Q(user_subject=self.user_object, user_object=self.user_subject)
|
||||||
''' remove follow or follow request rels after a block is created '''
|
).delete()
|
||||||
UserFollows.objects.filter(
|
UserFollowRequest.objects.filter(
|
||||||
Q(user_subject=instance.user_subject,
|
Q(user_subject=self.user_subject, user_object=self.user_object) | \
|
||||||
user_object=instance.user_object) | \
|
Q(user_subject=self.user_object, user_object=self.user_subject)
|
||||||
Q(user_subject=instance.user_object,
|
).delete()
|
||||||
user_object=instance.user_subject)
|
|
||||||
).delete()
|
|
||||||
UserFollowRequest.objects.filter(
|
|
||||||
Q(user_subject=instance.user_subject,
|
|
||||||
user_object=instance.user_object) | \
|
|
||||||
Q(user_subject=instance.user_object,
|
|
||||||
user_object=instance.user_subject)
|
|
||||||
).delete()
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ from django.apps import apps
|
||||||
from django.contrib.auth.models import AbstractUser
|
from django.contrib.auth.models import AbstractUser
|
||||||
from django.core.validators import MinValueValidator
|
from django.core.validators import MinValueValidator
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.dispatch import receiver
|
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
|
|
||||||
from bookwyrm import activitypub
|
from bookwyrm import activitypub
|
||||||
|
@ -172,15 +171,23 @@ class User(OrderedCollectionPageMixin, AbstractUser):
|
||||||
|
|
||||||
def save(self, *args, **kwargs):
|
def save(self, *args, **kwargs):
|
||||||
''' populate fields for new local users '''
|
''' populate fields for new local users '''
|
||||||
# this user already exists, no need to populate fields
|
|
||||||
if not self.local and not re.match(regex.full_username, self.username):
|
if not self.local and not re.match(regex.full_username, self.username):
|
||||||
# generate a username that uses the domain (webfinger format)
|
# generate a username that uses the domain (webfinger format)
|
||||||
actor_parts = urlparse(self.remote_id)
|
actor_parts = urlparse(self.remote_id)
|
||||||
self.username = '%s@%s' % (self.username, actor_parts.netloc)
|
self.username = '%s@%s' % (self.username, actor_parts.netloc)
|
||||||
return super().save(*args, **kwargs)
|
super().save(*args, **kwargs)
|
||||||
|
return
|
||||||
|
|
||||||
if self.id or not self.local:
|
# this user already exists, no need to populate fields
|
||||||
return super().save(*args, **kwargs)
|
if self.id:
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
return
|
||||||
|
|
||||||
|
# this is a new remote user, we need to set their remote server field
|
||||||
|
if not self.local:
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
set_remote_server.delay(self.id)
|
||||||
|
return
|
||||||
|
|
||||||
# populate fields for local users
|
# populate fields for local users
|
||||||
self.remote_id = 'https://%s/user/%s' % (DOMAIN, self.localname)
|
self.remote_id = 'https://%s/user/%s' % (DOMAIN, self.localname)
|
||||||
|
@ -188,7 +195,32 @@ class User(OrderedCollectionPageMixin, AbstractUser):
|
||||||
self.shared_inbox = 'https://%s/inbox' % DOMAIN
|
self.shared_inbox = 'https://%s/inbox' % DOMAIN
|
||||||
self.outbox = '%s/outbox' % self.remote_id
|
self.outbox = '%s/outbox' % self.remote_id
|
||||||
|
|
||||||
return super().save(*args, **kwargs)
|
# an id needs to be set before we can proceed with related models
|
||||||
|
super().save(*args, **kwargs)
|
||||||
|
|
||||||
|
# create keys and shelves for new local users
|
||||||
|
self.key_pair = KeyPair.objects.create(
|
||||||
|
remote_id='%s/#main-key' % self.remote_id)
|
||||||
|
self.save(broadcast=False)
|
||||||
|
|
||||||
|
shelves = [{
|
||||||
|
'name': 'To Read',
|
||||||
|
'identifier': 'to-read',
|
||||||
|
}, {
|
||||||
|
'name': 'Currently Reading',
|
||||||
|
'identifier': 'reading',
|
||||||
|
}, {
|
||||||
|
'name': 'Read',
|
||||||
|
'identifier': 'read',
|
||||||
|
}]
|
||||||
|
|
||||||
|
for shelf in shelves:
|
||||||
|
Shelf(
|
||||||
|
name=shelf['name'],
|
||||||
|
identifier=shelf['identifier'],
|
||||||
|
user=self,
|
||||||
|
editable=False
|
||||||
|
).save(broadcast=False)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def local_path(self):
|
def local_path(self):
|
||||||
|
@ -280,42 +312,6 @@ class AnnualGoal(BookWyrmModel):
|
||||||
finish_date__year__gte=self.year).count()
|
finish_date__year__gte=self.year).count()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(models.signals.post_save, sender=User)
|
|
||||||
#pylint: disable=unused-argument
|
|
||||||
def execute_after_save(sender, instance, created, *args, **kwargs):
|
|
||||||
''' create shelves for new users '''
|
|
||||||
if not created:
|
|
||||||
return
|
|
||||||
|
|
||||||
if not instance.local:
|
|
||||||
set_remote_server.delay(instance.id)
|
|
||||||
return
|
|
||||||
|
|
||||||
instance.key_pair = KeyPair.objects.create(
|
|
||||||
remote_id='%s/#main-key' % instance.remote_id)
|
|
||||||
instance.save(broadcast=False)
|
|
||||||
|
|
||||||
shelves = [{
|
|
||||||
'name': 'To Read',
|
|
||||||
'identifier': 'to-read',
|
|
||||||
}, {
|
|
||||||
'name': 'Currently Reading',
|
|
||||||
'identifier': 'reading',
|
|
||||||
}, {
|
|
||||||
'name': 'Read',
|
|
||||||
'identifier': 'read',
|
|
||||||
}]
|
|
||||||
|
|
||||||
for shelf in shelves:
|
|
||||||
Shelf(
|
|
||||||
name=shelf['name'],
|
|
||||||
identifier=shelf['identifier'],
|
|
||||||
user=instance,
|
|
||||||
editable=False
|
|
||||||
).save(broadcast=False)
|
|
||||||
|
|
||||||
|
|
||||||
@app.task
|
@app.task
|
||||||
def set_remote_server(user_id):
|
def set_remote_server(user_id):
|
||||||
''' figure out the user's remote server in the background '''
|
''' figure out the user's remote server in the background '''
|
||||||
|
|
Loading…
Reference in a new issue