Merge remote-tracking branch 'matrix-org/master' into travis/s2s/keys-swagger

pull/977/head
Travis Ralston 6 years ago
commit 7cb918407d

@ -0,0 +1,49 @@
gendoc: &gendoc
name: Generate the docs
command: |
source /env/bin/activate
scripts/gendoc.py
gendoc: &genswagger
name: Generate the swagger
command: |
source /env/bin/activate
scripts/dump-swagger.py
version: 2
jobs:
build-docs:
docker:
- image: uhoreg/matrix-doc-build
steps:
- checkout
- run: *gendoc
- store_artifacts:
path: scripts/gen
- run:
name: "Doc build is available at:"
command: DOCS_URL="${CIRCLE_BUILD_URL}/artifacts/${CIRCLE_NODE_INDEX}/${CIRCLE_WORKING_DIRECTORY/#\~/$HOME}/scripts/gen/index.html"; echo $DOCS_URL
build-swagger:
docker:
- image: uhoreg/matrix-doc-build
steps:
- checkout
- run: *genswagger
- store_artifacts:
path: scripts/swagger/api-docs.json
- run:
name: "Swagger UI is available at:"
command: SWAGGER_URL="${CIRCLE_BUILD_URL}/artifacts/${CIRCLE_NODE_INDEX}/${CIRCLE_WORKING_DIRECTORY/#\~/$HOME}/scripts/swagger/api-docs.json"; echo "https://matrix.org/docs/api/client-server/?url="$SWAGGER_URL
workflows:
version: 2
build-spec:
jobs:
- build-docs
- build-swagger
notify:
webhooks:
- url: https://giles.cadair.com/circleci

3
.gitignore vendored

@ -1,7 +1,7 @@
/api/node_modules /api/node_modules
/assets /assets
/assets.tar.gz /assets.tar.gz
/env /env*
/scripts/gen /scripts/gen
/scripts/continuserv/continuserv /scripts/continuserv/continuserv
/scripts/speculator/speculator /scripts/speculator/speculator
@ -10,3 +10,4 @@
/templating/out /templating/out
*.pyc *.pyc
*.swp *.swp
_rendered.rst

@ -2,15 +2,15 @@ language: go
go: go:
- 1.8 - 1.8
sudo: false sudo: required
# we only need a single git commit # we only need a single git commit
git: git:
depth: 1 depth: 1
# test-and-build does the installation, so tell travis to skip the install:
# installation step - sudo apt-get update
install: true - sudo apt-get install python3 python3-dev
script: script:
- ./scripts/test-and-build.sh - ./scripts/test-and-build.sh

@ -69,6 +69,41 @@ For such changes, please do just open a `pull request`_.
.. _pull request: https://help.github.com/articles/about-pull-requests .. _pull request: https://help.github.com/articles/about-pull-requests
Adding to the changelog
~~~~~~~~~~~~~~~~~~~~~~~
Currently only changes to the client-server API need to end up in a changelog. The
other APIs are not yet stable and therefore do not have a changelog. Adding to the
changelog can only be done after you've opened your pull request, so be sure to do
that first.
The changelog is managed by Towncrier (https://github.com/hawkowl/towncrier) in the
form of "news fragments". The news fragments for the client-server API are stored
under ``changelogs/client_server/newsfragments``.
To create a changelog entry, create a file named in the format ``prNumber.type`` in
the ``newsfragments`` directory. The ``type`` can be one of the following:
* ``new`` - Used when adding new endpoints. Please have the file contents be the
method and route being added, surrounded in RST code tags. For example: ``POST
/accounts/whoami``
* ``feature`` - Used when adding backwards-compatible changes to the API.
* ``clarification`` - Used when an area of the spec is being improved upon and does
not change or introduce any functionality.
* ``breaking`` - Used when the change is not backwards compatible.
* ``deprecation`` - Used when deprecating something
All news fragments must have a brief summary explaining the change in the contents
of the file.
Changes that do not change the spec, such as changes to the build script, formatting,
CSS, etc should not get a news fragment.
Sign off Sign off
-------- --------

@ -41,9 +41,9 @@ specs and event schemas in this repository.
Preparation Preparation
----------- -----------
To use the scripts, it is best to create a Python 2.x virtualenv as follows:: To use the scripts, it is best to create a Python 3.4+ virtualenv as follows::
virtualenv env virtualenv -p python3 env
env/bin/pip install -r scripts/requirements.txt env/bin/pip install -r scripts/requirements.txt
(Benjamin Synders has contributed a script for `Nix`_ users, which can be (Benjamin Synders has contributed a script for `Nix`_ users, which can be

@ -1,4 +1,5 @@
# Copyright 2016 OpenMarket Ltd # Copyright 2016 OpenMarket Ltd
# Copyright 2018 New Vector Ltd
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -29,8 +30,8 @@ paths:
put: put:
summary: Send some events to the application service. summary: Send some events to the application service.
description: |- description: |-
This API is called by the HS when the HS wants to push an event (or This API is called by the homeserver when it wants to push an event
batch of events) to the AS. (or batch of events) to the application service.
operationId: sendTransaction operationId: sendTransaction
parameters: parameters:
- in: path - in: path
@ -91,7 +92,6 @@ paths:
} }
schema: schema:
type: object type: object
"/rooms/{roomAlias}": "/rooms/{roomAlias}":
get: get:
summary: Query if a room alias should exist on the application service. summary: Query if a room alias should exist on the application service.
@ -131,16 +131,16 @@ paths:
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
} }
schema: schema:
type: object $ref: ../client-server/definitions/errors/error.yaml
403: 403:
description: |- description: |-
The credentials supplied by the homeserver were rejected. The credentials supplied by the homeserver were rejected.
examples: examples:
application/json: { application/json: {
"errcode": "M_FORBIDDEN" "errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN"
} }
schema: schema:
type: object $ref: ../client-server/definitions/errors/error.yaml
404: 404:
description: |- description: |-
The application service indicates that this room alias does not exist. The application service indicates that this room alias does not exist.
@ -150,7 +150,7 @@ paths:
"errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND"
} }
schema: schema:
type: object $ref: ../client-server/definitions/errors/error.yaml
"/users/{userId}": "/users/{userId}":
get: get:
summary: Query if a user should exist on the application service. summary: Query if a user should exist on the application service.
@ -187,16 +187,16 @@ paths:
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED" "errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
} }
schema: schema:
type: object $ref: ../client-server/definitions/errors/error.yaml
403: 403:
description: |- description: |-
The credentials supplied by the homeserver were rejected. The credentials supplied by the homeserver were rejected.
examples: examples:
application/json: { application/json: {
"errcode": "M_FORBIDDEN" "errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN"
} }
schema: schema:
type: object $ref: ../client-server/definitions/errors/error.yaml
404: 404:
description: |- description: |-
The application service indicates that this user does not exist. The application service indicates that this user does not exist.
@ -206,4 +206,244 @@ paths:
"errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND" "errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND"
} }
schema: schema:
type: object $ref: ../client-server/definitions/errors/error.yaml
"/_matrix/app/unstable/thirdparty/protocol/{protocol}":
get:
summary: Retrieve metadata about a specific protocol that the application service supports.
description: |-
This API is called by the homeserver when it wants to present clients
with specific information about the various third party networks that
an application service supports.
operationId: queryMetadata
parameters:
- in: path
name: protocol
type: string
description: The protocol ID.
required: true
x-example: "irc"
responses:
200:
description: The protocol was found and metadata returned.
schema:
$ref: definitions/protocol_metadata.yaml
401:
description: |-
The homeserver has not supplied credentials to the application service.
Optional error information can be included in the body of this response.
examples:
application/json: {
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
}
schema:
$ref: ../client-server/definitions/errors/error.yaml
403:
description: |-
The credentials supplied by the homeserver were rejected.
examples:
application/json: {
"errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN"
}
schema:
$ref: ../client-server/definitions/errors/error.yaml
404:
description: No protocol was found with the given path.
examples:
application/json: {
"errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND"
}
schema:
$ref: ../client-server/definitions/errors/error.yaml
"/_matrix/app/unstable/thirdparty/user/{protocol}":
get:
summary: Retrieve the Matrix User ID of a corresponding third party user.
description: |-
This API is called by the homeserver in order to retrieve a Matrix
User ID linked to a user on the third party network, given a set of
user parameters.
operationId: queryUserByProtocol
parameters:
- in: path
name: protocol
type: string
description: The protocol ID.
required: true
x-example: irc
- in: query
name: field1, field2...
type: string
description: |-
One or more custom fields that are passed to the application
service to help identify the user.
responses:
200:
description: The Matrix User IDs found with the given parameters.
schema:
$ref: definitions/user_batch.yaml
401:
description: |-
The homeserver has not supplied credentials to the application service.
Optional error information can be included in the body of this response.
examples:
application/json: {
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
}
schema:
$ref: ../client-server/definitions/errors/error.yaml
403:
description: |-
The credentials supplied by the homeserver were rejected.
examples:
application/json: {
"errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN"
}
schema:
$ref: ../client-server/definitions/errors/error.yaml
404:
description: No users were found with the given parameters.
examples:
application/json: {
"errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND"
}
schema:
$ref: ../client-server/definitions/errors/error.yaml
"/_matrix/app/unstable/thirdparty/location/{protocol}":
get:
summary: Retreive Matrix-side portal rooms leading to a third party location.
description: |-
Retrieve a list of Matrix portal rooms that lead to the matched third party location.
operationId: queryLocationByProtocol
parameters:
- in: path
name: protocol
type: string
description: The protocol ID.
required: true
x-example: irc
- in: query
name: field1, field2...
type: string
description: |-
One or more custom fields that are passed to the application
service to help identify the third party location.
responses:
200:
description: At least one portal room was found.
schema:
$ref: definitions/location_batch.yaml
401:
description: |-
The homeserver has not supplied credentials to the application service.
Optional error information can be included in the body of this response.
examples:
application/json: {
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
}
schema:
$ref: ../client-server/definitions/errors/error.yaml
403:
description: |-
The credentials supplied by the homeserver were rejected.
examples:
application/json: {
"errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN"
}
schema:
$ref: ../client-server/definitions/errors/error.yaml
404:
description: No mappings were found with the given parameters.
examples:
application/json: {
"errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND"
}
schema:
$ref: ../client-server/definitions/errors/error.yaml
"/_matrix/app/unstable/thirdparty/location":
get:
summary: Reverse-lookup third party locations given a Matrix room alias.
description: |-
Retreive an array of third party network locations from a Matrix room
alias.
operationId: queryLocationByAlias
parameters:
- in: query
name: alias
type: string
description: The Matrix room alias to look up.
responses:
200:
description: |-
All found third party locations.
schema:
$ref: definitions/location_batch.yaml
401:
description: |-
The homeserver has not supplied credentials to the application service.
Optional error information can be included in the body of this response.
examples:
application/json: {
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
}
schema:
$ref: ../client-server/definitions/errors/error.yaml
403:
description: |-
The credentials supplied by the homeserver were rejected.
examples:
application/json: {
"errcode": "COM.EXAMPLE.MYAPPSERVICE_FORBIDDEN"
}
schema:
$ref: ../client-server/definitions/errors/error.yaml
404:
description: No mappings were found with the given parameters.
examples:
application/json: {
"errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND"
}
schema:
$ref: ../client-server/definitions/errors/error.yaml
"/_matrix/app/unstable/thirdparty/user":
get:
summary: Reverse-lookup third party users given a Matrix User ID.
description: |-
Retreive an array of third party users from a Matrix User ID.
operationId: queryUserByID
parameters:
- in: query
name: userid
type: string
description: The Matrix User ID to look up.
responses:
200:
description: |-
An array of third party users.
schema:
$ref: definitions/user_batch.yaml
401:
description: |-
The homeserver has not supplied credentials to the application service.
Optional error information can be included in the body of this response.
examples:
application/json: {
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
}
schema:
$ref: ../client-server/definitions/errors/error.yaml
403:
description: |-
The credentials supplied by the homeserver were rejected.
examples:
application/json: {
"errcode": "COM.EXAMPLE.MYAPPSERVICE_UNAUTHORIZED"
}
schema:
$ref: ../client-server/definitions/errors/error.yaml
404:
description: No mappings were found with the given parameters.
examples:
application/json: {
"errcode": "COM.EXAMPLE.MYAPPSERVICE_NOT_FOUND"
}
schema:
$ref: ../client-server/definitions/errors/error.yaml

@ -0,0 +1,30 @@
# Copyright 2018 New Vector Ltd
#
# 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.
properties:
alias:
description: An alias for a matrix room.
type: string
example: "#freenode_#matrix:matrix.org"
protocol:
description: The protocol ID that the third party location is a part of.
type: string
example: irc
fields:
description: Information used to identify this third party location.
type: object
example:
"network": "freenode"
"channel": "#matrix"
title: Location
type: object

@ -0,0 +1,17 @@
# Copyright 2018 New Vector Ltd
#
# 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.
type: array
description: List of matched third party locations.
items:
$ref: location.yaml

@ -0,0 +1,79 @@
# Copyright 2018 New Vector Ltd
#
# 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.
properties:
user_fields:
description: Fields used to identify a third party user.
type: array
items:
type: string
description: Field used to identify a third party user.
example: ["network", "nickname"]
location_fields:
description: Fields used to identify a third party location.
type: array
items:
type: string
description: Field used to identify a third party location.
example: ["network", "channel"]
icon:
description: An icon representing the third party protocol.
type: string
example: "mxc://example.org/aBcDeFgH"
field_types:
title: Field Types
description: All location or user fields should have an entry here.
type: object
properties:
fieldname:
title: Field Type
description: Definition of valid values for a field.
type: object
properties:
regexp:
description: A regular expression for validation of a field's value.
type: string
placeholder:
description: An placeholder serving as a valid example of the field value.
type: string
example: {
"network": {
"regexp": "([a-z0-9]+\\.)*[a-z0-9]+",
"placeholder": "irc.example.org"
},
"nickname": {
"regexp": "[^\\s#]+",
"placeholder": "username"
},
"channel": {
"regexp": "#[^\\s]+",
"placeholder": "#foobar"
}
}
instances:
description: |-
A list of objects representing independent instances of configuration.
For instance multiple networks on IRC if multiple are bridged by the
same bridge.
type: array
items:
type: object
example: {
"desc": "Freenode",
"icon": "mxc://example.org/JkLmNoPq",
"fields": {
"network": "freenode.net",
}
}
title: Protocol
type: object

@ -0,0 +1,66 @@
# Copyright 2018 New Vector Ltd
#
# 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.
type: object
description: Dictionary of supported third party protocols.
example: {
"irc": {
"user_fields": ["network", "nickname"],
"location_fields": ["network", "channel"],
"icon": "mxc://example.org/aBcDeFgH",
"field_types": {
"network": {
"regexp": "([a-z0-9]+\\.)*[a-z0-9]+",
"placeholder": "irc.example.org"
},
"nickname": {
"regexp": "[^\\s]+",
"placeholder": "username"
},
"channel": {
"regexp": "#[^\\s]+",
"placeholder": "#foobar"
}
},
"instances": [
{
"desc": "Freenode",
"icon": "mxc://example.org/JkLmNoPq",
"fields": {
"network": "freenode.net",
}
}
]
},
"gitter": {
"user_fields": ["username"],
"location_fields": ["room"],
"field_types": {
"username": {
"regexp": "@[^\\s]+",
"placeholder": "@username"
},
"room": {
"regexp": "[^\\s]+\\/[^\\s]+",
"placeholder": "matrix-org/matrix-doc"
}
},
"instances": [
{
"desc": "Gitter",
"icon": "mxc://example.org/zXyWvUt",
"fields": {}
}
]
}
}

@ -0,0 +1,31 @@
# Copyright 2018 New Vector Ltd
#
# 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.
# TODO: Change userid to user_id as a breaking change
properties:
userid:
description: A Matrix User ID represting a third party user.
type: string
example: "@_gitter_jim:matrix.org"
protocol:
description: The protocol ID that the third party location is a part of.
type: string
example: gitter
fields:
description: Information used to identify this third party location.
type: object
example:
"user": "jim"
title: Location
type: object

@ -0,0 +1,17 @@
# Copyright 2018 New Vector Ltd
#
# 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.
type: array
description: List of matched third party users.
items:
$ref: user.yaml

@ -129,6 +129,8 @@ paths:
"errcode": "M_THREEPID_AUTH_FAILED", "errcode": "M_THREEPID_AUTH_FAILED",
"error": "The third party credentials could not be verified by the identity server." "error": "The third party credentials could not be verified by the identity server."
} }
schema:
"$ref": "definitions/errors/error.yaml"
tags: tags:
- User data - User data
"/account/3pid/email/requestToken": "/account/3pid/email/requestToken":

@ -83,6 +83,8 @@ paths:
"errcode": "M_FORBIDDEN", "errcode": "M_FORBIDDEN",
"error": "You do not have a high enough power level to ban from this room." "error": "You do not have a high enough power level to ban from this room."
} }
schema:
"$ref": "definitions/errors/error.yaml"
tags: tags:
- Room membership - Room membership
"/rooms/{roomId}/unban": "/rooms/{roomId}/unban":
@ -134,5 +136,7 @@ paths:
"errcode": "M_FORBIDDEN", "errcode": "M_FORBIDDEN",
"error": "You do not have a high enough power level to unban from this room." "error": "You do not have a high enough power level to unban from this room."
} }
schema:
"$ref": "definitions/errors/error.yaml"
tags: tags:
- Room membership - Room membership

@ -72,7 +72,7 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Media - Media
"/download/{serverName}/{mediaId}": "/download/{serverName}/{mediaId}":
@ -120,7 +120,7 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Media - Media
"/download/{serverName}/{mediaId}/{fileName}": "/download/{serverName}/{mediaId}/{fileName}":
@ -175,7 +175,7 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Media - Media
"/thumbnail/{serverName}/{mediaId}": "/thumbnail/{serverName}/{mediaId}":
@ -241,7 +241,7 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Media - Media
"/preview_url": "/preview_url":
@ -296,7 +296,7 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Media - Media
"/config": "/config":
@ -336,7 +336,7 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/error.yaml"
tags: tags:
- Media - Media

