Пример #1
0
def handle_incoming_follow(activity):
    '''
    {
	"@context": "https://www.w3.org/ns/activitystreams",
	"id": "https://friend.camp/768222ce-a1c7-479c-a544-c93b8b67fb54",
	"type": "Follow",
	"actor": "https://friend.camp/users/tripofmice",
	"object": "https://ff2cb3e9.ngrok.io/api/u/mouse"
    }
    '''
    # figure out who they want to follow
    to_follow = models.User.objects.get(actor=activity['object'])
    # figure out who they are
    user = get_or_create_remote_user(activity['actor'])
    to_follow.followers.add(user)
    # verify uuid and accept the request
    models.FollowActivity(
        uuid=activity['id'],
        user=user,
        followed=to_follow,
        content=activity,
        activity_type='Follow',
    )
    uuid = uuid4()
    # TODO does this need to be signed?
    return JsonResponse({
        '@context': 'https://www.w3.org/ns/activitystreams',
        'id': 'https://%s/%s' % (DOMAIN, uuid),
        'type': 'Accept',
        'actor': user.actor,
        'object': activity,
    })
Пример #2
0
def handle_incoming_create(activity):
    ''' someone did something, good on them '''
    user = get_or_create_remote_user(activity['actor'])

    if not 'object' in activity:
        return HttpResponseBadRequest()

    # TODO: should only create notes if they are relevent to a book,
    # so, not every single thing someone posts on mastodon
    response = HttpResponse()
    content = activity['object'].get('content')
    if activity['object'].get('fedireadsType') == 'Review' and \
            'inReplyToBook' in activity['object']:
        book = activity['object']['inReplyToBook']
        book = book.split('/')[-1]
        name = activity['object'].get('name')
        rating = activity['object'].get('rating')
        if user.local:
            review_id = activity['object']['id'].split('/')[-1]
            models.Review.objects.get(id=review_id)
        else:
            try:
                create_review(user, book, name, content, rating)
            except ValueError:
                return HttpResponseBadRequest()
    elif not user.local:
        try:
            create_status(user, content)
        except ValueError:
            return HttpResponseBadRequest()

    return response
Пример #3
0
def handle_follow(activity):
    ''' someone wants to follow a local user '''
    # figure out who they want to follow
    to_follow = models.User.objects.get(actor=activity['object'])
    # figure out who they are
    user = get_or_create_remote_user(activity['actor'])
    try:
        request = models.UserFollowRequest.objects.create(
            user_subject=user,
            user_object=to_follow,
            relationship_id=activity['id'])
    except django.db.utils.IntegrityError as err:
        if err.__cause__.diag.constraint_name != 'userfollowrequest_unique':
            raise
        # Duplicate follow request. Not sure what the correct behaviour is, but
        # just dropping it works for now. We should perhaps generate the
        # Accept, but then do we need to match the activity id?
        return

    if not to_follow.manually_approves_followers:
        status_builder.create_notification(to_follow,
                                           'FOLLOW',
                                           related_user=user)
        outgoing.handle_accept(user, to_follow, request)
    else:
        status_builder.create_notification(to_follow,
                                           'FOLLOW_REQUEST',
                                           related_user=user)
Пример #4
0
def handle_incoming_create(activity):
    ''' someone did something, good on them '''
    user = get_or_create_remote_user(activity['actor'])
    uuid = activity['id']
    # if it's an article and in reply to a book, we have a review
    if activity['object']['type'] == 'Article' and \
            'inReplyTo' in activity['object']:
        possible_book = activity['object']['inReplyTo']
        try:
            # TODO idk about this error handling, should probs be more granular
            book = get_or_create_book(possible_book)
            models.Review(
                uuid=uuid,
                user=user,
                content=activity,
                activity_type='Article',
                book=book,
                name=activity['object']['name'],
                rating=activity['object']['rating'],
                review_content=activity['objet']['content'],
            ).save()
            return HttpResponse()
        except KeyError:
            pass

    models.Activity(
        uuid=uuid,
        user=user,
        content=activity,
        activity_type=activity['object']['type']
    )
    return HttpResponse()
Пример #5
0
def handle_incoming_follow_accept(activity):
    ''' hurray, someone remote accepted a follow request '''
    # figure out who they want to follow
    requester = models.User.objects.get(actor=activity['object']['actor'])
    # figure out who they are
    accepter = get_or_create_remote_user(activity['actor'])

    accepter.followers.add(requester)
    return HttpResponse()
Пример #6
0
def handle_incoming_add(activity):
    ''' someone is tagging or shelving a book '''
    if activity['object']['type'] == 'Tag':
        user = get_or_create_remote_user(activity['actor'])
        if not user.local:
            book = activity['target']['id'].split('/')[-1]
            create_tag(user, book, activity['object']['name'])
            return HttpResponse()
        return HttpResponse()
    return HttpResponseNotFound()
Пример #7
0
def handle_unfollow(activity):
    ''' unfollow a local user '''
    obj = activity['object']
    try:
        requester = get_or_create_remote_user(obj['actor'])
        to_unfollow = models.User.objects.get(remote_id=obj['object'])
    except models.User.DoesNotExist:
        return False

    to_unfollow.followers.remove(requester)
Пример #8
0
def handle_follow_reject(activity):
    ''' someone is rejecting a follow request '''
    requester = models.User.objects.get(actor=activity['object']['actor'])
    rejecter = get_or_create_remote_user(activity['actor'])

    try:
        request = models.UserFollowRequest.objects.get(user_subject=requester,
                                                       user_object=rejecter)
        request.delete()
    except models.UserFollowRequest.DoesNotExist:
        pass
Пример #9
0
def handle_incoming_accept(activity):
    ''' someone is accepting a follow request '''
    # our local user
    user = models.User.objects.get(actor=activity['actor'])
    # the person our local user wants to follow, who said yes
    followed = get_or_create_remote_user(activity['object']['actor'])

    # save this relationship in the db
    followed.followers.add(user)

    return HttpResponse()
Пример #10
0
def handle_incoming_favorite(activity):
    ''' approval of your good good post '''
    try:
        status_id = activity['object'].split('/')[-1]
        status = models.Status.objects.get(id=status_id)
        liker = get_or_create_remote_user(activity['actor'])
    except (models.Status.DoesNotExist, models.User.DoesNotExist):
        return HttpResponseNotFound()

    if not liker.local:
        status.favorites.add(liker)
    return HttpResponse()
Пример #11
0
def handle_unfollow(activity):
    ''' unfollow a local user '''
    obj = activity['object']
    if not obj['type'] == 'Follow':
        #idk how to undo other things
        return HttpResponseNotFound()
    try:
        requester = get_or_create_remote_user(obj['actor'])
        to_unfollow = models.User.objects.get(actor=obj['object'])
    except models.User.DoesNotExist:
        return HttpResponseNotFound()

    to_unfollow.followers.remove(requester)
Пример #12
0
def handle_incoming_follow(activity):
    ''' someone wants to follow a local user '''
    # figure out who they want to follow
    to_follow = models.User.objects.get(actor=activity['object'])
    # figure out who they are
    user = get_or_create_remote_user(activity['actor'])
    # TODO: allow users to manually approve requests
    models.UserRelationship.objects.create(user_subject=to_follow,
                                           user_object=user,
                                           status='follow_request',
                                           relationship_id=activity['id'])
    outgoing.handle_outgoing_accept(user, to_follow, activity)
    return HttpResponse()
Пример #13
0
def handle_follow_accept(activity):
    ''' hurray, someone remote accepted a follow request '''
    # figure out who they want to follow
    requester = models.User.objects.get(actor=activity['object']['actor'])
    # figure out who they are
    accepter = get_or_create_remote_user(activity['actor'])

    try:
        request = models.UserFollowRequest.objects.get(user_subject=requester,
                                                       user_object=accepter)
        request.delete()
    except models.UserFollowRequest.DoesNotExist:
        pass
    accepter.followers.add(requester)
Пример #14
0
def handle_account_search(query):
    ''' webfingerin' other servers '''
    user = None
    domain = query.split('@')[1]
    try:
        user = models.User.objects.get(username=query)
    except models.User.DoesNotExist:
        url = 'https://%s/.well-known/webfinger?resource=acct:%s' % \
            (domain, query)
        response = requests.get(url)
        if not response.ok:
            response.raise_for_status()
        data = response.json()
        for link in data['links']:
            if link['rel'] == 'self':
                user = get_or_create_remote_user(link['href'])
    return user
Пример #15
0
def handle_boost(activity):
    ''' someone gave us a boost! '''
    try:
        status_id = activity['object'].split('/')[-1]
        status = models.Status.objects.get(id=status_id)
        booster = get_or_create_remote_user(activity['actor'])
    except (models.Status.DoesNotExist, models.User.DoesNotExist):
        return False

    if not booster.local:
        status_builder.create_boost_from_activity(booster, activity)

    status_builder.create_notification(
        status.user,
        'BOOST',
        related_user=booster,
        related_status=status,
    )
