Verified Commit 76937363 authored by Eliot Berriot's avatar Eliot Berriot
Browse files

WIP service messages

parent ba4039fb
......@@ -3,6 +3,7 @@ import factory
from funkwhale_api.factories import registry, NoUpdateOnCreate
from funkwhale_api.federation import factories as federation_factories
from funkwhale_api.users import factories as users_factories
@registry.register
......@@ -23,3 +24,26 @@ class MutationFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory):
return
self.target = extracted
self.save()
@registry.register
class ServiceMessageFactory(NoUpdateOnCreate, factory.django.DjangoModelFactory):
code = factory.Faker("word")
title = factory.Faker("paragraph")
content = factory.Faker("paragraph")
expiration_date = None
class Meta:
model = "common.ServiceMessage"
@registry.register
class ServiceMessageNotificationFactory(
NoUpdateOnCreate, factory.django.DjangoModelFactory
):
user = factory.SubFactory(users_factories.UserFactory)
service_message = factory.SubFactory(ServiceMessageFactory)
is_read = False
class Meta:
model = "common.ServiceMessageNotification"
# Generated by Django 2.2.3 on 2019-07-25 15:10
from django.conf import settings
import django.contrib.postgres.fields.jsonb
import django.core.serializers.json
from django.db import migrations, models
import django.db.models.deletion
import django.utils.timezone
import uuid
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("common", "0003_cit_extension"),
]
operations = [
migrations.CreateModel(
name="ServiceMessage",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
(
"code",
models.CharField(
db_index=True, default=uuid.uuid4, max_length=255, unique=True
),
),
("title", models.CharField(max_length=255, null=True)),
("content", models.TextField(max_length=255, null=True)),
(
"creation_date",
models.DateTimeField(default=django.utils.timezone.now),
),
("expiration_date", models.DateTimeField(null=True)),
],
),
migrations.CreateModel(
name="ServiceMessageNotification",
fields=[
(
"id",
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("is_read", models.BooleanField(default=False)),
(
"service_message",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="notifications",
to="common.ServiceMessage",
),
),
(
"user",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="service_message_notifications",
to=settings.AUTH_USER_MODEL,
),
),
],
),
]
......@@ -150,3 +150,26 @@ class Mutation(models.Model):
self.applied_date = timezone.now()
self.save(update_fields=["is_applied", "applied_date", "previous_state"])
return previous_state
class ServiceMessage(models.Model):
code = models.CharField(
unique=True, db_index=True, default=uuid.uuid4, max_length=255
)
title = models.CharField(null=True, max_length=255)
content = models.TextField(null=True, max_length=255)
creation_date = models.DateTimeField(default=timezone.now)
expiration_date = models.DateTimeField(null=True)
class ServiceMessageNotification(models.Model):
service_message = models.ForeignKey(
ServiceMessage, related_name="notifications", on_delete=models.CASCADE
)
user = models.ForeignKey(
"users.User",
related_name="service_message_notifications",
on_delete=models.CASCADE,
)
is_read = models.BooleanField(default=False)
......@@ -272,3 +272,20 @@ class APIMutationSerializer(serializers.ModelSerializer):
if value not in self.context["registry"]:
raise serializers.ValidationError("Invalid mutation type {}".format(value))
return value
class ServiceMessageSerializer(serializers.ModelSerializer):
class Meta:
model = models.ServiceMessage
fields = ["code", "title", "content", "creation_date", "expiration_date"]
class ServiceMessageNotificationSerializer(serializers.Serializer):
class Meta:
model = models.ServiceMessageNotification
fields = ["is_read"]
def to_representation(self, instance):
data = ServiceMessageSerializer(instance.service_message).data
data["is_read"] = instance.is_read
return data
......@@ -4,6 +4,7 @@ from django.dispatch import receiver
from funkwhale_api.common import channels
from funkwhale_api.taskapp import celery
from funkwhale_api.users.models import User
from . import models
from . import serializers
......@@ -57,3 +58,24 @@ def broadcast_mutation_update(mutation, old_is_approved, new_is_approved, **kwar
},
},
)
@celery.app.task(name="common.broadcast_service_message")
@transaction.atomic
@celery.require_instance(models.ServiceMessage.objects.all(), "message")
def broadcast_service_message(message, user_ids):
existing_ids = list(
User.objects.filter(pk__in=user_ids).values_list("pk", flat=True)
)
notifications = []
for user_id in existing_ids:
notifications.append(
models.ServiceMessageNotification(
service_message_id=message.pk, user_id=user_id
)
)
models.ServiceMessageNotification.objects.bulk_create(
notifications, batch_size=2000, ignore_conflicts=True
)
......@@ -182,3 +182,21 @@ def test_strip_exif_field():
cleaned = PIL.Image.open(field.to_internal_value(uploaded))
assert cleaned._getexif() is None
def test_message_notification_serializer(factories, now):
notification = factories["common.ServiceMessageNotification"](
service_message__expiration_date=now
)
message = notification.service_message
expected = {
"code": message.code,
"title": message.title,
"content": message.content,
"creation_date": message.creation_date.isoformat().split("+")[0] + "Z",
"expiration_date": message.expiration_date.isoformat().split("+")[0] + "Z",
"is_read": False,
}
serializer = serializers.ServiceMessageNotificationSerializer(notification)
assert serializer.data == expected
......@@ -63,3 +63,28 @@ def test_cannot_apply_already_applied_migration(factories):
mutation = factories["common.Mutation"](payload={}, is_applied=True)
with pytest.raises(mutation.__class__.DoesNotExist):
tasks.apply_mutation(mutation_id=mutation.pk)
def test_can_broadcast_service_message(factories, now):
message = factories["common.ServiceMessage"](
code="test", content="Hello world", expiration_date=now
)
user1 = factories["users.User"]()
user2 = factories["users.User"]()
factories["users.User"]()
tasks.broadcast_service_message(
message_id=message.pk, user_ids=[user1.pk, user2.pk]
)
assert message.notifications.count() == 2
assert (
user1.service_message_notifications.get(service_message=message).is_read
is False
)
assert (
user2.service_message_notifications.get(service_message=message).is_read
is False
)
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment