def handle_import_books(user, items): ''' process a goodreads csv and then post about it ''' new_books = [] for item in items: if item.shelf: desired_shelf = models.Shelf.objects.get(identifier=item.shelf, user=user) if isinstance(item.book, models.Work): item.book = item.book.default_edition if not item.book: continue _, created = models.ShelfBook.objects.get_or_create( book=item.book, shelf=desired_shelf, added_by=user) if created: new_books.append(item.book) activity = activitypub.get_add(user, item.book, desired_shelf) broadcast(user, activity) for read in item.reads: read.book = item.book read.user = user read.save() if new_books: message = 'imported {} books'.format(len(new_books)) status = create_status(user, message, mention_books=new_books) status.status_type = 'Update' status.save() create_activity = activitypub.get_create( user, activitypub.get_status(status)) broadcast(user, create_activity)
def handle_tag(user, book, name): ''' tag a book ''' tag = create_tag(user, book, name) tag_activity = activitypub.get_add_tag(tag) recipients = get_recipients(user, 'public') broadcast(user, tag_activity, recipients)
def handle_unfollow(user, to_unfollow): ''' someone local wants to follow someone ''' relationship = models.UserFollows.objects.get(user_subject=user, user_object=to_unfollow) activity = activitypub.get_unfollow(relationship) broadcast(user, activity, [to_unfollow.inbox]) to_unfollow.followers.remove(user)
def handle_reject(user, to_follow, relationship): ''' a local user who managed follows rejects a follow request ''' relationship.delete() activity = activitypub.get_reject(to_follow, relationship) recipient = get_recipients(to_follow, 'direct', direct_recipients=[user]) broadcast(to_follow, activity, recipient)
def handle_untag(user, book, name): ''' tag a book ''' book = models.Book.objects.get(fedireads_key=book) tag = models.Tag.objects.get(name=name, book=book, user=user) tag_activity = activitypub.get_remove_tag(tag) tag.delete() broadcast(user, tag_activity)
def handle_accept(user, to_follow, follow_request): ''' send an acceptance message to a follow request ''' with transaction.atomic(): relationship = models.UserFollows.from_request(follow_request) follow_request.delete() relationship.save() activity = activitypub.get_accept(to_follow, follow_request) broadcast(to_follow, activity, privacy='direct', direct_recipients=[user])
def handle_unshelve(user, book, shelf): ''' a local user is getting a book put on their shelf ''' # update the database row = models.ShelfBook.objects.get(book=book, shelf=shelf) row.delete() activity = activitypub.get_remove(user, book, shelf) broadcast(user, activity)
def handle_untag(user, book, name): ''' tag a book ''' book = models.Book.objects.get(openlibrary_key=book) tag = models.Tag.objects.get(name=name, book=book, user=user) tag_activity = activitypub.get_remove_tag(tag) tag.delete() recipients = get_recipients(user, 'public') broadcast(user, tag_activity, recipients)
def handle_outgoing_accept(user, to_follow, request_activity): ''' send an acceptance message to a follow request ''' relationship = models.UserRelationship.objects.get( relationship_id=request_activity['id']) relationship.status = 'follow' relationship.save() activity = activitypub.get_accept(to_follow, request_activity) recipient = get_recipients(to_follow, 'direct', direct_recipients=[user]) broadcast(to_follow, activity, recipient)
def handle_comment(user, review, content): ''' respond to a review or status ''' # validated and saves the comment in the database so it has an id comment = create_status(user, content, reply_parent=review) comment_activity = activitypub.get_status(comment) create_activity = activitypub.get_create(user, comment_activity) recipients = get_recipients(user, 'public') broadcast(user, create_activity, recipients)
def handle_unfavorite(user, status): ''' a user likes a status ''' try: favorite = models.Favorite.objects.get(status=status, user=user) except models.Favorite.DoesNotExist: # can't find that status, idk return fav_activity = activitypub.get_unfavorite(favorite) broadcast(user, fav_activity, [status.user])
def handle_outgoing_favorite(user, status): ''' a user likes a status ''' try: favorite = models.Favorite.objects.create(status=status, user=user) except IntegrityError: # you already fav'ed that return fav_activity = activitypub.get_favorite(favorite) recipients = get_recipients(user, 'direct', [status.user]) broadcast(user, fav_activity, recipients)
def handle_boost(user, status): ''' a user wishes to boost a status ''' if models.Boost.objects.filter(boosted_status=status, user=user).exists(): # you already boosted that. return boost = models.Boost.objects.create( boosted_status=status, user=user, ) boost.save() boost_activity = activitypub.get_boost(boost) broadcast(user, boost_activity)
def handle_status(user, book, \ builder, fr_serializer, ap_serializer, *args): ''' generic handler for statuses ''' status = builder(user, book, *args) activity = fr_serializer(status) create_activity = activitypub.get_create(user, activity) broadcast(user, create_activity, software='fedireads') # re-format the activity for non-fedireads servers remote_activity = ap_serializer(status) remote_create_activity = activitypub.get_create(user, remote_activity) broadcast(user, remote_create_activity, software='other')
def handle_rate(user, book, rating): ''' a review that's just a rating ''' rating = create_rating(user, book, rating) rating_activity = activitypub.get_rating(rating) rating_create_activity = activitypub.get_create(user, rating_activity) fr_recipients = get_recipients(user, 'public', limit='fedireads') broadcast(user, rating_create_activity, fr_recipients) # re-format the activity for non-fedireads servers note_activity = activitypub.get_rating_note(rating) note_create_activity = activitypub.get_create(user, note_activity) other_recipients = get_recipients(user, 'public', limit='other') broadcast(user, note_create_activity, other_recipients)
def handle_reply(user, review, content): ''' respond to a review or status ''' # validated and saves the comment in the database so it has an id reply = create_status(user, content, reply_parent=review) if reply.reply_parent: create_notification( reply.reply_parent.user, 'REPLY', related_user=user, related_status=reply, ) reply_activity = activitypub.get_status(reply) create_activity = activitypub.get_create(user, reply_activity) broadcast(user, create_activity)
def handle_review(user, book, name, content, rating): ''' post a review ''' # validated and saves the review in the database so it has an id review = create_review(user, book, name, content, rating) review_activity = activitypub.get_review(review) review_create_activity = activitypub.get_create(user, review_activity) fr_recipients = get_recipients(user, 'public', limit='fedireads') broadcast(user, review_create_activity, fr_recipients) # re-format the activity for non-fedireads servers article_activity = activitypub.get_review_article(review) article_create_activity = activitypub.get_create(user, article_activity) other_recipients = get_recipients(user, 'public', limit='other') broadcast(user, article_create_activity, other_recipients)
def handle_comment(user, book, content): ''' post a review ''' # validated and saves the review in the database so it has an id comment = create_comment(user, book, content) comment_activity = activitypub.get_comment(comment) comment_create_activity = activitypub.get_create(user, comment_activity) fr_recipients = get_recipients(user, 'public', limit='fedireads') broadcast(user, comment_create_activity, fr_recipients) # re-format the activity for non-fedireads servers article_activity = activitypub.get_comment_article(comment) article_create_activity = activitypub.get_create(user, article_activity) other_recipients = get_recipients(user, 'public', limit='other') broadcast(user, article_create_activity, other_recipients)
def handle_outgoing_unfollow(user, to_unfollow): ''' someone local wants to follow someone ''' relationship = models.UserRelationship.objects.get( user_object=user, user_subject=to_unfollow) activity = activitypub.get_unfollow(relationship) errors = broadcast(user, activity, [to_unfollow.inbox]) to_unfollow.followers.remove(user) for error in errors: raise (error['error'])
def handle_shelve(user, book, shelf): ''' a local user is getting a book put on their shelf ''' # update the database models.ShelfBook(book=book, shelf=shelf, added_by=user).save() activity = activitypub.get_add(user, book, shelf) recipients = get_recipients(user, 'public') broadcast(user, activity, recipients) # tell the world about this cool thing that happened verb = { 'to-read': 'wants to read', 'reading': 'started reading', 'read': 'finished reading' }[shelf.identifier] message = '%s "%s"' % (verb, book.title) status = create_status(user, message, mention_books=[book]) status.status_type = 'Update' status.save() if shelf.identifier == 'reading': read = models.ReadThrough(user=user, book=book, start_date=datetime.now()) read.save() elif shelf.identifier == 'read': read = models.ReadThrough.objects.filter( user=user, book=book, finish_date=None).order_by('-created_date').first() if not read: read = models.ReadThrough(user=user, book=book, start_date=datetime.now()) read.finish_date = datetime.now() read.save() activity = activitypub.get_status(status) create_activity = activitypub.get_create(user, activity) broadcast(user, create_activity, recipients)
def handle_unshelve(user, book, shelf): ''' a local user is getting a book put on their shelf ''' # update the database row = models.ShelfBook.objects.get(book=book, shelf=shelf) row.delete() # send out the activitypub action summary = '%s removed %s from %s' % (user.username, book.data['title'], shelf.name) uuid = uuid4() activity = { '@context': 'https://www.w3.org/ns/activitystreams', 'id': str(uuid), 'summary': summary, 'type': 'Remove', 'actor': user.actor, 'object': { 'type': 'Document', 'name': book.data['title'], 'url': book.openlibrary_key }, 'target': { 'type': 'Collection', 'name': shelf.name, 'id': shelf.activitypub_id } } recipients = get_recipients(user, 'public') models.ShelveActivity( uuid=uuid, user=user, content=activity, shelf=shelf, book=book, activity_type='Remove', ).save() broadcast(user, activity, recipients)
def handle_review(user, book, name, content, rating): ''' post a review ''' review_uuid = uuid4() obj = { '@context': 'https://www.w3.org/ns/activitystreams', 'id': str(review_uuid), 'type': 'Article', 'published': datetime.utcnow().isoformat(), 'attributedTo': user.actor, 'content': content, 'inReplyTo': book.openlibrary_key, # TODO is this the right identifier? 'rating': rating, # fedireads-only custom field 'to': 'https://www.w3.org/ns/activitystreams#Public' } # TODO: create alt version for mastodon recipients = get_recipients(user, 'public') create_uuid = uuid4() activity = { '@context': 'https://www.w3.org/ns/activitystreams', 'id': str(create_uuid), 'type': 'Create', 'actor': user.actor, 'to': ['%s/followers' % user.actor], 'cc': ['https://www.w3.org/ns/activitystreams#Public'], 'object': obj, } models.Review( uuid=create_uuid, user=user, content=activity, activity_type='Article', book=book, name=name, rating=rating, review_content=content, ).save() broadcast(user, activity, recipients)
def handle_shelve(user, book, shelf): ''' a local user is getting a book put on their shelf ''' # update the database models.ShelfBook(book=book, shelf=shelf, added_by=user).save() activity = activitypub.get_add(user, book, shelf) recipients = get_recipients(user, 'public') broadcast(user, activity, recipients) # tell the world about this cool thing that happened verb = { 'to-read': 'wants to read', 'reading': 'started reading', 'read': 'finished reading' }[shelf.identifier] name = user.name if user.name else user.localname message = '%s %s %s' % (name, verb, book.data['title']) status = create_status(user, message, mention_books=[book]) activity = activitypub.get_status(status) create_activity = activitypub.get_create(user, activity) broadcast(user, create_activity, recipients)
def handle_outgoing_follow(user, to_follow): ''' someone local wants to follow someone ''' uuid = uuid4() activity = { '@context': 'https://www.w3.org/ns/activitystreams', 'id': 'https://%s/%s' % (DOMAIN, str(uuid)), 'summary': '', 'type': 'Follow', 'actor': user.actor, 'object': to_follow.actor, } errors = broadcast(user, activity, [to_follow.inbox]) for error in errors: # TODO: following masto users is returning 400 raise (error['error'])
def handle_follow(user, to_follow): ''' someone local wants to follow someone ''' activity = activitypub.get_follow_request(user, to_follow) broadcast(user, activity, direct_recipients=[to_follow])
def handle_follow(user, to_follow): ''' someone local wants to follow someone ''' activity = activitypub.get_follow_request(user, to_follow) broadcast(user, activity, [to_follow.inbox])
def handle_update_user(user): ''' broadcast editing a user's profile ''' actor = activitypub.get_actor(user) update_activity = activitypub.get_update(user, actor) broadcast(user, update_activity)
def handle_update_book(user, book): ''' broadcast the news about our book ''' book_activity = activitypub.get_book(book) update_activity = activitypub.get_update(user, book_activity) broadcast(user, update_activity)
def handle_outgoing_follow(user, to_follow): ''' someone local wants to follow someone ''' activity = activitypub.get_follow_request(user, to_follow) errors = broadcast(user, activity, [to_follow.inbox]) for error in errors: raise (error['error'])
def handle_tag(user, book, name): ''' tag a book ''' tag = create_tag(user, book, name) tag_activity = activitypub.get_add_tag(tag) broadcast(user, tag_activity)