kopia lustrzana https://gitlab.com/marnanel/chapeau
Tombstones. Closes #7.
rodzic
fb1444e4ef
commit
7a57d691df
|
@ -140,6 +140,14 @@ class ThingRequest(HttpRequest):
|
||||||
|
|
||||||
self.method = 'ACTIVITY'
|
self.method = 'ACTIVITY'
|
||||||
|
|
||||||
|
class TombstoneException(Exception):
|
||||||
|
def __init__(self, tombstone, *args, **kwargs):
|
||||||
|
self.tombstone = tombstone
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.tombstone.__str__()
|
||||||
|
|
||||||
def find_local(path):
|
def find_local(path):
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -160,6 +168,9 @@ def find_local(path):
|
||||||
**resolved.kwargs)
|
**resolved.kwargs)
|
||||||
logger.debug('%s: resulting in %s', path, str(result))
|
logger.debug('%s: resulting in %s', path, str(result))
|
||||||
|
|
||||||
|
if result.f_type == 'Tombstone':
|
||||||
|
raise TombstoneException(result)
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def find_remote(url):
|
def find_remote(url):
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
from django.db import models, IntegrityError
|
from django.db import models, IntegrityError
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django_kepi.find import find
|
from django_kepi.find import find, is_local
|
||||||
from django_kepi.delivery import deliver
|
from django_kepi.delivery import deliver
|
||||||
import django_kepi.models.following
|
import django_kepi.models.following
|
||||||
import logging
|
import logging
|
||||||
|
@ -211,6 +211,39 @@ class Thing(models.Model):
|
||||||
following = self['actor'],
|
following = self['actor'],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_local(self):
|
||||||
|
if not self.remote_url:
|
||||||
|
return True
|
||||||
|
|
||||||
|
return is_local(self.remote_url)
|
||||||
|
|
||||||
|
def entomb(self):
|
||||||
|
logger.info('%s: entombing', self)
|
||||||
|
|
||||||
|
if self.f_type=='Tombstone':
|
||||||
|
logger.warn(' -- already entombed; ignoring')
|
||||||
|
return
|
||||||
|
|
||||||
|
if not self.is_local:
|
||||||
|
raise ValueError("%s: you can't entomb remote things %s",
|
||||||
|
self, str(self.remote_url))
|
||||||
|
|
||||||
|
former_type = self.f_type
|
||||||
|
|
||||||
|
self.f_type = 'Tombstone'
|
||||||
|
self.active = True
|
||||||
|
|
||||||
|
ThingField.objects.filter(parent=self).delete()
|
||||||
|
|
||||||
|
for f,v in [
|
||||||
|
('former_type', former_type),
|
||||||
|
# XXX 'deleted', when we're doing timestamps
|
||||||
|
]:
|
||||||
|
ThingField(parent=self, name=f, value=json.dumps(v)).save()
|
||||||
|
|
||||||
|
self.save()
|
||||||
|
logger.info('%s: entombing finished', self)
|
||||||
|
|
||||||
TYPES = {
|
TYPES = {
|
||||||
# actor object target
|
# actor object target
|
||||||
|
@ -335,8 +368,6 @@ class Thing(models.Model):
|
||||||
record_fields['f_type'] = value['type']
|
record_fields['f_type'] = value['type']
|
||||||
|
|
||||||
if 'id' in value:
|
if 'id' in value:
|
||||||
# FIXME this allows people to create "remote" Activities
|
|
||||||
# with local URLs, which is weird and shouldn't happen.
|
|
||||||
record_fields['remote_url'] = value['id']
|
record_fields['remote_url'] = value['id']
|
||||||
|
|
||||||
for f in ['id', 'type', 'actor', 'name']:
|
for f in ['id', 'type', 'actor', 'name']:
|
||||||
|
|
|
@ -97,6 +97,10 @@ class KepiView(django.views.View):
|
||||||
|
|
||||||
result['Content-Type'] = 'application/activity+json'
|
result['Content-Type'] = 'application/activity+json'
|
||||||
|
|
||||||
|
if data['type']=='Tombstone':
|
||||||
|
result.reason = 'Entombed'
|
||||||
|
result.status_code = 410
|
||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
def _collection_get(self, request, items):
|
def _collection_get(self, request, items):
|
||||||
|
@ -252,6 +256,9 @@ class ActorView(ThingView):
|
||||||
def activity(self, request, *args, **kwargs):
|
def activity(self, request, *args, **kwargs):
|
||||||
thing = super().activity(request, *args, **kwargs)
|
thing = super().activity(request, *args, **kwargs)
|
||||||
|
|
||||||
|
if thing.f_type=='Tombstone':
|
||||||
|
return thing
|
||||||
|
|
||||||
logger.debug(' -- found Thing %s; does it have an Actor?',
|
logger.debug(' -- found Thing %s; does it have an Actor?',
|
||||||
thing)
|
thing)
|
||||||
|
|
||||||
|
|
|
@ -78,3 +78,36 @@ class TestKepiView(TestCase):
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
class TestTombstone(TestCase):
|
||||||
|
|
||||||
|
def test_tombstone(self):
|
||||||
|
|
||||||
|
queen_anne = create_local_person('queen_anne')
|
||||||
|
|
||||||
|
c = Client()
|
||||||
|
response = c.get('/users/queen_anne')
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertDictEqual(
|
||||||
|
_response_to_dict(response),
|
||||||
|
{
|
||||||
|
'name': 'queen_anne',
|
||||||
|
'id': 'https://altair.example.com/users/queen_anne',
|
||||||
|
'type': 'Person',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
queen_anne.entomb()
|
||||||
|
|
||||||
|
response = c.get('/users/queen_anne')
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 410)
|
||||||
|
self.assertDictEqual(
|
||||||
|
_response_to_dict(response),
|
||||||
|
{
|
||||||
|
'id': 'https://altair.example.com/users/queen_anne',
|
||||||
|
'type': 'Tombstone',
|
||||||
|
'former_type': 'Person',
|
||||||
|
'name': 'queen_anne',
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
Ładowanie…
Reference in New Issue