Пример #16
0
def handle_favorite(activity):
    ''' approval of your good good post '''
    try:
        status_id = activity['object'].split('/')[-1]
        status = models.Status.objects.get(id=status_id)
        liker = get_or_create_remote_user(activity['actor'])
    except (models.Status.DoesNotExist, models.User.DoesNotExist):
        return False

    if not liker.local:
        status_builder.create_favorite_from_activity(liker, activity)

    status_builder.create_notification(
        status.user,
        'FAVORITE',
        related_user=liker,
        related_status=status,
    )
Пример #17
0
def handle_incoming_follow(activity):
    ''' someone wants to follow a local user '''
    # figure out who they want to follow
    to_follow = models.User.objects.get(actor=activity['object'])
    # figure out who they are
    user = get_or_create_remote_user(activity['actor'])
    # TODO: allow users to manually approve requests
    try:
        models.UserRelationship.objects.create(user_subject=to_follow,
                                               user_object=user,
                                               status='follow_request',
                                               relationship_id=activity['id'])
    except django.db.utils.IntegrityError:
        # Duplicate follow request. Not sure what the correct behaviour is, but
        # just dropping it works for now. We should perhaps generate the
        # Accept, but then do we need to match the activity id?
        return HttpResponse()

    outgoing.handle_outgoing_accept(user, to_follow, activity)
    return HttpResponse()
Пример #18
0
def has_valid_signature(request, activity):
    try:
        signature = Signature.parse(request)

        key_actor = urldefrag(signature.key_id).url
        if key_actor != activity.get('actor'):
            raise ValueError("Wrong actor created signature.")

        remote_user = get_or_create_remote_user(key_actor)

        try:
            signature.verify(remote_user.public_key, request)
        except ValueError:
            old_key = remote_user.public_key
            refresh_remote_user(remote_user)
            if remote_user.public_key == old_key:
                raise # Key unchanged.
            signature.verify(remote_user.public_key, request)
    except (ValueError, requests.exceptions.HTTPError):
        return False
    return True
Пример #19
0
def handle_create(activity):
    ''' someone did something, good on them '''
    user = get_or_create_remote_user(activity['actor'])

    if not 'object' in activity:
        return HttpResponseBadRequest()

    if user.local:
        # we really oughtn't even be sending in this case
        return

    if activity['object'].get('fedireadsType') and \
            'inReplyToBook' in activity['object']:
        try:
            if activity['object']['fedireadsType'] == 'Review':
                builder = status_builder.create_review_from_activity
            elif activity['object']['fedireadsType'] == 'Quotation':
                builder = status_builder.create_quotation_from_activity
            else:
                builder = status_builder.create_comment_from_activity

            # create the status, it'll throw a valueerror if anything is missing
            builder(user, activity['object'])
        except ValueError:
            return HttpResponseBadRequest()
    else:
        # TODO: should only create notes if they are relevent to a book,
        # so, not every single thing someone posts on mastodon
        try:
            status = status_builder.create_status_from_activity(
                user, activity['object'])
            if status and status.reply_parent:
                status_builder.create_notification(
                    status.reply_parent.user,
                    'REPLY',
                    related_user=status.user,
                    related_status=status,
                )
        except ValueError:
            return HttpResponseBadRequest()
Пример #20
0
def handle_create(activity):
    ''' someone did something, good on them '''
    user = get_or_create_remote_user(activity['actor'])

    if user.local:
        # we really oughtn't even be sending in this case
        return True

    if activity['object'].get('fedireadsType') and \
            'inReplyToBook' in activity['object']:
        if activity['object']['fedireadsType'] == 'Review':
            builder = status_builder.create_review_from_activity
        elif activity['object']['fedireadsType'] == 'Quotation':
            builder = status_builder.create_quotation_from_activity
        else:
            builder = status_builder.create_comment_from_activity

        # create the status, it'll throw a ValueError if anything is missing
        builder(user, activity['object'])
    elif activity['object'].get('inReplyTo'):
        # only create the status if it's in reply to a status we already know
        if not status_builder.get_status(activity['object']['inReplyTo']):
            return True

        status = status_builder.create_status_from_activity(
            user,
            activity['object']
        )
        if status and status.reply_parent:
            status_builder.create_notification(
                status.reply_parent.user,
                'REPLY',
                related_user=status.user,
                related_status=status,
            )
    return True
Пример #21
0
 def test_get_remote_user(self):
     actor = 'https://example.com/users/mouse'
     user = remote_user.get_or_create_remote_user(actor)
     self.assertEqual(user, self.remote_user)
Пример #22
0
def handle_tag(activity):
    ''' someone is tagging a book '''
    user = get_or_create_remote_user(activity['actor'])
    if not user.local:
        book = activity['target']['id']
        status_builder.create_tag(user, book, activity['object']['name'])