2019-07-22 16:30:15 +00:00
|
|
|
import logging
|
2019-07-22 16:59:59 +00:00
|
|
|
from django.conf import settings
|
2019-08-11 18:44:49 +00:00
|
|
|
from django_kepi.find import find, is_local
|
2019-07-22 16:30:15 +00:00
|
|
|
from django_kepi.delivery import deliver
|
|
|
|
|
|
|
|
logger = logging.getLogger(name='django_kepi')
|
|
|
|
|
|
|
|
def accept(activity):
|
|
|
|
|
2019-08-10 19:21:27 +00:00
|
|
|
from django_kepi.models.following import Following
|
|
|
|
|
2019-07-22 16:30:15 +00:00
|
|
|
obj = activity['object__obj']
|
|
|
|
|
|
|
|
if obj['type']!='Follow':
|
|
|
|
logger.warn('Object %s was Accepted, but it isn\'t a Follow',
|
|
|
|
obj)
|
|
|
|
return False
|
|
|
|
|
|
|
|
logger.debug(' -- follow accepted')
|
|
|
|
|
2019-08-10 19:21:27 +00:00
|
|
|
Following.accept_request(
|
2019-07-22 16:30:15 +00:00
|
|
|
follower = obj['actor'],
|
|
|
|
following = activity['actor'],
|
|
|
|
)
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
def follow(activity):
|
|
|
|
|
2019-08-04 21:44:53 +00:00
|
|
|
from django_kepi.models.following import Following
|
|
|
|
from django_kepi.create import create
|
|
|
|
|
2019-07-22 16:30:15 +00:00
|
|
|
local_user = find(activity['object'], local_only=True)
|
|
|
|
remote_user = find(activity['actor'])
|
|
|
|
|
|
|
|
if local_user is not None and local_user.auto_follow:
|
|
|
|
logger.info('Local user %s has auto_follow set; must Accept',
|
|
|
|
local_user)
|
2019-08-04 21:44:53 +00:00
|
|
|
|
|
|
|
Following.accept_request(
|
2019-07-22 16:30:15 +00:00
|
|
|
follower = activity['actor'],
|
|
|
|
following = activity['object'],
|
2019-08-04 21:44:53 +00:00
|
|
|
warn_on_unknown = False,
|
2019-07-22 16:30:15 +00:00
|
|
|
)
|
|
|
|
|
2019-08-04 21:44:53 +00:00
|
|
|
accept_the_request = create(
|
2019-07-22 16:30:15 +00:00
|
|
|
f_to = remote_user.url,
|
|
|
|
f_type = 'Accept',
|
|
|
|
f_actor = activity['object'],
|
|
|
|
f_object = activity.url,
|
|
|
|
run_side_effects = False,
|
|
|
|
)
|
|
|
|
|
|
|
|
deliver(accept_the_request.number)
|
|
|
|
|
|
|
|
else:
|
2019-08-04 21:44:53 +00:00
|
|
|
logger.info('Local user %s does not have auto_follow set.',
|
|
|
|
local_user)
|
|
|
|
|
|
|
|
Following.make_request(
|
2019-07-22 16:30:15 +00:00
|
|
|
follower = activity['actor'],
|
|
|
|
following = activity['object'],
|
|
|
|
)
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
def reject(activity):
|
2019-08-04 21:44:53 +00:00
|
|
|
|
|
|
|
from django_kepi.models.following import Following
|
|
|
|
|
2019-07-22 16:30:15 +00:00
|
|
|
obj = activity['object__obj']
|
|
|
|
|
|
|
|
if obj['type']!='Follow':
|
|
|
|
logger.warn('Object %s was Rejected, but it isn\'t a Follow',
|
|
|
|
obj)
|
|
|
|
return False
|
|
|
|
|
|
|
|
logger.debug(' -- follow rejected')
|
|
|
|
|
2019-08-04 21:44:53 +00:00
|
|
|
Following.reject_request(
|
2019-07-22 16:30:15 +00:00
|
|
|
follower = obj['actor'],
|
|
|
|
following = activity['actor'],
|
|
|
|
)
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
def create(activity):
|
2019-08-04 21:44:53 +00:00
|
|
|
|
2019-08-05 14:25:20 +00:00
|
|
|
import django_kepi.models as kepi_models
|
2019-07-22 16:30:15 +00:00
|
|
|
from django_kepi.create import create as kepi_create
|
2019-08-11 18:44:49 +00:00
|
|
|
from django_kepi.models.audience import AUDIENCE_FIELD_KEYS
|
2019-07-22 16:30:15 +00:00
|
|
|
|
2019-08-11 18:44:49 +00:00
|
|
|
raw_material = activity['object'].copy()
|
2019-07-22 16:30:15 +00:00
|
|
|
|
2019-08-11 18:44:49 +00:00
|
|
|
f_type = raw_material['type'].title()
|
2019-07-22 16:30:15 +00:00
|
|
|
|
2019-08-11 18:44:49 +00:00
|
|
|
logger.debug('Raw material before adjustments is %s.',
|
|
|
|
raw_material)
|
|
|
|
|
|
|
|
for field in AUDIENCE_FIELD_KEYS.union(['attributedTo']):
|
|
|
|
# copy audiences, per
|
|
|
|
# https://www.w3.org/TR/activitypub/ 6.2
|
|
|
|
if field in activity:
|
|
|
|
value = activity[field]
|
|
|
|
if value:
|
|
|
|
raw_material[field] = value
|
|
|
|
|
|
|
|
try:
|
|
|
|
if issubclass(getattr(kepi_models,
|
|
|
|
f_type),
|
|
|
|
kepi_models.Activity):
|
|
|
|
|
|
|
|
logger.warn('Attempt to use Create to create '+\
|
|
|
|
'an object of type %s. '+\
|
|
|
|
'Create can only create non-activities. '+\
|
|
|
|
'Deleting original Create.',
|
|
|
|
f_type)
|
|
|
|
|
|
|
|
return False
|
|
|
|
except AttributeError:
|
2019-07-22 16:30:15 +00:00
|
|
|
logger.warn('Attempt to use Create to create '+\
|
|
|
|
'an object of type %s. '+\
|
2019-08-11 18:44:49 +00:00
|
|
|
'I have no idea what that is!',
|
|
|
|
f_type)
|
2019-07-22 16:30:15 +00:00
|
|
|
return False
|
|
|
|
|
2019-08-11 18:44:49 +00:00
|
|
|
if 'actor' in activity:
|
|
|
|
attributedTo = raw_material.get('attributedTo', None)
|
|
|
|
|
|
|
|
if attributedTo!=activity['actor']:
|
|
|
|
logger.warn('Attribution on object is %s, but '+\
|
|
|
|
'actor on Create is %s; '+\
|
|
|
|
'fixing this and continuing',
|
|
|
|
attributedTo,
|
|
|
|
activity['actor'],
|
|
|
|
)
|
|
|
|
raw_material['attributedTo'] = activity['actor']
|
|
|
|
|
|
|
|
logger.debug('Raw material after adjustments is %s.',
|
|
|
|
raw_material)
|
|
|
|
|
|
|
|
def it_is_relevant(something, activity):
|
|
|
|
|
|
|
|
logger.debug('Checking whether the new object is relevant to us.')
|
|
|
|
|
|
|
|
for f,v in something.items():
|
|
|
|
if (f not in AUDIENCE_FIELD_KEYS) and \
|
|
|
|
f!='attributedTo':
|
|
|
|
continue
|
|
|
|
|
|
|
|
if type(v)!=list:
|
|
|
|
v=[v]
|
|
|
|
|
|
|
|
logger.debug(' -- checking %s, currently %s',
|
|
|
|
f, v)
|
|
|
|
for a in v:
|
|
|
|
logger.debug(' -- is %s local?', a)
|
|
|
|
if is_local(a):
|
|
|
|
logger.debug(' -- yes!')
|
|
|
|
return True
|
|
|
|
|
|
|
|
try:
|
|
|
|
tags = something['tag']
|
|
|
|
logger.debug(' -- checking mentions; tags are %s',
|
|
|
|
tags)
|
|
|
|
for tag in tags:
|
|
|
|
if tag['type'].title()!='Mention':
|
|
|
|
continue
|
|
|
|
|
|
|
|
logger.debug(' -- is %s local?', tag['href'])
|
|
|
|
if is_local(tag['href']):
|
|
|
|
logger.debug(' -- yes!')
|
|
|
|
return True
|
|
|
|
|
|
|
|
except KeyError:
|
|
|
|
logger.debug(' -- failed to find anything out '+\
|
|
|
|
'from the mentions.')
|
|
|
|
|
|
|
|
try:
|
|
|
|
inReplyTo = something['inReplyTo']
|
|
|
|
|
|
|
|
logger.debug(' -- checking inReplyTo, currently %s',
|
|
|
|
inReplyTo)
|
|
|
|
|
|
|
|
if find(inReplyTo, local_only=True):
|
|
|
|
logger.debug(' -- which is one of ours, so yes')
|
|
|
|
return True
|
|
|
|
except KeyError:
|
|
|
|
logger.debug(' -- failed to find anything out '+\
|
|
|
|
'from inReplyTo.')
|
|
|
|
|
|
|
|
|
|
|
|
logger.debug(' -- does actor %s have local followers?',
|
|
|
|
activity['actor'])
|
|
|
|
try:
|
|
|
|
if kepi_models.Following.objects.filter(
|
|
|
|
following = activity['actor'],
|
|
|
|
):
|
|
|
|
logger.debug(' -- yes!')
|
|
|
|
return True
|
|
|
|
except KeyError:
|
|
|
|
logger.debug(' -- failed to find anything out '+\
|
|
|
|
'about local followers of actor.')
|
|
|
|
|
|
|
|
logger.debug(' -- no, so it\'s irrelevant.')
|
|
|
|
return False
|
2019-07-22 16:30:15 +00:00
|
|
|
|
2019-08-11 18:44:49 +00:00
|
|
|
if not it_is_relevant(raw_material, activity):
|
|
|
|
logger.warn('Attempt to use Create to create '+\
|
|
|
|
'an object which isn\'t addressed to us. '+\
|
|
|
|
'To be honest, that\'s none of our business.')
|
|
|
|
return False
|
2019-07-22 16:30:15 +00:00
|
|
|
|
2019-08-11 18:44:49 +00:00
|
|
|
creation = kepi_create(
|
|
|
|
value = raw_material,
|
2019-07-22 16:30:15 +00:00
|
|
|
is_local = activity.is_local,
|
|
|
|
run_side_effects = False)
|
|
|
|
activity['object'] = creation
|
|
|
|
activity.save()
|
|
|
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
def update(activity):
|
|
|
|
|
|
|
|
new_object = activity['object']
|
|
|
|
|
|
|
|
if 'id' not in new_object:
|
|
|
|
logger.warn('Update did not include an id.')
|
|
|
|
return False
|
|
|
|
|
|
|
|
existing = find(new_object['id'],
|
|
|
|
local_only = True)
|
|
|
|
|
|
|
|
if existing is None:
|
|
|
|
logger.warn('Update to non-existent object, %s.',
|
|
|
|
new_object['id'])
|
|
|
|
return False
|
|
|
|
|
|
|
|
if existing['attributedTo']!=activity['actor']:
|
|
|
|
logger.warn('Update by %s to object owned by %s. '+\
|
|
|
|
'Deleting update.',
|
|
|
|
activity['actor'],
|
|
|
|
existing['attributedTo'],
|
|
|
|
)
|
|
|
|
return False
|
|
|
|
|
|
|
|
logger.debug('Updating object %s',
|
|
|
|
new_object['id'])
|
|
|
|
|
|
|
|
for f, v in sorted(new_object.items()):
|
|
|
|
if f=='id':
|
|
|
|
continue
|
|
|
|
|
|
|
|
existing[f] = v
|
|
|
|
|
|
|
|
# FIXME if not activity.is_local we have to remove
|
|
|
|
# all properties of "existing" which aren't in
|
|
|
|
# "new_object"
|
|
|
|
|
|
|
|
existing.save()
|
|
|
|
logger.debug(' -- done')
|
|
|
|
|
|
|
|
return True
|
2019-07-22 16:59:59 +00:00
|
|
|
|
|
|
|
def delete(activity):
|
|
|
|
|
|
|
|
victim = find(activity['object'],
|
|
|
|
local_only = True)
|
|
|
|
|
|
|
|
if victim is None:
|
|
|
|
logger.info(' -- attempt to Delete non-existent object.')
|
|
|
|
return False
|
|
|
|
|
|
|
|
if settings.KEPI['TOMBSTONES']:
|
|
|
|
# I have a lovely cask of amontillado to show you
|
|
|
|
victim.entomb()
|
|
|
|
else:
|
|
|
|
victim.delete()
|
|
|
|
logger.info(' -- %s deleted',
|
|
|
|
victim)
|
|
|
|
|
|
|
|
return True
|