diff --git a/api/config/settings/common.py b/api/config/settings/common.py index 251167f4e..a20081dd2 100644 --- a/api/config/settings/common.py +++ b/api/config/settings/common.py @@ -884,3 +884,7 @@ FEDERATION_OBJECT_FETCH_DELAY = env.int( MODERATION_EMAIL_NOTIFICATIONS_ENABLED = env.bool( "MODERATION_EMAIL_NOTIFICATIONS_ENABLED", default=True ) + +# Delay in days after signup before we show the "support us" messages +INSTANCE_SUPPORT_MESSAGE_DELAY = env.int("INSTANCE_SUPPORT_MESSAGE_DELAY", default=15) +FUNKWHALE_SUPPORT_MESSAGE_DELAY = env.int("FUNKWHALE_SUPPORT_MESSAGE_DELAY", default=15) diff --git a/api/funkwhale_api/instance/dynamic_preferences_registry.py b/api/funkwhale_api/instance/dynamic_preferences_registry.py index 0d6260a83..be360701d 100644 --- a/api/funkwhale_api/instance/dynamic_preferences_registry.py +++ b/api/funkwhale_api/instance/dynamic_preferences_registry.py @@ -82,6 +82,35 @@ class InstanceContactEmail(types.StringPreference): field_kwargs = {"required": False} +@global_preferences_registry.register +class InstanceSupportMessage(types.StringPreference): + show_in_api = True + section = instance + name = "support_message" + verbose_name = "Support message" + default = "" + help_text = ( + "A short message that will be displayed periodically to local users. " + "Use it to ask for financial support or anything else you might need. " + "(markdown allowed)." + ) + widget = widgets.Textarea + field_kwargs = {"required": False} + + +@global_preferences_registry.register +class InstanceFunkwhaleSupportMessageEnabled(types.BooleanPreference): + show_in_api = True + section = instance + name = "funkwhale_support_message_enabled" + verbose_name = "Funkwhale Support message" + default = True + help_text = ( + "If this is enabled, we will periodically display a message to encourage " + "local users to support Funkwhale." + ) + + @global_preferences_registry.register class RavenDSN(types.StringPreference): show_in_api = True diff --git a/api/funkwhale_api/instance/nodeinfo.py b/api/funkwhale_api/instance/nodeinfo.py index ebeee2b03..712578c3c 100644 --- a/api/funkwhale_api/instance/nodeinfo.py +++ b/api/funkwhale_api/instance/nodeinfo.py @@ -63,6 +63,10 @@ def get(): {"type": t, "label": l, "anonymous": t in unauthenticated_report_types} for t, l in moderation_models.REPORT_TYPES ], + "funkwhaleSupportMessageEnabled": all_preferences.get( + "instance__funkwhale_support_message_enabled" + ), + "instanceSupportMessage": all_preferences.get("instance__support_message"), }, } diff --git a/api/funkwhale_api/users/admin.py b/api/funkwhale_api/users/admin.py index cd372e80a..24f08d026 100644 --- a/api/funkwhale_api/users/admin.py +++ b/api/funkwhale_api/users/admin.py @@ -90,6 +90,15 @@ class UserAdmin(AuthUserAdmin): }, ), (_("Important dates"), {"fields": ("last_login", "date_joined")}), + ( + _("Other"), + { + "fields": ( + "instance_support_message_display_date", + "funkwhale_support_message_display_date", + ) + }, + ), (_("Useless fields"), {"fields": ("user_permissions", "groups")}), ) diff --git a/api/funkwhale_api/users/migrations/0016_auto_20190920_0857.py b/api/funkwhale_api/users/migrations/0016_auto_20190920_0857.py new file mode 100644 index 000000000..a3fc6cf26 --- /dev/null +++ b/api/funkwhale_api/users/migrations/0016_auto_20190920_0857.py @@ -0,0 +1,47 @@ +# Generated by Django 2.2.4 on 2019-09-20 08:57 + +import datetime +from django.conf import settings + +from django.db import migrations, models +import django.utils.timezone +import funkwhale_api.users.models + + +def set_display_date(apps, schema_editor): + """ + Set display date for instance/funkwhale support message on existing users + """ + User = apps.get_model("users", "User") + now = django.utils.timezone.now() + instance_support_message_display_date = now + datetime.timedelta(days=settings.INSTANCE_SUPPORT_MESSAGE_DELAY) + funkwhale_support_message_display_date = now + datetime.timedelta(days=settings.FUNKWHALE_SUPPORT_MESSAGE_DELAY) + + User.objects.update(instance_support_message_display_date=instance_support_message_display_date) + User.objects.update(funkwhale_support_message_display_date=funkwhale_support_message_display_date) + + +def rewind(*args, **kwargs): + pass + + + +class Migration(migrations.Migration): + + dependencies = [ + ('users', '0015_application_scope'), + ] + + operations = [ + migrations.AddField( + model_name='user', + name='funkwhale_support_message_display_date', + field=models.DateTimeField(blank=True, null=True, default=funkwhale_api.users.models.get_default_funkwhale_support_message_display_date), + ), + migrations.AddField( + model_name='user', + name='instance_support_message_display_date', + field=models.DateTimeField(blank=True, null=True, default=funkwhale_api.users.models.get_default_instance_support_message_display_date), + ), + migrations.RunPython(set_display_date, rewind), + ] diff --git a/api/funkwhale_api/users/models.py b/api/funkwhale_api/users/models.py index 44bb06d2b..2a2f875a6 100644 --- a/api/funkwhale_api/users/models.py +++ b/api/funkwhale_api/users/models.py @@ -82,6 +82,18 @@ PERMISSIONS = sorted(PERMISSIONS_CONFIGURATION.keys()) get_file_path = common_utils.ChunkedPath("users/avatars", preserve_file_name=False) +def get_default_instance_support_message_display_date(): + return timezone.now() + datetime.timedelta( + days=settings.INSTANCE_SUPPORT_MESSAGE_DELAY + ) + + +def get_default_funkwhale_support_message_display_date(): + return timezone.now() + datetime.timedelta( + days=settings.FUNKWHALE_SUPPORT_MESSAGE_DELAY + ) + + @python_2_unicode_compatible class User(AbstractUser): @@ -149,6 +161,15 @@ class User(AbstractUser): upload_quota = models.PositiveIntegerField(null=True, blank=True) + instance_support_message_display_date = models.DateTimeField( + default=get_default_instance_support_message_display_date, null=True, blank=True + ) + funkwhale_support_message_display_date = models.DateTimeField( + default=get_default_funkwhale_support_message_display_date, + null=True, + blank=True, + ) + def __str__(self): return self.username diff --git a/api/funkwhale_api/users/serializers.py b/api/funkwhale_api/users/serializers.py index 67171b49b..cddc2e82a 100644 --- a/api/funkwhale_api/users/serializers.py +++ b/api/funkwhale_api/users/serializers.py @@ -109,7 +109,13 @@ class UserWriteSerializer(serializers.ModelSerializer): class Meta: model = models.User - fields = ["name", "privacy_level", "avatar"] + fields = [ + "name", + "privacy_level", + "avatar", + "instance_support_message_display_date", + "funkwhale_support_message_display_date", + ] class UserReadSerializer(serializers.ModelSerializer): @@ -146,7 +152,11 @@ class MeSerializer(UserReadSerializer): quota_status = serializers.SerializerMethodField() class Meta(UserReadSerializer.Meta): - fields = UserReadSerializer.Meta.fields + ["quota_status"] + fields = UserReadSerializer.Meta.fields + [ + "quota_status", + "instance_support_message_display_date", + "funkwhale_support_message_display_date", + ] def get_quota_status(self, o): return o.get_quota_status() if o.actor else 0 diff --git a/api/tests/instance/test_nodeinfo.py b/api/tests/instance/test_nodeinfo.py index c765ba4f9..2e9075d26 100644 --- a/api/tests/instance/test_nodeinfo.py +++ b/api/tests/instance/test_nodeinfo.py @@ -87,6 +87,10 @@ def test_nodeinfo_dump(preferences, mocker, avatar): }, {"type": "other", "label": "Other", "anonymous": True}, ], + "funkwhaleSupportMessageEnabled": preferences[ + "instance__funkwhale_support_message_enabled" + ], + "instanceSupportMessage": preferences["instance__support_message"], }, } assert nodeinfo.get() == expected @@ -151,6 +155,10 @@ def test_nodeinfo_dump_stats_disabled(preferences, mocker): }, {"type": "other", "label": "Other", "anonymous": True}, ], + "funkwhaleSupportMessageEnabled": preferences[ + "instance__funkwhale_support_message_enabled" + ], + "instanceSupportMessage": preferences["instance__support_message"], }, } assert nodeinfo.get() == expected diff --git a/api/tests/users/test_models.py b/api/tests/users/test_models.py index 973316424..7552094ae 100644 --- a/api/tests/users/test_models.py +++ b/api/tests/users/test_models.py @@ -220,3 +220,20 @@ def test_user_get_quota_status(factories, preferences, mocker): "errored": 3, "finished": 4, } + + +@pytest.mark.parametrize( + "setting_name, field", + [ + ("INSTANCE_SUPPORT_MESSAGE_DELAY", "instance_support_message_display_date"), + ("FUNKWHALE_SUPPORT_MESSAGE_DELAY", "funkwhale_support_message_display_date"), + ], +) +def test_creating_user_set_support_display_date( + setting_name, field, settings, factories, now +): + setattr(settings, setting_name, 66) # display message every 66 days + expected = now + datetime.timedelta(days=66) + user = factories["users.User"]() + + assert getattr(user, field) == expected diff --git a/changes/changelog.d/839.feature b/changes/changelog.d/839.feature new file mode 100644 index 000000000..7f72f000c --- /dev/null +++ b/changes/changelog.d/839.feature @@ -0,0 +1 @@ +Added periodical message to incite people to support their pod and Funkwhale (#839) diff --git a/changes/notes.rst b/changes/notes.rst index 51c53e857..4a9d1eddb 100644 --- a/changes/notes.rst +++ b/changes/notes.rst @@ -113,6 +113,16 @@ your pod. If you want to enable this feature on your pod, or learn more, please refer to `our documentation `_! +Periodic message to incite people to support their pod and Funkwhale +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Users will now be reminded on a regular basis that they can help Funkwhale by donating or contributing. + +If specified by the pod admin, a separate and custom message will also be displayed in a similar way to provide instructions and links to support the pod. + +Both messages will appear for the first time 15 days after signup, in the notifications tab. For each message, users can schedule a reminder for a later time, or disable the messages entirely. + + Replaced Daphne by Gunicorn/Uvicorn [manual action required, non-docker only] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/front/src/components/Sidebar.vue b/front/src/components/Sidebar.vue index d35d040d6..9b99e6a27 100644 --- a/front/src/components/Sidebar.vue +++ b/front/src/components/Sidebar.vue @@ -46,9 +46,9 @@ Notifications
- {{ $store.state.ui.notifications.inbox }}
+ {{ $store.state.ui.notifications.inbox + additionalNotifications }} Logout