Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
petitminion
funkwhale
Commits
76937363
Verified
Commit
76937363
authored
Jul 25, 2019
by
Eliot Berriot
Browse files
WIP service messages
parent
ba4039fb
Changes
7
Hide whitespace changes
Inline
Side-by-side
api/funkwhale_api/common/factories.py
View file @
76937363
...
...
@@ -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"
api/funkwhale_api/common/migrations/0004_auto_20190725_1510.py
0 → 100644
View file @
76937363
# 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
,
),
),
],
),
]
api/funkwhale_api/common/models.py
View file @
76937363
...
...
@@ -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
)
api/funkwhale_api/common/serializers.py
View file @
76937363
...
...
@@ -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
api/funkwhale_api/common/tasks.py
View file @
76937363
...
...
@@ -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
)
api/tests/common/test_serializers.py
View file @
76937363
...
...
@@ -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
api/tests/common/test_tasks.py
View file @
76937363
...
...
@@ -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
)
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment