Skip to content

Commit

Permalink
Support giving a reason for all membership API
Browse files Browse the repository at this point in the history
Implement MSC2367 (matrix-org/matrix-spec-proposals#2367),
already supported by synapse: allow giving a reason when joining,
leaving, inviting, and unbanning in addition to kicking and banning.
  • Loading branch information
mirukana committed Mar 29, 2021
1 parent 190ec1b commit d1313ca
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 23 deletions.
27 changes: 18 additions & 9 deletions mio/rooms/room.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from dataclasses import dataclass, field
from pathlib import Path
from typing import TYPE_CHECKING, List, Set, Tuple
from typing import TYPE_CHECKING, List, Optional, Set, Tuple

from ..core.callbacks import CallbackGroup, Callbacks, EventCallbacks
from ..core.data import JSONFile, Parent, Runtime
from ..core.types import RoomAlias, RoomId, UserId
from ..core.utils import remove_none
from .state import RoomState
from .timeline import Timeline

Expand Down Expand Up @@ -75,23 +76,31 @@ async def create_alias(self, alias: RoomAlias) -> None:
)


async def invite(self, user_id: UserId) -> None:
url = self.client.api / "rooms" / self.id / "invite"
await self.client.send_json("POST", url, {"user_id": user_id})
async def invite(
self, user_id: UserId, reason: Optional[str] = None,
) -> None:
await self.client.send_json(
"POST",
self.client.api / "rooms" / self.id / "invite",
remove_none({"user_id": user_id, "reason": reason}),
)


async def leave(self) -> None:
url = self.client.api / "rooms" / self.id / "leave"
await self.client.send_json("POST", url)
async def leave(self, reason: Optional[str] = None) -> None:
await self.client.send_json(
"POST",
self.client.api / "rooms" / self.id / "leave",
remove_none({"reason": reason}),
)


async def forget(self) -> None:
async def forget(self, leave_reason: Optional[str] = None) -> None:
# Prevent a sync from occuring AFTER leaving room, but BEFORE having
# marked it as forgotten. We will get a "we left" event on next sync,
# which we must ignore if we know we forgot the room.
with self.client.sync.pause():
if not self.left:
await self.leave()
await self.leave(leave_reason)

url = self.client.api / "rooms" / self.id / "forget"
await self.client.send_json("POST", url)
Expand Down
15 changes: 12 additions & 3 deletions mio/rooms/rooms.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,9 +139,18 @@ async def create(
return result["room_id"]


async def join(self, id_or_alias: Union[RoomId, RoomAlias]) -> RoomId:
url = self.client.api / "join" / id_or_alias
result = await self.client.send_json("POST", url)
async def join(
self,
id_or_alias: Union[RoomId, RoomAlias],
reason: Optional[str] = None,
) -> RoomId:

result = await self.client.send_json(
"POST",
self.client.api / "join" / id_or_alias,
remove_none({"reason": reason}),
)

return result["room_id"]


Expand Down
9 changes: 5 additions & 4 deletions mio/rooms/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

from ..core.data import Parent
from ..core.types import MXC, UserId
from ..core.utils import remove_none
from .contents.users import Member
from .events import StateBase

Expand Down Expand Up @@ -90,21 +91,21 @@ async def kick(self, reason: Optional[str] = None) -> None:
await self.room.client.send_json(
"POST",
self.room.client.api / "rooms" / self.room.id / "kick",
{"user_id": self.user_id, "reason": reason},
remove_none({"user_id": self.user_id, "reason": reason}),
)


async def ban(self, reason: Optional[str] = None) -> None:
await self.room.client.send_json(
"POST",
self.room.client.api / "rooms" / self.room.id / "ban",
{"user_id": self.user_id, "reason": reason},
remove_none({"user_id": self.user_id, "reason": reason}),
)


async def unban(self) -> None:
async def unban(self, reason: Optional[str] = None) -> None:
await self.room.client.send_json(
"POST",
self.room.client.api / "rooms" / self.room.id / "unban",
{"user_id": self.user_id},
remove_none({"user_id": self.user_id, "reason": reason}),
)
12 changes: 9 additions & 3 deletions tests/test_room.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,33 +35,39 @@ async def test_create_alias(room: Room):

async def test_invite(room: Room, bob: Client):
assert room.id not in bob.rooms
await room.invite(bob.user_id)
await room.invite(bob.user_id, reason="test")
await bob.sync.once()
assert room.id in bob.rooms.invited
assert bob.rooms[room.id].state.me.membership_reason == "test"


async def test_leave(e2e_room: Room):
await e2e_room.timeline.send(Text("make a session"))
assert e2e_room.id in e2e_room.client._e2e.out_group_sessions

await e2e_room.leave()
await e2e_room.leave(reason="bye")
await e2e_room.client.sync.once()
assert e2e_room.left
assert e2e_room.id not in e2e_room.client._e2e.out_group_sessions
assert e2e_room.state.me.membership_reason == "bye"


async def test_forget(room: Room, bob: Client):
# Server will destroy the room if there's only one user in who forgets it
await bob.rooms.join(room.id)

assert not room.left
await room.forget()
await room.forget(leave_reason="bye")
await room.client.sync.once()

assert room.left
assert room.id not in room.client.rooms
assert room.id in room.client.rooms.forgotten

await bob.sync.once()
bob_members = bob.rooms[room.id].state.leavers
assert bob_members[room.client.user_id].membership_reason == "bye"

# Make sure events are not ignored if we rejoin or get invited again
await room.client.rooms.join(room.id)
await room.client.sync.once()
Expand Down
4 changes: 2 additions & 2 deletions tests/test_room_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ async def test_ban_unban(alice: Client, bob: Client, room: Room):
with raises(MatrixError):
await bob.rooms.join(room.id)

await room.state.banned[bob.user_id].unban()
await room.state.banned[bob.user_id].unban("mistake")
await alice.sync.once()
assert room.state.leavers[bob.user_id].banned_by is None
assert room.state.leavers[bob.user_id].membership_reason is None
assert room.state.leavers[bob.user_id].membership_reason == "mistake"

await bob.rooms.join(room.id)
6 changes: 4 additions & 2 deletions tests/test_rooms.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,10 @@ async def test_join_room_id(room: Room, bob: Client):
await bob.sync.once()
assert room.id not in bob.rooms

await bob.rooms.join(room.id)
await bob.rooms.join(room.id, reason="test")
await bob.sync.once()
assert room.id in bob.rooms
assert bob.rooms[room.id].state.me.membership_reason == "test"


async def test_join_room_alias(room: Room, bob: Client):
Expand All @@ -180,6 +181,7 @@ async def test_join_room_alias(room: Room, bob: Client):
await bob.sync.once()
assert room.id not in bob.rooms

await bob.rooms.join(alias)
await bob.rooms.join(alias, reason="test")
await bob.sync.once()
assert room.id in bob.rooms
assert bob.rooms[room.id].state.me.membership_reason == "test"

0 comments on commit d1313ca

Please sign in to comment.