getContent(), true); RequestValidator::validateJson(); $creationContent = $body["creation_content"] ?? []; $initialState = $body["initial_state"] ?? []; $invite = $body["invite"] ?? []; $body["invite_3pid"] ?? []; $body["is_direct"] ?? false; $name = $body["name"] ?? ""; $body["power_level_content_override"] ?? []; $preset = $body["preset"] ?? ""; $roomAliasName = $body["room_alias_name"] ?? ""; $roomVersion = $body["room_version"] ?? "DEFAULT_ROOM_VERSION"; $topic = $body["topic"] ?? ""; $visibility = RoomVisibility::tryFrom($body["visibility"] ?? "private"); if (! $preset) { $preset = $visibility->value . "_chat"; } # TODO: get events for preset # TODO: override preset events with initial state # TODO: override events with name and topic if applicable $state = []; if ($name) { $state[EventType::ROOM_NAME->value] = $name; } if ($topic) { $state[EventType::ROOM_TOPIC->value] = $topic; } // create room $roomId = Id::generateRoomId(); Database::getInstance()->query(<< $roomId, "name" => $roomAliasName, # "#$roomAliasName:$_ENV[DOMAIN]", ]); $roomCreateEvent = new RoomEvent(new CreateEvent( eventId: Id::generateEventId(), originServerTimestamp: time(), roomId: $roomId, sender: $user->getId(), roomVersion: "12", )); $roomCreateEvent->insert(); $roomMemberEvent = new RoomEvent(new MemberEvent( eventId: Id::generateEventId(), originServerTimestamp: time(), roomId: $roomId, sender: $user->getId(), stateKey: $user->getId(), isDirect: false, membership: MembershipState::JOIN, displayName: $user->getName(), )); $roomMemberEvent->insert(); $roomPowerLevelsEvent = new RoomEvent(new PowerLevelsEvent( eventId: Id::generateEventId(), originServerTimestamp: time(), roomId: $roomId, sender: $user->getId(), )); $roomPowerLevelsEvent->insert(); $roomJoinRulesEvent = new RoomEvent(new JoinRulesEvent( eventId: Id::generateEventId(), originServerTimestamp: time(), roomId: $roomId, sender: $user->getId(), joinRule: RoomJoinRule::INVITE, )); $roomJoinRulesEvent->insert(); $roomHistoryVisibilityEvent = new RoomEvent(new HistoryVisibilityEvent( eventId: Id::generateEventId(), originServerTimestamp: time(), roomId: $roomId, sender: $user->getId(), historyVisibility: RoomHistoryVisibility::SHARED, )); $roomHistoryVisibilityEvent->insert(); $roomGuestAccessEvent = new RoomEvent(new GuestAccessEvent( eventId: Id::generateEventId(), originServerTimestamp: time(), roomId: $roomId, sender: $user->getId(), guestAccess: RoomGuestAccess::CAN_JOIN, )); $roomGuestAccessEvent->insert(); $roomNameEvent = new RoomEvent(new NameEvent( eventId: Id::generateEventId(), originServerTimestamp: time(), roomId: $roomId, sender: $user->getId(), name: $roomAliasName, )); $roomNameEvent->insert(); Database::getInstance()->query(<< $roomId, "user_id" => $user->getId(), "state" => MembershipState::JOIN->value, ]); return new JsonResponse([ "room_id" => $roomId, ]); } /** * @see https://spec.matrix.org/v1.15/client-server-api/#get_matrixclientv3directoryroomroomalias */ #[Route(path: "/_matrix/client/v3/directory/room/{roomAlias}", methods: ["GET"])] public function resolveAlias(Request $request): Response { $alias = $request->attributes->get("roomAlias"); $roomAlias = Parser::parseRoomAlias($alias); # TODO: on parse error => 400 $roomId = null; if ($roomAlias["server"] != $_ENV["DOMAIN"]) { # TODO: federation API resolve $roomId = -1; } else { $room = Database::getInstance()->query(<< $roomAlias["name"], ])->fetch(); $roomId = $room["id"] ?? null; } if (empty($roomId)) { throw new AppException( ErrorCode::NOT_FOUND, "Room alias $alias not found.", Response::HTTP_NOT_FOUND ); } return new JsonResponse([ "room_id" => $roomId, "servers" => [], ]); } #[Route(path: "/_matrix/client/v3/{roomId}/messages", methods: ["GET"])] public function getMessages(Request $request): Response { $user = User::authenticateWithRequest($request); $roomId = $request->attributes->get("roomId"); $membership = Database::getInstance() ->query("select state from room_memberships where user_id=:user_id and room_id=:room_id", [ "user_id" => $user->getId(), "room_id" => $roomId, ]) ->fetchColumn(); if (MembershipState::from($membership) !== MembershipState::JOIN) { throw new Exception(ErrorCode::FORBIDDEN, "You aren't a member of the room.", Response::HTTP_FORBIDDEN); } $direction = $request->query->get("dir"); $filter = $request->query->get("filter"); $from = $request->query->get("from"); $limit = $request->query->get("limit", 10); $to = $request->query->get("to"); $events = Database::getInstance()->query(<< $roomId, #"limit" => ($filter["room"]["timeline"]["limit"] ?? false) ? "limit " . $filter["room"]["timeline"]["limit"] : "", ])->fetchAll(); return new JsonResponse([ "chunk" => array_map([RoomEvent::class, "transformEvent"], $events), "end" => "", "start" => "", "state" => [], ]); } #[Route(path: "/_matrix/client/v3/rooms/{roomId}/read_markers", methods: ["POST"])] public function readMarkers(Request $request): Response { $user = User::authenticateWithRequest($request); $body = json_decode($request->getContent(), true); RequestValidator::validateJson(); $roomId = $request->attributes->get("roomId"); return new JsonResponse(); } /** * @see https://spec.matrix.org/v1.15/client-server-api/#put_matrixclientv3roomsroomidsendeventtypetxnid */ #[Route(path: "/_matrix/client/v3/rooms/{roomId}/send/{eventType}/{txnId}", methods: ["PUT"])] public function send(Request $request): Response { $user = User::authenticateWithRequest($request); if (empty($user)) { throw new UnauthorizedError(); } $roomId = $request->attributes->get("roomId"); $eventType = EventType::from($request->attributes->get("eventType")); $transactionId = $request->attributes->get("txnId"); $body = json_decode($request->getContent(), true); RequestValidator::validateJson(); // validate msgtype MessageType::from($body["msgtype"]); $eventId = Id::generateEventId(); $event = new RoomEvent(new ClientEvent( content: $body, eventId: $eventId, originServerTimestamp: time(), roomId: $roomId, sender: $user->getId(), type: $eventType, unsigned: new UnsignedData( age: 1234, # TODO membership: MembershipState::JOIN, ), )); $event->insert(); return new JsonResponse([ "event_id" => $eventId, ]); } }