From 2f4bea192bf45fe619d0c9662d99173751e2349b Mon Sep 17 00:00:00 2001
From: Jonathan Weth <git@jonathanweth.de>
Date: Sun, 20 Feb 2022 16:44:14 +0100
Subject: [PATCH] Add preferences for power level setting

---
 aleksis/apps/matrix/models.py            | 17 +++---
 aleksis/apps/matrix/preferences.py       | 28 +++++++++-
 aleksis/apps/matrix/tests/test_matrix.py | 68 ++++++++++++++++++++++++
 3 files changed, 106 insertions(+), 7 deletions(-)

diff --git a/aleksis/apps/matrix/models.py b/aleksis/apps/matrix/models.py
index 71dcf1c..af52611 100644
--- a/aleksis/apps/matrix/models.py
+++ b/aleksis/apps/matrix/models.py
@@ -191,7 +191,7 @@ class MatrixRoom(ExtensiblePolymorphicModel):
 
         all_profiles = MatrixProfile.objects.filter(
             Q(person__in=group.members.all()) | Q(person__in=group.owners.all())
-        )
+        ).distinct()
 
         return all_profiles
 
@@ -211,14 +211,19 @@ class MatrixRoom(ExtensiblePolymorphicModel):
                 self._invite(profile)
 
         # Set power levels for all users
-        # Mod = 50 = Owners
-        # User = 0 = Members
         user_levels = self.power_levels
         for profile in all_profiles:
             if profile.person in self.group.owners.all():
-                user_levels[profile.matrix_id] = 50
-            elif profile.person in self.group.members.all():
-                user_levels[profile.matrix_id] = 0
+                power_level = get_site_preferences()["matrix__power_level_for_owners"]
+            else:
+                power_level = get_site_preferences()["matrix__power_level_for_members"]
+
+            if (
+                profile.matrix_id not in user_levels
+                or user_levels[profile.matrix_id] < power_level
+                or get_site_preferences()["matrix__reduce_power_levels"]
+            ):
+                user_levels[profile.matrix_id] = power_level
         self._set_power_levels(user_levels)
 
     def sync_space(self):
diff --git a/aleksis/apps/matrix/preferences.py b/aleksis/apps/matrix/preferences.py
index 123be1c..6722633 100644
--- a/aleksis/apps/matrix/preferences.py
+++ b/aleksis/apps/matrix/preferences.py
@@ -1,7 +1,7 @@
 from django.utils.translation import gettext as _
 
 from dynamic_preferences.preferences import Section
-from dynamic_preferences.types import BooleanPreference, StringPreference
+from dynamic_preferences.types import BooleanPreference, IntegerPreference, StringPreference
 
 from aleksis.core.registries import site_preferences_registry
 
@@ -47,3 +47,29 @@ class UseSpaces(BooleanPreference):
     name = "use_spaces"
     verbose_name = _("Use Matrix spaces")
     default = True
+
+
+@site_preferences_registry.register
+class ReducePowerLevels(BooleanPreference):
+    section = matrix
+    name = "reduce_power_levels"
+    verbose_name = _("Reduce existing power levels")
+    default = False
+
+
+@site_preferences_registry.register
+class PowerLevelForOwners(IntegerPreference):
+    section = matrix
+    name = "power_level_for_owners"
+    verbose_name = _("Power level for owners")
+    default = 50
+    required = True
+
+
+@site_preferences_registry.register
+class PowerLevelForMembers(IntegerPreference):
+    section = matrix
+    name = "power_level_for_members"
+    verbose_name = _("Power level for members")
+    default = 0
+    required = True
diff --git a/aleksis/apps/matrix/tests/test_matrix.py b/aleksis/apps/matrix/tests/test_matrix.py
index 71530bb..cd05c50 100644
--- a/aleksis/apps/matrix/tests/test_matrix.py
+++ b/aleksis/apps/matrix/tests/test_matrix.py
@@ -121,6 +121,9 @@ def test_room_alias_collision_school_term(matrix_bot_user):
 
 def test_sync_room_members(matrix_bot_user):
     get_site_preferences()["matrix__homeserver_ids"] = "matrix.aleksis.example.org"
+    get_site_preferences()["matrix__reduce_power_levels"] = False
+    get_site_preferences()["matrix__power_level_for_owners"] = 50
+    get_site_preferences()["matrix__power_level_for_members"] = 0
 
     g = Group.objects.create(name="Test Room")
     u1 = User.objects.create_user("test1", "test1@example.org", "test1")
@@ -183,6 +186,71 @@ def test_sync_room_members(matrix_bot_user):
         break
 
 
+def test_power_levels(matrix_bot_user):
+    get_site_preferences()["matrix__homeserver_ids"] = "matrix.aleksis.example.org"
+    get_site_preferences()["matrix__power_level_for_owners"] = 55
+    get_site_preferences()["matrix__power_level_for_members"] = 11
+    get_site_preferences()["matrix__reduce_power_levels"] = False
+
+    g = Group.objects.create(name="Test Room")
+    u1 = User.objects.create_user("test1", "test1@example.org", "test1")
+    u2 = User.objects.create_user("test2", "test2@example.org", "test2")
+
+    p1 = Person.objects.create(first_name="Test", last_name="Person", user=u1)
+    p2 = Person.objects.create(first_name="Test 2", last_name="Person", user=u2)
+
+    g.members.set([p1])
+    g.owners.set([p2])
+
+    room = MatrixRoom.from_group(g)
+    room.sync_profiles()
+
+    # Get power levels
+    r = do_matrix_request("GET", f"rooms/{room.room_id}/state")
+    for event in r:
+        if not event["type"] == "m.room.power_levels":
+            continue
+        current_power_levels = event["content"]["users"]
+
+        assert current_power_levels[p1.matrix_profile.matrix_id] == 11
+        assert current_power_levels[p2.matrix_profile.matrix_id] == 55
+
+        break
+
+    # Test reducing of power levels
+    g.owners.set([])
+    g.members.set([p1, p2])
+
+    room.sync_profiles()
+
+    # Not reduced here
+    r = do_matrix_request("GET", f"rooms/{room.room_id}/state")
+    for event in r:
+        if not event["type"] == "m.room.power_levels":
+            continue
+        current_power_levels = event["content"]["users"]
+
+        assert current_power_levels[p1.matrix_profile.matrix_id] == 11
+        assert current_power_levels[p2.matrix_profile.matrix_id] == 55
+
+        break
+
+    get_site_preferences()["matrix__reduce_power_levels"] = True
+    room.sync_profiles()
+
+    # Reduced here
+    r = do_matrix_request("GET", f"rooms/{room.room_id}/state")
+    for event in r:
+        if not event["type"] == "m.room.power_levels":
+            continue
+        current_power_levels = event["content"]["users"]
+
+        assert current_power_levels[p1.matrix_profile.matrix_id] == 11
+        assert current_power_levels[p2.matrix_profile.matrix_id] == 11
+
+        break
+
+
 def test_sync_room_members_without_user(matrix_bot_user):
 
     get_site_preferences()["matrix__homeserver_ids"] = "matrix.aleksis.example.org"
-- 
GitLab