new Audience model, plus tests. Not yet linked in to Thing.

2019-08-17
Marnanel Thurman 2019-06-05 00:07:05 +01:00
rodzic 63a3a82356
commit 51b8d7f347
4 zmienionych plików z 220 dodań i 6 usunięć

Wyświetl plik

@ -0,0 +1,28 @@
# Generated by Django 2.2.1 on 2019-06-04 17:52
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('django_kepi', '0002_auto_20190527_1458'),
]
operations = [
migrations.AlterField(
model_name='thing',
name='f_type',
field=models.CharField(choices=[('Accept', 'Accept'), ('Add', 'Add'), ('Create', 'Create'), ('Delete', 'Delete'), ('Follow', 'Follow'), ('Like', 'Like'), ('Reject', 'Reject'), ('Remove', 'Remove'), ('Undo', 'Undo'), ('Update', 'Update')], max_length=255),
),
migrations.CreateModel(
name='Audience',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('field', models.PositiveSmallIntegerField(choices=[(1, 'audience'), (2, 'to'), (4, 'cc'), (114, 'bto'), (116, 'bcc')])),
('recipient', models.CharField(max_length=255)),
('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='django_kepi.Thing')),
],
),
]

Wyświetl plik

@ -1,11 +1,7 @@
from django_kepi.models.thing import Thing, ThingField, create
from django_kepi.models.following import Following
from django_kepi.models.actor import Actor
def new_activity_identifier():
# we have to keep this in for now,
# to pacify makemigrations
return None
from django_kepi.models.audience import Audience
#######################
@ -15,5 +11,5 @@ __all__ = [
'ThingField',
'create',
'Following',
'new_activity_identifier',
'Audience',
]

Wyświetl plik

@ -0,0 +1,113 @@
from django.db import models
from collections import defaultdict
import logging
logger = logging.getLogger('django_kepi')
FIELD_AUDIENCE = 0x01 # literally "audience"
FIELD_TO = 0x02
FIELD_CC = 0x04
BLIND = 0x70
FIELD_BTO = BLIND + FIELD_TO
FIELD_BCC = BLIND + FIELD_CC
# the spec doesn't allow for blind audience; idk why
FIELD_CHOICES = [
(FIELD_AUDIENCE, 'audience'),
(FIELD_TO, 'to'),
(FIELD_CC, 'cc'),
(FIELD_BTO, 'bto'),
(FIELD_BCC, 'bcc'),
]
FIELD_NAMES = dict([(v,f) for (f,v) in FIELD_CHOICES])
class Audience(models.Model):
parent = models.ForeignKey(
'django_kepi.Thing',
on_delete = models.CASCADE,
)
field = models.PositiveSmallIntegerField(
choices = FIELD_CHOICES,
)
recipient = models.CharField(
max_length=255,
)
@property
def blind(self):
return (self.field & BLIND) != 0
def __str__(self):
return '[%s %12s %s]' % (
self.parent.number,
self.get_field_display(),
self.recipient,
)
@classmethod
def add_audiences_for(cls, thing,
field, value):
"""
Add new Audiences for a given Thing.
"value" is a list of strings.
This function only adds Audiences of
a single field type. This is
deliberately asymmetrical to
get_audiences_for(), which returns
all Audiences of all field types.
The difference is because of
where it's needed.
"""
if field not in FIELD_NAMES:
raise ValueError('%s is not an audience field' % (
field,
))
logger.debug('Adding Audiences for %s: %s=%s',
thing.number, field, value)
field = FIELD_NAMES[field]
if not isinstance(value, list):
value = [value]
for line in value:
a = Audience(
parent = thing,
field = field,
recipient = str(line),
)
a.save()
logger.debug(' -- created %s',
a)
@classmethod
def get_audiences_for(cls, thing,
hide_blind = False,
):
result = defaultdict(lambda: [])
for a in Audience.objects.filter(
parent=thing,
):
if hide_blind and a.blind:
logger.debug('Not counting %s because blind fields are hidden',
a)
continue
result[a.get_field_display()].append(a.recipient)
result = dict(result)
logger.debug('Audience is: %s', result)
return result

Wyświetl plik

@ -0,0 +1,77 @@
from django.test import TestCase
from django_kepi.models import create, Audience
from . import create_local_person, REMOTE_FRED, REMOTE_JIM
class TestAudience(TestCase):
def test_add_audiences_for(self):
narcissus = create_local_person(
name = 'narcissus',
)
like = create(
f_type = 'Like',
f_actor = narcissus,
f_object = narcissus,
)
a = Audience.add_audiences_for(
thing = like,
field = 'to',
value = [
REMOTE_FRED,
REMOTE_JIM,
],
)
results = Audience.objects.filter(
parent = like,
)
self.assertEqual(len(results), 2)
self.assertEqual(results[0].recipient, REMOTE_FRED)
self.assertEqual(results[1].recipient, REMOTE_JIM)
def test_get_audiences_for(self):
narcissus = create_local_person(
name = 'narcissus',
)
like = create(
f_type = 'Like',
f_actor = narcissus,
f_object = narcissus,
)
for fieldname in ['to', 'cc', 'bcc']:
a = Audience.add_audiences_for(
thing = like,
field = fieldname,
value = [
REMOTE_FRED,
REMOTE_JIM,
],
)
self.assertDictEqual(
Audience.get_audiences_for(like),
{'to': ['https://remote.example.org/users/fred',
'https://remote.example.org/users/jim'],
'cc': ['https://remote.example.org/users/fred',
'https://remote.example.org/users/jim'],
'bcc': ['https://remote.example.org/users/fred',
'https://remote.example.org/users/jim']
})
self.assertDictEqual(
Audience.get_audiences_for(like,
hide_blind = True,
),
{'to': ['https://remote.example.org/users/fred',
'https://remote.example.org/users/jim'],
'cc': ['https://remote.example.org/users/fred',
'https://remote.example.org/users/jim'],
})