From 508c694c3d551cddb3b15c1b0d4787dae3c00530 Mon Sep 17 00:00:00 2001 From: Rory& Date: Thu, 2 May 2024 07:20:13 +0200 Subject: HomeserverEmulator work --- .../Controllers/Rooms/RoomStateController.cs | 7 +- .../Controllers/Rooms/RoomTimelineController.cs | 116 +++++++++++++++++++++ .../Controllers/Rooms/RoomsController.cs | 59 ++++------- 3 files changed, 138 insertions(+), 44 deletions(-) (limited to 'Tests/LibMatrix.HomeserverEmulator/Controllers/Rooms') 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 logger, TokenServi } [HttpPut("{eventType}")] - public async Task SetState(string roomId, string eventType, [FromBody] StateEvent request) { + public async Task SetState(string roomId, string eventType, [FromBody] JsonObject? request) { return await SetState(roomId, eventType, "", request); } [HttpPut("{eventType}/{stateKey}")] - public async Task SetState(string roomId, string eventType, string stateKey, [FromBody] StateEvent request) { + public async Task 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 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 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 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 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> 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() == 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 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 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 LeaveRoom(string roomId) { + public async Task 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 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 }; -- cgit 1.4.1