Use custom model fields in user model
This commit is contained in:
@ -1,6 +1,5 @@
|
||||
''' database schema for user data '''
|
||||
from urllib.parse import urlparse
|
||||
import requests
|
||||
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.db import models
|
||||
@ -13,40 +12,51 @@ from bookwyrm.models.status import Status, Review
|
||||
from bookwyrm.settings import DOMAIN
|
||||
from bookwyrm.signatures import create_key_pair
|
||||
from bookwyrm.tasks import app
|
||||
from .base_model import ActivityMapping, OrderedCollectionPageMixin
|
||||
from .base_model import OrderedCollectionPageMixin
|
||||
from .base_model import ActivitypubMixin, BookWyrmModel
|
||||
from .federated_server import FederatedServer
|
||||
from . import fields
|
||||
|
||||
|
||||
class User(OrderedCollectionPageMixin, AbstractUser):
|
||||
''' a user who wants to read books '''
|
||||
private_key = models.TextField(blank=True, null=True)
|
||||
public_key = models.TextField(blank=True, null=True)
|
||||
inbox = models.CharField(max_length=255, unique=True)
|
||||
shared_inbox = models.CharField(max_length=255, blank=True, null=True)
|
||||
username = fields.UsernameField()
|
||||
|
||||
key_pair = fields.OneToOneField(
|
||||
'KeyPair',
|
||||
on_delete=models.CASCADE,
|
||||
blank=True, null=True,
|
||||
related_name='owner'
|
||||
)
|
||||
inbox = fields.RemoteIdField(unique=True)
|
||||
shared_inbox = fields.RemoteIdField(
|
||||
activitypub_wrapper='endpoints', null=True)
|
||||
federated_server = models.ForeignKey(
|
||||
'FederatedServer',
|
||||
on_delete=models.PROTECT,
|
||||
null=True,
|
||||
blank=True,
|
||||
)
|
||||
outbox = models.CharField(max_length=255, unique=True)
|
||||
summary = models.TextField(blank=True, null=True)
|
||||
local = models.BooleanField(default=True)
|
||||
bookwyrm_user = models.BooleanField(default=True)
|
||||
outbox = fields.RemoteIdField(unique=True)
|
||||
summary = fields.TextField(blank=True, null=True)
|
||||
local = models.BooleanField(default=False)
|
||||
bookwyrm_user = fields.BooleanField(default=True)
|
||||
localname = models.CharField(
|
||||
max_length=255,
|
||||
null=True,
|
||||
unique=True
|
||||
)
|
||||
# name is your display name, which you can change at will
|
||||
name = models.CharField(max_length=100, blank=True, null=True)
|
||||
avatar = models.ImageField(upload_to='avatars/', blank=True, null=True)
|
||||
following = models.ManyToManyField(
|
||||
name = fields.CharField(max_length=100, blank=True, null=True)
|
||||
avatar = fields.ImageField(
|
||||
upload_to='avatars/', blank=True, null=True, activitypub_field='icon')
|
||||
followers = fields.ManyToManyField(
|
||||
'self',
|
||||
link_only=True,
|
||||
symmetrical=False,
|
||||
through='UserFollows',
|
||||
through_fields=('user_subject', 'user_object'),
|
||||
related_name='followers'
|
||||
through_fields=('user_object', 'user_subject'),
|
||||
related_name='following'
|
||||
)
|
||||
follow_requests = models.ManyToManyField(
|
||||
'self',
|
||||
@ -69,60 +79,13 @@ class User(OrderedCollectionPageMixin, AbstractUser):
|
||||
through_fields=('user', 'status'),
|
||||
related_name='favorite_statuses'
|
||||
)
|
||||
remote_id = models.CharField(max_length=255, null=True, unique=True)
|
||||
remote_id = fields.RemoteIdField(
|
||||
null=True, unique=True, activitypub_field='id')
|
||||
created_date = models.DateTimeField(auto_now_add=True)
|
||||
updated_date = models.DateTimeField(auto_now=True)
|
||||
last_active_date = models.DateTimeField(auto_now=True)
|
||||
manually_approves_followers = models.BooleanField(default=False)
|
||||
manually_approves_followers = fields.BooleanField(default=False)
|
||||
|
||||
# ---- activitypub serialization settings for this model ----- #
|
||||
@property
|
||||
def ap_followers(self):
|
||||
''' generates url for activitypub followers page '''
|
||||
return '%s/followers' % self.remote_id
|
||||
|
||||
@property
|
||||
def ap_public_key(self):
|
||||
''' format the public key block for activitypub '''
|
||||
return activitypub.PublicKey(**{
|
||||
'id': '%s/#main-key' % self.remote_id,
|
||||
'owner': self.remote_id,
|
||||
'publicKeyPem': self.public_key,
|
||||
})
|
||||
|
||||
activity_mappings = [
|
||||
ActivityMapping('id', 'remote_id'),
|
||||
ActivityMapping(
|
||||
'preferredUsername',
|
||||
'username',
|
||||
activity_formatter=lambda x: x.split('@')[0]
|
||||
),
|
||||
ActivityMapping('name', 'name'),
|
||||
ActivityMapping('bookwyrmUser', 'bookwyrm_user'),
|
||||
ActivityMapping('inbox', 'inbox'),
|
||||
ActivityMapping('outbox', 'outbox'),
|
||||
ActivityMapping('followers', 'ap_followers'),
|
||||
ActivityMapping('summary', 'summary'),
|
||||
ActivityMapping(
|
||||
'publicKey',
|
||||
'public_key',
|
||||
model_formatter=lambda x: x.get('publicKeyPem')
|
||||
),
|
||||
ActivityMapping('publicKey', 'ap_public_key'),
|
||||
ActivityMapping(
|
||||
'endpoints',
|
||||
'shared_inbox',
|
||||
activity_formatter=lambda x: {'sharedInbox': x},
|
||||
model_formatter=lambda x: x.get('sharedInbox')
|
||||
),
|
||||
ActivityMapping('icon', 'avatar'),
|
||||
ActivityMapping(
|
||||
'manuallyApprovesFollowers',
|
||||
'manually_approves_followers'
|
||||
),
|
||||
# this field isn't in the activity but should always be false
|
||||
ActivityMapping(None, 'local', model_formatter=lambda x: False),
|
||||
]
|
||||
activity_serializer = activitypub.Person
|
||||
|
||||
def to_outbox(self, **kwargs):
|
||||
@ -183,12 +146,30 @@ class User(OrderedCollectionPageMixin, AbstractUser):
|
||||
self.inbox = '%s/inbox' % self.remote_id
|
||||
self.shared_inbox = 'https://%s/inbox' % DOMAIN
|
||||
self.outbox = '%s/outbox' % self.remote_id
|
||||
if not self.private_key:
|
||||
self.private_key, self.public_key = create_key_pair()
|
||||
if not self.key_pair:
|
||||
self.key_pair = KeyPair.objects.create()
|
||||
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
|
||||
class KeyPair(ActivitypubMixin, BookWyrmModel):
|
||||
''' public and private keys for a user '''
|
||||
private_key = models.TextField(blank=True, null=True)
|
||||
public_key = fields.TextField(
|
||||
blank=True, null=True, activitypub_field='publicKeyPem')
|
||||
|
||||
activity_serializer = activitypub.PublicKey
|
||||
|
||||
def get_remote_id(self):
|
||||
# self.owner is set by the OneToOneField on User
|
||||
return '%s/#main-key' % self.owner.remote_id
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
''' create a key pair '''
|
||||
self.private_key, self.public_key = create_key_pair()
|
||||
return super().save(*args, **kwargs)
|
||||
|
||||
|
||||
@receiver(models.signals.post_save, sender=User)
|
||||
def execute_after_save(sender, instance, created, *args, **kwargs):
|
||||
''' create shelves for new users '''
|
||||
@ -217,6 +198,7 @@ def execute_after_save(sender, instance, created, *args, **kwargs):
|
||||
editable=False
|
||||
).save()
|
||||
|
||||
|
||||
@app.task
|
||||
def set_remote_server(user_id):
|
||||
''' figure out the user's remote server in the background '''
|
||||
@ -227,7 +209,6 @@ def set_remote_server(user_id):
|
||||
user.save()
|
||||
if user.bookwyrm_user:
|
||||
get_remote_reviews.delay(user.outbox)
|
||||
return
|
||||
|
||||
|
||||
def get_or_create_remote_server(domain):
|
||||
|
Reference in New Issue
Block a user