# Copyright 2021 The Matrix.org Foundation C.I.C.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
openapi: 3.1.0
info:
  title: Matrix Federation Space Hierarchy API
  version: 1.0.0
paths:
  "/hierarchy/{roomId}":
    get:
      x-addedInMatrixVersion: "1.2"
      summary: Retrieve a portion of a space tree.
      description: |-
        Federation version of the Client-Server [`GET /hierarchy`](/client-server-api/#get_matrixclientv1roomsroomidhierarchy)
        endpoint. Unlike the Client-Server API version, this endpoint does not paginate. Instead, all
        the space-room's children the requesting server could feasibly peek/join are returned. The
        requesting server is responsible for filtering the results further down for the user's request.

        Only [`m.space.child`](/client-server-api/#mspacechild) state events of the room are considered. Invalid child
        rooms and parent events are not covered by this endpoint.

        Responses to this endpoint should be cached for a period of time.
      operationId: getSpaceHierarchy
      security:
        - signedRequest: []
      parameters:
        - in: path
          name: roomId
          description: The room ID of the space to get a hierarchy for.
          required: true
          example: "!space:example.org"
          schema:
            type: string
        - in: query
          name: suggested_only
          description: |-
            Optional (default `false`) flag to indicate whether or not the server should only consider
            suggested rooms. Suggested rooms are annotated in their [`m.space.child`](/client-server-api/#mspacechild) event
            contents.
          example: true
          schema:
            type: boolean
      responses:
        "200":
          description: The space room and its children.
          content:
            application/json:
              schema:
                type: object
                properties:
                  room:
                    description: A summary of the room requested.
                    allOf:
                      - $ref: ../client-server/definitions/public_rooms_chunk.yaml
                      - type: object
                        title: SpaceHierarchyParentRoom
                        properties:
                          room_type:
                            type: string
                            description: The `type` of room (from
                              [`m.room.create`](/client-server-api/#mroomcreate)),
                              if any.
                          allowed_room_ids:
                            type: array
                            items:
                              type: string
                            description: |-
                              If the room is a [restricted room](#restricted-rooms), these are the room IDs which
                              are specified by the join rules. Empty or omitted otherwise.
                          children_state:
                            type: array
                            description: |-
                              The [`m.space.child`](/client-server-api/#mspacechild) events of the space-room, represented
                              as [Stripped State Events](/client-server-api/#stripped-state) with an added
                              `origin_server_ts` key.

                              If the room is not a space-room, this should be empty.
                            items:
                              allOf:
                                - $ref: ../../event-schemas/schema/core-event-schema/stripped_state.yaml
                                - type: object
                                  properties:
                                    origin_server_ts:
                                      type: integer
                                      format: int64
                                      description: The `origin_server_ts` for the event.
                                  required:
                                    - origin_server_ts
                        required:
                          - children_state
                  children:
                    type: array
                    description: |-
                      A summary of the space's children. Rooms which the requesting server cannot peek/join will
                      be excluded.
                    items:
                      allOf:
                        - $ref: ../client-server/definitions/public_rooms_chunk.yaml
                        - type: object
                          title: SpaceHierarchyChildRoomsChunk
                          properties:
                            room_type:
                              type: string
                              description: The `type` of room (from
                                [`m.room.create`](/client-server-api/#mroomcreate)),
                                if any.
                            allowed_room_ids:
                              type: array
                              items:
                                type: string
                              description: |-
                                If the room is a [restricted room](#restricted-rooms), these are the room IDs which
                                are specified by the join rules. Empty or omitted otherwise.
                  inaccessible_children:
                    type: array
                    items:
                      type: string
                    description: |-
                      The list of room IDs the requesting server doesn't have a viable way to peek/join. Rooms which
                      the responding server cannot provide details on will be outright excluded from the response instead.

                      Assuming both the requesting and responding server are well behaved, the requesting server should
                      consider these room IDs as not accessible from anywhere. They should not be re-requested.
                required:
                  - room
                  - children
                  - inaccessible_children
              examples:
                response:
                  value: {
                    "room": {
                      "room_id": "!space:example.org",
                      "avatar_url": "mxc://example.org/abcdef",
                      "guest_can_join": false,
                      "name": "The First Space",
                      "topic": "No other spaces were created first, ever",
                      "world_readable": true,
                      "join_rule": "public",
                      "room_type": "m.space",
                      "num_joined_members": 42,
                      "canonical_alias": "#general:example.org",
                      "allowed_room_ids": [],
                      "children_state": [
                        {
                          "type": "m.space.child",
                          "state_key": "!a:example.org",
                          "content": {
                            "via": [
                              "remote.example.org"
                            ]
                          },
                          "sender": "@alice:example.org",
                          "origin_server_ts": 1629413349153
                        }
                      ]
                    },
                    "inaccessible_children": [
                      "!secret:example.org"
                    ],
                    "children": [
                      {
                        "room_id": "!second_room:example.org",
                        "avatar_url": "mxc://example.org/abcdef2",
                        "guest_can_join": false,
                        "name": "The ~~First~~ Second Space",
                        "topic": "Hello world",
                        "world_readable": true,
                        "join_rule": "restricted",
                        "room_type": "m.space",
                        "num_joined_members": 42,
                        "canonical_alias": "#general:example.org",
                        "allowed_room_ids": [
                          "!upstream:example.org"
                        ],
                        "children_state": [
                          {
                            "type": "m.space.child",
                            "state_key": "!b:example.org",
                            "content": {
                              "via": [
                                "remote.example.org"
                              ]
                            },
                            "sender": "@alice:example.org",
                            "origin_server_ts": 1629422222222
                          }
                        ]
                      }
                    ]
                  }
        "404":
          description: |-
            The room is not known to the server or the requesting server is unable to peek/join
            it (if it were to attempt this).
          content:
            application/json:
              schema:
                $ref: ../client-server/definitions/errors/error.yaml
              examples:
                response:
                  value: {
                    "errcode": "M_NOT_FOUND",
                    "error": "Room does not exist."
                  }
      tags:
        - Spaces
servers:
  - url: "{protocol}://{hostname}{basePath}"
    variables:
      protocol:
        enum:
          - http
          - https
        default: https
      hostname:
        default: localhost:8448
      basePath:
        default: /_matrix/federation/v1
components:
  securitySchemes:
    signedRequest:
      $ref: definitions/security.yaml#/signedRequest