@ -1,4 +1,5 @@
# Copyright 2016 OpenMarket Ltd # Copyright 2016 OpenMarket Ltd
# Copyright 2018 New Vector Ltd
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -40,7 +41,7 @@ paths:
0. A default ``m.room.power_levels`` event, giving the room creator 0. A default ``m.room.power_levels`` event, giving the room creator
(and not other members) permission to send state events. (and not other members) permission to send state events.
1. Events set by ``presets``. 1. Events set by the ``preset``.
2. Events listed in ``initial_state``, in the order that they are 2. Events listed in ``initial_state``, in the order that they are
listed. listed.
@ -49,6 +50,16 @@ paths:
4. Invite events implied by ``invite`` and ``invite_3pid``. 4. Invite events implied by ``invite`` and ``invite_3pid``.
The available presets do the following with respect to room state:
======================== ============== ====================== ================ =========
Preset ``join_rules`` ``history_visibility`` ``guest_access`` Other
======================== ============== ====================== ================ =========
``private_chat`` ``invite`` ``shared`` ``can_join``
``trusted_private_chat`` ``invite`` ``shared`` ``can_join`` All invitees are given the same power level as the room creator.
``public_chat`` ``public`` ``shared`` ``forbidden``
======================== ============== ====================== ================ =========
operationId: createRoom operationId: createRoom
security: security:
- accessToken: [] - accessToken: []
@ -142,7 +153,7 @@ paths:
room. The expected format of the state events are an object room. The expected format of the state events are an object
with type, state_key and content keys set. with type, state_key and content keys set.
Takes precedence over events set by ``presets``, but gets Takes precedence over events set by ``preset``, but gets
overriden by ``name`` and ``topic`` keys. overriden by ``name`` and ``topic`` keys.
items: items:
type: object type: object
@ -163,20 +174,7 @@ paths:
enum: ["private_chat", "public_chat", "trusted_private_chat"] enum: ["private_chat", "public_chat", "trusted_private_chat"]
description: |- description: |-
Convenience parameter for setting various default state events Convenience parameter for setting various default state events
based on a preset. Must be either: based on a preset.
``private_chat`` =>
``join_rules`` is set to ``invite``.
``history_visibility`` is set to ``shared``.
``trusted_private_chat`` =>
``join_rules`` is set to ``invite``.
``history_visibility`` is set to ``shared``.
All invitees are given the same power level as the room creator.
``public_chat``: =>
``join_rules`` is set to ``public``.
``history_visibility`` is set to ``shared``.
is_direct: is_direct:
type: boolean type: boolean
description: |- description: |-
@ -218,6 +216,8 @@ paths:
invalid: for example, the user's ``power_level`` is set below invalid: for example, the user's ``power_level`` is set below
that necessary to set the room name (``errcode`` set to that necessary to set the room name (``errcode`` set to
``M_INVALID_ROOM_STATE``). ``M_INVALID_ROOM_STATE``).
schema:
"$ref": "definitions/errors/error.yaml"
tags: tags:
- Room creation - Room creation

@ -17,7 +17,9 @@ properties:
errcode: errcode:
type: string type: string
description: An error code. description: An error code.
example: M_UNKNOWN
error: error:
type: string type: string
description: A human-readable error message. description: A human-readable error message.
example: An unknown error occurred
required: ["errcode"] required: ["errcode"]

@ -0,0 +1,32 @@
# Copyright 2018 New Vector Ltd
#
# 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.
$ref: error.yaml
type: object
description: The rate limit was reached for this request
properties:
errcode:
type: string
description: The M_LIMIT_EXCEEDED error code
example: M_LIMIT_EXCEEDED
error:
type: string
description: A human-readable error message.
example: Too many requests
retry_after_ms:
type: integer
description: |-
The amount of time in milliseconds the client should wait
before trying the request again.
example: 2000
required: ["errcode"]

@ -68,6 +68,8 @@ paths:
"errcode": "M_UNKNOWN", "errcode": "M_UNKNOWN",
"error": "Room alias #monkeys:matrix.org already exists." "error": "Room alias #monkeys:matrix.org already exists."
} }
schema:
"$ref": "definitions/errors/error.yaml"
tags: tags:
- Room directory - Room directory
get: get:
@ -118,6 +120,8 @@ paths:
"errcode": "M_NOT_FOUND", "errcode": "M_NOT_FOUND",
"error": "Room alias #monkeys:matrix.org not found." "error": "Room alias #monkeys:matrix.org not found."
} }
schema:
"$ref": "definitions/errors/error.yaml"
tags: tags:
- Room directory - Room directory
delete: delete:

@ -93,9 +93,11 @@ paths:
examples: examples:
application/json: { application/json: {
"errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room"} "errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room"}
schema:
"$ref": "definitions/errors/error.yaml"
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Room membership - Room membership

@ -110,10 +110,12 @@ paths:
examples: examples:
application/json: { application/json: {
"errcode": "M_FORBIDDEN", "error": "You are not invited to this room."} "errcode": "M_FORBIDDEN", "error": "You are not invited to this room."}
schema:
"$ref": "definitions/errors/error.yaml"
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Room membership - Room membership
"/join/{roomIdOrAlias}": "/join/{roomIdOrAlias}":
@ -215,9 +217,11 @@ paths:
examples: examples:
application/json: { application/json: {
"errcode": "M_FORBIDDEN", "error": "You are not invited to this room."} "errcode": "M_FORBIDDEN", "error": "You are not invited to this room."}
schema:
"$ref": "definitions/errors/error.yaml"
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Room membership - Room membership

@ -87,5 +87,7 @@ paths:
"errcode": "M_FORBIDDEN", "errcode": "M_FORBIDDEN",
"error": "You do not have a high enough power level to kick from this room." "error": "You do not have a high enough power level to kick from this room."
} }
schema:
"$ref": "definitions/errors/error.yaml"
tags: tags:
- Room membership - Room membership

@ -64,7 +64,7 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Room membership - Room membership
"/rooms/{roomId}/forget": "/rooms/{roomId}/forget":
@ -107,10 +107,10 @@ paths:
"error": "User @example:matrix.org is in room !au1ba7o:matrix.org" "error": "User @example:matrix.org is in room !au1ba7o:matrix.org"
} }
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/error.yaml"
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Room membership - Room membership

@ -59,6 +59,8 @@ paths:
"errcode": "M_NOT_FOUND", "errcode": "M_NOT_FOUND",
"error": "Room not found" "error": "Room not found"
} }
schema:
"$ref": "definitions/errors/error.yaml"
put: put:
summary: Sets the visibility of a room in the room directory summary: Sets the visibility of a room in the room directory
description: |- description: |-
@ -107,6 +109,8 @@ paths:
"errcode": "M_NOT_FOUND", "errcode": "M_NOT_FOUND",
"error": "Room not found" "error": "Room not found"
} }
schema:
"$ref": "definitions/errors/error.yaml"
"/publicRooms": "/publicRooms":
get: get:
summary: Lists the public rooms on the server. summary: Lists the public rooms on the server.

@ -61,7 +61,7 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Session management - Session management
post: post:
@ -167,15 +167,19 @@ paths:
"errcode": "M_UNKNOWN", "errcode": "M_UNKNOWN",
"error": "Bad login type." "error": "Bad login type."
} }
schema:
"$ref": "definitions/errors/error.yaml"
403: 403:
description: |- description: |-
The login attempt failed. For example, the password may have been incorrect. The login attempt failed. For example, the password may have been incorrect.
examples: examples:
application/json: { application/json: {
"errcode": "M_FORBIDDEN"} "errcode": "M_FORBIDDEN"}
schema:
"$ref": "definitions/errors/error.yaml"
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Session management - Session management

@ -75,7 +75,7 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Presence - Presence
get: get:
@ -123,6 +123,8 @@ paths:
description: |- description: |-
There is no presence state for this user. This user may not exist or There is no presence state for this user. This user may not exist or
isn't exposing presence information to you. isn't exposing presence information to you.
schema:
"$ref": "definitions/errors/error.yaml"
403: 403:
description: You are not allowed to see this user's presence status. description: You are not allowed to see this user's presence status.
examples: examples:
@ -131,7 +133,7 @@ paths:
"error": "You are not allowed to see their presence" "error": "You are not allowed to see their presence"
} }
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/error.yaml"
tags: tags:
- Presence - Presence
"/presence/list/{userId}": "/presence/list/{userId}":
@ -187,7 +189,7 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Presence - Presence
get: get:

@ -67,7 +67,7 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- User data - User data
get: get:
@ -141,7 +141,7 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- User data - User data
get: get:

@ -228,10 +228,10 @@ paths:
"errcode": "M_MISSING_PARAM" "errcode": "M_MISSING_PARAM"
} }
schema: schema:
type: object "$ref": "definitions/errors/error.yaml"
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Push notifications - Push notifications

@ -438,11 +438,11 @@ paths:
"errcode": "M_UNKNOWN" "errcode": "M_UNKNOWN"
} }
schema: schema:
type: object "$ref": "definitions/errors/error.yaml"
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Push notifications - Push notifications
"/pushrules/{scope}/{kind}/{ruleId}/enabled": "/pushrules/{scope}/{kind}/{ruleId}/enabled":

@ -76,6 +76,6 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Room participation - Room participation

@ -177,6 +177,8 @@ paths:
"errcode": "M_USER_IN_USE", "errcode": "M_USER_IN_USE",
"error": "Desired user ID is already taken." "error": "Desired user ID is already taken."
} }
schema:
"$ref": "definitions/errors/error.yaml"
401: 401:
description: |- description: |-
The homeserver requires additional authentication information. The homeserver requires additional authentication information.
@ -185,7 +187,7 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- User data - User data
"/register/email/requestToken": "/register/email/requestToken":
@ -249,7 +251,7 @@ paths:
"error": "The specified address is already in use" "error": "The specified address is already in use"
} }
schema: schema:
type: object "$ref": "definitions/errors/error.yaml"
"/account/password": "/account/password":
post: post:
summary: "Changes a user's password." summary: "Changes a user's password."
@ -296,7 +298,7 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- User data - User data
"/account/password/email/requestToken": "/account/password/email/requestToken":
@ -363,7 +365,7 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- User data - User data
"/register/available": "/register/available":
@ -420,9 +422,11 @@ paths:
"errcode": "M_USER_IN_USE", "errcode": "M_USER_IN_USE",
"error": "Desired user ID is already taken." "error": "Desired user ID is already taken."
} }
schema:
"$ref": "definitions/errors/error.yaml"
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- User data - User data

@ -227,6 +227,9 @@ paths:
description: |- description: |-
The historic profile information of the The historic profile information of the
users that sent the events returned. users that sent the events returned.
The ``string`` key is the user ID for which
the profile belongs to.
additionalProperties: additionalProperties:
type: object type: object
title: User Profile title: User Profile
@ -260,15 +263,24 @@ paths:
The current state for every room in the results. The current state for every room in the results.
This is included if the request had the This is included if the request had the
``include_state`` key set with a value of ``true``. ``include_state`` key set with a value of ``true``.
The ``string`` key is the room ID for which the ``State
Event`` array belongs to.
additionalProperties: additionalProperties:
type: array type: array
title: Room State title: Room State
items: items:
type: object
"$ref": "definitions/event-schemas/schema/core-event-schema/state_event.yaml" "$ref": "definitions/event-schemas/schema/core-event-schema/state_event.yaml"
groups: groups:
type: object type: object
title: Groups title: Groups
description: Any groups that were requested. description: |-
Any groups that were requested.
The outer ``string`` key is the group key requested (eg: ``room_id``
or ``sender``). The inner ``string`` key is the grouped value (eg:
a room's ID or a user's ID).
additionalProperties: additionalProperties:
type: object type: object
title: Group Key title: Group Key
@ -355,6 +367,6 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Search - Search

@ -0,0 +1,194 @@
# Copyright 2018 New Vector Ltd
#
# 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.
swagger: '2.0'
info:
title: "Matrix Client-Server Third Party Lookup API"
version: "1.0.0"
host: localhost:8008
schemes:
- https
- http
basePath: /_matrix/client/%CLIENT_MAJOR_VERSION%
consumes:
- application/json
produces:
- application/json
securityDefinitions:
$ref: definitions/security.yaml
paths:
"/thirdparty/protocols":
get:
summary: Retrieve metadata about all protocols that a homeserver supports.
description: |-
Fetches the overall metadata about protocols supported by the
homeserver. Includes both the available protocols and all fields
required for queries against each protocol.
operationId: queryMetadata
responses:
200:
description: The protocols supported by the homeserver.
schema:
$ref: ../application-service/definitions/protocol_metadata.yaml
"/thirdparty/protocol/{protocol}":
get:
summary: Retrieve metadata about a specific protocol that the homeserver supports.
description: |-
Fetches the metadata from the homeserver about a particular third party protocol.
operationId: queryMetadata
parameters:
- in: path
name: protocol
type: string
description: |-
The name of the protocol.
required: true
x-example: "irc"
responses:
200:
description: The protocol was found and metadata returned.
schema:
$ref: ../application-service/definitions/protocol.yaml
404:
description: The protocol is unknown.
examples:
application/json: {
"errcode": "M_NOT_FOUND"
}
schema:
$ref: definitions/errors/error.yaml
"/thirdparty/location/{protocol}":
get:
summary: Retreive Matrix-side portals rooms leading to a third party location.
description: |-
Requesting this endpoint with a valid protocol name results in a list
of successful mapping results in a JSON array. Each result contains
objects to represent the Matrix room or rooms that represent a portal
to this third party network. Each has the Matrix room alias string,
an identifier for the particular third party network protocol, and an
object containing the network-specific fields that comprise this
identifier. It should attempt to canonicalise the identifier as much
as reasonably possible given the network type.
operationId: queryLocationByProtocol
parameters:
- in: path
name: protocol
type: string
description: The protocol used to communicate to the third party network.
required: true
x-example: irc
- in: query
name: searchFields
type: string
description: |-
One or more custom fields to help identify the third party
location.
responses:
200:
description: At least one portal room was found.
schema:
$ref: ../application-service/definitions/location_batch.yaml
404:
description: No portal rooms were found.
examples:
application/json: {
"errcode": "M_NOT_FOUND"
}
schema:
$ref: definitions/errors/error.yaml
"/thirdparty/user/{protocol}":
get:
summary: Retrieve the Matrix User ID of a corresponding third party user.
description: |-
Retrieve a Matrix User ID linked to a user on the third party service, given
a set of user parameters.
operationId: queryUserByProtocol
parameters:
- in: path
name: protocol
type: string
description: |-
The name of the protocol.
required: true
x-example: irc
- in: query
name: field1, field2...
type: string
description: |-
One or more custom fields that are passed to the AS to help identify the user.
responses:
200:
description: The Matrix User IDs found with the given parameters.
schema:
$ref: ../application-service/definitions/user_batch.yaml
404:
description: The Matrix User ID was not found
examples:
application/json: {
"errcode": "M_NOT_FOUND"
}
schema:
$ref: definitions/errors/error.yaml
"/thirdparty/location":
get:
summary: Reverse-lookup third party locations given a Matrix room alias.
description: |-
Retreive an array of third party network locations from a Matrix room
alias.
operationId: queryLocationByAlias
parameters:
- in: query
name: alias
type: string
description: The Matrix room alias to look up.
required: true
responses:
200:
description: |-
All found third party locations.
schema:
$ref: ../application-service/definitions/location_batch.yaml
404:
description: The Matrix room alias was not found
examples:
application/json: {
"errcode": "M_NOT_FOUND"
}
schema:
$ref: definitions/errors/error.yaml
"/thirdparty/user":
get:
summary: Reverse-lookup third party users given a Matrix User ID.
description: |-
Retreive an array of third party users from a Matrix User ID.
operationId: queryUserByID
parameters:
- in: query
name: userid
type: string
description: The Matrix User ID to look up.
required: true
responses:
200:
description: |-
An array of third party users.
schema:
$ref: ../application-service/definitions/user_batch.yaml
404:
description: The Matrix User ID was not found
examples:
application/json: {
"errcode": "M_NOT_FOUND"
}
schema:
$ref: definitions/errors/error.yaml

@ -126,9 +126,11 @@ paths:
examples: examples:
application/json: { application/json: {
"errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room"} "errcode": "M_FORBIDDEN", "error": "@cheeky_monkey:matrix.org is banned from the room"}
schema:
"$ref": "definitions/errors/error.yaml"
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Room membership - Room membership

@ -82,6 +82,6 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- Room participation - Room participation

@ -95,6 +95,6 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- User data - User data

@ -73,6 +73,6 @@ paths:
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- VOIP - VOIP

@ -65,7 +65,7 @@ paths:
"error": "Unrecognised access token." "error": "Unrecognised access token."
} }
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/error.yaml"
403: 403:
description: description:
The appservice cannot masquerade as the user or has not registered them. The appservice cannot masquerade as the user or has not registered them.
@ -75,10 +75,10 @@ paths:
"error": "Application service has not registered this user." "error": "Application service has not registered this user."
} }
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/error.yaml"
429: 429:
description: This request was rate-limited. description: This request was rate-limited.
schema: schema:
"$ref": "definitions/error.yaml" "$ref": "definitions/errors/rate_limited.yaml"
tags: tags:
- User data - User data

@ -1,4 +1,5 @@
# Copyright 2017 Kamax.io # Copyright 2017 Kamax.io
# Copyright 2018 New Vector Ltd
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.
@ -14,7 +15,7 @@
swagger: '2.0' swagger: '2.0'
info: info:
title: "Matrix Federation Query Directory API" title: "Matrix Federation Query API"
version: "1.0.0" version: "1.0.0"
host: localhost:8448 host: localhost:8448
schemes: schemes:

@ -0,0 +1,44 @@
# Copyright 2018 New Vector Ltd
#
# 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.
swagger: '2.0'
info:
title: "Matrix Federation Query API"
version: "1.0.0"
host: localhost:8448
schemes:
- https
basePath: /_matrix/federation/v1
produces:
- application/json
paths:
"/query/{queryType}":
get:
summary: Query for information
description: |-
Performs a single query request on the receiving homeserver. The query string
arguments are dependent on which type of query is being made. Known query types
are specified as their own endpoints as an extension to this definition.
operationId: queryInfo
parameters:
- in: path
name: queryType
type: string
description: The type of query to make
required: true
x-example: profile
responses:
200:
description: |-
The query response. The schema varies depending on the query being made.

@ -0,0 +1,55 @@
<!-- Note: This is a markdown file so the build script's RST processing doesn't grab it -->
# Changelogs
[Towncrier](https://github.com/hawkowl/towncrier) is used to manage the changelog and
keep it up to date. Because of this, updating a changelog is really easy.
## How to update a changelog when releasing an API
1. Ensure you're in your Python 3 virtual environment
2. `cd` your way to the API you're releasing (eg: `cd changelogs/client_server`)
3. Run `towncrier --version "r0.4.0" --name "client-server" --yes` substituting the
variables as approprite. Note that `--name` is required although the value is ignored.
4. Commit the changes and finish the release process.
## How to prepare a changelog for a new API
For this example, we're going to pretend that the `server_server` API doesn't exist.
1. Create the file `changelogs/server_server.rst`
2. Create the folder `changelogs/server_server`
3. In the new folder, create a `pyproject.toml` file with these contents:
```toml
[tool.towncrier]
filename = "../server_server.rst"
directory = "newsfragments"
issue_format = "`#{issue} <https://github.com/matrix-org/matrix-doc/issues/{issue}>`_"
title_format = "{version}"
[[tool.towncrier.type]]
directory = "breaking"
name = "Breaking Changes"
showcontent = true
[[tool.towncrier.type]]
directory = "deprecation"
name = "Deprecations"
showcontent = true
[[tool.towncrier.type]]
directory = "new"
name = "New Endpoints"
showcontent = true
[[tool.towncrier.type]]
directory = "feature"
name = "Backwards Compatible Changes"
showcontent = true
[[tool.towncrier.type]]
directory = "clarification"
name = "Spec Clarifications"
showcontent = true
```
4. Create a `.gitignore` in `changelogs/server_server/newsfragments` with the contents `!.gitignore`

@ -1,77 +1,3 @@
Unreleased changes
==================
- Changes to the API which will be backwards-compatible for clients:
- New endpoints:
- ``POST /user_directory/search``
(`#1096 <https://github.com/matrix-org/matrix-doc/pull/1096>`_).
- ``GET /rooms/{roomId}/event/{eventId}``
(`#1110 <https://github.com/matrix-org/matrix-doc/pull/1110>`_).
- ``POST /delete_devices``
(`#1239 <https://github.com/matrix-org/matrix-doc/pull/1239>`_).
- Sticker messages:
- Add sticker message event definition.
(`#1158 <https://github.com/matrix-org/matrix-doc/pull/1158>`_).
- Document the ``server_name`` parameter on ``/join/{roomIdOrAlias}``
(`#1364 <https://github.com/matrix-org/matrix-doc/pull/1364>`_).
- Add 'token' parameter to /keys/query endpoint
(`#1104 <https://github.com/matrix-org/matrix-doc/pull/1104>`_).
- Add the room visibility options for the room directory
(`#1141 <https://github.com/matrix-org/matrix-doc/pull/1141>`_).
- Add spec for ignoring users
(`#1142 <https://github.com/matrix-org/matrix-doc/pull/1142>`_).
- Add the ``/register/available`` endpoint for username availability
(`#1151 <https://github.com/matrix-org/matrix-doc/pull/1151>`_).
- Add ``allow_remote`` to the content repo to avoid routing loops
(`#1265 <https://github.com/matrix-org/matrix-doc/pull/1265>`_).
- Add report content API
(`#1264 <https://github.com/matrix-org/matrix-doc/pull/1264>`_).
- Document ``/logout/all`` endpoint
(`#1263 <https://github.com/matrix-org/matrix-doc/pull/1263>`_).
- Document `highlights` field in /search response
(`#1274 <https://github.com/matrix-org/matrix-doc/pull/1274>`_).
- Document the GET version of ``/login``
(`#1361 <https://github.com/matrix-org/matrix-doc/pull/1361>`_).
- Document the CORS/preflight headers
(`#1365 <https://github.com/matrix-org/matrix-doc/pull/1365>`_).
- Spec clarifications:
- Update ``ImageInfo`` and ``ThumbnailInfo`` dimension schema descriptions
to clarify that they relate to intended display size, as opposed to the
intrinsic size of the image file.
(`#1158 <https://github.com/matrix-org/matrix-doc/pull/1158>`_).
- Mark ``home_server`` return field for ``/login`` and ``/register``
endpoints as deprecated
(`#1097 <https://github.com/matrix-org/matrix-doc/pull/1097>`_).
- Fix response format of ``/keys/changes`` endpoint
(`#1106 <https://github.com/matrix-org/matrix-doc/pull/1106>`_).
- Clarify default values for some fields on the /search API
(`#1109 <https://github.com/matrix-org/matrix-doc/pull/1109>`_).
- Fix the representation of ``m.presence`` events
(`#1137 <https://github.com/matrix-org/matrix-doc/pull/1137>`_).
- Clarify that ``m.tag`` ordering is done with numbers, not strings
(`#1139 <https://github.com/matrix-org/matrix-doc/pull/1139>`_).
- Clarify that ``/account/whoami`` should consider application services
(`#1152 <https://github.com/matrix-org/matrix-doc/pull/1152>`_).
- Mark ``GET /rooms/{roomId}/members`` as requiring authentication
(`#1245 <https://github.com/matrix-org/matrix-doc/pull/1244>`_).
- Define what a ``RoomEvent`` is on ``/rooms/{roomId}/messages``
(`#1380 <https://github.com/matrix-org/matrix-doc/pull/1380>`_).
- Mark ``GET /presence/{userId}/status`` as requiring authentication
(`#1371 <https://github.com/matrix-org/matrix-doc/pull/1371>`_).
- Describe ``StateEvent`` for ``/createRoom``
(`#1329 <https://github.com/matrix-org/matrix-doc/pull/1329>`_).
- Describe how the ``reason`` is handled for kicks/bans
(`#1362 <https://github.com/matrix-org/matrix-doc/pull/1362>`_).
- Clarify that clients must leave rooms before forgetting them
(`#1378 <https://github.com/matrix-org/matrix-doc/pull/1378>`_).
- Clarify the request and result types on ``/search``
(`#1381 <https://github.com/matrix-org/matrix-doc/pull/1381>`_).
r0.3.0 r0.3.0
====== ======

@ -0,0 +1 @@
``POST /user_directory/search``

@ -0,0 +1 @@
Mark ``home_server`` return field for ``/login`` and ``/register`` endpoints as deprecated

@ -0,0 +1 @@
Add ``token`` parameter to the ``/keys/query`` endpoint

@ -0,0 +1 @@
Fix response format of ``/keys/changes`` endpoint

@ -0,0 +1 @@
Clarify default values for some fields on the ``/search`` API

@ -0,0 +1 @@
``GET /rooms/{roomId}/event/{eventId}``

@ -0,0 +1 @@
Fix the representation of ``m.presence`` events

@ -0,0 +1 @@
Clarify that ``m.tag`` ordering is done with numbers, not strings

@ -0,0 +1 @@
Add the room visibility options for the room directory

@ -0,0 +1 @@
Add the ``/register/available`` endpoint for username availability

@ -0,0 +1 @@
Clarify that ``/account/whoami`` should consider application services

@ -0,0 +1,3 @@
Update ``ImageInfo`` and ``ThumbnailInfo`` dimension schema descriptions
to clarify that they relate to intended display size, as opposed to the
intrinsic size of the image file.

@ -0,0 +1 @@
Mark ``GET /rooms/{roomId}/members`` as requiring authentication

@ -0,0 +1 @@
Document ``/logout/all`` endpoint

@ -0,0 +1 @@
Add ``allow_remote`` to the content repo to avoid routing loops

@ -0,0 +1 @@
Document `highlights` field in /search response

@ -0,0 +1 @@
Describe ``StateEvent`` for ``/createRoom``

@ -0,0 +1 @@
``GET /thirdparty/*`` Endpoints

@ -0,0 +1 @@
Document the GET version of ``/login``

@ -0,0 +1 @@
Describe how the ``reason`` is handled for kicks/bans

@ -0,0 +1 @@
Document the ``server_name`` parameter on ``/join/{roomIdOrAlias}``

@ -0,0 +1 @@
Document the CORS/preflight headers

@ -0,0 +1 @@
Mark ``GET /presence/{userId}/status`` as requiring authentication

@ -0,0 +1 @@
Describe the rate limit error response schema

@ -0,0 +1 @@
Clarify that clients must leave rooms before forgetting them

@ -0,0 +1 @@
Document guest access in ``/createRoom`` presets

@ -0,0 +1 @@
Define what a ``RoomEvent`` is on ``/rooms/{roomId}/messages``

@ -0,0 +1 @@
Clarify the request and result types on ``/search``

@ -0,0 +1 @@
Clarify some of the properties on the search result

@ -0,0 +1,30 @@
[tool.towncrier]
filename = "../client_server.rst"
directory = "newsfragments"
issue_format = "`#{issue} <https://github.com/matrix-org/matrix-doc/issues/{issue}>`_"
title_format = "{version}"
[[tool.towncrier.type]]
directory = "breaking"
name = "Breaking Changes"
showcontent = true
[[tool.towncrier.type]]
directory = "deprecation"
name = "Deprecations"
showcontent = true
[[tool.towncrier.type]]
directory = "new"
name = "New Endpoints"
showcontent = true
[[tool.towncrier.type]]
directory = "feature"
name = "Backwards Compatible Changes"
showcontent = true
[[tool.towncrier.type]]
directory = "clarification"
name = "Spec Clarifications"
showcontent = true

@ -103,7 +103,7 @@ for filename in os.listdir(cs_api_dir):
output["paths"][path] = {} output["paths"][path] = {}
output["paths"][path][method] = spec output["paths"][path][method] = spec
print "Generating %s" % output_file print("Generating %s" % output_file)
try: try:
os.makedirs(os.path.dirname(output_file)) os.makedirs(os.path.dirname(output_file))

@ -31,6 +31,7 @@ script_dir = os.path.dirname(os.path.abspath(__file__))
docs_dir = os.path.dirname(script_dir) docs_dir = os.path.dirname(script_dir)
spec_dir = os.path.join(docs_dir, "specification") spec_dir = os.path.join(docs_dir, "specification")
tmp_dir = os.path.join(script_dir, "tmp") tmp_dir = os.path.join(script_dir, "tmp")
changelog_dir = os.path.join(docs_dir, "changelogs")
VERBOSE = False VERBOSE = False
@ -151,7 +152,7 @@ def is_title_line(prev_line, line, title_styles):
def get_rst(file_info, title_level, title_styles, spec_dir, adjust_titles): def get_rst(file_info, title_level, title_styles, spec_dir, adjust_titles):
# string are file paths to RST blobs # string are file paths to RST blobs
if isinstance(file_info, basestring): if isinstance(file_info, str):
log("%s %s" % (">" * (1 + title_level), file_info)) log("%s %s" % (">" * (1 + title_level), file_info))
with open(os.path.join(spec_dir, file_info), "r") as f: with open(os.path.join(spec_dir, file_info), "r") as f:
rst = None rst = None
@ -194,7 +195,7 @@ def build_spec(target, out_filename):
spec_dir=spec_dir, spec_dir=spec_dir,
adjust_titles=True adjust_titles=True
) )
outfile.write(section) outfile.write(section.encode('UTF-8'))
""" """
@ -279,15 +280,16 @@ def rst2html(i, o, stylesheets):
def addAnchors(path): def addAnchors(path):
log("add anchors %s" % path) log("add anchors %s" % path)
with open(path, "r") as f: with open(path, "rb") as f:
lines = f.readlines() lines = f.readlines()
replacement = replacement = r'<p><a class="anchor" id="\3"></a></p>\n\1' replacement = r'<p><a class="anchor" id="\2"></a></p>\n\1'
with open(path, "w") as f: with open(path, "wb") as f:
for line in lines: for line in lines:
line = line.decode("UTF-8")
line = re.sub(r'(<h\d id="#?(.*?)">)', replacement, line.rstrip()) line = re.sub(r'(<h\d id="#?(.*?)">)', replacement, line.rstrip())
line = re.sub(r'(<div class="section" (id)="(.*?)">)', replacement, line.rstrip()) line = re.sub(r'(<div class="section" id="(.*?)">)', replacement, line.rstrip())
f.write(line + "\n") f.write((line + "\n").encode('UTF-8'))
def run_through_template(input_files, set_verbose, substitutions): def run_through_template(input_files, set_verbose, substitutions):
@ -364,7 +366,7 @@ def get_build_target(all_targets, target_name):
resolved_files = [] resolved_files = []
for file_entry in target["files"]: for file_entry in target["files"]:
# file_entry is a group id # file_entry is a group id
if isinstance(file_entry, basestring) and file_entry.startswith("group:"): if isinstance(file_entry, str) and file_entry.startswith("group:"):
group = get_group(file_entry, 0) group = get_group(file_entry, 0)
# The group may be resolved to a list of file entries, in which case # The group may be resolved to a list of file entries, in which case
# we want to extend the array to insert each of them rather than # we want to extend the array to insert each of them rather than
@ -376,8 +378,8 @@ def get_build_target(all_targets, target_name):
# file_entry is a dict which has more file entries as values # file_entry is a dict which has more file entries as values
elif isinstance(file_entry, dict): elif isinstance(file_entry, dict):
resolved_entry = {} resolved_entry = {}
for (depth, entry) in file_entry.iteritems(): for (depth, entry) in file_entry.items():
if not isinstance(entry, basestring): if not isinstance(entry, str):
raise Exception( raise Exception(
"Double-nested depths are not supported. Entry: %s" % (file_entry,) "Double-nested depths are not supported. Entry: %s" % (file_entry,)
) )
@ -395,11 +397,11 @@ def get_build_target(all_targets, target_name):
return build_target return build_target
def log(line): def log(line):
print "gendoc: %s" % line print("gendoc: %s" % line)
def logv(line): def logv(line):
if VERBOSE: if VERBOSE:
print "gendoc:V: %s" % line print("gendoc:V: %s" % line)
def cleanup_env(): def cleanup_env():
@ -445,7 +447,7 @@ def main(targets, dest_dir, keep_intermediates, substitutions):
stylesheets = glob.glob(os.path.join(script_dir, "css", "*.css")) stylesheets = glob.glob(os.path.join(script_dir, "css", "*.css"))
for target_name, templated_file in templated_files.iteritems(): for target_name, templated_file in templated_files.items():
target = target_defs["targets"].get(target_name) target = target_defs["targets"].get(target_name)
version_label = None version_label = None
if target: if target:
@ -480,7 +482,7 @@ def list_targets():
with open(os.path.join(spec_dir, "targets.yaml"), "r") as targ_file: with open(os.path.join(spec_dir, "targets.yaml"), "r") as targ_file:
target_defs = yaml.load(targ_file.read()) target_defs = yaml.load(targ_file.read())
targets = target_defs["targets"].keys() targets = target_defs["targets"].keys()
print "\n".join(targets) print("\n".join(targets))
def extract_major(s): def extract_major(s):

@ -12,13 +12,18 @@ authors = set()
prs = set() prs = set()
def getpage(url, page): def getpage(url, page):
resp = requests.get(url + str(page)) url = url + str(page)
resp = requests.get(url)
for link in resp.links.values(): for link in resp.links.values():
if link['rel'] == 'last': if link['rel'] == 'last':
pagecount = re.search('page=(.+?)', link['url']).group(1) pagecount = re.search('page=(.+?)', link['url']).group(1)
return resp.json() val = resp.json()
if not isinstance(val, list):
print(val) # Just dump the raw (likely error) response to the log
raise Exception("Error calling %s" % url)
return val
def getbylabel(label): def getbylabel(label):
pagecount = 1 pagecount = 1
@ -27,7 +32,7 @@ def getbylabel(label):
print(urlbase) print(urlbase)
json.extend(getpage(urlbase, 1)) json.extend(getpage(urlbase, 1))
for page in range(2, int(pagecount) + 1): for page in range(2, int(pagecount) + 1):
getpage(urlbase, page) json.extend(getpage(urlbase, page))
return json return json

@ -7,3 +7,5 @@ Jinja2 >= 2.9.6
jsonschema >= 2.6.0 jsonschema >= 2.6.0
PyYAML >= 3.12 PyYAML >= 3.12
requests >= 2.18.4 requests >= 2.18.4
towncrier == 18.6.0
six >= 1.11.0

@ -19,14 +19,14 @@
import argparse import argparse
import os import os
import SimpleHTTPServer import http.server
import SocketServer import socketserver
# Thanks to http://stackoverflow.com/a/13354482 # Thanks to http://stackoverflow.com/a/13354482
class MyHTTPRequestHandler(SimpleHTTPServer.SimpleHTTPRequestHandler): class MyHTTPRequestHandler(http.server.SimpleHTTPRequestHandler):
def end_headers(self): def end_headers(self):
self.send_my_headers() self.send_my_headers()
SimpleHTTPServer.SimpleHTTPRequestHandler.end_headers(self) http.server.SimpleHTTPRequestHandler.end_headers(self)
def send_my_headers(self): def send_my_headers(self):
self.send_header("Access-Control-Allow-Origin", "*") self.send_header("Access-Control-Allow-Origin", "*")
@ -49,7 +49,7 @@ if __name__ == '__main__':
os.chdir(args.swagger_dir) os.chdir(args.swagger_dir)
httpd = SocketServer.TCPServer(("localhost", args.port), httpd = socketserver.TCPServer(("localhost", args.port),
MyHTTPRequestHandler) MyHTTPRequestHandler)
print "Serving at http://localhost:%i/api-docs.json" % args.port print("Serving at http://localhost:%i/api-docs.json" % args.port)
httpd.serve_forever() httpd.serve_forever()

@ -11,7 +11,6 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from sets import Set
class AccessKeyStore(object): class AccessKeyStore(object):
@ -22,7 +21,7 @@ class AccessKeyStore(object):
if not existing_data: if not existing_data:
existing_data = {} existing_data = {}
self.data = existing_data self.data = existing_data
self.accessed_set = Set() self.accessed_set = set()
def keys(self): def keys(self):
return self.data.keys() return self.data.keys()
@ -35,5 +34,5 @@ class AccessKeyStore(object):
return self.data[key] return self.data[key]
def get_unaccessed_set(self): def get_unaccessed_set(self):
data_list = Set(self.data.keys()) data_list = set(self.data.keys())
return data_list - self.accessed_set return data_list - self.accessed_set

@ -29,7 +29,7 @@ class Sections(object):
def log(self, text): def log(self, text):
if self.debug: if self.debug:
print "batesian:sections: %s" % text print("batesian:sections: %s" % text)
def get_sections(self): def get_sections(self):
render_list = inspect.getmembers(self, predicate=inspect.ismethod) render_list = inspect.getmembers(self, predicate=inspect.ismethod)
@ -40,7 +40,7 @@ class Sections(object):
section_key = func_name[len("render_"):] section_key = func_name[len("render_"):]
self.log("Generating section '%s'" % section_key) self.log("Generating section '%s'" % section_key)
section = func() section = func()
if isinstance(section, basestring): if isinstance(section, str):
if section_key in section_dict: if section_key in section_dict:
raise Exception( raise Exception(
("%s : Section %s already exists. It must have been " + ("%s : Section %s already exists. It must have been " +
@ -54,8 +54,8 @@ class Sections(object):
) )
elif isinstance(section, dict): elif isinstance(section, dict):
self.log(" Generated multiple sections:") self.log(" Generated multiple sections:")
for (k, v) in section.iteritems(): for (k, v) in section.items():
if not isinstance(k, basestring) or not isinstance(v, basestring): if not isinstance(k, str) or not isinstance(v, str):
raise Exception( raise Exception(
("Method %s returned multiple sections as a dict but " + ("Method %s returned multiple sections as a dict but " +
"expected the dict elements to be strings but they aren't.") % "expected the dict elements to be strings but they aren't.") %

@ -41,7 +41,7 @@ class Units(object):
trace = inspect.stack() trace = inspect.stack()
if len(trace) > 1 and len(trace[1]) > 2: if len(trace) > 1 and len(trace[1]) > 2:
func_name = trace[1][3] + ":" func_name = trace[1][3] + ":"
print "batesian:units:%s %s" % (func_name, text) print("batesian:units:%s %s" % (func_name, text))
def get_units(self, debug=False): def get_units(self, debug=False):
unit_list = inspect.getmembers(self, predicate=inspect.ismethod) unit_list = inspect.getmembers(self, predicate=inspect.ismethod)
@ -50,7 +50,7 @@ class Units(object):
if not func_name.startswith("load_"): if not func_name.startswith("load_"):
continue continue
unit_key = func_name[len("load_"):] unit_key = func_name[len("load_"):]
if len(inspect.getargs(func.func_code).args) > 1: if len(inspect.getargs(func.__code__).args) > 1:
unit_dict[unit_key] = func(self.substitutions) unit_dict[unit_key] = func(self.substitutions)
else: else:
unit_dict[unit_key] = func() unit_dict[unit_key] = func()

@ -63,6 +63,7 @@ import sys
from textwrap import TextWrapper from textwrap import TextWrapper
from matrix_templates.units import TypeTableRow from matrix_templates.units import TypeTableRow
from functools import reduce
def create_from_template(template, sections): def create_from_template(template, sections):
@ -138,7 +139,7 @@ def main(input_module, files=None, out_dir=None, verbose=False, substitutions={}
return reduce(max, rowwidths, return reduce(max, rowwidths,
default if default is not None else default_width) default if default is not None else default_width)
results = map(colwidth, keys, defaults) results = list(map(colwidth, keys, defaults))
return results return results
# make Jinja aware of the templates and filters # make Jinja aware of the templates and filters
@ -167,7 +168,7 @@ def main(input_module, files=None, out_dir=None, verbose=False, substitutions={}
# print out valid section keys if no file supplied # print out valid section keys if no file supplied
if not files: if not files:
print "\nValid template variables:" print("\nValid template variables:")
for key in sections.keys(): for key in sections.keys():
sec_text = "" if (len(sections[key]) > 75) else ( sec_text = "" if (len(sections[key]) > 75) else (
"(Value: '%s')" % sections[key] "(Value: '%s')" % sections[key]
@ -175,8 +176,8 @@ def main(input_module, files=None, out_dir=None, verbose=False, substitutions={}
sec_info = "%s characters" % len(sections[key]) sec_info = "%s characters" % len(sections[key])
if sections[key].count("\n") > 0: if sections[key].count("\n") > 0:
sec_info += ", %s lines" % sections[key].count("\n") sec_info += ", %s lines" % sections[key].count("\n")
print " %s" % key print(" %s" % key)
print " %s %s" % (sec_info, sec_text) print(" %s %s" % (sec_info, sec_text))
return return
# check the input files and substitute in sections where required # check the input files and substitute in sections where required
@ -190,8 +191,8 @@ def main(input_module, files=None, out_dir=None, verbose=False, substitutions={}
def process_file(env, sections, filename, output_filename): def process_file(env, sections, filename, output_filename):
log("Parsing input template: %s" % filename) log("Parsing input template: %s" % filename)
with open(filename, "r") as file_stream: with open(filename, "rb") as file_stream:
temp_str = file_stream.read().decode("utf-8") temp_str = file_stream.read().decode('UTF-8')
# do sanity checking on the template to make sure they aren't reffing things # do sanity checking on the template to make sure they aren't reffing things
# which will never be replaced with a section. # which will never be replaced with a section.
@ -213,13 +214,13 @@ def process_file(env, sections, filename, output_filename):
for old, new in substitutions.items(): for old, new in substitutions.items():
output = output.replace(old, new) output = output.replace(old, new)
with open(output_filename, "w") as f: with open(output_filename, "wb") as f:
f.write(output.encode("utf-8")) f.write(output.encode('UTF-8'))
log("Output file for: %s" % output_filename) log("Output file for: %s" % output_filename)
def log(line): def log(line):
print "batesian: %s" % line print("batesian: %s" % line)
if __name__ == '__main__': if __name__ == '__main__':
parser = ArgumentParser( parser = ArgumentParser(

@ -11,8 +11,8 @@
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and # See the License for the specific language governing permissions and
# limitations under the License. # limitations under the License.
from sections import MatrixSections from .sections import MatrixSections
from units import MatrixUnits from .units import MatrixUnits
import os import os
exports = { exports = {

@ -29,8 +29,9 @@ import os.path
import re import re
import subprocess import subprocess
import sys import sys
import urllib
import yaml import yaml
from functools import reduce
from six.moves.urllib.parse import urlencode, quote
matrix_doc_dir=reduce(lambda acc,_: os.path.dirname(acc), matrix_doc_dir=reduce(lambda acc,_: os.path.dirname(acc),
range(1, 5), os.path.abspath(__file__)) range(1, 5), os.path.abspath(__file__))
@ -147,7 +148,7 @@ def inherit_parents(obj):
# settings defined in the child take priority over the parents, so we # settings defined in the child take priority over the parents, so we
# iterate through the parents first, and then overwrite with the settings # iterate through the parents first, and then overwrite with the settings
# from the child. # from the child.
for p in map(inherit_parents, parents) + [obj]: for p in list(map(inherit_parents, parents)) + [obj]:
# child blats out type, title and description # child blats out type, title and description
for key in ('type', 'title', 'description'): for key in ('type', 'title', 'description'):
if p.get(key): if p.get(key):
@ -250,12 +251,12 @@ def get_json_schema_object_fields(obj, enforce_title=False):
tables.extend(res["tables"]) tables.extend(res["tables"])
logger.debug("Done property %s" % key_name) logger.debug("Done property %s" % key_name)
except Exception, e: except Exception as e:
e2 = Exception("Error reading property %s.%s: %s" % e2 = Exception("Error reading property %s.%s: %s" %
(obj_title, key_name, str(e))) (obj_title, key_name, str(e)))
# throw the new exception with the old stack trace, so that # throw the new exception with the old stack trace, so that
# we don't lose information about where the error occurred. # we don't lose information about where the error occurred.
raise e2, None, sys.exc_info()[2] raise e2.with_traceback(sys.exc_info()[2])
tables.insert(0, TypeTable(title=obj_title, rows=first_table_rows)) tables.insert(0, TypeTable(title=obj_title, rows=first_table_rows))
@ -380,7 +381,7 @@ def get_example_for_schema(schema):
if 'properties' not in schema: if 'properties' not in schema:
raise Exception('"object" property has neither properties nor example') raise Exception('"object" property has neither properties nor example')
res = OrderedDict() res = OrderedDict()
for prop_name, prop in schema['properties'].iteritems(): for prop_name, prop in schema['properties'].items():
logger.debug("Parsing property %r" % prop_name) logger.debug("Parsing property %r" % prop_name)
prop_example = get_example_for_schema(prop) prop_example = get_example_for_schema(prop)
res[prop_name] = prop_example res[prop_name] = prop_example
@ -523,7 +524,7 @@ class MatrixUnits(Units):
if param_loc == "path": if param_loc == "path":
path_template = path_template.replace( path_template = path_template.replace(
"{%s}" % param_name, urllib.quote(example) "{%s}" % param_name, quote(example)
) )
elif param_loc == "query": elif param_loc == "query":
if type(example) == list: if type(example) == list:
@ -532,7 +533,7 @@ class MatrixUnits(Units):
else: else:
example_query_params.append((param_name, example)) example_query_params.append((param_name, example))
except Exception, e: except Exception as e:
raise Exception("Error handling parameter %s" % param_name, e) raise Exception("Error handling parameter %s" % param_name, e)
# endfor[param] # endfor[param]
good_response = None good_response = None
@ -556,14 +557,14 @@ class MatrixUnits(Units):
) )
if "headers" in good_response: if "headers" in good_response:
headers = TypeTable() headers = TypeTable()
for (header_name, header) in good_response["headers"].iteritems(): for (header_name, header) in good_response["headers"].items():
headers.add_row( headers.add_row(
TypeTableRow(key=header_name, title=header["type"], TypeTableRow(key=header_name, title=header["type"],
desc=header["description"]), desc=header["description"]),
) )
endpoint["res_headers"] = headers endpoint["res_headers"] = headers
query_string = "" if len( query_string = "" if len(
example_query_params) == 0 else "?" + urllib.urlencode( example_query_params) == 0 else "?" + urlencode(
example_query_params) example_query_params)
if example_body: if example_body:
endpoint["example"][ endpoint["example"][
@ -605,12 +606,12 @@ class MatrixUnits(Units):
body_tables = req_body_tables[1:] body_tables = req_body_tables[1:]
endpoint_data['req_body_tables'].extend(body_tables) endpoint_data['req_body_tables'].extend(body_tables)
except Exception, e: except Exception as e:
e2 = Exception( e2 = Exception(
"Error decoding body of API endpoint %s %s: %s" % "Error decoding body of API endpoint %s %s: %s" %
(endpoint_data["method"], endpoint_data["path"], e) (endpoint_data["method"], endpoint_data["path"], e)
) )
raise e2, None, sys.exc_info()[2] raise e2.with_traceback(sys.exc_info()[2])
def load_swagger_apis(self): def load_swagger_apis(self):
@ -711,12 +712,12 @@ class MatrixUnits(Units):
if filename != event_name: if filename != event_name:
examples[event_name] = examples.get(event_name, []) examples[event_name] = examples.get(event_name, [])
examples[event_name].append(example) examples[event_name].append(example)
except Exception, e: except Exception as e:
e2 = Exception("Error reading event example "+filepath+": "+ e2 = Exception("Error reading event example "+filepath+": "+
str(e)) str(e))
# throw the new exception with the old stack trace, so that # throw the new exception with the old stack trace, so that
# we don't lose information about where the error occurred. # we don't lose information about where the error occurred.
raise e2, None, sys.exc_info()[2] raise e2.with_traceback(sys.exc_info()[2])
return examples return examples
@ -730,12 +731,12 @@ class MatrixUnits(Units):
filepath = os.path.join(path, filename) filepath = os.path.join(path, filename)
try: try:
schemata[filename] = self.read_event_schema(filepath) schemata[filename] = self.read_event_schema(filepath)
except Exception, e: except Exception as e:
e2 = Exception("Error reading event schema "+filepath+": "+ e2 = Exception("Error reading event schema "+filepath+": "+
str(e)) str(e))
# throw the new exception with the old stack trace, so that # throw the new exception with the old stack trace, so that
# we don't lose information about where the error occurred. # we don't lose information about where the error occurred.
raise e2, None, sys.exc_info()[2] raise e2.with_traceback(sys.exc_info()[2])
return schemata return schemata
@ -831,12 +832,42 @@ class MatrixUnits(Units):
path = os.path.join(CHANGELOG_DIR, f) path = os.path.join(CHANGELOG_DIR, f)
name = f[:-4] name = f[:-4]
# If there's a directory with the same name, we'll try to generate
# a towncrier changelog and prepend it to the general changelog.
tc_path = os.path.join(CHANGELOG_DIR, name)
tc_lines = []
if os.path.isdir(tc_path):
logger.info("Generating towncrier changelog for: %s" % name)
p = subprocess.Popen(
['towncrier', '--version', 'Unreleased Changes', '--name', name, '--draft'],
cwd=tc_path,
stderr=subprocess.PIPE,
stdout=subprocess.PIPE,
)
stdout, stderr = p.communicate()
if p.returncode != 0:
# Something broke - dump as much information as we can
logger.error("Towncrier exited with code %s" % p.returncode)
logger.error(stdout.decode('UTF-8'))
logger.error(stderr.decode('UTF-8'))
raw_log = ""
else:
raw_log = stdout.decode('UTF-8')
# This is a bit of a hack, but it does mean that the log at least gets *something*
# to tell us it broke
if not raw_log.startswith("Unreleased Changes"):
logger.error("Towncrier appears to have failed to generate a changelog")
logger.error(raw_log)
raw_log = ""
tc_lines = raw_log.splitlines()
title_part = None title_part = None
changelog_lines = [] changelog_lines = []
with open(path, "r") as f: with open(path, "r") as f:
lines = f.readlines() lines = f.readlines()
prev_line = None prev_line = None
for line in lines: for line in (tc_lines + lines):
if prev_line is None: if prev_line is None:
prev_line = line prev_line = line
continue continue
@ -852,7 +883,10 @@ class MatrixUnits(Units):
# then bail out. # then bail out.
changelog_lines.pop() changelog_lines.pop()
break break
changelog_lines.append(" " + line) # Don't generate subheadings (we'll keep the title though)
if re.match("^[-]{3,}$", line.strip()):
continue
changelog_lines.append(" " + line + '\n')
changelogs[name] = "".join(changelog_lines) changelogs[name] = "".join(changelog_lines)
return changelogs return changelogs
@ -871,7 +905,7 @@ class MatrixUnits(Units):
['git', 'rev-parse', '--abbrev-ref', 'HEAD'], ['git', 'rev-parse', '--abbrev-ref', 'HEAD'],
stderr=null, stderr=null,
cwd=cwd, cwd=cwd,
).strip() ).strip().decode('UTF-8')
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
git_branch = "" git_branch = ""
try: try:
@ -879,7 +913,7 @@ class MatrixUnits(Units):
['git', 'describe', '--exact-match'], ['git', 'describe', '--exact-match'],
stderr=null, stderr=null,
cwd=cwd, cwd=cwd,
).strip() ).strip().decode('UTF-8')
git_tag = "tag=" + git_tag git_tag = "tag=" + git_tag
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
git_tag = "" git_tag = ""
@ -888,7 +922,7 @@ class MatrixUnits(Units):
['git', 'rev-parse', '--short', 'HEAD'], ['git', 'rev-parse', '--short', 'HEAD'],
stderr=null, stderr=null,
cwd=cwd, cwd=cwd,
).strip() ).strip().decode('UTF-8')
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
git_commit = "" git_commit = ""
try: try:
@ -897,7 +931,7 @@ class MatrixUnits(Units):
['git', 'describe', '--dirty=' + dirty_string, "--all"], ['git', 'describe', '--dirty=' + dirty_string, "--all"],
stderr=null, stderr=null,
cwd=cwd, cwd=cwd,
).strip().endswith(dirty_string) ).strip().decode('UTF-8').endswith(dirty_string)
git_dirty = "dirty" if is_dirty else "" git_dirty = "dirty" if is_dirty else ""
except subprocess.CalledProcessError: except subprocess.CalledProcessError:
git_dirty = "" git_dirty = ""
@ -908,7 +942,7 @@ class MatrixUnits(Units):
s for s in s for s in
(git_branch, git_tag, git_commit, git_dirty,) (git_branch, git_tag, git_commit, git_dirty,)
if s if s
).encode("ascii") ).encode("ascii").decode('ascii')
return { return {
"string": git_version, "string": git_version,
"revision": git_commit "revision": git_commit

@ -4,8 +4,13 @@ set -ex
cd `dirname $0`/.. cd `dirname $0`/..
virtualenv env virtualenv -p python3 env
. env/bin/activate . env/bin/activate
# Print out the python versions for debugging purposes
python --version
pip --version
pip install -r scripts/requirements.txt pip install -r scripts/requirements.txt
# do sanity checks on the examples and swagger # do sanity checks on the examples and swagger

@ -42,6 +42,7 @@ Summary
`Server Side Search`_ Optional Optional Optional Optional Optional `Server Side Search`_ Optional Optional Optional Optional Optional
`Server Administration`_ Optional Optional Optional Optional Optional `Server Administration`_ Optional Optional Optional Optional Optional
`Event Context`_ Optional Optional Optional Optional Optional `Event Context`_ Optional Optional Optional Optional Optional
`Third Party Networks`_ Optional Optional Optional Optional Optional
===================================== ========== ========== ========== ========== ========== ===================================== ========== ========== ========== ========== ==========
*Please see each module for more details on what clients need to implement.* *Please see each module for more details on what clients need to implement.*
@ -57,6 +58,7 @@ Summary
.. _Server Side Search: `module:search`_ .. _Server Side Search: `module:search`_
.. _Server Administration: `module:admin`_ .. _Server Administration: `module:admin`_
.. _Event Context: `module:event-context`_ .. _Event Context: `module:event-context`_
.. _Third Party Networks: `module:third-party-networks`_
Clients Clients
------- -------

@ -0,0 +1,20 @@
Third Party Networks
====================
.. _module:third-party-networks:
Application services can provide access to third party networks via bridging.
This allows Matrix users to communicate with users on other communication
platforms, with messages ferried back and forth by the application service. A
single application service may bridge multiple third party networks, and many
individual locations within those networks. A single third party network
location may be bridged to multiple Matrix rooms.
Third Party Lookups
-------------------
A client may wish to provide a rich interface for joining third party
locations and connecting with third party users. Information necessary for
such an interface is provided by third party lookups.
{{third_party_lookup_cs_http_api}}

@ -729,16 +729,7 @@ Retrieves all of the transactions later than any version given by the "v"
arguments. arguments.
To make a query:: {{query_general_ss_http_api}}
GET .../query/<query_type>
Query args: as specified by the individual query types
Response: JSON encoding of a response object
Performs a single query request on the receiving homeserver. The Query Type
part of the path specifies the kind of query being made, and its query
arguments have a meaning specific to that kind of query. The response is a
JSON-encoded object whose meaning also depends on the kind of query.
To join a room:: To join a room::

@ -68,6 +68,7 @@ groups: # reusable blobs of files when prefixed with 'group:'
- modules/ignore_users.rst - modules/ignore_users.rst
- modules/stickers.rst - modules/stickers.rst
- modules/report_content.rst - modules/report_content.rst
- modules/third_party_networks.rst
title_styles: ["=", "-", "~", "+", "^", "`", "@", ":"] title_styles: ["=", "-", "~", "+", "^", "`", "@", ":"]

Loading…
Cancel
Save