Merge branch 'master' into module-im
This commit is contained in:
commit
47cf958b54
18 changed files with 473 additions and 192 deletions
|
@ -6,6 +6,34 @@
|
||||||
.. in Jenkins. Comments like this are ignored by both RST and the templating
|
.. in Jenkins. Comments like this are ignored by both RST and the templating
|
||||||
.. system. Add the newest release notes beneath this comment.
|
.. system. Add the newest release notes beneath this comment.
|
||||||
|
|
||||||
|
Specification changes in v0.2.0 (2015-10-02)
|
||||||
|
============================================
|
||||||
|
|
||||||
|
This update fundamentally restructures the specification. The specification has
|
||||||
|
been split into more digestible "modules" which each describe a particular
|
||||||
|
function (e.g. typing). This was done in order make the specification easier to
|
||||||
|
maintain and help define which modules are mandatory for certain types
|
||||||
|
of clients. Types of clients along with the mandatory modules can be found in a
|
||||||
|
new "Feature Profiles" section. This update also begins to aggressively
|
||||||
|
standardise on using Swagger and JSON Schema to document HTTP endpoints and
|
||||||
|
Events respectively. It also introduces a number of new concepts to Matrix.
|
||||||
|
|
||||||
|
Additions:
|
||||||
|
- New section: Feature Profiles.
|
||||||
|
- New section: Receipts.
|
||||||
|
- New section: Room history visibility.
|
||||||
|
- New event: ``m.receipt``.
|
||||||
|
- New event: ``m.room.canonical_alias``
|
||||||
|
- New event: ``m.room.history_visibility``
|
||||||
|
- New keys: ``/createRoom`` - allows room "presets" using ``preset`` and
|
||||||
|
``initial_state`` keys.
|
||||||
|
- New endpoint: ``/tokenrefresh`` - Related to refreshing access tokens.
|
||||||
|
|
||||||
|
Modifications:
|
||||||
|
- Convert most of the older HTTP APIs to Swagger documentation.
|
||||||
|
- Convert most of the older event formats to JSON Schema.
|
||||||
|
- Move selected client-server sections to be "Modules".
|
||||||
|
|
||||||
Specification changes in v0.1.0 (2015-06-01)
|
Specification changes in v0.1.0 (2015-06-01)
|
||||||
============================================
|
============================================
|
||||||
- First numbered release.
|
- First numbered release.
|
||||||
|
|
|
@ -34,7 +34,7 @@ def check_parameter(filepath, request, parameter):
|
||||||
example = None
|
example = None
|
||||||
try:
|
try:
|
||||||
example_json = schema.get('example')
|
example_json = schema.get('example')
|
||||||
if example_json:
|
if example_json and not schema.get("format") == "byte":
|
||||||
example = json.loads(example_json)
|
example = json.loads(example_json)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise ValueError("Error parsing JSON example request for %r" % (
|
raise ValueError("Error parsing JSON example request for %r" % (
|
||||||
|
|
|
@ -15,16 +15,22 @@ paths:
|
||||||
summary: Upload some content to the content repository.
|
summary: Upload some content to the content repository.
|
||||||
produces: ["application/json"]
|
produces: ["application/json"]
|
||||||
parameters:
|
parameters:
|
||||||
|
- in: header
|
||||||
|
name: Content-Type
|
||||||
|
type: string
|
||||||
|
description: The content type of the file being uploaded
|
||||||
|
x-example: "Content-Type: audio/mpeg"
|
||||||
- in: body
|
- in: body
|
||||||
name: content
|
name: "<content>"
|
||||||
description: The content to be uploaded.
|
description: The content to be uploaded.
|
||||||
required: true
|
required: true
|
||||||
schema:
|
schema:
|
||||||
type: string
|
type: string
|
||||||
|
example: "<bytes>"
|
||||||
format: byte
|
format: byte
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: Information about the uploaded content.
|
description: The MXC URI for the uploaded content.
|
||||||
schema:
|
schema:
|
||||||
type: object
|
type: object
|
||||||
required: ["content_uri"]
|
required: ["content_uri"]
|
||||||
|
@ -32,6 +38,11 @@ paths:
|
||||||
content_uri:
|
content_uri:
|
||||||
type: string
|
type: string
|
||||||
description: "The MXC URI to the uploaded content."
|
description: "The MXC URI to the uploaded content."
|
||||||
|
examples:
|
||||||
|
"application/json": |-
|
||||||
|
{
|
||||||
|
"content_uri": "mxc://example.com/AQwafuaFswefuhsfAFAgsw"
|
||||||
|
}
|
||||||
"/download/{serverName}/{mediaId}":
|
"/download/{serverName}/{mediaId}":
|
||||||
get:
|
get:
|
||||||
summary: "Download content from the content repository."
|
summary: "Download content from the content repository."
|
||||||
|
@ -40,18 +51,27 @@ paths:
|
||||||
- in: path
|
- in: path
|
||||||
type: string
|
type: string
|
||||||
name: serverName
|
name: serverName
|
||||||
|
x-example: matrix.org
|
||||||
required: true
|
required: true
|
||||||
description: |
|
description: |
|
||||||
The server name from the ``mxc://`` URI (the authoritory component)
|
The server name from the ``mxc://`` URI (the authoritory component)
|
||||||
- in: path
|
- in: path
|
||||||
type: string
|
type: string
|
||||||
name: mediaId
|
name: mediaId
|
||||||
|
x-example: ascERGshawAWawugaAcauga
|
||||||
required: true
|
required: true
|
||||||
description: |
|
description: |
|
||||||
The media ID from the ``mxc://`` URI (the path component)
|
The media ID from the ``mxc://`` URI (the path component)
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: "The content downloaded."
|
description: "The content that was previously uploaded."
|
||||||
|
headers:
|
||||||
|
Content-Type:
|
||||||
|
description: "The content type of the file that was previously uploaded."
|
||||||
|
type: "string"
|
||||||
|
Content-Disposition:
|
||||||
|
description: "The name of the file that was previously uploaded, if set."
|
||||||
|
type: "string"
|
||||||
schema:
|
schema:
|
||||||
type: file
|
type: file
|
||||||
"/thumbnail/{serverName}/{mediaId}":
|
"/thumbnail/{serverName}/{mediaId}":
|
||||||
|
@ -63,30 +83,44 @@ paths:
|
||||||
type: string
|
type: string
|
||||||
name: serverName
|
name: serverName
|
||||||
required: true
|
required: true
|
||||||
|
x-example: matrix.org
|
||||||
description: |
|
description: |
|
||||||
The server name from the ``mxc://`` URI (the authoritory component)
|
The server name from the ``mxc://`` URI (the authoritory component)
|
||||||
- in: path
|
- in: path
|
||||||
type: string
|
type: string
|
||||||
name: mediaId
|
name: mediaId
|
||||||
|
x-example: ascERGshawAWawugaAcauga
|
||||||
required: true
|
required: true
|
||||||
description: |
|
description: |
|
||||||
The media ID from the ``mxc://`` URI (the path component)
|
The media ID from the ``mxc://`` URI (the path component)
|
||||||
- in: query
|
- in: query
|
||||||
type: integer
|
type: integer
|
||||||
|
x-example: 64
|
||||||
name: width
|
name: width
|
||||||
description: The desired width of the thumbnail.
|
description: |-
|
||||||
|
The *desired* width of the thumbnail. The actual thumbnail may not
|
||||||
|
match the size specified.
|
||||||
- in: query
|
- in: query
|
||||||
type: integer
|
type: integer
|
||||||
|
x-example: 64
|
||||||
name: height
|
name: height
|
||||||
description: The desired height of the thumbnail.
|
description: |-
|
||||||
|
The *desired* height of the thumbnail. The actual thumbnail may not
|
||||||
|
match the size specified.
|
||||||
- in: query
|
- in: query
|
||||||
type: string
|
type: string
|
||||||
enum: ["crop", "scale"]
|
enum: ["crop", "scale"]
|
||||||
name: method
|
name: method
|
||||||
|
x-example: "scale"
|
||||||
description: The desired resizing method.
|
description: The desired resizing method.
|
||||||
responses:
|
responses:
|
||||||
200:
|
200:
|
||||||
description: "A thumbnail of the requested content."
|
description: "A thumbnail of the requested content."
|
||||||
|
headers:
|
||||||
|
Content-Type:
|
||||||
|
description: "The content type of the thumbnail."
|
||||||
|
type: "string"
|
||||||
|
enum: ["image/jpeg", "image/png"]
|
||||||
schema:
|
schema:
|
||||||
type: file
|
type: file
|
||||||
|
|
||||||
|
|
77
api/client-server/v1/typing.yaml
Normal file
77
api/client-server/v1/typing.yaml
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
swagger: '2.0'
|
||||||
|
info:
|
||||||
|
title: "Matrix Client-Server v1 Typing API"
|
||||||
|
version: "1.0.0"
|
||||||
|
host: localhost:8008
|
||||||
|
schemes:
|
||||||
|
- https
|
||||||
|
- http
|
||||||
|
basePath: /_matrix/client/api/v1
|
||||||
|
consumes:
|
||||||
|
- application/json
|
||||||
|
produces:
|
||||||
|
- application/json
|
||||||
|
securityDefinitions:
|
||||||
|
accessToken:
|
||||||
|
type: apiKey
|
||||||
|
description: The user_id or application service access_token
|
||||||
|
name: access_token
|
||||||
|
in: query
|
||||||
|
paths:
|
||||||
|
"/rooms/{roomId}/typing/{userId}":
|
||||||
|
put:
|
||||||
|
summary: Informs the server that the user has started or stopped typing.
|
||||||
|
description: |-
|
||||||
|
This tells the server that the user is typing for the next N
|
||||||
|
milliseconds where N is the value specified in the ``timeout`` key.
|
||||||
|
Alternatively, if ``typing`` is ``false``, it tells the server that the
|
||||||
|
user has stopped typing.
|
||||||
|
security:
|
||||||
|
- accessToken: []
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: userId
|
||||||
|
description: The user who has started to type.
|
||||||
|
required: true
|
||||||
|
x-example: "@alice:example.com"
|
||||||
|
- in: path
|
||||||
|
type: string
|
||||||
|
name: roomId
|
||||||
|
description: The room in which the user is typing.
|
||||||
|
required: true
|
||||||
|
x-example: "!wefh3sfukhs:example.com"
|
||||||
|
- in: body
|
||||||
|
name: typingState
|
||||||
|
description: The current typing state.
|
||||||
|
required: true
|
||||||
|
schema:
|
||||||
|
type: object
|
||||||
|
example: |-
|
||||||
|
{
|
||||||
|
"typing": true,
|
||||||
|
"timeout": 30000
|
||||||
|
}
|
||||||
|
properties:
|
||||||
|
typing:
|
||||||
|
type: boolean
|
||||||
|
description: |-
|
||||||
|
Whether the user is typing or not. If ``false``, the ``timeout``
|
||||||
|
key can be omitted.
|
||||||
|
timeout:
|
||||||
|
type: integer
|
||||||
|
description: The length of time in milliseconds to mark this user as typing.
|
||||||
|
required: ["typing"]
|
||||||
|
responses:
|
||||||
|
200:
|
||||||
|
description: The new typing state was set.
|
||||||
|
examples:
|
||||||
|
application/json: |-
|
||||||
|
{}
|
||||||
|
schema:
|
||||||
|
type: object # empty json object
|
||||||
|
429:
|
||||||
|
description: This request was rate-limited.
|
||||||
|
schema:
|
||||||
|
"$ref": "definitions/error.yaml"
|
||||||
|
|
|
@ -10,6 +10,6 @@
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nopt": "^3.0.2",
|
"nopt": "^3.0.2",
|
||||||
"swagger-parser": "^2.4.1"
|
"swagger-parser": "^3.2.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,11 +26,10 @@ if (!opts.schema) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var errFn = function(err, api, metadata) {
|
var errFn = function(err, api) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
console.log(metadata);
|
|
||||||
console.error(err);
|
console.error(err);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
};
|
};
|
||||||
|
@ -46,11 +45,12 @@ if (isDir) {
|
||||||
files.forEach(function(f) {
|
files.forEach(function(f) {
|
||||||
var suffix = ".yaml";
|
var suffix = ".yaml";
|
||||||
if (f.indexOf(suffix, f.length - suffix.length) > 0) {
|
if (f.indexOf(suffix, f.length - suffix.length) > 0) {
|
||||||
parser.parse(path.join(opts.schema, f), function(err, api, metadata) {
|
parser.validate(path.join(opts.schema, f), function(err, api, metadata) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
console.log("%s is valid.", f);
|
console.log("%s is valid.", f);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
console.error("%s is not valid.", f);
|
||||||
errFn(err, api, metadata);
|
errFn(err, api, metadata);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -59,12 +59,12 @@ if (isDir) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
parser.parse(opts.schema, function(err, api, metadata) {
|
parser.validate(opts.schema, function(err, api) {
|
||||||
if (!err) {
|
if (!err) {
|
||||||
console.log("%s is valid", opts.schema);
|
console.log("%s is valid", opts.schema);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
errFn(err, api, metadata);
|
errFn(err, api);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
7
event-schemas/examples/v1/m.typing
Normal file
7
event-schemas/examples/v1/m.typing
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"type": "m.typing",
|
||||||
|
"room_id": "!z0mnsuiwhifuhwwfw:matrix.org",
|
||||||
|
"content": {
|
||||||
|
"user_ids": ["@alice:matrix.org", "@bob:example.com"]
|
||||||
|
}
|
||||||
|
}
|
|
@ -12,6 +12,10 @@
|
||||||
"creator": {
|
"creator": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "The ``user_id`` of the room creator. This is set by the homeserver."
|
"description": "The ``user_id`` of the room creator. This is set by the homeserver."
|
||||||
|
},
|
||||||
|
"m.federate": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Whether users on other servers can join this room. Defaults to ``true`` if key does not exist."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["creator"]
|
"required": ["creator"]
|
||||||
|
|
28
event-schemas/schema/v1/m.typing
Normal file
28
event-schemas/schema/v1/m.typing
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"title": "Typing Event",
|
||||||
|
"description": "Informs the client of the list of users currently typing.",
|
||||||
|
"properties": {
|
||||||
|
"content": {
|
||||||
|
"type": "object",
|
||||||
|
"properties": {
|
||||||
|
"user_ids": {
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"description": "The list of user IDs typing in this room, if any."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["user_ids"]
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["m.typing"]
|
||||||
|
},
|
||||||
|
"room_id": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["type", "room_id", "content"]
|
||||||
|
}
|
|
@ -278,3 +278,9 @@ td[colspan]:not([colspan="1"]) {
|
||||||
thead {
|
thead {
|
||||||
background: #eeeeee;
|
background: #eeeeee;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
div.admonition-rationale {
|
||||||
|
background-color: #efe;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,11 +60,10 @@ func (u *User) IsTrusted() bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
pullsPrefix = "https://api.github.com/repos/matrix-org/matrix-doc/pulls"
|
pullsPrefix = "https://api.github.com/repos/matrix-org/matrix-doc/pulls"
|
||||||
matrixDocCloneURL = "https://github.com/matrix-org/matrix-doc.git"
|
matrixDocCloneURL = "https://github.com/matrix-org/matrix-doc.git"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
func gitClone(url string, shared bool) (string, error) {
|
func gitClone(url string, shared bool) (string, error) {
|
||||||
directory := path.Join("/tmp/matrix-doc", strconv.FormatInt(rand.Int63(), 10))
|
directory := path.Join("/tmp/matrix-doc", strconv.FormatInt(rand.Int63(), 10))
|
||||||
cmd := exec.Command("git", "clone", url, directory)
|
cmd := exec.Command("git", "clone", url, directory)
|
||||||
|
@ -80,21 +79,22 @@ func gitClone(url string, shared bool) (string, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func gitCheckout(path, sha string) error {
|
func gitCheckout(path, sha string) error {
|
||||||
cmd := exec.Command("git", "checkout", sha)
|
return runGitCommand(path, []string{"checkout", sha})
|
||||||
cmd.Dir = path
|
|
||||||
err := cmd.Run()
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error checking out repo: %v", err)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func gitFetch(path string) error {
|
func gitFetchAndMerge(path string) error {
|
||||||
cmd := exec.Command("git", "fetch")
|
if err := runGitCommand(path, []string{"fetch"}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return runGitCommand(path, []string{"merge"})
|
||||||
|
}
|
||||||
|
|
||||||
|
func runGitCommand(path string, args []string) error {
|
||||||
|
cmd := exec.Command("git", args...)
|
||||||
cmd.Dir = path
|
cmd.Dir = path
|
||||||
err := cmd.Run()
|
err := cmd.Run()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("error fetching repo: %v", err)
|
return fmt.Errorf("error running %q: %v", strings.Join(cmd.Args, " "), err)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
@ -145,7 +145,7 @@ type server struct {
|
||||||
// generateAt generates spec from repo at sha.
|
// generateAt generates spec from repo at sha.
|
||||||
// Returns the path where the generation was done.
|
// Returns the path where the generation was done.
|
||||||
func (s *server) generateAt(sha string) (dst string, err error) {
|
func (s *server) generateAt(sha string) (dst string, err error) {
|
||||||
err = gitFetch(s.matrixDocCloneURL)
|
err = gitFetchAndMerge(s.matrixDocCloneURL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -362,6 +362,8 @@ func main() {
|
||||||
http.HandleFunc("/diff/html/", s.serveHTMLDiff)
|
http.HandleFunc("/diff/html/", s.serveHTMLDiff)
|
||||||
http.HandleFunc("/healthz", serveText("ok"))
|
http.HandleFunc("/healthz", serveText("ok"))
|
||||||
http.HandleFunc("/", listPulls)
|
http.HandleFunc("/", listPulls)
|
||||||
|
|
||||||
|
fmt.Printf("Listening on port %d\n", *port)
|
||||||
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), nil))
|
log.Fatal(http.ListenAndServe(fmt.Sprintf(":%d", *port), nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -180,6 +180,8 @@ of a "Room".
|
||||||
Event Graphs
|
Event Graphs
|
||||||
~~~~~~~~~~~~
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. _sect:event-graph:
|
||||||
|
|
||||||
Events exchanged in the context of a room are stored in a directed acyclic graph
|
Events exchanged in the context of a room are stored in a directed acyclic graph
|
||||||
(DAG) called an ``event graph``. The partial ordering of this graph gives the
|
(DAG) called an ``event graph``. The partial ordering of this graph gives the
|
||||||
chronological ordering of events within the room. Each event in the graph has a
|
chronological ordering of events within the room. Each event in the graph has a
|
||||||
|
@ -332,49 +334,6 @@ Usage of an IS is not required in order for a client application to be part of
|
||||||
the Matrix ecosystem. However, without one clients will not be able to look up
|
the Matrix ecosystem. However, without one clients will not be able to look up
|
||||||
user IDs using 3PIDs.
|
user IDs using 3PIDs.
|
||||||
|
|
||||||
Presence
|
|
||||||
~~~~~~~~
|
|
||||||
|
|
||||||
Each user has the concept of presence information. This encodes:
|
|
||||||
|
|
||||||
* Whether the user is currently online
|
|
||||||
* How recently the user was last active (as seen by the server)
|
|
||||||
* Whether a given client considers the user to be currently idle
|
|
||||||
* Arbitrary information about the user's current status (e.g. "in a meeting").
|
|
||||||
|
|
||||||
This information is collated from both per-device (online; idle; last_active) and
|
|
||||||
per-user (status) data, aggregated by the user's homeserver and transmitted as
|
|
||||||
an ``m.presence`` event. This is one of the few events which are sent *outside
|
|
||||||
the context of a room*. Presence events are sent to all users who subscribe to
|
|
||||||
this user's presence through a presence list or by sharing membership of a room.
|
|
||||||
|
|
||||||
.. TODO
|
|
||||||
How do we let users hide their presence information?
|
|
||||||
|
|
||||||
.. TODO
|
|
||||||
The last_active specifics should be moved to the detailed presence event section
|
|
||||||
|
|
||||||
Last activity is tracked by the server maintaining a timestamp of the last time
|
|
||||||
it saw a pro-active event from the user. Any event which could be triggered by a
|
|
||||||
human using the application is considered pro-active (e.g. sending an event to a
|
|
||||||
room). An example of a non-proactive client activity would be a client setting
|
|
||||||
'idle' presence status, or polling for events. This timestamp is presented via a
|
|
||||||
key called ``last_active_ago``, which gives the relative number of milliseconds
|
|
||||||
since the message is generated/emitted that the user was last seen active.
|
|
||||||
|
|
||||||
N.B. in v1 API, status/online/idle state are muxed into a single 'presence'
|
|
||||||
field on the ``m.presence`` event.
|
|
||||||
|
|
||||||
Presence Lists
|
|
||||||
~~~~~~~~~~~~~~
|
|
||||||
|
|
||||||
Each user's home server stores a "presence list". This stores a list of user IDs
|
|
||||||
whose presence the user wants to follow.
|
|
||||||
|
|
||||||
To be added to this list, the user being added must be invited by the list owner
|
|
||||||
and accept the invitation. Once accepted, both user's HSes track the
|
|
||||||
subscription.
|
|
||||||
|
|
||||||
|
|
||||||
Profiles
|
Profiles
|
||||||
~~~~~~~~
|
~~~~~~~~
|
||||||
|
|
|
@ -779,13 +779,65 @@ options which can be set when creating a room:
|
||||||
This will tell the server to invite everyone in the list to the newly
|
This will tell the server to invite everyone in the list to the newly
|
||||||
created room.
|
created room.
|
||||||
|
|
||||||
|
``creation_content``
|
||||||
|
Type:
|
||||||
|
Object
|
||||||
|
Optional:
|
||||||
|
Yes
|
||||||
|
Value:
|
||||||
|
Extra keys to be added to the content of the ``m.room.create``. The server
|
||||||
|
will clober the following keys: ``creator``. Future versions of this
|
||||||
|
spec may allow the server to clobber other keys if required.
|
||||||
|
Description:
|
||||||
|
Allows clients to add keys to the content of ``m.room.create``.
|
||||||
|
|
||||||
|
``preset``
|
||||||
|
Type:
|
||||||
|
String
|
||||||
|
Optional:
|
||||||
|
Yes
|
||||||
|
Value:
|
||||||
|
``private_chat``, ``trusted_private_chat`` or ``public_chat``
|
||||||
|
Description:
|
||||||
|
Convenience parameter for setting various default state events based on a
|
||||||
|
preset.
|
||||||
|
|
||||||
|
Three presets are defined:
|
||||||
|
|
||||||
|
- ``private_chat``: Sets the ``join_rules`` to ``invite`` and
|
||||||
|
``history_visibility`` to ``shared``
|
||||||
|
- ``trusted_private_chat``: Set the ``join_rules`` to ``invite``,
|
||||||
|
``history_visibility`` to ``shared`` and gives all invitees the same
|
||||||
|
power level as the creator.
|
||||||
|
- ``public_chat``: Sets the ``join_rules`` to ``public`` and
|
||||||
|
``history_visibility`` to ``shared``
|
||||||
|
|
||||||
|
``initial_state``
|
||||||
|
Type:
|
||||||
|
List
|
||||||
|
Optional:
|
||||||
|
Yes
|
||||||
|
Value:
|
||||||
|
A list of state events to set in the new room.
|
||||||
|
Description:
|
||||||
|
Allows the user to override the default state events set in the new room.
|
||||||
|
|
||||||
|
The expected format of the state events are an object with ``type``,
|
||||||
|
``state_key`` and ``content`` keys set.
|
||||||
|
|
||||||
|
Takes precedence over events set by ``presets``, but gets overriden by
|
||||||
|
``name`` and ``topic`` keys.
|
||||||
|
|
||||||
Example::
|
Example::
|
||||||
|
|
||||||
{
|
{
|
||||||
"visibility": "public",
|
"preset": "public_chat",
|
||||||
"room_alias_name": "thepub",
|
"room_alias_name": "thepub",
|
||||||
"name": "The Grand Duke Pub",
|
"name": "The Grand Duke Pub",
|
||||||
"topic": "All about happy hour"
|
"topic": "All about happy hour",
|
||||||
|
"creation_content": {
|
||||||
|
"m.federate": false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
The home server will create a ``m.room.create`` event when the room is created,
|
The home server will create a ``m.room.create`` event when the room is created,
|
||||||
|
@ -1084,6 +1136,27 @@ Profiles
|
||||||
|
|
||||||
{{profile_http_api}}
|
{{profile_http_api}}
|
||||||
|
|
||||||
|
Events on Change of Profile Information
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
Because the profile display name and avatar information are likely to be used in
|
||||||
|
many places of a client's display, changes to these fields cause an automatic
|
||||||
|
propagation event to occur, informing likely-interested parties of the new
|
||||||
|
values. This change is conveyed using two separate mechanisms:
|
||||||
|
|
||||||
|
- a ``m.room.member`` event is sent to every room the user is a member of,
|
||||||
|
to update the ``displayname`` and ``avatar_url``.
|
||||||
|
- a ``m.presence`` presence status update is sent, again containing the new
|
||||||
|
values of the ``displayname`` and ``avatar_url`` keys, in addition to the
|
||||||
|
required ``presence`` key containing the current presence state of the user.
|
||||||
|
|
||||||
|
Both of these should be done automatically by the home server when a user
|
||||||
|
successfully changes their display name or avatar URL fields.
|
||||||
|
|
||||||
|
Additionally, when home servers emit room membership events for their own
|
||||||
|
users, they should include the display name and avatar URL fields in these
|
||||||
|
events so that clients already have these details to hand, and do not have to
|
||||||
|
perform extra round trips to query it.
|
||||||
|
|
||||||
Security
|
Security
|
||||||
--------
|
--------
|
||||||
|
|
||||||
|
|
|
@ -3,44 +3,31 @@ Content repository
|
||||||
|
|
||||||
.. _module:content:
|
.. _module:content:
|
||||||
|
|
||||||
HTTP API
|
This module allows users to upload content to their homeserver which is
|
||||||
--------
|
retrievable from other homeservers. Its' purpose is to allow users to share
|
||||||
|
attachments in a room. Content locations are represented as Matrix Content (MXC)
|
||||||
|
URIs. They look like::
|
||||||
|
|
||||||
Uploads are POSTed to a resource which returns a token which is used to GET
|
mxc://<server-name>/<media-id>
|
||||||
the download. Uploads are POSTed to the sender's local homeserver, but are
|
|
||||||
downloaded from the recipient's local homeserver, which must thus first transfer
|
|
||||||
the content from the origin homeserver using the same API (unless the origin
|
|
||||||
and destination homeservers are the same). The upload/download API is::
|
|
||||||
|
|
||||||
=> POST /_matrix/media/v1/upload HTTP/1.1
|
<server-name> : The name of the homeserver where this content originated, e.g. matrix.org
|
||||||
Content-Type: <media-type>
|
<media-id> : An opaque ID which identifies the content.
|
||||||
|
|
||||||
<media>
|
Uploads are POSTed to a resource on the user's local homeserver which returns a
|
||||||
|
token which is used to GET the download. Content is downloaded from the
|
||||||
|
recipient's local homeserver, which must first transfer the content from the
|
||||||
|
origin homeserver using the same API (unless the origin and destination
|
||||||
|
homeservers are the same).
|
||||||
|
|
||||||
<= HTTP/1.1 200 OK
|
Client behaviour
|
||||||
Content-Type: application/json
|
----------------
|
||||||
|
|
||||||
{ "content-uri": "mxc://<server-name>/<media-id>" }
|
Clients can upload and download content using the following HTTP APIs.
|
||||||
|
|
||||||
=> GET /_matrix/media/v1/download/<server-name>/<media-id> HTTP/1.1
|
{{content_repo_http_api}}
|
||||||
|
|
||||||
<= HTTP/1.1 200 OK
|
|
||||||
Content-Type: <media-type>
|
|
||||||
Content-Disposition: attachment;filename=<upload-filename>
|
|
||||||
|
|
||||||
<media>
|
|
||||||
|
|
||||||
Clients can get thumbnails by supplying a desired width and height and
|
|
||||||
thumbnailing method::
|
|
||||||
|
|
||||||
=> GET /_matrix/media/v1/thumbnail/<server_name>
|
|
||||||
/<media-id>?width=<w>&height=<h>&method=<m> HTTP/1.1
|
|
||||||
|
|
||||||
<= HTTP/1.1 200 OK
|
|
||||||
Content-Type: image/jpeg or image/png
|
|
||||||
|
|
||||||
<thumbnail>
|
|
||||||
|
|
||||||
|
Thumbnails
|
||||||
|
~~~~~~~~~~
|
||||||
The thumbnail methods are "crop" and "scale". "scale" tries to return an
|
The thumbnail methods are "crop" and "scale". "scale" tries to return an
|
||||||
image where either the width or the height is smaller than the requested
|
image where either the width or the height is smaller than the requested
|
||||||
size. The client should then scale and letterbox the image if it needs to
|
size. The client should then scale and letterbox the image if it needs to
|
||||||
|
@ -49,6 +36,9 @@ width and height are close to the requested size and the aspect matches
|
||||||
the requested size. The client should scale the image if it needs to fit
|
the requested size. The client should scale the image if it needs to fit
|
||||||
within a given rectangle.
|
within a given rectangle.
|
||||||
|
|
||||||
|
Server behaviour
|
||||||
|
----------------
|
||||||
|
|
||||||
Homeservers may generate thumbnails for content uploaded to remote
|
Homeservers may generate thumbnails for content uploaded to remote
|
||||||
homeservers themselves or may rely on the remote homeserver to thumbnail
|
homeservers themselves or may rely on the remote homeserver to thumbnail
|
||||||
the content. Homeservers may return thumbnails of a different size to that
|
the content. Homeservers may return thumbnails of a different size to that
|
||||||
|
@ -58,13 +48,19 @@ Homeservers must never upscale images.
|
||||||
Security considerations
|
Security considerations
|
||||||
-----------------------
|
-----------------------
|
||||||
|
|
||||||
|
The HTTP GET endpoint does not require any authentication. Knowing the URL of
|
||||||
|
the content is sufficient to retrieve the content, even if the entity isn't in
|
||||||
|
the room.
|
||||||
|
|
||||||
|
Homeservers have additional concerns:
|
||||||
|
|
||||||
- Clients may try to upload very large files. Homeservers should not store files
|
- Clients may try to upload very large files. Homeservers should not store files
|
||||||
that are too large and should not serve them to clients.
|
that are too large and should not serve them to clients.
|
||||||
|
|
||||||
- Clients may try to upload very large images. Homeservers should not attempt to
|
- Clients may try to upload very large images. Homeservers should not attempt to
|
||||||
generate thumbnails for images that are too large.
|
generate thumbnails for images that are too large.
|
||||||
|
|
||||||
- Remote homeservers may host very large files or images. Homeserver should not
|
- Remote homeservers may host very large files or images. Homeservers should not
|
||||||
proxy or thumbnail large files or images from remote homeservers.
|
proxy or thumbnail large files or images from remote homeservers.
|
||||||
|
|
||||||
- Clients may try to upload a large number of files. Homeservers should limit the
|
- Clients may try to upload a large number of files. Homeservers should limit the
|
||||||
|
|
|
@ -2,64 +2,111 @@ Presence
|
||||||
========
|
========
|
||||||
|
|
||||||
.. _module:presence:
|
.. _module:presence:
|
||||||
|
|
||||||
|
Each user has the concept of presence information. This encodes:
|
||||||
|
|
||||||
|
* Whether the user is currently online
|
||||||
|
* How recently the user was last active (as seen by the server)
|
||||||
|
* Whether a given client considers the user to be currently idle
|
||||||
|
* Arbitrary information about the user's current status (e.g. "in a meeting").
|
||||||
|
|
||||||
|
This information is collated from both per-device (``online``, ``idle``,
|
||||||
|
``last_active``) and per-user (status) data, aggregated by the user's homeserver
|
||||||
|
and transmitted as an ``m.presence`` event. This is one of the few events which
|
||||||
|
are sent *outside the context of a room*. Presence events are sent to all users
|
||||||
|
who subscribe to this user's presence through a presence list or by sharing
|
||||||
|
membership of a room.
|
||||||
|
|
||||||
|
A presence list is a list of user IDs whose presence the user wants to follow.
|
||||||
|
To be added to this list, the user being added must be invited by the list owner
|
||||||
|
who must accept the invitation.
|
||||||
|
|
||||||
Each user has the concept of presence information. This encodes the
|
User's presence state is represented by the ``presence`` key, which is an enum
|
||||||
"availability" of that user, suitable for display on other user's clients.
|
of one of the following:
|
||||||
This is transmitted as an ``m.presence`` event and is one of the few events
|
|
||||||
which are sent *outside the context of a room*. The basic piece of presence
|
|
||||||
information is represented by the ``presence`` key, which is an enum of one
|
|
||||||
of the following:
|
|
||||||
|
|
||||||
- ``online`` : The default state when the user is connected to an event
|
- ``online`` : The default state when the user is connected to an event
|
||||||
stream.
|
stream.
|
||||||
- ``unavailable`` : The user is not reachable at this time.
|
- ``unavailable`` : The user is not reachable at this time e.g. they are
|
||||||
- ``offline`` : The user is not connected to an event stream.
|
idle.
|
||||||
|
- ``offline`` : The user is not connected to an event stream or is
|
||||||
|
explicitly suppressing their profile information from being sent.
|
||||||
- ``free_for_chat`` : The user is generally willing to receive messages
|
- ``free_for_chat`` : The user is generally willing to receive messages
|
||||||
moreso than default.
|
moreso than default.
|
||||||
- ``hidden`` : Behaves as offline, but allows the user to see the client
|
|
||||||
state anyway and generally interact with client features. (Not yet
|
|
||||||
implemented in synapse).
|
|
||||||
|
|
||||||
In addition, the server maintains a timestamp of the last time it saw a
|
|
||||||
pro-active event from the user; either sending a message to a room, or
|
|
||||||
changing presence state from a lower to a higher level of availability
|
|
||||||
(thus: changing state from ``unavailable`` to ``online`` counts as a
|
|
||||||
proactive event, whereas in the other direction it will not). This timestamp
|
|
||||||
is presented via a key called ``last_active_ago``, which gives the relative
|
|
||||||
number of milliseconds since the message is generated/emitted that the user
|
|
||||||
was last seen active.
|
|
||||||
|
|
||||||
Events
|
Events
|
||||||
------
|
------
|
||||||
|
|
||||||
{{presence_events}}
|
{{presence_events}}
|
||||||
|
|
||||||
Presence HTTP API
|
Client behaviour
|
||||||
-----------------
|
----------------
|
||||||
.. TODO-spec
|
|
||||||
- Define how users receive presence invites, and how they accept/decline them
|
Clients can manually set/get their presence/presence list using the HTTP APIs
|
||||||
|
listed below.
|
||||||
|
|
||||||
{{presence_http_api}}
|
{{presence_http_api}}
|
||||||
|
|
||||||
|
Idle timeout
|
||||||
|
~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Clients SHOULD implement an "idle timeout". This is a timer which fires after
|
||||||
|
a period of inactivity on the client. The definition of inactivity varies
|
||||||
|
depending on the client. For example, web implementations may determine
|
||||||
|
inactivity to be not moving the mouse for a certain period of time. When this
|
||||||
|
timer fires it should set the presence state to ``unavailable``. When the user
|
||||||
|
becomes active again (e.g. by moving the mouse) the client should set the
|
||||||
|
presence state to ``online``. A timeout value between 1 and 5 minutes is
|
||||||
|
recommended.
|
||||||
|
|
||||||
|
Server behaviour
|
||||||
|
----------------
|
||||||
|
|
||||||
|
Each user's home server stores a "presence list" per user. Once a user accepts
|
||||||
|
a presence list, both user's HSes must track the subscription.
|
||||||
|
|
||||||
|
Propagating profile information
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Because the profile display name and avatar information are likely to be used in
|
||||||
|
many places of a client's display, changes to these fields SHOULD cause an
|
||||||
|
automatic propagation event to occur, informing likely-interested parties of the
|
||||||
|
new values. One of these change mechanisms SHOULD be via ``m.presence`` events.
|
||||||
|
These events should set ``displayname`` and ``avatar_url`` to the new values
|
||||||
|
along with the presence-specific keys. This SHOULD be done automatically by the
|
||||||
|
home server when a user successfully changes their display name or avatar URL.
|
||||||
|
|
||||||
|
.. admonition:: Rationale
|
||||||
|
|
||||||
|
The intention for sending this information in ``m.presence`` is so that any
|
||||||
|
"user list" can display the *current* name/presence for a user ID outside the
|
||||||
|
scope of a room e.g. for a user page. This is bundled into a single event for
|
||||||
|
several reasons. The user's display name can change per room. This
|
||||||
|
event provides the "canonical" name for the user. In addition, the name is
|
||||||
|
bundled into a single event for the ease of client implementations. If this
|
||||||
|
was not done, the client would need to search all rooms for their own
|
||||||
|
membership event to pull out the display name.
|
||||||
|
|
||||||
|
|
||||||
|
Last active ago
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
The server maintains a timestamp of the last time it saw a
|
||||||
|
pro-active event from the user. A pro-active event may be sending a message to a
|
||||||
|
room or changing presence state to a higher level of availability. Levels of
|
||||||
|
availability are defined from low to high as follows:
|
||||||
|
|
||||||
|
- ``offline``
|
||||||
|
- ``unavailable``
|
||||||
|
- ``online``
|
||||||
|
- ``free_for_chat``
|
||||||
|
|
||||||
|
Based on this list, changing state from ``unavailable`` to ``online`` counts as
|
||||||
|
a pro-active event, whereas ``online`` to ``unavailable`` does not. This
|
||||||
|
timestamp is presented via a key called ``last_active_ago`` which gives the
|
||||||
|
relative number of milliseconds since the pro-active event.
|
||||||
|
|
||||||
|
Security considerations
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Presence information is shared with all users who share a room with the target
|
||||||
Events on Change of Profile Information
|
user. In large public rooms this could be undesirable.
|
||||||
---------------------------------------
|
|
||||||
Because the profile displayname and avatar information are likely to be used in
|
|
||||||
many places of a client's display, changes to these fields cause an automatic
|
|
||||||
propagation event to occur, informing likely-interested parties of the new
|
|
||||||
values. This change is conveyed using two separate mechanisms:
|
|
||||||
|
|
||||||
- a ``m.room.member`` event is sent to every room the user is a member of,
|
|
||||||
to update the ``displayname`` and ``avatar_url``.
|
|
||||||
- a ``m.presence`` presence status update is sent, again containing the new values of the
|
|
||||||
``displayname`` and ``avatar_url`` keys, in addition to the required
|
|
||||||
``presence`` key containing the current presence state of the user.
|
|
||||||
|
|
||||||
Both of these should be done automatically by the home server when a user
|
|
||||||
successfully changes their displayname or avatar URL fields.
|
|
||||||
|
|
||||||
Additionally, when home servers emit room membership events for their own
|
|
||||||
users, they should include the displayname and avatar URL fields in these
|
|
||||||
events so that clients already have these details to hand, and do not have to
|
|
||||||
perform extra roundtrips to query it.
|
|
||||||
|
|
||||||
|
|
|
@ -1,49 +1,46 @@
|
||||||
Typing Notifications
|
Typing Notifications
|
||||||
--------------------
|
====================
|
||||||
|
|
||||||
.. _module:typing:
|
.. _module:typing:
|
||||||
|
|
||||||
Client APIs
|
Users may wish to be informed when another user is typing in a room. This can be
|
||||||
~~~~~~~~~~~
|
achieved using typing notifications. These are ephemeral events scoped to a
|
||||||
|
``room_id``. This means they do not form part of the `Event Graph`_ but still
|
||||||
|
have a ``room_id`` key.
|
||||||
|
|
||||||
To set "I am typing for the next N msec"::
|
.. _Event Graph: `sect:event-graph`_
|
||||||
|
|
||||||
PUT .../rooms/<room_id>/typing/<user_id>
|
Events
|
||||||
Content: { "typing": true, "timeout": N }
|
------
|
||||||
# timeout is in milliseconds; suggested no more than 20 or 30 seconds
|
|
||||||
|
|
||||||
This should be re-sent by the client to continue informing the server the user
|
{{m_typing_event}}
|
||||||
is still typing; a safety margin of 5 seconds before the expected
|
|
||||||
timeout runs out is recommended. Just keep declaring a new timeout, it will
|
|
||||||
replace the old one.
|
|
||||||
|
|
||||||
To set "I am no longer typing"::
|
Client behaviour
|
||||||
|
----------------
|
||||||
|
|
||||||
PUT ../rooms/<room_id>/typing/<user_id>
|
When a client receives an ``m.typing`` event, it MUST use the user ID list to
|
||||||
Content: { "typing": false }
|
**REPLACE** its knowledge of every user who is currently typing. The reason for
|
||||||
|
this is that the server *does not remember* users who are not currently typing
|
||||||
|
as that list gets big quickly. The client should mark as not typing any user ID
|
||||||
|
who is not in that list.
|
||||||
|
|
||||||
Client Events
|
It is recommended that clients store a ``boolean`` indicating whether the user
|
||||||
~~~~~~~~~~~~~
|
is typing or not. Whilst this value is ``true`` a timer should fire periodically
|
||||||
|
every N seconds to send a typing HTTP request. The value of N is recommended to
|
||||||
|
be no more than 20-30 seconds. This request should be re-sent by the client to
|
||||||
|
continue informing the server the user is still typing. As subsequent
|
||||||
|
requests will replace older requests, a safety margin of 5 seconds before the
|
||||||
|
expected timeout runs out is recommended. When the user stops typing, the
|
||||||
|
state change of the ``boolean`` to ``false`` should trigger another HTTP request
|
||||||
|
to inform the server that the user has stopped typing.
|
||||||
|
|
||||||
All room members will receive an event on the event stream::
|
{{typing_http_api}}
|
||||||
|
|
||||||
{
|
Server behaviour
|
||||||
"type": "m.typing",
|
----------------
|
||||||
"room_id": "!room-id-here:matrix.org",
|
|
||||||
"content": {
|
|
||||||
"user_ids": ["list of", "every user", "who is", "currently typing"]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
The client must use this list to *REPLACE* its knowledge of every user who is
|
Servers MUST emit typing EDUs in a different form to ``m.typing`` events which
|
||||||
currently typing. The reason for this is that the server DOES NOT remember
|
are shown to clients. This form looks like::
|
||||||
users who are not currently typing, as that list gets big quickly. The client
|
|
||||||
should mark as not typing, any user ID who is not in that list.
|
|
||||||
|
|
||||||
Server APIs
|
|
||||||
~~~~~~~~~~~
|
|
||||||
|
|
||||||
Servers will emit EDUs in the following form::
|
|
||||||
|
|
||||||
{
|
{
|
||||||
"type": "m.typing",
|
"type": "m.typing",
|
||||||
|
@ -54,10 +51,16 @@ Servers will emit EDUs in the following form::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Server EDUs don't (currently) contain timing information; it is up to
|
This does not contain timing information so it is up to originating homeservers
|
||||||
originating HSes to ensure they eventually send "stop" notifications.
|
to ensure they eventually send "stop" notifications.
|
||||||
|
|
||||||
.. TODO
|
.. TODO
|
||||||
((This will eventually need addressing, as part of the wider typing/presence
|
((This will eventually need addressing, as part of the wider typing/presence
|
||||||
timer addition work))
|
timer addition work))
|
||||||
|
|
||||||
|
Security considerations
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
Clients may not wish to inform everyone in a room that they are typing and
|
||||||
|
instead only specific users in the room.
|
||||||
|
|
||||||
|
|
|
@ -31,18 +31,18 @@ Response format:
|
||||||
{% for table in endpoint.res_tables -%}
|
{% for table in endpoint.res_tables -%}
|
||||||
{{"``"+table.title+"``" if table.title else "" }}
|
{{"``"+table.title+"``" if table.title else "" }}
|
||||||
|
|
||||||
================== ================= ===========================================
|
=================== ================= ==========================================
|
||||||
Param Type Description
|
Param Type Description
|
||||||
================== ================= ===========================================
|
=================== ================= ==========================================
|
||||||
{% for row in table.rows -%}
|
{% for row in table.rows -%}
|
||||||
{# -#}
|
{# -#}
|
||||||
{# Row type needs to prepend spaces to line up with the type column (19 ch) -#}
|
{# Row type needs to prepend spaces to line up with the type column (20 ch) -#}
|
||||||
{# Desc needs to prepend the required text (maybe) and prepend spaces too -#}
|
{# Desc needs to prepend the required text (maybe) and prepend spaces too -#}
|
||||||
{# It also needs to then wrap inside the desc col (43 ch width) -#}
|
{# It also needs to then wrap inside the desc col (42 ch width) -#}
|
||||||
{# -#}
|
{# -#}
|
||||||
{{row.key}}{{row.type|indent(19-row.key|length)}}{{row.desc|wrap(43,row.req_str | indent(18 - (row.type|length))) |indent_block(37)}}
|
{{row.key}}{{row.type|indent(20-row.key|length)}}{{row.desc|wrap(42,row.req_str | indent(18 - (row.type|length))) |indent_block(38)}}
|
||||||
{% endfor -%}
|
{% endfor -%}
|
||||||
================== ================= ===========================================
|
=================== ================= ==========================================
|
||||||
|
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
{% endif -%}
|
{% endif -%}
|
||||||
|
|
|
@ -168,6 +168,13 @@ class MatrixUnits(Units):
|
||||||
|
|
||||||
# assign value expected for this param
|
# assign value expected for this param
|
||||||
val_type = param.get("type") # integer/string
|
val_type = param.get("type") # integer/string
|
||||||
|
|
||||||
|
if param.get("enum"):
|
||||||
|
val_type = "enum"
|
||||||
|
desc += (
|
||||||
|
" One of: %s" % json.dumps(param.get("enum"))
|
||||||
|
)
|
||||||
|
|
||||||
refType = Units.prop(param, "schema/$ref/") # Error,Event
|
refType = Units.prop(param, "schema/$ref/") # Error,Event
|
||||||
schemaFmt = Units.prop(param, "schema/format") # bytes e.g. uploads
|
schemaFmt = Units.prop(param, "schema/format") # bytes e.g. uploads
|
||||||
if not val_type and refType:
|
if not val_type and refType:
|
||||||
|
@ -270,17 +277,27 @@ class MatrixUnits(Units):
|
||||||
if good_response:
|
if good_response:
|
||||||
self.log("Found a 200 response for this API")
|
self.log("Found a 200 response for this API")
|
||||||
res_type = Units.prop(good_response, "schema/type")
|
res_type = Units.prop(good_response, "schema/type")
|
||||||
|
res_name = Units.prop(good_response, "schema/name")
|
||||||
if res_type and res_type not in ["object", "array"]:
|
if res_type and res_type not in ["object", "array"]:
|
||||||
# response is a raw string or something like that
|
# response is a raw string or something like that
|
||||||
endpoint["res_tables"].append({
|
good_table = {
|
||||||
"title": None,
|
"title": None,
|
||||||
"rows": [{
|
"rows": [{
|
||||||
"key": good_response["schema"].get("name", ""),
|
"key": "<" + res_type + ">" if not res_name else res_name,
|
||||||
"type": res_type,
|
"type": res_type,
|
||||||
"desc": res.get("description", ""),
|
"desc": res.get("description", ""),
|
||||||
"req_str": ""
|
"req_str": ""
|
||||||
}]
|
}]
|
||||||
})
|
}
|
||||||
|
if good_response.get("headers"):
|
||||||
|
for (header_name, header) in good_response.get("headers").iteritems():
|
||||||
|
good_table["rows"].append({
|
||||||
|
"key": header_name,
|
||||||
|
"type": "Header<" + header["type"] + ">",
|
||||||
|
"desc": header["description"],
|
||||||
|
"req_str": ""
|
||||||
|
})
|
||||||
|
endpoint["res_tables"].append(good_table)
|
||||||
elif res_type and Units.prop(good_response, "schema/properties"):
|
elif res_type and Units.prop(good_response, "schema/properties"):
|
||||||
# response is an object:
|
# response is an object:
|
||||||
schema = good_response["schema"]
|
schema = good_response["schema"]
|
||||||
|
@ -352,7 +369,7 @@ class MatrixUnits(Units):
|
||||||
self.log("Reading swagger API: %s" % filename)
|
self.log("Reading swagger API: %s" % filename)
|
||||||
with open(os.path.join(path, filename), "r") as f:
|
with open(os.path.join(path, filename), "r") as f:
|
||||||
# strip .yaml
|
# strip .yaml
|
||||||
group_name = filename[:-5]
|
group_name = filename[:-5].replace("-", "_")
|
||||||
if is_v2:
|
if is_v2:
|
||||||
group_name = "v2_" + group_name
|
group_name = "v2_" + group_name
|
||||||
api = yaml.load(f.read())
|
api = yaml.load(f.read())
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue