diff --git a/aleksis/apps/matrix/filters.py b/aleksis/apps/matrix/filters.py index ac7c9184431babd64be2c969e8737a35ca2df0c9..fe145bec6db2c98d03120f959eb8c10de3f19ae4 100644 --- a/aleksis/apps/matrix/filters.py +++ b/aleksis/apps/matrix/filters.py @@ -2,4 +2,4 @@ from aleksis.core.filters import GroupFilter class GroupMatrixRoomFilter(GroupFilter): - pass + """Custom filter for groups on Matrix room overview.""" diff --git a/aleksis/apps/matrix/model_extensions.py b/aleksis/apps/matrix/model_extensions.py index ab620422e697417717caa69f7d7519761abdfdbb..04057970c013522d3fd33b7569479fe78e2b4476 100644 --- a/aleksis/apps/matrix/model_extensions.py +++ b/aleksis/apps/matrix/model_extensions.py @@ -10,7 +10,7 @@ from aleksis.core.models import Group @Group.method -def use_in_matrix(self, sync=False) -> Union[MatrixRoom, AsyncResult]: +def use_in_matrix(self, sync: bool = False) -> Union[MatrixRoom, AsyncResult]: """Create and sync a room for this group in Matrix.""" if sync: return self._use_in_matrix() @@ -19,7 +19,7 @@ def use_in_matrix(self, sync=False) -> Union[MatrixRoom, AsyncResult]: @Group.method -def _use_in_matrix(self): +def _use_in_matrix(self) -> MatrixRoom: """Create and sync a room for this group in Matrix.""" room = MatrixRoom.from_group(self) room.sync() diff --git a/aleksis/apps/matrix/models.py b/aleksis/apps/matrix/models.py index 381d555a26b8d94035670eb78e92ee6eaa4630ee..f61ea6dd472c5f1e504aae89b97d4167c3f184c9 100644 --- a/aleksis/apps/matrix/models.py +++ b/aleksis/apps/matrix/models.py @@ -2,7 +2,7 @@ import re from typing import Any, Optional, Union from django.db import models -from django.db.models import Q +from django.db.models import Q, QuerySet from django.template.defaultfilters import slugify from django.utils.translation import gettext_lazy as _ @@ -27,12 +27,14 @@ class MatrixProfile(ExtensibleModel): ) @classmethod - def build_matrix_id(cls, username, homeserver: Optional[str] = None): + def build_matrix_id(cls, username: str, homeserver: Optional[str] = None) -> str: + """Build a Matrix ID from a username.""" homeserver = homeserver or get_site_preferences()["matrix__homeserver_ids"] return f"@{username}:{homeserver}" @classmethod def from_person(cls, person: Person, commit: bool = False) -> Union["MatrixProfile", None]: + """Get or create a Matrix profile from a person.""" if hasattr(person, "matrix_profile"): return person.matrix_profile if not person.user: @@ -65,15 +67,17 @@ class MatrixRoom(ExtensiblePolymorphicModel): @classmethod def get_queryset(cls): + """Get a queryset for only Matrix rooms.""" return cls.objects.not_instance_of(MatrixSpace) @classmethod def build_alias(cls, group: Group) -> str: + """Build a room alias from a group.""" return slugify(group.short_name or group.name) @classmethod def from_group(cls, group: Group) -> "MatrixRoom": - """Create a Matrix room from a group.""" + """Get or create a Matrix room from a group.""" try: room = cls.get_queryset().get(group=group) except cls.DoesNotExist: @@ -119,11 +123,12 @@ class MatrixRoom(ExtensiblePolymorphicModel): @classmethod def _create_room( self, - name, - alias, + name: str, + alias: str, invite: Optional[list[str]] = None, creation_content: Optional[dict] = None, ) -> dict[str, Any]: + """Create a Matrix room.""" body = {"preset": "private_chat", "name": name, "room_alias_name": alias} if invite: @@ -146,6 +151,7 @@ class MatrixRoom(ExtensiblePolymorphicModel): return user_levels def get_members(self) -> list[str]: + """Get all members of this room.""" r = do_matrix_request( "GET", f"rooms/{self.room_id}/members", body={"membership": ["join", "invite"]} ) @@ -170,7 +176,7 @@ class MatrixRoom(ExtensiblePolymorphicModel): return r @classmethod - def get_profiles_for_group(cls, group: Group): + def get_profiles_for_group(cls, group: Group) -> QuerySet: """Get all profile objects for the members/owners of a group.""" existing_profiles = MatrixProfile.objects.filter( Q(person__member_of=group) | Q(person__owner_of=group) @@ -193,7 +199,7 @@ class MatrixRoom(ExtensiblePolymorphicModel): return all_profiles - def get_profiles(self): + def get_profiles(self) -> QuerySet: """Get all profile objects for the members/owners of this group.""" return self.get_profiles_for_group(self.group) @@ -225,6 +231,7 @@ class MatrixRoom(ExtensiblePolymorphicModel): self._set_power_levels(user_levels) def sync_space(self): + """Sync the space for this room.""" if self.group.child_groups.all(): # Do space stuff space = MatrixSpace.from_group(self.group) @@ -250,6 +257,7 @@ class MatrixSpace(MatrixRoom): @classmethod def get_queryset(cls): + """Get a queryset with only Matrix spaces.""" return cls.objects.instance_of(MatrixSpace) @classmethod @@ -260,11 +268,12 @@ class MatrixSpace(MatrixRoom): @classmethod def _create_room( self, - name, - alias, + name: str, + alias: str, invite: Optional[list[str]] = None, creation_content: Optional[dict] = None, ) -> dict[str, Any]: + """Create a Matrix space.""" if not creation_content: creation_content = {} creation_content["type"] = "m.space" @@ -275,7 +284,7 @@ class MatrixSpace(MatrixRoom): r = do_matrix_request("GET", f"rooms/{self.room_id}/state") return [c["state_key"] for c in r if c["type"] == "m.space.child"] - def _add_child(self, room_id: str): + def _add_child(self, room_id: str) -> dict[str, Any]: """Add a child room to this space.""" r = do_matrix_request( "PUT", @@ -287,13 +296,19 @@ class MatrixSpace(MatrixRoom): def sync_children(self): """Sync membership of child spaces and rooms.""" current_children = self.get_children() - child_spaces = MatrixSpace.get_queryset().filter( - group__in=self.group.child_groups.filter(child_groups__isnull=False) - ).values_list("room_id", flat=True) - child_rooms = MatrixRoom.get_queryset().filter( - Q(group__in=self.group.child_groups.filter(child_groups__isnull=True)) - | Q(group=self.group) - ).values_list("room_id", flat=True) + child_spaces = ( + MatrixSpace.get_queryset() + .filter(group__in=self.group.child_groups.filter(child_groups__isnull=False)) + .values_list("room_id", flat=True) + ) + child_rooms = ( + MatrixRoom.get_queryset() + .filter( + Q(group__in=self.group.child_groups.filter(child_groups__isnull=True)) + | Q(group=self.group) + ) + .values_list("room_id", flat=True) + ) child_ids = list(child_spaces) + list(child_rooms) diff --git a/aleksis/apps/matrix/tasks.py b/aleksis/apps/matrix/tasks.py index 20f8d5750efd2bb1fdba97b32afd0ec26345b4f6..59be28ce689ca12c9fb9e3383c4511a1f2c39f46 100644 --- a/aleksis/apps/matrix/tasks.py +++ b/aleksis/apps/matrix/tasks.py @@ -7,12 +7,14 @@ from aleksis.core.models import Group @app.task def sync_room(pk: int): + """Synchronise a Matrix room.""" room = MatrixRoom.objects.get(pk=pk) room.sync() @app.task def use_groups_in_matrix(pks: Sequence[int]): + """Use provided groups in Matrix.""" groups = Group.objects.filter(pk__in=pks) for group in groups: group._use_in_matrix() @@ -20,5 +22,6 @@ def use_groups_in_matrix(pks: Sequence[int]): @app.task def use_group_in_matrix(pk: int): + """Use provided group in Matrix.""" group = Group.objects.get(pk=pk) group._use_in_matrix() diff --git a/aleksis/apps/matrix/util/matrix.py b/aleksis/apps/matrix/util/matrix.py index 8e0463fc313c88efe1086faeffe2626d7e8e7e63..864a3f6ebbbefc34219dad31b94b0ccdfc8459ae 100644 --- a/aleksis/apps/matrix/util/matrix.py +++ b/aleksis/apps/matrix/util/matrix.py @@ -12,13 +12,15 @@ class MatrixException(Exception): pass -def build_url(path): +def build_url(path: str) -> str: + """Build a URL to the Matrix Client Server API.""" return urljoin( urljoin(get_site_preferences()["matrix__homeserver"], "_matrix/client/v3/"), path ) -def get_headers(): +def get_headers() -> dict[str, str]: + """Get the headers for a Matrix Client Server API request.""" return { "Authorization": "Bearer " + get_site_preferences()["matrix__access_token"], } diff --git a/aleksis/apps/matrix/views.py b/aleksis/apps/matrix/views.py index 92c4aafa2655773646a0e2ae0634e0112edc70fb..8da912ade0bdd9852c580cff9e6feebc21202127 100644 --- a/aleksis/apps/matrix/views.py +++ b/aleksis/apps/matrix/views.py @@ -10,6 +10,8 @@ from aleksis.core.models import Group class MatrixRoomListView(PermissionRequiredMixin, SingleTableMixin, FilterView): + """Overview about groups and their Matrix rooms.""" + model = Group template_name = "matrix/room/list.html" permission_required = "matrix.view_matrixrooms_rule"