def handle_create(activity): ''' someone did something, good on them ''' if activity['object'].get('type') not in \ ['Note', 'Comment', 'Quotation', 'Review', 'GeneratedNote']: # if it's an article or unknown type, ignore it return user = get_or_create_remote_user(activity['actor']) if user.local: # we really oughtn't even be sending in this case return # deduplicate incoming activities status_id = activity['object']['id'] if models.Status.objects.filter(remote_id=status_id).count(): return status = status_builder.create_status(activity['object']) if not status: return # create a notification if this is a reply if status.reply_parent and status.reply_parent.user.local: status_builder.create_notification( status.reply_parent.user, 'REPLY', related_user=status.user, related_status=status, )
def import_data(job_id): ''' does the actual lookup work in a celery task ''' job = ImportJob.objects.get(id=job_id) try: results = [] for item in job.items.all(): try: item.resolve() except Exception as e: # pylint: disable=broad-except logger.exception(e) item.fail_reason = 'Error loading book' item.save() continue if item.book: item.save() results.append(item) # shelves book and handles reviews outgoing.handle_imported_book(job.user, item, job.include_reviews, job.privacy) else: item.fail_reason = 'Could not find a match for book' item.save() finally: create_notification(job.user, 'IMPORT', related_import=job)
def handle_create(activity): ''' someone did something, good on them ''' # deduplicate incoming activities status_id = activity['object']['id'] if models.Status.objects.filter(remote_id=status_id).count(): return serializer = activitypub.activity_objects[activity['type']] status = serializer(**activity) try: model = models.activity_models[activity.type] except KeyError: # not a type of status we are prepared to deserialize return if activity.type == 'Note': reply = models.Status.objects.filter( remote_id=activity.inReplyTo).first() if not reply: return activity.to_model(model) # create a notification if this is a reply if status.reply_parent and status.reply_parent.user.local: status_builder.create_notification( status.reply_parent.user, 'REPLY', related_user=status.user, related_status=status, )
def handle_boost(activity): ''' someone gave us a boost! ''' boost = activitypub.Boost(**activity).to_model(models.Boost) if not boost.user.local: status_builder.create_notification( boost.boosted_status.user, 'BOOST', related_user=boost.user, related_status=boost.boosted_status, )
def handle_favorite(activity): ''' approval of your good good post ''' fav = activitypub.Like(**activity) fav = fav.to_model(models.Favorite) if fav.user.local: return status_builder.create_notification( fav.status.user, 'FAVORITE', related_user=fav.user, related_status=fav.status, )
def handle_boost(activity): ''' someone gave us a boost! ''' try: boost = activitypub.Boost(**activity).to_model(models.Boost) except activitypub.ActivitySerializerError: # this probably just means we tried to boost an unknown status return if not boost.user.local: status_builder.create_notification( boost.boosted_status.user, 'BOOST', related_user=boost.user, related_status=boost.boosted_status, )
def handle_favorite(activity): ''' approval of your good good post ''' fav = activitypub.Like(**activity) liker = get_or_create_remote_user(activity['actor']) if liker.local: return fav = fav.to_model(models.Favorite) status_builder.create_notification( fav.status.user, 'FAVORITE', related_user=liker, related_status=fav.status, )
def handle_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 = favorite.to_activity() broadcast(user, fav_activity, privacy='direct', direct_recipients=[status.user]) create_notification(status.user, 'FAVORITE', related_user=user, related_status=status)
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 = boost.to_activity() broadcast(user, boost_activity) create_notification(status.user, 'BOOST', related_user=user, related_status=status)
def handle_follow(activity): ''' someone wants to follow a local user ''' # figure out who they want to follow -- not using get_or_create because # we only care if you want to follow local users try: to_follow = models.User.objects.get(remote_id=activity['object']) except models.User.DoesNotExist: # some rando, who cares return if not to_follow.local: # just ignore follow alerts about other servers. maybe they should be # handled. maybe they shouldn't be sent at all. return # figure out who the actor is actor = get_or_create_remote_user(activity['actor']) try: relationship = models.UserFollowRequest.objects.create( user_subject=actor, user_object=to_follow, remote_id=activity['id'] ) except django.db.utils.IntegrityError as err: if err.__cause__.diag.constraint_name != 'userfollowrequest_unique': raise relationship = models.UserFollowRequest.objects.get( remote_id=activity['id'] ) # send the accept normally for a duplicate request if not to_follow.manually_approves_followers: status_builder.create_notification( to_follow, 'FOLLOW', related_user=actor ) outgoing.handle_accept(relationship) else: # Accept will be triggered manually status_builder.create_notification( to_follow, 'FOLLOW_REQUEST', related_user=actor )
def handle_follow(activity): ''' someone wants to follow a local user ''' try: relationship = activitypub.Follow(**activity).to_model( models.UserFollowRequest) except django.db.utils.IntegrityError as err: if err.__cause__.diag.constraint_name != 'userfollowrequest_unique': raise relationship = models.UserFollowRequest.objects.get( remote_id=activity['id']) # send the accept normally for a duplicate request manually_approves = relationship.user_object.manually_approves_followers status_builder.create_notification( relationship.user_object, 'FOLLOW_REQUEST' if manually_approves else 'FOLLOW', related_user=relationship.user_subject) if not manually_approves: outgoing.handle_accept(relationship)
def handle_status(user, form): ''' generic handler for statuses ''' status = form.save() # inspect the text for user tags text = status.content matches = re.finditer(regex.username, text) for match in matches: username = match.group().strip().split('@')[1:] if len(username) == 1: # this looks like a local user (@user), fill in the domain username.append(DOMAIN) username = '******'.join(username) mention_user = handle_remote_webfinger(username) if not mention_user: # we can ignore users we don't know about continue # add them to status mentions fk status.mention_users.add(mention_user) # create notification if the mentioned user is local if mention_user.local: create_notification(mention_user, 'MENTION', related_user=user, related_status=status) status.save() # notify reply parent or tagged users if status.reply_parent and status.reply_parent.user.local: create_notification(status.reply_parent.user, 'REPLY', related_user=user, related_status=status) broadcast(user, status.to_create_activity(user), software='bookwyrm') # re-format the activity for non-bookwyrm servers if hasattr(status, 'pure_activity_serializer'): remote_activity = status.to_create_activity(user, pure=True) broadcast(user, remote_activity, software='other')
def import_data(job_id): ''' does the actual lookup work in a celery task ''' job = ImportJob.objects.get(id=job_id) try: results = [] for item in job.items.all(): try: item.resolve() except HTTPError: pass if item.book: item.save() results.append(item) # shelves book and handles reviews outgoing.handle_imported_book(job.user, item, job.include_reviews, job.privacy) else: item.fail_reason = "Could not find a match for book" item.save() finally: create_notification(job.user, 'IMPORT', related_import=job)