diff --git a/Tests/LibMatrix.HomeserverEmulator/Controllers/Rooms/RoomStateController.cs b/Tests/LibMatrix.HomeserverEmulator/Controllers/Rooms/RoomStateController.cs
index 3896ac0..a1738c9 100644
--- a/Tests/LibMatrix.HomeserverEmulator/Controllers/Rooms/RoomStateController.cs
+++ b/Tests/LibMatrix.HomeserverEmulator/Controllers/Rooms/RoomStateController.cs
@@ -1,4 +1,5 @@
using System.Collections.Frozen;
+using System.Text.Json.Nodes;
using LibMatrix.HomeserverEmulator.Extensions;
using LibMatrix.HomeserverEmulator.Services;
using Microsoft.AspNetCore.Mvc;
@@ -73,12 +74,12 @@ public class RoomStateController(ILogger<RoomStateController> logger, TokenServi
}
[HttpPut("{eventType}")]
- public async Task<EventIdResponse> SetState(string roomId, string eventType, [FromBody] StateEvent request) {
+ public async Task<EventIdResponse> SetState(string roomId, string eventType, [FromBody] JsonObject? request) {
return await SetState(roomId, eventType, "", request);
}
[HttpPut("{eventType}/{stateKey}")]
- public async Task<EventIdResponse> SetState(string roomId, string eventType, string stateKey, [FromBody] StateEvent request) {
+ public async Task<EventIdResponse> SetState(string roomId, string eventType, string stateKey, [FromBody] JsonObject? request) {
var token = tokenService.GetAccessTokenOrNull(HttpContext);
if (token == null)
throw new MatrixException() {
@@ -99,7 +100,7 @@ public class RoomStateController(ILogger<RoomStateController> logger, TokenServi
ErrorCode = "M_NOT_FOUND",
Error = "Room not found"
};
- var evt = room.SetStateInternal(request.ToStateEvent(user, room));
+ var evt = room.SetStateInternal(new StateEvent() { Type = eventType, StateKey = stateKey, RawContent = request }.ToStateEvent(user, room));
evt.Type = eventType;
evt.StateKey = stateKey;
return new EventIdResponse() {
diff --git a/Tests/LibMatrix.HomeserverEmulator/Controllers/Rooms/RoomTimelineController.cs b/Tests/LibMatrix.HomeserverEmulator/Controllers/Rooms/RoomTimelineController.cs
index 3d23660..afd69d1 100644
--- a/Tests/LibMatrix.HomeserverEmulator/Controllers/Rooms/RoomTimelineController.cs
+++ b/Tests/LibMatrix.HomeserverEmulator/Controllers/Rooms/RoomTimelineController.cs
@@ -124,6 +124,122 @@ public class RoomTimelineController(
return evt;
}
+
+ [HttpGet("relations/{eventId}")]
+ public async Task<RecursedBatchedChunkedStateEventResponse> GetRelations(string roomId, string eventId, [FromQuery] string? dir = "b", [FromQuery] string? from = null, [FromQuery] int? limit = 100, [FromQuery] bool? recurse = false, [FromQuery] string? to = null) {
+ var token = tokenService.GetAccessToken(HttpContext);
+ var user = await userStore.GetUserByToken(token);
+
+ var room = roomStore.GetRoomById(roomId);
+ if (room == null)
+ throw new MatrixException() {
+ ErrorCode = "M_NOT_FOUND",
+ Error = "Room not found"
+ };
+
+ if (!room.JoinedMembers.Any(x => x.StateKey == user.UserId))
+ throw new MatrixException() {
+ ErrorCode = "M_FORBIDDEN",
+ Error = "User is not in the room"
+ };
+
+ var evt = room.Timeline.SingleOrDefault(x => x.EventId == eventId);
+ if (evt == null)
+ throw new MatrixException() {
+ ErrorCode = "M_NOT_FOUND",
+ Error = "Event not found"
+ };
+
+ var matchingEvents = await GetRelationsInternal(roomId, eventId, dir, from, limit, recurse, to);
+
+ return new() {
+ Chunk = matchingEvents.ToList()
+ };
+ }
+
+ [HttpGet("relations/{eventId}/{relationType}")]
+ public async Task<RecursedBatchedChunkedStateEventResponse> GetRelations(string roomId, string eventId, string relationType, [FromQuery] string? dir = "b", [FromQuery] string? from = null, [FromQuery] int? limit = 100, [FromQuery] bool? recurse = false, [FromQuery] string? to = null) {
+ var token = tokenService.GetAccessToken(HttpContext);
+ var user = await userStore.GetUserByToken(token);
+
+ var room = roomStore.GetRoomById(roomId);
+ if (room == null)
+ throw new MatrixException() {
+ ErrorCode = "M_NOT_FOUND",
+ Error = "Room not found"
+ };
+
+ if (!room.JoinedMembers.Any(x => x.StateKey == user.UserId))
+ throw new MatrixException() {
+ ErrorCode = "M_FORBIDDEN",
+ Error = "User is not in the room"
+ };
+
+ var evt = room.Timeline.SingleOrDefault(x => x.EventId == eventId);
+ if (evt == null)
+ throw new MatrixException() {
+ ErrorCode = "M_NOT_FOUND",
+ Error = "Event not found"
+ };
+
+ var matchingEvents = await GetRelationsInternal(roomId, eventId, dir, from, limit, recurse, to);
+
+ return new() {
+ Chunk = matchingEvents.ToList()
+ };
+ }
+
+ [HttpGet("relations/{eventId}/{relationType}/{eventType}")]
+ public async Task<RecursedBatchedChunkedStateEventResponse> GetRelations(string roomId, string eventId, string relationType, string eventType, [FromQuery] string? dir = "b", [FromQuery] string? from = null, [FromQuery] int? limit = 100, [FromQuery] bool? recurse = false, [FromQuery] string? to = null) {
+ var token = tokenService.GetAccessToken(HttpContext);
+ var user = await userStore.GetUserByToken(token);
+
+ var room = roomStore.GetRoomById(roomId);
+ if (room == null)
+ throw new MatrixException() {
+ ErrorCode = "M_NOT_FOUND",
+ Error = "Room not found"
+ };
+
+ if (!room.JoinedMembers.Any(x => x.StateKey == user.UserId))
+ throw new MatrixException() {
+ ErrorCode = "M_FORBIDDEN",
+ Error = "User is not in the room"
+ };
+
+ var evt = room.Timeline.SingleOrDefault(x => x.EventId == eventId);
+ if (evt == null)
+ throw new MatrixException() {
+ ErrorCode = "M_NOT_FOUND",
+ Error = "Event not found"
+ };
+
+ var matchingEvents = await GetRelationsInternal(roomId, eventId, dir, from, limit, recurse, to);
+
+ return new() {
+ Chunk = matchingEvents.ToList()
+ };
+ }
+
+ private async Task<IEnumerable<StateEventResponse>> GetRelationsInternal(string roomId, string eventId, string dir, string? from, int? limit, bool? recurse, string? to) {
+ var room = roomStore.GetRoomById(roomId);
+ var evt = room.Timeline.SingleOrDefault(x => x.EventId == eventId);
+ if (evt == null)
+ throw new MatrixException() {
+ ErrorCode = "M_NOT_FOUND",
+ Error = "Event not found"
+ };
+
+ var relatedEvents = room.Timeline.Where(x => x.RawContent?["m.relates_to"]?["event_id"]?.GetValue<string>() == eventId);
+ if (dir == "b") {
+ relatedEvents = relatedEvents.TakeLast(limit ?? 100);
+ }
+ else if (dir == "f") {
+ relatedEvents = relatedEvents.Take(limit ?? 100);
+ }
+
+ return relatedEvents;
+ }
#region Commands
diff --git a/Tests/LibMatrix.HomeserverEmulator/Controllers/Rooms/RoomsController.cs b/Tests/LibMatrix.HomeserverEmulator/Controllers/Rooms/RoomsController.cs
index 6849ff8..c24e6e9 100644
--- a/Tests/LibMatrix.HomeserverEmulator/Controllers/Rooms/RoomsController.cs
+++ b/Tests/LibMatrix.HomeserverEmulator/Controllers/Rooms/RoomsController.cs
@@ -28,42 +28,9 @@ public class RoomsController(ILogger<RoomsController> logger, TokenService token
Error = "No such user"
};
- var room = new RoomStore.Room($"!{Guid.NewGuid()}:{tokenService.GenerateServerName(HttpContext)}");
- var createEvent = room.SetStateInternal(new() {
- Type = RoomCreateEventContent.EventId,
- RawContent = new() {
- ["creator"] = user.UserId
- }
- });
- foreach (var (key, value) in request.CreationContent) {
- createEvent.RawContent[key] = value.DeepClone();
- }
-
- if (!string.IsNullOrWhiteSpace(request.Name))
- room.SetStateInternal(new StateEvent() {
- Type = RoomNameEventContent.EventId,
- TypedContent = new RoomNameEventContent() {
- Name = request.Name
- }
- });
-
- if (!string.IsNullOrWhiteSpace(request.RoomAliasName))
- room.SetStateInternal(new StateEvent() {
- Type = RoomCanonicalAliasEventContent.EventId,
- TypedContent = new RoomCanonicalAliasEventContent() {
- Alias = $"#{request.RoomAliasName}:localhost"
- }
- });
-
- if (request.InitialState is { Count: > 0 }) {
- foreach (var stateEvent in request.InitialState) {
- room.SetStateInternal(stateEvent);
- }
- }
+ // var room = new RoomStore.Room($"!{Guid.NewGuid()}:{tokenService.GenerateServerName(HttpContext)}");
+ var room = roomStore.CreateRoom(request, user);
- room.AddUser(user.UserId);
-
- // user.Rooms.Add(room.RoomId, room);
return new() {
RoomId = room.RoomId
};
@@ -122,9 +89,13 @@ public class RoomsController(ILogger<RoomsController> logger, TokenService token
replacement_room = room.RoomId
};
}
-
+
+ public class ReasonBody {
+ [JsonPropertyName("reason")]
+ public string? Reason { get; set; }
+ }
[HttpPost("rooms/{roomId}/leave")] // TODO: implement
- public async Task<object> LeaveRoom(string roomId) {
+ public async Task<object> LeaveRoom(string roomId, [FromBody] ReasonBody body) {
var token = tokenService.GetAccessTokenOrNull(HttpContext);
if (token == null)
throw new MatrixException() {
@@ -145,11 +116,17 @@ public class RoomsController(ILogger<RoomsController> logger, TokenService token
ErrorCode = "M_NOT_FOUND",
Error = "Room not found"
};
+
+ room.SetStateInternal(new() {
+ Type = RoomMemberEventContent.EventId,
+ TypedContent = new RoomMemberEventContent() {
+ Membership = "leave",
+ Reason = body.Reason
+ },
+ StateKey = user.UserId
+ });
- // room.RemoveUser(user.UserId);
-
- // room.SetStateInternal(new StateEventResponse() { });
-
+ logger.LogTrace($"User {user.UserId} left room {room.RoomId}");
return new {
room_id = room.RoomId
};
|