mirror of
https://github.com/bookwyrm-social/bookwyrm.git
synced 2024-11-27 03:51:08 +00:00
Unify concept of absolute_id and remote_id
This commit is contained in:
parent
93493fc8e4
commit
e76f96eb6c
33 changed files with 263 additions and 236 deletions
|
@ -24,18 +24,18 @@ def get_actor(user):
|
|||
},
|
||||
],
|
||||
|
||||
'id': user.actor,
|
||||
'id': user.remote_id,
|
||||
'type': 'Person',
|
||||
'preferredUsername': user.localname,
|
||||
'name': user.name,
|
||||
'inbox': user.inbox,
|
||||
'outbox': '%s/outbox' % user.actor,
|
||||
'followers': '%s/followers' % user.actor,
|
||||
'following': '%s/following' % user.actor,
|
||||
'outbox': '%s/outbox' % user.remote_id,
|
||||
'followers': '%s/followers' % user.remote_id,
|
||||
'following': '%s/following' % user.remote_id,
|
||||
'summary': user.summary,
|
||||
'publicKey': {
|
||||
'id': '%s/#main-key' % user.actor,
|
||||
'owner': user.actor,
|
||||
'id': '%s/#main-key' % user.remote_id,
|
||||
'owner': user.remote_id,
|
||||
'publicKeyPem': user.public_key,
|
||||
},
|
||||
'endpoints': {
|
||||
|
|
|
@ -34,9 +34,9 @@ def get_book(book, recursive=True):
|
|||
'type': 'Document',
|
||||
'book_type': book_type,
|
||||
'name': book.title,
|
||||
'url': book.absolute_id,
|
||||
'url': book.local_id,
|
||||
|
||||
'authors': [a.absolute_id for a in book.authors.all()],
|
||||
'authors': [a.local_id for a in book.authors.all()],
|
||||
'first_published_date': book.first_published_date.isoformat() if \
|
||||
book.first_published_date else None,
|
||||
'published_date': book.published_date.isoformat() if \
|
||||
|
@ -79,7 +79,7 @@ def get_author(author):
|
|||
]
|
||||
activity = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'url': author.absolute_id,
|
||||
'url': author.local_id,
|
||||
'type': 'Person',
|
||||
}
|
||||
for field in fields:
|
||||
|
@ -90,7 +90,7 @@ def get_author(author):
|
|||
|
||||
def get_shelf(shelf, page=None):
|
||||
''' serialize shelf object '''
|
||||
id_slug = shelf.absolute_id
|
||||
id_slug = shelf.remote_id
|
||||
if page:
|
||||
return get_shelf_page(shelf, page)
|
||||
count = shelf.books.count()
|
||||
|
@ -110,7 +110,7 @@ def get_shelf_page(shelf, page):
|
|||
start = (page - 1) * page_length
|
||||
end = start + page_length
|
||||
shelf_page = shelf.books.all()[start:end]
|
||||
id_slug = shelf.absolute_id
|
||||
id_slug = shelf.local_id
|
||||
data = {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': '%s?page=%d' % (id_slug, page),
|
||||
|
|
|
@ -14,16 +14,16 @@ def get_create(user, status_json):
|
|||
|
||||
'id': '%s/activity' % status_json['id'],
|
||||
'type': 'Create',
|
||||
'actor': user.actor,
|
||||
'actor': user.remote_id,
|
||||
'published': status_json['published'],
|
||||
|
||||
'to': ['%s/followers' % user.actor],
|
||||
'to': ['%s/followers' % user.remote_id],
|
||||
'cc': ['https://www.w3.org/ns/activitystreams#Public'],
|
||||
|
||||
'object': status_json,
|
||||
'signature': {
|
||||
'type': 'RsaSignature2017',
|
||||
'creator': '%s#main-key' % user.absolute_id,
|
||||
'creator': '%s#main-key' % user.remote_id,
|
||||
'created': status_json['published'],
|
||||
'signatureValue': b64encode(signed_message).decode('utf8'),
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ def get_update(user, activity_json):
|
|||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': 'https://friend.camp/users/tripofmice#updates/1585446332',
|
||||
'type': 'Update',
|
||||
'actor': user.actor,
|
||||
'actor': user.remote_id,
|
||||
'to': [
|
||||
'https://www.w3.org/ns/activitystreams#Public'
|
||||
],
|
||||
|
|
|
@ -12,22 +12,22 @@ def get_follow_request(user, to_follow):
|
|||
'id': 'https://%s/%s' % (DOMAIN, str(uuid)),
|
||||
'summary': '',
|
||||
'type': 'Follow',
|
||||
'actor': user.actor,
|
||||
'object': to_follow.actor,
|
||||
'actor': user.remote_id,
|
||||
'object': to_follow.remote_id,
|
||||
}
|
||||
|
||||
def get_unfollow(relationship):
|
||||
''' undo that precious bond of friendship '''
|
||||
return {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': '%s/undo' % relationship.absolute_id,
|
||||
'id': '%s/undo' % relationship.remote_id,
|
||||
'type': 'Undo',
|
||||
'actor': relationship.user_subject.actor,
|
||||
'actor': relationship.user_subject.remote_id,
|
||||
'object': {
|
||||
'id': relationship.relationship_id,
|
||||
'type': 'Follow',
|
||||
'actor': relationship.user_subject.actor,
|
||||
'object': relationship.user_object.actor,
|
||||
'actor': relationship.user_subject.remote_id,
|
||||
'object': relationship.user_object.remote_id,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -36,14 +36,14 @@ def get_accept(user, relationship):
|
|||
''' accept a follow request '''
|
||||
return {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': '%s#accepts/follows/' % user.absolute_id,
|
||||
'id': '%s#accepts/follows/' % user.remote_id,
|
||||
'type': 'Accept',
|
||||
'actor': user.actor,
|
||||
'actor': user.remote_id,
|
||||
'object': {
|
||||
'id': relationship.relationship_id,
|
||||
'type': 'Follow',
|
||||
'actor': relationship.user_subject.actor,
|
||||
'object': relationship.user_object.actor,
|
||||
'actor': relationship.user_subject.remote_id,
|
||||
'object': relationship.user_object.remote_id,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -52,27 +52,27 @@ def get_reject(user, relationship):
|
|||
''' reject a follow request '''
|
||||
return {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': '%s#rejects/follows/' % user.absolute_id,
|
||||
'id': '%s#rejects/follows/' % user.remote_id,
|
||||
'type': 'Reject',
|
||||
'actor': user.actor,
|
||||
'actor': user.remote_id,
|
||||
'object': {
|
||||
'id': relationship.relationship_id,
|
||||
'type': 'Follow',
|
||||
'actor': relationship.user_subject.actor,
|
||||
'object': relationship.user_object.actor,
|
||||
'actor': relationship.user_subject.remote_id,
|
||||
'object': relationship.user_object.remote_id,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def get_followers(user, page, follow_queryset):
|
||||
''' list of people who follow a user '''
|
||||
id_slug = '%s/followers' % user.actor
|
||||
id_slug = '%s/followers' % user.remote_id
|
||||
return get_follow_info(id_slug, page, follow_queryset)
|
||||
|
||||
|
||||
def get_following(user, page, follow_queryset):
|
||||
''' list of people who follow a user '''
|
||||
id_slug = '%s/following' % user.actor
|
||||
id_slug = '%s/following' % user.remote_id
|
||||
return get_follow_info(id_slug, page, follow_queryset)
|
||||
|
||||
|
||||
|
@ -103,7 +103,7 @@ def get_follow_page(user_list, id_slug, page):
|
|||
'type': 'OrderedCollectionPage',
|
||||
'totalItems': user_list.count(),
|
||||
'partOf': id_slug,
|
||||
'orderedItems': [u.actor for u in follower_page],
|
||||
'orderedItems': [u.remote_id for u in follower_page],
|
||||
}
|
||||
if end <= user_list.count():
|
||||
# there are still more pages
|
||||
|
|
|
@ -18,16 +18,15 @@ def get_add_remove(user, book, shelf, action='Add'):
|
|||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': str(uuid),
|
||||
'type': action,
|
||||
'actor': user.actor,
|
||||
'actor': user.remote_id,
|
||||
'object': {
|
||||
# TODO: document??
|
||||
'type': 'Document',
|
||||
'name': book.title,
|
||||
'url': book.absolute_id,
|
||||
'url': book.local_id,
|
||||
},
|
||||
'target': {
|
||||
'type': 'Collection',
|
||||
'name': shelf.name,
|
||||
'id': shelf.absolute_id,
|
||||
'id': shelf.remote_id,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ from fedireads.settings import DOMAIN
|
|||
def get_rating(review):
|
||||
''' activitypub serialize rating activity '''
|
||||
status = get_status(review)
|
||||
status['inReplyToBook'] = review.book.absolute_id
|
||||
status['inReplyToBook'] = review.book.local_id
|
||||
status['fedireadsType'] = review.status_type
|
||||
status['rating'] = review.rating
|
||||
status['content'] = '%d star rating of "%s"' % (
|
||||
|
@ -18,7 +18,7 @@ def get_rating(review):
|
|||
def get_quotation(quotation):
|
||||
''' fedireads json for quotations '''
|
||||
status = get_status(quotation)
|
||||
status['inReplyToBook'] = quotation.book.absolute_id
|
||||
status['inReplyToBook'] = quotation.book.local_id
|
||||
status['fedireadsType'] = quotation.status_type
|
||||
status['quote'] = quotation.quote
|
||||
return status
|
||||
|
@ -29,7 +29,7 @@ def get_quotation_article(quotation):
|
|||
status = get_status(quotation)
|
||||
content = '"%s"<br>-- <a href="%s">"%s"</a>)<br><br>%s' % (
|
||||
quotation.quote,
|
||||
quotation.book.absolute_id,
|
||||
quotation.book.local_id,
|
||||
quotation.book.title,
|
||||
quotation.content,
|
||||
)
|
||||
|
@ -40,7 +40,7 @@ def get_quotation_article(quotation):
|
|||
def get_review(review):
|
||||
''' fedireads json for book reviews '''
|
||||
status = get_status(review)
|
||||
status['inReplyToBook'] = review.book.absolute_id
|
||||
status['inReplyToBook'] = review.book.local_id
|
||||
status['fedireadsType'] = review.status_type
|
||||
status['name'] = review.name
|
||||
status['rating'] = review.rating
|
||||
|
@ -50,7 +50,7 @@ def get_review(review):
|
|||
def get_comment(comment):
|
||||
''' fedireads json for book reviews '''
|
||||
status = get_status(comment)
|
||||
status['inReplyToBook'] = comment.book.absolute_id
|
||||
status['inReplyToBook'] = comment.book.local_id
|
||||
status['fedireadsType'] = comment.status_type
|
||||
return status
|
||||
|
||||
|
@ -87,15 +87,15 @@ def get_comment_article(comment):
|
|||
''' a book comment formatted for a non-fedireads isntance (mastodon) '''
|
||||
status = get_status(comment)
|
||||
status['content'] += '<br><br>(comment on <a href="%s">"%s"</a>)' % \
|
||||
(comment.book.absolute_id, comment.book.title)
|
||||
(comment.book.local_id, comment.book.title)
|
||||
return status
|
||||
|
||||
|
||||
def get_status(status):
|
||||
''' create activitypub json for a status '''
|
||||
user = status.user
|
||||
uri = status.absolute_id
|
||||
reply_parent_id = status.reply_parent.absolute_id \
|
||||
uri = status.remote_id
|
||||
reply_parent_id = status.reply_parent.remote_id \
|
||||
if status.reply_parent else None
|
||||
|
||||
image_attachments = []
|
||||
|
@ -117,10 +117,10 @@ def get_status(status):
|
|||
'url': uri,
|
||||
'inReplyTo': reply_parent_id,
|
||||
'published': status.published_date.isoformat(),
|
||||
'attributedTo': user.actor,
|
||||
'attributedTo': user.remote_id,
|
||||
# TODO: assuming all posts are public -- should check privacy db field
|
||||
'to': ['https://www.w3.org/ns/activitystreams#Public'],
|
||||
'cc': ['%s/followers' % user.absolute_id],
|
||||
'cc': ['%s/followers' % user.remote_id],
|
||||
'sensitive': status.sensitive,
|
||||
'content': status.content,
|
||||
'type': status.activity_type,
|
||||
|
@ -142,7 +142,7 @@ def get_status(status):
|
|||
|
||||
def get_replies(status, replies):
|
||||
''' collection of replies '''
|
||||
id_slug = status.absolute_id + '/replies'
|
||||
id_slug = status.remote_id + '/replies'
|
||||
return {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': id_slug,
|
||||
|
@ -159,7 +159,7 @@ def get_replies(status, replies):
|
|||
|
||||
def get_replies_page(status, replies):
|
||||
''' actual reply list content '''
|
||||
id_slug = status.absolute_id + '/replies?page=true&only_other_accounts=true'
|
||||
id_slug = status.remote_id + '/replies?page=true&only_other_accounts=true'
|
||||
items = []
|
||||
for reply in replies:
|
||||
if reply.user.local:
|
||||
|
@ -171,7 +171,7 @@ def get_replies_page(status, replies):
|
|||
'id': id_slug,
|
||||
'type': 'CollectionPage',
|
||||
'next': '%s&min_id=%d' % (id_slug, replies[len(replies) - 1].id),
|
||||
'partOf': status.absolute_id + '/replies',
|
||||
'partOf': status.remote_id + '/replies',
|
||||
'items': [items]
|
||||
}
|
||||
|
||||
|
@ -180,10 +180,10 @@ def get_favorite(favorite):
|
|||
''' like a post '''
|
||||
return {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': favorite.absolute_id,
|
||||
'id': favorite.remote_id,
|
||||
'type': 'Like',
|
||||
'actor': favorite.user.actor,
|
||||
'object': favorite.status.absolute_id,
|
||||
'actor': favorite.user.remote_id,
|
||||
'object': favorite.status.remote_id,
|
||||
}
|
||||
|
||||
|
||||
|
@ -191,14 +191,14 @@ def get_unfavorite(favorite):
|
|||
''' like a post '''
|
||||
return {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': '%s/undo' % favorite.absolute_id,
|
||||
'id': '%s/undo' % favorite.remote_id,
|
||||
'type': 'Undo',
|
||||
'actor': favorite.user.actor,
|
||||
'actor': favorite.user.remote_id,
|
||||
'object': {
|
||||
'id': favorite.absolute_id,
|
||||
'id': favorite.remote_id,
|
||||
'type': 'Like',
|
||||
'actor': favorite.user.actor,
|
||||
'object': favorite.status.absolute_id,
|
||||
'actor': favorite.user.remote_id,
|
||||
'object': favorite.status.remote_id,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -207,10 +207,10 @@ def get_boost(boost):
|
|||
''' boost/announce a post '''
|
||||
return {
|
||||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': boost.absolute_id,
|
||||
'id': boost.remote_id,
|
||||
'type': 'Announce',
|
||||
'actor': boost.user.actor,
|
||||
'object': boost.boosted_status.absolute_id,
|
||||
'actor': boost.user.remote_id,
|
||||
'object': boost.boosted_status.remote_id,
|
||||
}
|
||||
|
||||
|
||||
|
@ -221,15 +221,15 @@ def get_add_tag(tag):
|
|||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': str(uuid),
|
||||
'type': 'Add',
|
||||
'actor': tag.user.actor,
|
||||
'actor': tag.user.remote_id,
|
||||
'object': {
|
||||
'type': 'Tag',
|
||||
'id': tag.absolute_id,
|
||||
'id': tag.remote_id,
|
||||
'name': tag.name,
|
||||
},
|
||||
'target': {
|
||||
'type': 'Book',
|
||||
'id': tag.book.absolute_id,
|
||||
'id': tag.book.local_id,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -241,14 +241,14 @@ def get_remove_tag(tag):
|
|||
'@context': 'https://www.w3.org/ns/activitystreams',
|
||||
'id': str(uuid),
|
||||
'type': 'Remove',
|
||||
'actor': tag.user.actor,
|
||||
'actor': tag.user.remote_id,
|
||||
'object': {
|
||||
'type': 'Tag',
|
||||
'id': tag.absolute_id,
|
||||
'id': tag.remote_id,
|
||||
'name': tag.name,
|
||||
},
|
||||
'target': {
|
||||
'type': 'Book',
|
||||
'id': tag.book.absolute_id,
|
||||
'id': tag.book.local_id,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ from requests import HTTPError
|
|||
import importlib
|
||||
from urllib.parse import urlparse
|
||||
|
||||
from fedireads import models, settings
|
||||
from fedireads import models
|
||||
from fedireads.tasks import app
|
||||
|
||||
|
||||
|
@ -18,7 +18,9 @@ def get_edition(book_id):
|
|||
|
||||
def get_or_create_book(remote_id):
|
||||
''' pull up a book record by whatever means possible '''
|
||||
book = get_by_absolute_id(remote_id, models.Book)
|
||||
book = models.Book.objects.select_subclasses().filter(
|
||||
remote_id=remote_id
|
||||
).first()
|
||||
if book:
|
||||
return book
|
||||
|
||||
|
@ -52,38 +54,6 @@ def get_or_create_connector(remote_id):
|
|||
return load_connector(connector_info)
|
||||
|
||||
|
||||
def get_by_absolute_id(absolute_id, model):
|
||||
''' generalized function to get from a model with a remote_id field '''
|
||||
if not absolute_id:
|
||||
return None
|
||||
|
||||
# check if it's a remote status
|
||||
try:
|
||||
return model.objects.get(remote_id=absolute_id)
|
||||
except model.DoesNotExist:
|
||||
pass
|
||||
|
||||
url = urlparse(absolute_id)
|
||||
if url.netloc != settings.DOMAIN:
|
||||
return None
|
||||
|
||||
# try finding a local status with that id
|
||||
local_id = absolute_id.split('/')[-1]
|
||||
try:
|
||||
if hasattr(model.objects, 'select_subclasses'):
|
||||
possible_match = model.objects.select_subclasses().get(id=local_id)
|
||||
else:
|
||||
possible_match = model.objects.get(id=local_id)
|
||||
except model.DoesNotExist:
|
||||
return None
|
||||
|
||||
# make sure it's not actually a remote status with an id that
|
||||
# clashes with a local id
|
||||
if possible_match.absolute_id == absolute_id:
|
||||
return possible_match
|
||||
return None
|
||||
|
||||
|
||||
@app.task
|
||||
def load_more_data(book_id):
|
||||
''' background the work of getting all 10,000 editions of LoTR '''
|
||||
|
|
|
@ -74,7 +74,7 @@ def make_signature(sender, destination, date):
|
|||
signer = pkcs1_15.new(RSA.import_key(sender.private_key))
|
||||
signed_message = signer.sign(SHA256.new(message_to_sign.encode('utf8')))
|
||||
signature = {
|
||||
'keyId': '%s#main-key' % sender.actor,
|
||||
'keyId': '%s#main-key' % sender.remote_id,
|
||||
'algorithm': 'rsa-sha256',
|
||||
'headers': '(request-target) host date',
|
||||
'signature': b64encode(signed_message).decode('utf8'),
|
||||
|
|
|
@ -124,7 +124,7 @@ class Connector(AbstractConnector):
|
|||
|
||||
|
||||
def format_search_result(self, doc):
|
||||
# build the absolute id from the openlibrary key
|
||||
# build the remote id from the openlibrary key
|
||||
key = self.books_url + doc['key']
|
||||
author = doc.get('author_name') or ['Unknown']
|
||||
return SearchResult(
|
||||
|
|
|
@ -41,7 +41,7 @@ class Connector(AbstractConnector):
|
|||
def format_search_result(self, book):
|
||||
return SearchResult(
|
||||
book.title,
|
||||
book.absolute_id,
|
||||
book.local_id,
|
||||
book.author_text,
|
||||
book.published_date.year if book.published_date else None,
|
||||
)
|
||||
|
|
|
@ -295,7 +295,7 @@ def handle_favorite(activity):
|
|||
def handle_unfavorite(activity):
|
||||
''' approval of your good good post '''
|
||||
favorite_id = activity['object']['id']
|
||||
fav = status_builder.get_favorite(favorite_id)
|
||||
fav = models.Favorite.objects.filter(remote_id=favorite_id).first()
|
||||
if not fav:
|
||||
return False
|
||||
|
||||
|
|
77
fedireads/migrations/0040_auto_20200513_0153.py
Normal file
77
fedireads/migrations/0040_auto_20200513_0153.py
Normal file
|
@ -0,0 +1,77 @@
|
|||
# Generated by Django 3.0.3 on 2020-05-13 01:53
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('fedireads', '0039_auto_20200510_2342'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='user',
|
||||
name='actor',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='connector',
|
||||
name='remote_id',
|
||||
field=models.CharField(max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='federatedserver',
|
||||
name='remote_id',
|
||||
field=models.CharField(max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='notification',
|
||||
name='remote_id',
|
||||
field=models.CharField(max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='readthrough',
|
||||
name='remote_id',
|
||||
field=models.CharField(max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='shelf',
|
||||
name='remote_id',
|
||||
field=models.CharField(max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='shelfbook',
|
||||
name='remote_id',
|
||||
field=models.CharField(max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='tag',
|
||||
name='remote_id',
|
||||
field=models.CharField(max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='userblocks',
|
||||
name='remote_id',
|
||||
field=models.CharField(max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='userfollowrequest',
|
||||
name='remote_id',
|
||||
field=models.CharField(max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='userfollows',
|
||||
name='remote_id',
|
||||
field=models.CharField(max_length=255, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='favorite',
|
||||
name='remote_id',
|
||||
field=models.CharField(max_length=255, null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='status',
|
||||
name='remote_id',
|
||||
field=models.CharField(max_length=255, null=True),
|
||||
),
|
||||
]
|
18
fedireads/migrations/0041_user_remote_id.py
Normal file
18
fedireads/migrations/0041_user_remote_id.py
Normal file
|
@ -0,0 +1,18 @@
|
|||
# Generated by Django 3.0.3 on 2020-05-13 02:23
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('fedireads', '0040_auto_20200513_0153'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='user',
|
||||
name='remote_id',
|
||||
field=models.CharField(max_length=255, null=True, unique=True),
|
||||
),
|
||||
]
|
|
@ -1,5 +1,6 @@
|
|||
''' base model with default fields '''
|
||||
from django.db import models
|
||||
from django.dispatch import receiver
|
||||
|
||||
from fedireads.settings import DOMAIN
|
||||
|
||||
|
@ -7,18 +8,24 @@ class FedireadsModel(models.Model):
|
|||
''' fields and functions for every model '''
|
||||
created_date = models.DateTimeField(auto_now_add=True)
|
||||
updated_date = models.DateTimeField(auto_now=True)
|
||||
remote_id = models.CharField(max_length=255, null=True)
|
||||
|
||||
@property
|
||||
def absolute_id(self):
|
||||
''' constructs the absolute reference to any db object '''
|
||||
if hasattr(self, 'remote_id') and self.remote_id:
|
||||
return self.remote_id
|
||||
|
||||
def get_remote_id(self):
|
||||
''' generate a url that resolves to the local object '''
|
||||
base_path = 'https://%s' % DOMAIN
|
||||
if hasattr(self, 'user'):
|
||||
base_path = self.user.absolute_id
|
||||
base_path = self.user.remote_id
|
||||
model_name = type(self).__name__.lower()
|
||||
return '%s/%s/%d' % (base_path, model_name, self.id)
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
||||
|
||||
@receiver(models.signals.post_save, sender=FedireadsModel)
|
||||
def execute_after_save(sender, instance, created, *args, **kwargs):
|
||||
''' set the remote_id after save (when the id is available) '''
|
||||
if not created:
|
||||
return
|
||||
instance.remote_id = instance.get_remote_id()
|
||||
instance.save()
|
||||
|
|
|
@ -5,7 +5,7 @@ from model_utils.managers import InheritanceManager
|
|||
|
||||
from fedireads import activitypub
|
||||
from fedireads.settings import DOMAIN
|
||||
from fedireads.utils.fields import JSONField, ArrayField
|
||||
from fedireads.utils.fields import ArrayField
|
||||
from .base_model import FedireadsModel
|
||||
|
||||
from fedireads.connectors.settings import CONNECTORS
|
||||
|
@ -47,7 +47,6 @@ class Connector(FedireadsModel):
|
|||
|
||||
class Book(FedireadsModel):
|
||||
''' a generic book, which can mean either an edition or a work '''
|
||||
remote_id = models.CharField(max_length=255, null=True)
|
||||
# these identifiers apply to both works and editions
|
||||
openlibrary_key = models.CharField(max_length=255, blank=True, null=True)
|
||||
librarything_key = models.CharField(max_length=255, blank=True, null=True)
|
||||
|
@ -87,20 +86,27 @@ class Book(FedireadsModel):
|
|||
published_date = models.DateTimeField(blank=True, null=True)
|
||||
objects = InheritanceManager()
|
||||
|
||||
@property
|
||||
def absolute_id(self):
|
||||
''' constructs the absolute reference to any db object '''
|
||||
if self.sync and self.remote_id:
|
||||
return self.remote_id
|
||||
base_path = 'https://%s' % DOMAIN
|
||||
return '%s/book/%d' % (base_path, self.id)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
''' can't be abstract for query reasons, but you shouldn't USE it '''
|
||||
if not isinstance(self, Edition) and not isinstance(self, Work):
|
||||
raise ValueError('Books should be added as Editions or Works')
|
||||
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
def get_remote_id(self):
|
||||
''' editions and works both use "book" instead of model_name '''
|
||||
return 'https://%s/book/%d' % (DOMAIN, self.id)
|
||||
|
||||
|
||||
@property
|
||||
def local_id(self):
|
||||
''' when a book is ingested from an outside source, it becomes local to
|
||||
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 '''
|
||||
return 'https://%s/book/%d' % (DOMAIN, self.id)
|
||||
|
||||
|
||||
def __repr__(self):
|
||||
return "<{} key={!r} title={!r}>".format(
|
||||
self.__class__,
|
||||
|
@ -152,7 +158,6 @@ class Edition(Book):
|
|||
|
||||
class Author(FedireadsModel):
|
||||
''' copy of an author from OL '''
|
||||
remote_id = models.CharField(max_length=255, null=True)
|
||||
openlibrary_key = models.CharField(max_length=255, blank=True, null=True)
|
||||
sync = models.BooleanField(default=True)
|
||||
last_sync_date = models.DateTimeField(default=timezone.now)
|
||||
|
@ -168,6 +173,14 @@ class Author(FedireadsModel):
|
|||
)
|
||||
bio = models.TextField(null=True, blank=True)
|
||||
|
||||
@property
|
||||
def local_id(self):
|
||||
''' when a book is ingested from an outside source, it becomes local to
|
||||
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)
|
||||
|
||||
@property
|
||||
def activitypub_serialize(self):
|
||||
return activitypub.get_author(self)
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
''' puttin' books on shelves '''
|
||||
from django.db import models
|
||||
|
||||
from fedireads import activitypub
|
||||
from .base_model import FedireadsModel
|
||||
|
||||
|
||||
|
@ -17,12 +16,10 @@ class Shelf(FedireadsModel):
|
|||
through_fields=('shelf', 'book')
|
||||
)
|
||||
|
||||
@property
|
||||
def absolute_id(self):
|
||||
''' use shelf identifier as absolute id '''
|
||||
base_path = self.user.absolute_id
|
||||
model_name = type(self).__name__.lower()
|
||||
return '%s/%s/%s' % (base_path, model_name, self.identifier)
|
||||
def get_remote_id(self):
|
||||
''' shelf identifier instead of id '''
|
||||
base_path = self.user.remote_id
|
||||
return '%s/shelf/%s' % (base_path, self.identifier)
|
||||
|
||||
class Meta:
|
||||
unique_together = ('user', 'identifier')
|
||||
|
|
|
@ -12,7 +12,6 @@ from .base_model import FedireadsModel
|
|||
|
||||
class Status(FedireadsModel):
|
||||
''' any post, like a reply to a review, etc '''
|
||||
remote_id = models.CharField(max_length=255, unique=True, null=True)
|
||||
user = models.ForeignKey('User', on_delete=models.PROTECT)
|
||||
status_type = models.CharField(max_length=255, default='Note')
|
||||
content = models.TextField(blank=True, null=True)
|
||||
|
@ -39,16 +38,6 @@ class Status(FedireadsModel):
|
|||
)
|
||||
objects = InheritanceManager()
|
||||
|
||||
@property
|
||||
def absolute_id(self):
|
||||
''' constructs the absolute reference to any db object '''
|
||||
if self.remote_id:
|
||||
return self.remote_id
|
||||
base_path = self.user.absolute_id
|
||||
model_name = type(self).__name__.lower()
|
||||
return '%s/%s/%d' % (base_path, model_name, self.id)
|
||||
|
||||
|
||||
@property
|
||||
def activitypub_serialize(self):
|
||||
return activitypub.get_status(self)
|
||||
|
@ -111,7 +100,6 @@ class Favorite(FedireadsModel):
|
|||
''' fav'ing a post '''
|
||||
user = models.ForeignKey('User', on_delete=models.PROTECT)
|
||||
status = models.ForeignKey('Status', on_delete=models.PROTECT)
|
||||
remote_id = models.CharField(max_length=255, unique=True, null=True)
|
||||
|
||||
class Meta:
|
||||
unique_together = ('user', 'status')
|
||||
|
|
|
@ -15,7 +15,6 @@ class User(AbstractUser):
|
|||
''' a user who wants to read books '''
|
||||
private_key = models.TextField(blank=True, null=True)
|
||||
public_key = models.TextField(blank=True, null=True)
|
||||
actor = models.CharField(max_length=255, unique=True)
|
||||
inbox = models.CharField(max_length=255, unique=True)
|
||||
shared_inbox = models.CharField(max_length=255, blank=True, null=True)
|
||||
federated_server = models.ForeignKey(
|
||||
|
@ -63,17 +62,11 @@ class User(AbstractUser):
|
|||
through_fields=('user', 'status'),
|
||||
related_name='favorite_statuses'
|
||||
)
|
||||
remote_id = models.CharField(max_length=255, null=True, unique=True)
|
||||
created_date = models.DateTimeField(auto_now_add=True)
|
||||
updated_date = models.DateTimeField(auto_now=True)
|
||||
manually_approves_followers = models.BooleanField(default=False)
|
||||
|
||||
@property
|
||||
def absolute_id(self):
|
||||
''' users are identified by their username, so overriding this prop '''
|
||||
model_name = type(self).__name__.lower()
|
||||
username = self.localname or self.username
|
||||
return 'https://%s/%s/%s' % (DOMAIN, model_name, username)
|
||||
|
||||
@property
|
||||
def activitypub_serialize(self):
|
||||
return activitypub.get_actor(self)
|
||||
|
@ -107,10 +100,9 @@ class UserRelationship(FedireadsModel):
|
|||
)
|
||||
]
|
||||
|
||||
@property
|
||||
def absolute_id(self):
|
||||
''' use shelf identifier as absolute id '''
|
||||
base_path = self.user_subject.absolute_id
|
||||
def get_remote_id(self):
|
||||
''' use shelf identifier in remote_id '''
|
||||
base_path = self.user_subject.remote_id
|
||||
return '%s#%s/%d' % (base_path, self.status, self.id)
|
||||
|
||||
|
||||
|
@ -158,12 +150,13 @@ def execute_before_save(sender, instance, *args, **kwargs):
|
|||
return
|
||||
|
||||
# populate fields for local users
|
||||
instance.remote_id = 'https://%s/user/%s' % (DOMAIN, instance.username)
|
||||
instance.localname = instance.username
|
||||
instance.username = '%s@%s' % (instance.username, DOMAIN)
|
||||
instance.actor = instance.absolute_id
|
||||
instance.inbox = '%s/inbox' % instance.absolute_id
|
||||
instance.actor = instance.remote_id
|
||||
instance.inbox = '%s/inbox' % instance.remote_id
|
||||
instance.shared_inbox = 'https://%s/inbox' % DOMAIN
|
||||
instance.outbox = '%s/outbox' % instance.absolute_id
|
||||
instance.outbox = '%s/outbox' % instance.remote_id
|
||||
if not instance.private_key:
|
||||
random_generator = Random.new().read
|
||||
key = RSA.generate(1024, random_generator)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
from django.db import IntegrityError
|
||||
|
||||
from fedireads import models
|
||||
from fedireads.books_manager import get_or_create_book, get_by_absolute_id
|
||||
from fedireads.books_manager import get_or_create_book
|
||||
from fedireads.sanitize_html import InputHtmlParser
|
||||
|
||||
|
||||
|
@ -155,14 +155,11 @@ def create_boost_from_activity(user, activity):
|
|||
return models.Boost.objects.get(status=status, user=user)
|
||||
|
||||
|
||||
def get_status(absolute_id):
|
||||
def get_status(remote_id):
|
||||
''' find a status in the database '''
|
||||
return get_by_absolute_id(absolute_id, models.Status)
|
||||
|
||||
|
||||
def get_favorite(absolute_id):
|
||||
''' find a status in the database '''
|
||||
return get_by_absolute_id(absolute_id, models.Favorite)
|
||||
return models.Status.objects.select_subclasses().filter(
|
||||
remote_id=remote_id
|
||||
).first()
|
||||
|
||||
|
||||
def create_status(user, content, reply_parent=None, mention_books=None,
|
||||
|
|
|
@ -18,12 +18,12 @@
|
|||
{% include 'snippets/username.html' with user=notification.related_user %}
|
||||
{% if notification.notification_type == 'FAVORITE' %}
|
||||
favorited your
|
||||
<a href="{{ notification.related_status.absolute_id}}">status</a>
|
||||
<a href="{{ notification.related_status.remote_id}}">status</a>
|
||||
|
||||
{% elif notification.notification_type == 'REPLY' %}
|
||||
<a href="{{ notification.related_status.absolute_id}}">replied</a>
|
||||
<a href="{{ notification.related_status.remote_id}}">replied</a>
|
||||
to your
|
||||
<a href="{{ notification.related_status.reply_parent.absolute_id}}">status</a>
|
||||
<a href="{{ notification.related_status.reply_parent.remote_id}}">status</a>
|
||||
|
||||
{% elif notification.notification_type == 'FOLLOW' %}
|
||||
followed you
|
||||
|
@ -35,10 +35,10 @@
|
|||
</div>
|
||||
|
||||
{% elif notification.notification_type == 'BOOST' %}
|
||||
boosted your <a href="{{ notification.related_status.absolute_id}}">status</a>
|
||||
boosted your <a href="{{ notification.related_status.remote_id}}">status</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
your <a href="/import_status/{{ notification.related_import.id }}">import</a> completed.
|
||||
your <a href="/import_status/{{ notification.related_import.id }}">import</a> completed.
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
|
@ -60,7 +60,7 @@
|
|||
{% include 'snippets/status_content.html' with status=status|boosted_status %}
|
||||
{% endif %}
|
||||
|
||||
{% if not max_depth and status.reply_parent or status|replies %}<p><a href="{{ status.absolute_id }}">Thread</a>{% endif %}
|
||||
{% if not max_depth and status.reply_parent or status|replies %}<p><a href="{{ status.remote_id }}">Thread</a>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -17,9 +17,9 @@
|
|||
boosted
|
||||
{% elif status.reply_parent %}
|
||||
{% with parent_status=status|parent %}
|
||||
replied to {% include 'snippets/username.html' with user=parent_status.user possessive=True %} <a href="{{parent_status.absolute_id }}">{{ parent_status.status_type | lower }}</a>
|
||||
replied to {% include 'snippets/username.html' with user=parent_status.user possessive=True %} <a href="{{parent_status.remote_id }}">{{ parent_status.status_type | lower }}</a>
|
||||
{% endwith %}
|
||||
{% endif %}
|
||||
<span class="time-ago">
|
||||
<a href="{{ status.absolute_id }}">{{ status.published_date | naturaltime }}</a>
|
||||
<a href="{{ status.remote_id }}">{{ status.published_date | naturaltime }}</a>
|
||||
</span>
|
||||
|
|
|
@ -7,25 +7,19 @@ from fedireads.settings import DOMAIN
|
|||
|
||||
|
||||
class BaseModel(TestCase):
|
||||
def test_absolute_id(self):
|
||||
def test_remote_id(self):
|
||||
instance = FedireadsModel()
|
||||
instance.id = 1
|
||||
expected = instance.absolute_id
|
||||
expected = instance.get_remote_id()
|
||||
self.assertEqual(expected, 'https://%s/fedireadsmodel/1' % DOMAIN)
|
||||
|
||||
def test_absolute_id_with_remote(self):
|
||||
instance = FedireadsModel()
|
||||
instance.remote_id = 'boop doop'
|
||||
expected = instance.absolute_id
|
||||
self.assertEqual(expected, 'boop doop')
|
||||
|
||||
def test_absolute_id_with_user(self):
|
||||
def test_remote_id_with_user(self):
|
||||
user = models.User.objects.create_user(
|
||||
'mouse', 'mouse@mouse.com', 'mouseword')
|
||||
instance = FedireadsModel()
|
||||
instance.user = user
|
||||
instance.id = 1
|
||||
expected = instance.absolute_id
|
||||
expected = instance.get_remote_id()
|
||||
self.assertEqual(
|
||||
expected,
|
||||
'https://%s/user/mouse/fedireadsmodel/1' % DOMAIN)
|
||||
|
|
|
@ -7,14 +7,18 @@ from fedireads import models, settings
|
|||
class Book(TestCase):
|
||||
''' not too much going on in the books model but here we are '''
|
||||
def setUp(self):
|
||||
work = models.Work.objects.create(title='Example Work')
|
||||
models.Edition.objects.create(title='Example Edition', parent_work=work)
|
||||
self.work = models.Work.objects.create(title='Example Work')
|
||||
models.Edition.objects.create(title='Example Edition', parent_work=self.work)
|
||||
|
||||
def test_absolute_id(self):
|
||||
''' editions and works use the same absolute id syntax '''
|
||||
book = models.Edition.objects.first()
|
||||
expected_id = 'https://%s/book/%d' % (settings.DOMAIN, book.id)
|
||||
self.assertEqual(book.absolute_id, expected_id)
|
||||
def test_remote_id(self):
|
||||
''' editions and works use the same remote_id syntax '''
|
||||
expected_id = 'https://%s/book/%d' % (settings.DOMAIN, self.work.id)
|
||||
self.assertEqual(self.work.get_remote_id(), expected_id)
|
||||
|
||||
def test_local_id(self):
|
||||
''' the local_id property for books '''
|
||||
expected_id = 'https://%s/book/%d' % (settings.DOMAIN, self.work.id)
|
||||
self.assertEqual(self.work.local_id, expected_id)
|
||||
|
||||
def test_create_book(self):
|
||||
''' you shouldn't be able to create Books (only editions and works) '''
|
||||
|
@ -37,8 +41,8 @@ class Shelf(TestCase):
|
|||
models.Shelf.objects.create(
|
||||
name='Test Shelf', identifier='test-shelf', user=user)
|
||||
|
||||
def test_absolute_id(self):
|
||||
def test_remote_id(self):
|
||||
''' editions and works use the same absolute id syntax '''
|
||||
shelf = models.Shelf.objects.get(identifier='test-shelf')
|
||||
expected_id = 'https://%s/user/mouse/shelf/test-shelf' % settings.DOMAIN
|
||||
self.assertEqual(shelf.absolute_id, expected_id)
|
||||
self.assertEqual(shelf.get_remote_id(), expected_id)
|
||||
|
|
|
@ -35,33 +35,3 @@ class Book(TestCase):
|
|||
|
||||
same_connector = books_manager.get_or_create_connector(remote_id)
|
||||
self.assertEqual(connector.identifier, same_connector.identifier)
|
||||
|
||||
|
||||
def test_get_by_absolute_id_local(self):
|
||||
abs_id = 'https://%s/book/%d' % (DOMAIN, self.work.id)
|
||||
work = books_manager.get_by_absolute_id(abs_id, models.Work)
|
||||
self.assertEqual(work, self.work)
|
||||
|
||||
work = books_manager.get_by_absolute_id(abs_id, models.Edition)
|
||||
self.assertIsNone(work)
|
||||
|
||||
|
||||
def test_get_by_absolute_id_remote(self):
|
||||
remote_work = models.Work.objects.create(
|
||||
title='Example Work',
|
||||
remote_id='https://example.com/book/123',
|
||||
)
|
||||
|
||||
abs_id = 'https://example.com/book/123'
|
||||
work = books_manager.get_by_absolute_id(abs_id, models.Work)
|
||||
self.assertEqual(work, remote_work)
|
||||
|
||||
|
||||
def test_get_by_absolute_id_invalid(self):
|
||||
abs_id = 'https://%s/book/34534623' % DOMAIN
|
||||
result = books_manager.get_by_absolute_id(abs_id, models.Work)
|
||||
self.assertIsNone(result)
|
||||
|
||||
abs_id = 'httook534623'
|
||||
result = books_manager.get_by_absolute_id(abs_id, models.Work)
|
||||
self.assertIsNone(result)
|
||||
|
|
|
@ -11,7 +11,7 @@ class Book(TestCase):
|
|||
|
||||
follower = models.User.objects.create_user(
|
||||
'rat', 'rat@mouse.mouse', 'ratword', local=False,
|
||||
actor='http://example.com/u/1',
|
||||
remote_id='http://example.com/u/1',
|
||||
outbox='http://example.com/u/1/o',
|
||||
shared_inbox='http://example.com/inbox',
|
||||
inbox='http://example.com/u/1/inbox')
|
||||
|
@ -20,14 +20,14 @@ class Book(TestCase):
|
|||
no_inbox_follower = models.User.objects.create_user(
|
||||
'hamster', 'hamster@mouse.mouse', 'hamword',
|
||||
shared_inbox=None, local=False,
|
||||
actor='http://example.com/u/2',
|
||||
remote_id='http://example.com/u/2',
|
||||
outbox='http://example.com/u/2/o',
|
||||
inbox='http://example.com/u/2/inbox')
|
||||
self.user.followers.add(no_inbox_follower)
|
||||
|
||||
non_fr_follower = models.User.objects.create_user(
|
||||
'gerbil', 'gerb@mouse.mouse', 'gerbword',
|
||||
actor='http://example.com/u/3',
|
||||
remote_id='http://example.com/u/3',
|
||||
outbox='http://example2.com/u/3/o',
|
||||
inbox='http://example2.com/u/3/inbox',
|
||||
shared_inbox='http://example2.com/inbox',
|
||||
|
@ -40,7 +40,7 @@ class Book(TestCase):
|
|||
|
||||
models.User.objects.create_user(
|
||||
'nutria', 'nutria@mouse.mouse', 'nuword',
|
||||
actor='http://example.com/u/4',
|
||||
remote_id='http://example.com/u/4',
|
||||
outbox='http://example.com/u/4/o',
|
||||
shared_inbox='http://example.com/inbox',
|
||||
inbox='http://example.com/u/4/inbox',
|
||||
|
|
|
@ -45,7 +45,7 @@ class Comment(TestCase):
|
|||
"items": []
|
||||
}
|
||||
},
|
||||
"inReplyToBook": self.book.absolute_id,
|
||||
"inReplyToBook": self.book.remote_id,
|
||||
"fedireadsType": "Comment"
|
||||
}
|
||||
comment = status_builder.create_comment_from_activity(
|
||||
|
|
|
@ -53,7 +53,7 @@ class Quotation(TestCase):
|
|||
'items': []
|
||||
}
|
||||
},
|
||||
'inReplyToBook': self.book.absolute_id,
|
||||
'inReplyToBook': self.book.remote_id,
|
||||
'fedireadsType': 'Quotation',
|
||||
'quote': 'quote body'
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ class Review(TestCase):
|
|||
'items': []
|
||||
}
|
||||
},
|
||||
'inReplyToBook': self.book.absolute_id,
|
||||
'inReplyToBook': self.book.remote_id,
|
||||
'fedireadsType': 'Review',
|
||||
'name': 'review title',
|
||||
'rating': 3
|
||||
|
|
|
@ -22,6 +22,7 @@ class Status(TestCase):
|
|||
self.assertEqual(reply.content, content)
|
||||
self.assertEqual(reply.reply_parent, status)
|
||||
|
||||
|
||||
def test_create_status_from_activity(self):
|
||||
book = models.Edition.objects.create(title='Example Edition')
|
||||
review = status_builder.create_review(
|
||||
|
@ -29,7 +30,7 @@ class Status(TestCase):
|
|||
activity = {
|
||||
'id': 'https://example.com/user/mouse/status/12',
|
||||
'url': 'https://example.com/user/mouse/status/12',
|
||||
'inReplyTo': review.absolute_id,
|
||||
'inReplyTo': review.remote_id,
|
||||
'published': '2020-05-10T02:15:59.635557+00:00',
|
||||
'attributedTo': 'https://example.com/user/mouse',
|
||||
'to': [
|
||||
|
|
|
@ -23,7 +23,7 @@ class Status(TestCase):
|
|||
self.assertEqual(status.activity_type, 'Note')
|
||||
expected_id = 'https://%s/user/mouse/status/%d' % \
|
||||
(settings.DOMAIN, status.id)
|
||||
self.assertEqual(status.absolute_id, expected_id)
|
||||
self.assertEqual(status.remote_id, expected_id)
|
||||
|
||||
def test_comment(self):
|
||||
comment = models.Comment.objects.first()
|
||||
|
@ -31,7 +31,7 @@ class Status(TestCase):
|
|||
self.assertEqual(comment.activity_type, 'Note')
|
||||
expected_id = 'https://%s/user/mouse/comment/%d' % \
|
||||
(settings.DOMAIN, comment.id)
|
||||
self.assertEqual(comment.absolute_id, expected_id)
|
||||
self.assertEqual(comment.remote_id, expected_id)
|
||||
|
||||
def test_quotation(self):
|
||||
quotation = models.Quotation.objects.first()
|
||||
|
@ -39,7 +39,7 @@ class Status(TestCase):
|
|||
self.assertEqual(quotation.activity_type, 'Note')
|
||||
expected_id = 'https://%s/user/mouse/quotation/%d' % \
|
||||
(settings.DOMAIN, quotation.id)
|
||||
self.assertEqual(quotation.absolute_id, expected_id)
|
||||
self.assertEqual(quotation.remote_id, expected_id)
|
||||
|
||||
def test_review(self):
|
||||
review = models.Review.objects.first()
|
||||
|
@ -47,7 +47,7 @@ class Status(TestCase):
|
|||
self.assertEqual(review.activity_type, 'Article')
|
||||
expected_id = 'https://%s/user/mouse/review/%d' % \
|
||||
(settings.DOMAIN, review.id)
|
||||
self.assertEqual(review.absolute_id, expected_id)
|
||||
self.assertEqual(review.remote_id, expected_id)
|
||||
|
||||
|
||||
class Tag(TestCase):
|
||||
|
|
|
@ -14,10 +14,9 @@ class User(TestCase):
|
|||
''' username instead of id here '''
|
||||
user = models.User.objects.get(localname='mouse')
|
||||
expected_id = 'https://%s/user/mouse' % DOMAIN
|
||||
self.assertEqual(user.absolute_id, expected_id)
|
||||
self.assertEqual(user.remote_id, expected_id)
|
||||
self.assertEqual(user.username, 'mouse@%s' % DOMAIN)
|
||||
self.assertEqual(user.localname, 'mouse')
|
||||
self.assertEqual(user.actor, 'https://%s/user/mouse' % DOMAIN)
|
||||
self.assertEqual(user.shared_inbox, 'https://%s/inbox' % DOMAIN)
|
||||
self.assertEqual(user.inbox, '%s/inbox' % expected_id)
|
||||
self.assertEqual(user.outbox, '%s/outbox' % expected_id)
|
||||
|
|
|
@ -24,7 +24,7 @@ def webfinger(request):
|
|||
{
|
||||
'rel': 'self',
|
||||
'type': 'application/activity+json',
|
||||
'href': user.actor
|
||||
'href': user.remote_id
|
||||
}
|
||||
]
|
||||
})
|
||||
|
|
Loading…
Reference in a new issue