From 319ba8f40489ee8313df80fd2fc89109b5799bd8 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 7 Oct 2015 14:00:16 +0100 Subject: [PATCH 01/23] Combine push files into one We can fork it out again if it makes sense, but certainly 2/3 of the files were very small and it just adds more complexity when refactoring. --- .../modules/{push_cs_api.rst => push.rst} | 240 +++++++++++++++++- specification/modules/push_overview.rst | 80 ------ specification/modules/push_push_gw_api.rst | 144 ----------- specification/targets.yaml | 4 +- 4 files changed, 233 insertions(+), 235 deletions(-) rename specification/modules/{push_cs_api.rst => push.rst} (64%) delete mode 100644 specification/modules/push_overview.rst delete mode 100644 specification/modules/push_push_gw_api.rst diff --git a/specification/modules/push_cs_api.rst b/specification/modules/push.rst similarity index 64% rename from specification/modules/push_cs_api.rst rename to specification/modules/push.rst index c6301926..7a70c580 100644 --- a/specification/modules/push_cs_api.rst +++ b/specification/modules/push.rst @@ -1,3 +1,227 @@ +Push Notifications +================== + +.. _module:push: + +Overview +-------- + +:: + + +--------------------+ +-------------------+ + Matrix HTTP | | | | + Notification Protocol | App Developer | | Device Vendor | + | | | | + +-------------------+ | +----------------+ | | +---------------+ | + | | | | | | | | | | + | Matrix Home Server+-----> Push Gateway | +---> Push Provider | | + | | | | | | | | | | + +-^-----------------+ | +----------------+ | | +----+----------+ | + | | | | | | + Matrix | | | | | | + Client/Server API + | | | | | + | | +--------------------+ +-------------------+ + | +--+-+ | + | | <------------------------------------------+ + +---+ | + | | Provider Push Protocol + +----+ + + Mobile Device or Client + + +Matrix supports push notifications as a first class citizen. Home Servers send +notifications of user events to user-configured HTTP endpoints. User may also +configure a number of rules that determine what events generate notifications. +These are all stored and managed by the users home server such that settings can +be reused between client apps as appropriate. + +The above diagram shows the flow of push notifications being sent to a handset +where push notifications are submitted via the handset vendor, such as Apple's +APNS or Google's GCM. This happens as follows: + + 1. The client app signs in to a Matrix Home Server + 2. The client app registers with its vendor's Push Notification provider and + obtains a routing token of some kind. + 3. The mobile app, uses the Matrix client/server API to add a 'pusher', + providing the URL of a specific Push Gateway which is configured for that + application. It also provides the routing token it has acquired from the + Push Notification Provider. + 4. The Home Server starts sending notification HTTP requests to the Push + Gateway using the supplied URL. The Push Gateway relays this notification to + the Push Notification Provider, passing the routing token along with any + necessary private credentials the provider requires to send push + notifications. + 5. The Push Notification provider sends the notification to the device. + +Nomenclature +~~~~~~~~~~~~ + +Pusher + A 'pusher' is an activity in the Home Server that manages the sending + of HTTP notifications for a single device of a single user. + +Push Rules + A push rule is a single rule, configured by a matrix user, that gives + instructions to the Home Server about whether an event should be notified + about and how given a set of conditions. Matrix clients allow the user to + configure these. They create and view them via the Client to Server REST API. + +Push Gateway + A push gateway is a server that receives HTTP event notifications from Home + Servers and passes them on to a different protocol such as APNS for iOS + devices or GCM for Android devices. Matrix.org provides a reference push + gateway, 'sygnal'. A client app tells a Home Server what push gateway + to send notifications to when it sets up a pusher. + +For information on the client-server API for setting pushers and push rules, see +the Client Server API section. For more information on the format of HTTP +notifications, see the HTTP Notification Protocol section. + +HTTP Notification Protocol +-------------------------- + +This describes the format used by "HTTP" pushers to send notifications of +events. + +Notifications are sent as HTTP POST requests to the URL configured when the +pusher is created, but Matrix strongly recommends that the path should be:: + + /_matrix/push/v1/notify + +The body of the POST request is a JSON dictionary. The format +is as follows:: + + { + "notification": { + "id": "$3957tyerfgewrf384", + "room_id": "!slw48wfj34rtnrf:example.com", + "type": "m.room.message", + "sender": "@exampleuser:matrix.org", + "sender_display_name": "Major Tom", + "room_name": "Mission Control", + "room_alias": "#exampleroom:matrix.org", + "prio": "high", + "content": { + "msgtype": "m.text", + "body": "I'm floating in a most peculiar way." + } + }, + "counts": { + "unread" : 2, + "missed_calls": 1 + } + "devices": [ + { + "app_id": "org.matrix.matrixConsole.ios", + "pushkey": "V2h5IG9uIGVhcnRoIGRpZCB5b3UgZGVjb2RlIHRoaXM/", + "pushkey_ts": 12345678, + "data" : { + }, + "tweaks": { + "sound": "bing" + } + } + ] + } + } + +The contents of this dictionary are defined as follows: + +id + An identifier for this notification that may be used to detect duplicate + notification requests. This is not necessarily the ID of the event that + triggered the notification. +room_id + The ID of the room in which this event occurred. +type + The type of the event as in the event's 'type' field. +sender + The sender of the event as in the corresponding event field. +sender_display_name + The current display name of the sender in the room in which the event + occurred. +room_name + The name of the room in which the event occurred. +room_alias + An alias to display for the room in which the event occurred. +prio + The priority of the notification. Acceptable values are 'high' or 'low. If + omitted, 'high' is assumed. This may be used by push gateways to deliver less + time-sensitive notifications in a way that will preserve battery power on + mobile devices. +content + The 'content' field from the event, if present. If the event had no content + field, this field is omitted. +counts + This is a dictionary of the current number of unacknowledged communications + for the recipient user. Counts whose value is zero are omitted. +unread + The number of unread messages a user has across all of the rooms they are a + member of. +missed_calls + The number of unacknowledged missed calls a user has across all rooms of + which they are a member. +device + This is an array of devices that the notification should be sent to. +app_id + The app_id given when the pusher was created. +pushkey + The pushkey given when the pusher was created. +pushkey_ts + The unix timestamp (in seconds) when the pushkey was last updated. +data + A dictionary of additional pusher-specific data. For 'http' pushers, this is + the data dictionary passed in at pusher creation minus the 'url' key. +tweaks + A dictionary of customisations made to the way this notification is to be + presented. These are added by push rules. +sound + Sets the sound file that should be played. 'default' means that a default + sound should be played. + +And additional key is defined but only present on member events: + +user_is_target + This is true if the user receiving the notification is the subject of a member + event (i.e. the state_key of the member event is equal to the user's Matrix + ID). + +The recipient of an HTTP notification should respond with an HTTP 2xx response +when the notification has been processed. If the endpoint returns an HTTP error +code, the Home Server should retry for a reasonable amount of time with a +reasonable back-off scheme. + +The endpoint should return a JSON dictionary as follows:: + + { + "rejected": [ "V2h5IG9uIGVhcnRoIGRpZCB5b3UgZGVjb2RlIHRoaXM/" ] + } + +Whose keys are: + +rejected + A list of all pushkeys given in the notification request that are not valid. + These could have been rejected by an upstream gateway because they have + expired or have never been valid. Home Servers must cease sending notification + requests for these pushkeys and remove the associated pushers. It may not + necessarily be the notification in the request that failed: it could be that + a previous notification to the same pushkey failed. + +Push: Recommendations for APNS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +For sending APNS notifications, the exact format is flexible and up to the +client app and its push gateway to agree on (since APNS requires that the sender +have a private key owned by the app developer, each app must have its own push +gateway). However, Matrix strongly recommends: + + * That the APNS token be base64 encoded and used as the pushkey. + * That a different app_id be used for apps on the production and sandbox + APS environments. + * That APNS push gateways do not attempt to wait for errors from the APNS + gateway before returning and instead to store failures and return + 'rejected' responses next time that pushkey is used. + Pushers HTTP API ---------------- @@ -5,7 +229,7 @@ To receive any notification pokes at all, it is necessary to configure a 'pusher' on the Home Server that you wish to receive notifications from. There is a single API endpoint for this:: - POST $PREFIX/pushers/set + POST $PREFIX/pushers/set This takes a JSON object with the following keys: @@ -51,7 +275,7 @@ be empty). Push Rules ----------- +~~~~~~~~~~ Home Servers have an interface to configure what events trigger notifications. This behaviour is configured through 'Push Rules'. Push Rules come in a variety of different kinds and each kind of rule has an associated priority. The @@ -112,7 +336,7 @@ If no rules match an event, the Home Server should not notify for the message themselves are never alerted for. Predefined Rules ----------------- +~~~~~~~~~~~~~~~~ Matrix specifies the following rule IDs for server default rules. Home Servers may define rules as follows with the given IDs. If Home Servers provide rules with these IDs, their semantics should match those given below: @@ -215,7 +439,7 @@ with these IDs, their semantics should match those given below: } Push Rules: Actions: --------------------- +~~~~~~~~~~~~~~~~~~~~ All rules have an associated list of 'actions'. An action affects if and how a notification is delivered for a matching event. This standard defines the following actions, although if Home servers wish to support more, they are free @@ -241,7 +465,7 @@ represented as a dictionary with a key equal to their name and other keys as their parameters, e.g. ``{ "set_tweak": "sound", "value": "default" }`` Push Rules: Actions: Tweaks ---------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~ The ``set_tweak`` key action is used to add an entry to the 'tweaks' dictionary that is sent in the notification poke. The following tweaks are defined: @@ -263,7 +487,7 @@ If a kind of tweak that a client understands is not specified in an action, the client may choose a sensible behaviour for the tweak. Push Rules: Conditions ----------------------- +~~~~~~~~~~~~~~~~~~~~~~ Override, Underride and Default rules have a list of 'conditions'. All conditions must hold true for an event in order for a rule to be applied to an event. A rule with no conditions always matches. Matrix specifies the following @@ -300,7 +524,7 @@ using parameters named as described above. In the cases of room and sender rules, the rule_id of the rule determines its behaviour. Push Rules: API ---------------- +~~~~~~~~~~~~~~~ Rules live under a hierarchy in the REST API that resembles:: $PREFIX/pushrules/// @@ -411,7 +635,7 @@ Adding patch components to the request drills down into this structure to filter to only the requested set of rules. Enabling and Disabling Rules ----------------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Rules can be enabled or disabled with a PUT operation to the 'enabled' component beneath the rule's URI with a content of 'true' or 'false':: diff --git a/specification/modules/push_overview.rst b/specification/modules/push_overview.rst deleted file mode 100644 index 46028283..00000000 --- a/specification/modules/push_overview.rst +++ /dev/null @@ -1,80 +0,0 @@ -Push Notifications -================== - -.. _module:push: - -Overview --------- - -:: - - +--------------------+ +-------------------+ - Matrix HTTP | | | | - Notification Protocol | App Developer | | Device Vendor | - | | | | - +-------------------+ | +----------------+ | | +---------------+ | - | | | | | | | | | | - | Matrix Home Server+-----> Push Gateway | +---> Push Provider | | - | | | | | | | | | | - +-^-----------------+ | +----------------+ | | +----+----------+ | - | | | | | | - Matrix | | | | | | - Client/Server API + | | | | | - | | +--------------------+ +-------------------+ - | +--+-+ | - | | <------------------------------------------+ - +---+ | - | | Provider Push Protocol - +----+ - - Mobile Device or Client - - -Matrix supports push notifications as a first class citizen. Home Servers send -notifications of user events to user-configured HTTP endpoints. User may also -configure a number of rules that determine what events generate notifications. -These are all stored and managed by the users home server such that settings can -be reused between client apps as appropriate. - -The above diagram shows the flow of push notifications being sent to a handset -where push notifications are submitted via the handset vendor, such as Apple's -APNS or Google's GCM. This happens as follows: - - 1. The client app signs in to a Matrix Home Server - 2. The client app registers with its vendor's Push Notification provider and - obtains a routing token of some kind. - 3. The mobile app, uses the Matrix client/server API to add a 'pusher', - providing the URL of a specific Push Gateway which is configured for that - application. It also provides the routing token it has acquired from the - Push Notification Provider. - 4. The Home Server starts sending notification HTTP requests to the Push - Gateway using the supplied URL. The Push Gateway relays this notification to - the Push Notification Provider, passing the routing token along with any - necessary private credentials the provider requires to send push - notifications. - 5. The Push Notification provider sends the notification to the device. - -Nomenclature ------------- - -Pusher - A 'pusher' is an activity in the Home Server that manages the sending - of HTTP notifications for a single device of a single user. - -Push Rules - A push rule is a single rule, configured by a matrix user, that gives - instructions to the Home Server about whether an event should be notified - about and how given a set of conditions. Matrix clients allow the user to - configure these. They create and view them via the Client to Server REST API. - -Push Gateway - A push gateway is a server that receives HTTP event notifications from Home - Servers and passes them on to a different protocol such as APNS for iOS - devices or GCM for Android devices. Matrix.org provides a reference push - gateway, 'sygnal'. A client app tells a Home Server what push gateway - to send notifications to when it sets up a pusher. - -For information on the client-server API for setting pushers and push rules, see -the Client Server API section. For more information on the format of HTTP -notifications, see the HTTP Notification Protocol section. - diff --git a/specification/modules/push_push_gw_api.rst b/specification/modules/push_push_gw_api.rst deleted file mode 100644 index c970e93e..00000000 --- a/specification/modules/push_push_gw_api.rst +++ /dev/null @@ -1,144 +0,0 @@ -HTTP Notification Protocol --------------------------- - -This describes the format used by "HTTP" pushers to send notifications of -events. - -Notifications are sent as HTTP POST requests to the URL configured when the -pusher is created, but Matrix strongly recommends that the path should be:: - - /_matrix/push/v1/notify - -The body of the POST request is a JSON dictionary. The format -is as follows:: - - { - "notification": { - "id": "$3957tyerfgewrf384", - "room_id": "!slw48wfj34rtnrf:example.com", - "type": "m.room.message", - "sender": "@exampleuser:matrix.org", - "sender_display_name": "Major Tom", - "room_name": "Mission Control", - "room_alias": "#exampleroom:matrix.org", - "prio": "high", - "content": { - "msgtype": "m.text", - "body": "I'm floating in a most peculiar way." - } - }, - "counts": { - "unread" : 2, - "missed_calls": 1 - } - "devices": [ - { - "app_id": "org.matrix.matrixConsole.ios", - "pushkey": "V2h5IG9uIGVhcnRoIGRpZCB5b3UgZGVjb2RlIHRoaXM/", - "pushkey_ts": 12345678, - "data" : { - }, - "tweaks": { - "sound": "bing" - } - } - ] - } - } - -The contents of this dictionary are defined as follows: - -id - An identifier for this notification that may be used to detect duplicate - notification requests. This is not necessarily the ID of the event that - triggered the notification. -room_id - The ID of the room in which this event occurred. -type - The type of the event as in the event's 'type' field. -sender - The sender of the event as in the corresponding event field. -sender_display_name - The current display name of the sender in the room in which the event - occurred. -room_name - The name of the room in which the event occurred. -room_alias - An alias to display for the room in which the event occurred. -prio - The priority of the notification. Acceptable values are 'high' or 'low. If - omitted, 'high' is assumed. This may be used by push gateways to deliver less - time-sensitive notifications in a way that will preserve battery power on - mobile devices. -content - The 'content' field from the event, if present. If the event had no content - field, this field is omitted. -counts - This is a dictionary of the current number of unacknowledged communications - for the recipient user. Counts whose value is zero are omitted. -unread - The number of unread messages a user has across all of the rooms they are a - member of. -missed_calls - The number of unacknowledged missed calls a user has across all rooms of - which they are a member. -device - This is an array of devices that the notification should be sent to. -app_id - The app_id given when the pusher was created. -pushkey - The pushkey given when the pusher was created. -pushkey_ts - The unix timestamp (in seconds) when the pushkey was last updated. -data - A dictionary of additional pusher-specific data. For 'http' pushers, this is - the data dictionary passed in at pusher creation minus the 'url' key. -tweaks - A dictionary of customisations made to the way this notification is to be - presented. These are added by push rules. -sound - Sets the sound file that should be played. 'default' means that a default - sound should be played. - -And additional key is defined but only present on member events: - -user_is_target - This is true if the user receiving the notification is the subject of a member - event (i.e. the state_key of the member event is equal to the user's Matrix - ID). - -The recipient of an HTTP notification should respond with an HTTP 2xx response -when the notification has been processed. If the endpoint returns an HTTP error -code, the Home Server should retry for a reasonable amount of time with a -reasonable back-off scheme. - -The endpoint should return a JSON dictionary as follows:: - - { - "rejected": [ "V2h5IG9uIGVhcnRoIGRpZCB5b3UgZGVjb2RlIHRoaXM/" ] - } - -Whose keys are: - -rejected - A list of all pushkeys given in the notification request that are not valid. - These could have been rejected by an upstream gateway because they have - expired or have never been valid. Home Servers must cease sending notification - requests for these pushkeys and remove the associated pushers. It may not - necessarily be the notification in the request that failed: it could be that - a previous notification to the same pushkey failed. - -Push: Recommendations for APNS ------------------------------- -For sending APNS notifications, the exact format is flexible and up to the -client app and its push gateway to agree on (since APNS requires that the sender -have a private key owned by the app developer, each app must have its own push -gateway). However, Matrix strongly recommends: - - * That the APNS token be base64 encoded and used as the pushkey. - * That a different app_id be used for apps on the production and sandbox - APS environments. - * That APNS push gateways do not attempt to wait for errors from the APNS - gateway before returning and instead to store failures and return - 'rejected' responses next time that pushkey is used. - diff --git a/specification/targets.yaml b/specification/targets.yaml index d77bf8b5..8106b7cf 100644 --- a/specification/targets.yaml +++ b/specification/targets.yaml @@ -22,9 +22,7 @@ groups: # reusable blobs of files when prefixed with 'group:' - modules/content_repo.rst - modules/end_to_end_encryption.rst - modules/history_visibility.rst - - modules/push_overview.rst - # relative depth - - { 1: [modules/push_cs_api.rst , modules/push_push_gw_api.rst] } + - modules/push.rst title_styles: ["=", "-", "~", "+", "^"] From a7400508c6aec74ad564e2e42fed8a6e6954932e Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 7 Oct 2015 14:07:36 +0100 Subject: [PATCH 02/23] Define module titles from the template --- specification/modules/push.rst | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/specification/modules/push.rst b/specification/modules/push.rst index 7a70c580..d68e9ef0 100644 --- a/specification/modules/push.rst +++ b/specification/modules/push.rst @@ -3,9 +3,6 @@ Push Notifications .. _module:push: -Overview --------- - :: +--------------------+ +-------------------+ @@ -54,8 +51,7 @@ APNS or Google's GCM. This happens as follows: notifications. 5. The Push Notification provider sends the notification to the device. -Nomenclature -~~~~~~~~~~~~ +Definitions for terms used in this section are below: Pusher A 'pusher' is an activity in the Home Server that manages the sending @@ -222,7 +218,7 @@ gateway). However, Matrix strongly recommends: gateway before returning and instead to store failures and return 'rejected' responses next time that pushkey is used. -Pushers HTTP API +Client behaviour ---------------- To receive any notification pokes at all, it is necessary to configure a @@ -641,4 +637,15 @@ beneath the rule's URI with a content of 'true' or 'false':: curl -X PUT -H "Content-Type: application/json" -d 'false' "http://localhost:8008/_matrix/client/api/v1/pushrules/global/sender/%40spambot%3Amatrix.org/enabled?access_token=123456" +Server behaviour +---------------- + +- HS to sygnal? + +Security considerations +----------------------- +- Message content shouldn't be sent in the push itself as it will pass through + the Push Provider (Google/Apple). Instead, send a ping to tell the client to + sync. +- HTTPS should be used on the Matrix HTTP Notification Protocol. From d3ed517ebfc272d7aa0274882a5b647620ef72ac Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 7 Oct 2015 14:14:15 +0100 Subject: [PATCH 03/23] Finish laying out rough sections --- specification/modules/push.rst | 292 +++++++++++++++++---------------- 1 file changed, 147 insertions(+), 145 deletions(-) diff --git a/specification/modules/push.rst b/specification/modules/push.rst index d68e9ef0..addd92b6 100644 --- a/specification/modules/push.rst +++ b/specification/modules/push.rst @@ -74,150 +74,6 @@ For information on the client-server API for setting pushers and push rules, see the Client Server API section. For more information on the format of HTTP notifications, see the HTTP Notification Protocol section. -HTTP Notification Protocol --------------------------- - -This describes the format used by "HTTP" pushers to send notifications of -events. - -Notifications are sent as HTTP POST requests to the URL configured when the -pusher is created, but Matrix strongly recommends that the path should be:: - - /_matrix/push/v1/notify - -The body of the POST request is a JSON dictionary. The format -is as follows:: - - { - "notification": { - "id": "$3957tyerfgewrf384", - "room_id": "!slw48wfj34rtnrf:example.com", - "type": "m.room.message", - "sender": "@exampleuser:matrix.org", - "sender_display_name": "Major Tom", - "room_name": "Mission Control", - "room_alias": "#exampleroom:matrix.org", - "prio": "high", - "content": { - "msgtype": "m.text", - "body": "I'm floating in a most peculiar way." - } - }, - "counts": { - "unread" : 2, - "missed_calls": 1 - } - "devices": [ - { - "app_id": "org.matrix.matrixConsole.ios", - "pushkey": "V2h5IG9uIGVhcnRoIGRpZCB5b3UgZGVjb2RlIHRoaXM/", - "pushkey_ts": 12345678, - "data" : { - }, - "tweaks": { - "sound": "bing" - } - } - ] - } - } - -The contents of this dictionary are defined as follows: - -id - An identifier for this notification that may be used to detect duplicate - notification requests. This is not necessarily the ID of the event that - triggered the notification. -room_id - The ID of the room in which this event occurred. -type - The type of the event as in the event's 'type' field. -sender - The sender of the event as in the corresponding event field. -sender_display_name - The current display name of the sender in the room in which the event - occurred. -room_name - The name of the room in which the event occurred. -room_alias - An alias to display for the room in which the event occurred. -prio - The priority of the notification. Acceptable values are 'high' or 'low. If - omitted, 'high' is assumed. This may be used by push gateways to deliver less - time-sensitive notifications in a way that will preserve battery power on - mobile devices. -content - The 'content' field from the event, if present. If the event had no content - field, this field is omitted. -counts - This is a dictionary of the current number of unacknowledged communications - for the recipient user. Counts whose value is zero are omitted. -unread - The number of unread messages a user has across all of the rooms they are a - member of. -missed_calls - The number of unacknowledged missed calls a user has across all rooms of - which they are a member. -device - This is an array of devices that the notification should be sent to. -app_id - The app_id given when the pusher was created. -pushkey - The pushkey given when the pusher was created. -pushkey_ts - The unix timestamp (in seconds) when the pushkey was last updated. -data - A dictionary of additional pusher-specific data. For 'http' pushers, this is - the data dictionary passed in at pusher creation minus the 'url' key. -tweaks - A dictionary of customisations made to the way this notification is to be - presented. These are added by push rules. -sound - Sets the sound file that should be played. 'default' means that a default - sound should be played. - -And additional key is defined but only present on member events: - -user_is_target - This is true if the user receiving the notification is the subject of a member - event (i.e. the state_key of the member event is equal to the user's Matrix - ID). - -The recipient of an HTTP notification should respond with an HTTP 2xx response -when the notification has been processed. If the endpoint returns an HTTP error -code, the Home Server should retry for a reasonable amount of time with a -reasonable back-off scheme. - -The endpoint should return a JSON dictionary as follows:: - - { - "rejected": [ "V2h5IG9uIGVhcnRoIGRpZCB5b3UgZGVjb2RlIHRoaXM/" ] - } - -Whose keys are: - -rejected - A list of all pushkeys given in the notification request that are not valid. - These could have been rejected by an upstream gateway because they have - expired or have never been valid. Home Servers must cease sending notification - requests for these pushkeys and remove the associated pushers. It may not - necessarily be the notification in the request that failed: it could be that - a previous notification to the same pushkey failed. - -Push: Recommendations for APNS -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -For sending APNS notifications, the exact format is flexible and up to the -client app and its push gateway to agree on (since APNS requires that the sender -have a private key owned by the app developer, each app must have its own push -gateway). However, Matrix strongly recommends: - - * That the APNS token be base64 encoded and used as the pushkey. - * That a different app_id be used for apps on the production and sandbox - APS environments. - * That APNS push gateways do not attempt to wait for errors from the APNS - gateway before returning and instead to store failures and return - 'rejected' responses next time that pushkey is used. - Client behaviour ---------------- @@ -640,7 +496,152 @@ beneath the rule's URI with a content of 'true' or 'false':: Server behaviour ---------------- -- HS to sygnal? +HTTP Notification Protocol +~~~~~~~~~~~~~~~~~~~~~~~~~~ + +This describes the format used by "HTTP" pushers to send notifications of +events. + +Notifications are sent as HTTP POST requests to the URL configured when the +pusher is created, but Matrix strongly recommends that the path should be:: + + /_matrix/push/v1/notify + +The body of the POST request is a JSON dictionary. The format +is as follows:: + + { + "notification": { + "id": "$3957tyerfgewrf384", + "room_id": "!slw48wfj34rtnrf:example.com", + "type": "m.room.message", + "sender": "@exampleuser:matrix.org", + "sender_display_name": "Major Tom", + "room_name": "Mission Control", + "room_alias": "#exampleroom:matrix.org", + "prio": "high", + "content": { + "msgtype": "m.text", + "body": "I'm floating in a most peculiar way." + } + }, + "counts": { + "unread" : 2, + "missed_calls": 1 + } + "devices": [ + { + "app_id": "org.matrix.matrixConsole.ios", + "pushkey": "V2h5IG9uIGVhcnRoIGRpZCB5b3UgZGVjb2RlIHRoaXM/", + "pushkey_ts": 12345678, + "data" : { + }, + "tweaks": { + "sound": "bing" + } + } + ] + } + } + +The contents of this dictionary are defined as follows: + +id + An identifier for this notification that may be used to detect duplicate + notification requests. This is not necessarily the ID of the event that + triggered the notification. +room_id + The ID of the room in which this event occurred. +type + The type of the event as in the event's 'type' field. +sender + The sender of the event as in the corresponding event field. +sender_display_name + The current display name of the sender in the room in which the event + occurred. +room_name + The name of the room in which the event occurred. +room_alias + An alias to display for the room in which the event occurred. +prio + The priority of the notification. Acceptable values are 'high' or 'low. If + omitted, 'high' is assumed. This may be used by push gateways to deliver less + time-sensitive notifications in a way that will preserve battery power on + mobile devices. +content + The 'content' field from the event, if present. If the event had no content + field, this field is omitted. +counts + This is a dictionary of the current number of unacknowledged communications + for the recipient user. Counts whose value is zero are omitted. +unread + The number of unread messages a user has across all of the rooms they are a + member of. +missed_calls + The number of unacknowledged missed calls a user has across all rooms of + which they are a member. +device + This is an array of devices that the notification should be sent to. +app_id + The app_id given when the pusher was created. +pushkey + The pushkey given when the pusher was created. +pushkey_ts + The unix timestamp (in seconds) when the pushkey was last updated. +data + A dictionary of additional pusher-specific data. For 'http' pushers, this is + the data dictionary passed in at pusher creation minus the 'url' key. +tweaks + A dictionary of customisations made to the way this notification is to be + presented. These are added by push rules. +sound + Sets the sound file that should be played. 'default' means that a default + sound should be played. + +And additional key is defined but only present on member events: + +user_is_target + This is true if the user receiving the notification is the subject of a member + event (i.e. the state_key of the member event is equal to the user's Matrix + ID). + +The recipient of an HTTP notification should respond with an HTTP 2xx response +when the notification has been processed. If the endpoint returns an HTTP error +code, the Home Server should retry for a reasonable amount of time with a +reasonable back-off scheme. + +The endpoint should return a JSON dictionary as follows:: + + { + "rejected": [ "V2h5IG9uIGVhcnRoIGRpZCB5b3UgZGVjb2RlIHRoaXM/" ] + } + +Whose keys are: + +rejected + A list of all pushkeys given in the notification request that are not valid. + These could have been rejected by an upstream gateway because they have + expired or have never been valid. Home Servers must cease sending notification + requests for these pushkeys and remove the associated pushers. It may not + necessarily be the notification in the request that failed: it could be that + a previous notification to the same pushkey failed. + +Push: Recommendations for APNS +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +For sending APNS notifications, the exact format is flexible and up to the +client app and its push gateway to agree on (since APNS requires that the sender +have a private key owned by the app developer, each app must have its own push +gateway). However, Matrix strongly recommends: + + * That the APNS token be base64 encoded and used as the pushkey. + * That a different app_id be used for apps on the production and sandbox + APS environments. + * That APNS push gateways do not attempt to wait for errors from the APNS + gateway before returning and instead to store failures and return + 'rejected' responses next time that pushkey is used. + +Push Gateway behaviour +---------------------- Security considerations ----------------------- @@ -649,3 +650,4 @@ Security considerations the Push Provider (Google/Apple). Instead, send a ping to tell the client to sync. - HTTPS should be used on the Matrix HTTP Notification Protocol. + From c5edc60c4cf2d082384e4437a798464e6a380348 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 7 Oct 2015 16:01:36 +0100 Subject: [PATCH 04/23] Add push YAML for pushers endpoint. Also display "required" text on required JSON body request params. Also increase the size of the request param column to support longer param names present in the pushers API. --- api/client-server/v1/push.yaml | 144 ++++++++++++++++++ specification/modules/push.rst | 47 +----- .../matrix_templates/templates/http-api.tmpl | 18 +-- templating/matrix_templates/units.py | 8 +- 4 files changed, 162 insertions(+), 55 deletions(-) create mode 100644 api/client-server/v1/push.yaml diff --git a/api/client-server/v1/push.yaml b/api/client-server/v1/push.yaml new file mode 100644 index 00000000..fd179fe6 --- /dev/null +++ b/api/client-server/v1/push.yaml @@ -0,0 +1,144 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v1 Push 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: + "/pushers/set": + post: + summary: Modify a pusher for this user on the homeserver. + description: |- + This endpoint allows the creation, modification and deletion of pushers + for this user ID. The behaviour of this endpoint varies depending on the + values in the JSON body. + security: + - accessToken: [] + parameters: + - in: body + name: pusher + description: The pusher information + required: true + schema: + type: object + example: |- + { + "lang": "en", + "kind": "http", + "app_display_name": "Mat Rix", + "device_display_name": "iPhone 9", + "app_id": "com.example.app.ios", + "profile_tag": "4bea66906d0111e59d70feff819cdc9f", + "pushkey": "APA91bHPRgkF3JUikC4ENAHEeMrd41Zxv3hVZjC9KtT8OvPVGJ-hQMRKRrZuJAEcl7B338qju59zJMjw2DELjzEvxwYv7hH5Ynpc1ODQ0aT4U4OFEeco8ohsN5PjL1iC2dNtk2BAokeMCg2ZXKqpc8FXKmhX94kIxQ" + "data": { + "url": "https://push-gateway.location.here" + } + "append": false + } + properties: + pushkey: + type: string + description: |- + This is a unique identifier for this pusher. The value you + should use for this is the routing or destination address + information for the notification, for example, the APNS token + for APNS or the Registration ID for GCM. If your notification + client has no such concept, use any unique identifier. + Max length, 512 bytes. + kind: + type: string + enum: ["http", null] + description: |- + The kind of pusher to configure. 'http' makes a pusher that + sends HTTP pokes. null deletes the pusher. + profile_tag: + type: string + description: |- + This is a string that determines what set of device rules will + be matched when evaluating push rules for this pusher. It is + an arbitrary string. Multiple devices maybe use the same + ``profile_tag``. It is advised that when an app's data is + copied or restored to a different device, this value remain + the same. Client apps should offer ways to change the + ``profile_tag``, optionally copying rules from the old + profile tag. Max length, 32 bytes. + app_id: + type: string + description: |- + This is a reverse-DNS style identifier for the application. + It is recommended that this end with the platform, such that + different platform versions get different app identifiers. + Max length, 64 chars. + app_display_name: + type: string + description: |- + A string that will allow the user to identify what application + owns this pusher. + device_display_name: + type: string + description: |- + A string that will allow the user to identify what device owns + this pusher. + lang: + type: string + description: |- + The preferred language for receiving notifications (e.g. 'en' + or 'en-US') + data: + type: object + description: |- + A dictionary of information for the pusher implementation + itself. If ``kind`` is ``http``, this should contain ``url`` + which is the URL to use to send notifications to. + properties: + url: + type: string + description: |- + Required if ``kind`` is ``http``. The URL to use to send + notifications to. + append: + type: boolean + description: |- + If true, the homeserver should add another pusher with the + given pushkey and App ID in addition to any others with + different user IDs. Otherwise, the Home Server must remove any + other pushers with the same App ID and pushkey for different + users. The default is ``false``. + required: ['profile_tag', 'kind', 'app_id', 'app_display_name', + 'device_display_name', 'pushkey', 'lang', 'data'] + responses: + 200: + description: The pusher was set. + examples: + application/json: |- + {} + schema: + type: object # empty json object + 400: + description: One or more of the pusher values were invalid. + examples: + application/json: |- + { + "error": "Missing parameters: lang, data", + "errcode": "M_MISSING_PARAM" + } + schema: + type: object + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/error.yaml" + diff --git a/specification/modules/push.rst b/specification/modules/push.rst index addd92b6..bd08dc9e 100644 --- a/specification/modules/push.rst +++ b/specification/modules/push.rst @@ -79,52 +79,9 @@ Client behaviour To receive any notification pokes at all, it is necessary to configure a 'pusher' on the Home Server that you wish to receive notifications from. There -is a single API endpoint for this:: - - POST $PREFIX/pushers/set - -This takes a JSON object with the following keys: - -pushkey - This is a unique identifier for this pusher. The value you should use for this - is the routing or destination address information for the notification, for - example, the APNS token for APNS or the Registration ID for GCM. If your - notification client has no such concept, use any unique identifier. Max length, - 512 bytes. -kind - The kind of pusher to configure. 'http' makes a pusher that sends HTTP pokes. - null deletes the pusher. -profile_tag - This is a string that determines what set of device rules will be matched when - evaluating push rules for this pusher. It is an arbitrary string. Multiple - devices maybe use the same profile_tag. It is advised that when an app's - data is copied or restored to a different device, this value remain the same. - Client apps should offer ways to change the profile_tag, optionally copying - rules from the old profile tag. Max length, 32 bytes. -app_id - appId is a reverse-DNS style identifier for the application. It is recommended - that this end with the platform, such that different platform versions get - different app identifiers. Max length, 64 chars. -app_display_name - A string that will allow the user to identify what application owns this - pusher. -device_display_name - A string that will allow the user to identify what device owns this pusher. -lang - The preferred language for receiving notifications (eg, 'en' or 'en-US') -data - A dictionary of information for the pusher implementation itself. For HTTP - pushers, this must contain a 'url' key which is a string of the URL that - should be used to send notifications. -append - If this is set to boolean true, the Home Server should add another pusher - with the given pushkey and App ID in addition to any others with different - user IDs. Otherwise, the Home Server must remove any other pushers with the - same App ID and pushkey for different users. The default is false. - -If the pusher was created successfully, a JSON dictionary is returned (which may -be empty). +is a single API endpoint for this, as described below. +{{push_http_api}} Push Rules ~~~~~~~~~~ diff --git a/templating/matrix_templates/templates/http-api.tmpl b/templating/matrix_templates/templates/http-api.tmpl index 472c9d7a..f2c3d0b6 100644 --- a/templating/matrix_templates/templates/http-api.tmpl +++ b/templating/matrix_templates/templates/http-api.tmpl @@ -13,17 +13,17 @@ Request format: -================== ================= =========================================== +====================== ================= =========================================== Parameter Value Description -================== ================= =========================================== +====================== ================= =========================================== {% for loc in endpoint.req_param_by_loc -%} *{{loc}} parameters* --------------------------------------------------------------------------------- +------------------------------------------------------------------------------------ {% for param in endpoint.req_param_by_loc[loc] -%} -{{param.key}}{{param.type|indent(19-param.key|length)}}{{param.desc|indent(18-param.type|length)|wrap(43)|indent_block(37)}} +{{param.key}}{{param.type|indent(23-param.key|length)}}{{param.desc|indent(18-param.type|length)|wrap(43)|indent_block(41)}} {% endfor -%} {% endfor -%} -================== ================= =========================================== +====================== ================= =========================================== {% if endpoint.res_tables|length > 0 -%} Response format: @@ -31,18 +31,18 @@ Response format: {% for table in endpoint.res_tables -%} {{"``"+table.title+"``" if table.title else "" }} -=================== ================= ========================================== +======================= ================= ========================================== Param Type Description -=================== ================= ========================================== +======================= ================= ========================================== {% for row in table.rows -%} {# -#} {# 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 -#} {# It also needs to then wrap inside the desc col (42 ch width) -#} {# -#} -{{row.key}}{{row.type|indent(20-row.key|length)}}{{row.desc|wrap(42,row.req_str | indent(18 - (row.type|length))) |indent_block(38)}} +{{row.key}}{{row.type|indent(24-row.key|length)}}{{row.desc|wrap(40,row.req_str | indent(18 - (row.type|length))) |indent_block(42)}} {% endfor -%} -=================== ================= ========================================== +======================= ================= ========================================== {% endfor %} {% endif -%} diff --git a/templating/matrix_templates/units.py b/templating/matrix_templates/units.py index eebfba84..1b4b8c7d 100644 --- a/templating/matrix_templates/units.py +++ b/templating/matrix_templates/units.py @@ -207,12 +207,18 @@ class MatrixUnits(Units): ) # loop top-level json keys json_body = Units.prop(param, "schema/properties") + required_params = [] + if Units.prop(param, "schema/required"): + required_params = Units.prop(param, "schema/required") for key in json_body: + pdesc = json_body[key]["description"] + if key in required_params: + pdesc = "**Required.** " + pdesc endpoint["req_params"].append({ "key": key, "loc": "JSON body", "type": json_body[key]["type"], - "desc": json_body[key]["description"] + "desc": pdesc }) # endfor[param] for row in endpoint["req_params"]: From 9540069acd3106dacdfdcd85c5f1f225239ea4ce Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 7 Oct 2015 16:06:11 +0100 Subject: [PATCH 05/23] Use valid JSON --- api/client-server/v1/push.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/client-server/v1/push.yaml b/api/client-server/v1/push.yaml index fd179fe6..50bf318d 100644 --- a/api/client-server/v1/push.yaml +++ b/api/client-server/v1/push.yaml @@ -42,10 +42,10 @@ paths: "device_display_name": "iPhone 9", "app_id": "com.example.app.ios", "profile_tag": "4bea66906d0111e59d70feff819cdc9f", - "pushkey": "APA91bHPRgkF3JUikC4ENAHEeMrd41Zxv3hVZjC9KtT8OvPVGJ-hQMRKRrZuJAEcl7B338qju59zJMjw2DELjzEvxwYv7hH5Ynpc1ODQ0aT4U4OFEeco8ohsN5PjL1iC2dNtk2BAokeMCg2ZXKqpc8FXKmhX94kIxQ" + "pushkey": "APA91bHPRgkF3JUikC4ENAHEeMrd41Zxv3hVZjC9KtT8OvPVGJ-hQMRKRrZuJAEcl7B338qju59zJMjw2DELjzEvxwYv7hH5Ynpc1ODQ0aT4U4OFEeco8ohsN5PjL1iC2dNtk2BAokeMCg2ZXKqpc8FXKmhX94kIxQ", "data": { "url": "https://push-gateway.location.here" - } + }, "append": false } properties: From db25276856b1933cf9fc06707cecfaed5bd73d37 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Wed, 7 Oct 2015 17:44:05 +0100 Subject: [PATCH 06/23] Start adding in push definitions This is going to be painful to represent due to how the push API allows mixed types (strings or objects) and mixed top-level keys ("content" rule kind allowing "pattern" as a top-level key). We may wish to re-visit the design of this API for v2. --- .../v1/definitions/push_rule.yaml | 12 + .../v1/definitions/push_ruleset.yaml | 27 ++ .../v1/{push.yaml => pusher.yaml} | 4 +- api/client-server/v1/pushrules.yaml | 434 ++++++++++++++++++ specification/modules/push.rst | 8 +- 5 files changed, 480 insertions(+), 5 deletions(-) create mode 100644 api/client-server/v1/definitions/push_rule.yaml create mode 100644 api/client-server/v1/definitions/push_ruleset.yaml rename api/client-server/v1/{push.yaml => pusher.yaml} (97%) create mode 100644 api/client-server/v1/pushrules.yaml diff --git a/api/client-server/v1/definitions/push_rule.yaml b/api/client-server/v1/definitions/push_rule.yaml new file mode 100644 index 00000000..be4791c8 --- /dev/null +++ b/api/client-server/v1/definitions/push_rule.yaml @@ -0,0 +1,12 @@ +type: "object" +properties: + rule_id: + type: string + actions: + type: array + items: + type: string + default: + type: boolean + enabled: + type: boolean \ No newline at end of file diff --git a/api/client-server/v1/definitions/push_ruleset.yaml b/api/client-server/v1/definitions/push_ruleset.yaml new file mode 100644 index 00000000..77653b98 --- /dev/null +++ b/api/client-server/v1/definitions/push_ruleset.yaml @@ -0,0 +1,27 @@ +type: "object" +properties: + content: + type: array + items: + type: object + allOf: [ "$ref": "definitions/push_rule.yaml"] + override: + type: array + items: + type: object + allOf: [ "$ref": "definitions/push_rule.yaml"] + room: + type: array + items: + type: object + allOf: [ "$ref": "definitions/push_rule.yaml"] + sender: + type: array + items: + type: object + allOf: [ "$ref": "definitions/push_rule.yaml"] + underride: + type: array + items: + type: object + allOf: [ "$ref": "definitions/push_rule.yaml"] diff --git a/api/client-server/v1/push.yaml b/api/client-server/v1/pusher.yaml similarity index 97% rename from api/client-server/v1/push.yaml rename to api/client-server/v1/pusher.yaml index 50bf318d..3c9ffe8c 100644 --- a/api/client-server/v1/push.yaml +++ b/api/client-server/v1/pusher.yaml @@ -62,8 +62,8 @@ paths: type: string enum: ["http", null] description: |- - The kind of pusher to configure. 'http' makes a pusher that - sends HTTP pokes. null deletes the pusher. + The kind of pusher to configure. ``"http"`` makes a pusher that + sends HTTP pokes. ``null`` deletes the pusher. profile_tag: type: string description: |- diff --git a/api/client-server/v1/pushrules.yaml b/api/client-server/v1/pushrules.yaml new file mode 100644 index 00000000..29a8b0cc --- /dev/null +++ b/api/client-server/v1/pushrules.yaml @@ -0,0 +1,434 @@ +swagger: '2.0' +info: + title: "Matrix Client-Server v1 Push Rules 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: + "/pushrules/": + get: + summary: Retrieve all push rulesets. + description: |- + Retrieve all push rulesets for this user. Clients can "drill-down" on + the rulesets by suffixing a ``scope`` to this path e.g. + ``/pushrules/global/``. This will return a subset of this data under the + specified key: in this case the ``global`` key. + security: + - accessToken: [] + responses: + 200: + schema: + type: object + required: ["device", "global"] + properties: + device: + type: object + title: Devices + description: A dictionary of devices. + patternProperties: + ".*": + x-pattern: "$PROFILE_TAG" + type: object + description: The ruleset for this profile tag. + title: Ruleset + allOf: [ + "$ref": "definitions/push_ruleset.yaml" + ] + global: + type: object + description: The global ruleset. + title: Ruleset + allOf: [ + "$ref": "definitions/push_ruleset.yaml" + ] + examples: + application/json: |- + { + "device": {}, + "global": { + "content": [ + { + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight" + } + ], + "default": true, + "enabled": true, + "pattern": "alice", + "rule_id": ".m.rule.contains_user_name" + } + ], + "override": [ + { + "actions": [ + "dont_notify" + ], + "conditions": [], + "default": true, + "enabled": false, + "rule_id": ".m.rule.master" + }, + { + "actions": [ + "dont_notify" + ], + "conditions": [ + { + "key": "content.msgtype", + "kind": "event_match", + "pattern": "m.notice" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.suppress_notices" + } + ], + "room": [], + "sender": [], + "underride": [ + { + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "ring" + }, + { + "set_tweak": "highlight", + "value": false + } + ], + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.call.invite" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.call" + }, + { + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight" + } + ], + "conditions": [ + { + "kind": "contains_display_name" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.contains_display_name" + }, + { + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight", + "value": false + } + ], + "conditions": [ + { + "is": "2", + "kind": "room_member_count" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.room_one_to_one" + }, + { + "actions": [ + "notify", + { + "set_tweak": "sound", + "value": "default" + }, + { + "set_tweak": "highlight", + "value": false + } + ], + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.member" + }, + { + "key": "content.membership", + "kind": "event_match", + "pattern": "invite" + }, + { + "key": "state_key", + "kind": "event_match", + "pattern": "@alice:example.com" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.invite_for_me" + }, + { + "actions": [ + "notify", + { + "set_tweak": "highlight", + "value": false + } + ], + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.member" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.member_event" + }, + { + "actions": [ + "notify", + { + "set_tweak": "highlight", + "value": false + } + ], + "conditions": [ + { + "key": "type", + "kind": "event_match", + "pattern": "m.room.message" + } + ], + "default": true, + "enabled": true, + "rule_id": ".m.rule.message" + } + ] + } + } + "/pushrules/{scope}/{kind}/{ruleId}": + get: + summary: Retrieve a push rule. + description: |- + Retrieve a single specified push rule. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: scope + required: true + x-example: "global" + description: |- + Either ``global`` or ``device/`` to specify global + rules or device rules for the given ``profile_tag``. + - in: path + type: string + name: kind + required: true + x-example: room + enum: ["override", "underride", "sender", "room", "content"] + description: | + The kind of rule + - in: path + type: string + name: ruleId + required: true + x-example: "#spam:example.com" + description: | + The identifier for the rule. + responses: + 200: + description: |- + The specific push rule. This will also include keys specific to the + rule itself such as the rule's ``actions`` and ``conditions`` if set. + examples: + application/json: |- + { + "actions": [ + "dont_notify" + ], + "rule_id": "#spam:matrix.org", + "enabled": true + } + schema: + type: object + required: ["enabled", "rule_id", "actions"] + properties: + enabled: + type: boolean + description: Whether this rule is active or not. + rule_id: + type: string + description: The rule ID from the path. + delete: + summary: Delete a push rule. + description: |- + This endpoint removes the push rule defined in the path. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: scope + required: true + x-example: "global" + description: |- + Either ``global`` or ``device/`` to specify global + rules or device rules for the given ``profile_tag``. + - in: path + type: string + name: kind + required: true + x-example: room + enum: ["override", "underride", "sender", "room", "content"] + description: | + The kind of rule + - in: path + type: string + name: ruleId + required: true + x-example: "#spam:example.com" + description: | + The identifier for the rule. + put: + summary: Add or change a push rule. + description: |- + This endpoint allows the creation, modification and deletion of pushers + for this user ID. The behaviour of this endpoint varies depending on the + values in the JSON body. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: scope + required: true + x-example: "global" + description: |- + Either ``global`` or ``device/`` to specify global + rules or device rules for the given ``profile_tag``. + - in: path + type: string + name: kind + required: true + x-example: room + enum: ["override", "underride", "sender", "room", "content"] + description: | + The kind of rule + - in: path + type: string + name: ruleId + required: true + x-example: "#spam:example.com" + description: | + The identifier for the rule. + - in: query + type: string + name: before + required: false + x-example: someRuleId + description: |- + Use 'before' with a ``rule_id`` as its value to make the new rule the + next-most important rule with respect to the given rule. + - in: query + type: string + name: after + required: false + x-example: anotherRuleId + description: |- + This makes the new rule the next-less important rule relative to the + given rule. + - in: body + name: pushrule + description: |- + The push rule data. Additional top-level keys may be present depending + on the parameters for the rule ``kind``. + required: true + schema: + type: object + example: |- + { + "pattern": "cake*lie", + "actions": ["notify"] + } + properties: + actions: + type: array + description: |- + The action(s) to perform when the conditions for this rule are met. + items: + type: string + enum: ["notify", "dont_notify", "coalesce", "set_tweak"] + # TODO: type: object e.g. {"set_sound":"beeroclock.wav"} :/ + conditions: + type: array + description: |- + The conditions that must hold true for an event in order for a + rule to be applied to an event. A rule with no conditions + always matches. + items: + type: object + required: ["actions"] + responses: + 200: + description: The pusher was set. + examples: + application/json: |- + {} + schema: + type: object # empty json object + 400: + description: There was a problem configuring this push rule. + examples: + application/json: |- + { + "error": "before/after rule not found: someRuleId", + "errcode": "M_UNKNOWN" + } + schema: + type: object + 429: + description: This request was rate-limited. + schema: + "$ref": "definitions/error.yaml" + diff --git a/specification/modules/push.rst b/specification/modules/push.rst index bd08dc9e..72991565 100644 --- a/specification/modules/push.rst +++ b/specification/modules/push.rst @@ -81,12 +81,12 @@ To receive any notification pokes at all, it is necessary to configure a 'pusher' on the Home Server that you wish to receive notifications from. There is a single API endpoint for this, as described below. -{{push_http_api}} +{{pusher_http_api}} Push Rules ~~~~~~~~~~ -Home Servers have an interface to configure what events trigger notifications. -This behaviour is configured through 'Push Rules'. Push Rules come in a variety +Homeservers have an interface to configure what events trigger notifications. +This behaviour is configured through "Push Rules". Push Rules come in a variety of different kinds and each kind of rule has an associated priority. The different kinds of rule, in descending order of priority, are: @@ -332,6 +332,8 @@ but instead have predefined conditions, the behaviour of which can be configured using parameters named as described above. In the cases of room and sender rules, the rule_id of the rule determines its behaviour. +{{pushrules_http_api}} + Push Rules: API ~~~~~~~~~~~~~~~ Rules live under a hierarchy in the REST API that resembles:: From f6da9d7760537459e4facab69a6f03b3223b227e Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 8 Oct 2015 09:57:40 +0100 Subject: [PATCH 07/23] Give valid swagger. Split out rule/ruleset to separate definitions. --- .../v1/definitions/push_rule.json | 20 +++++++ .../v1/definitions/push_rule.yaml | 12 ---- .../v1/definitions/push_ruleset.json | 60 +++++++++++++++++++ .../v1/definitions/push_ruleset.yaml | 27 --------- api/client-server/v1/pushrules.yaml | 29 +++++---- 5 files changed, 97 insertions(+), 51 deletions(-) create mode 100644 api/client-server/v1/definitions/push_rule.json delete mode 100644 api/client-server/v1/definitions/push_rule.yaml create mode 100644 api/client-server/v1/definitions/push_ruleset.json delete mode 100644 api/client-server/v1/definitions/push_ruleset.yaml diff --git a/api/client-server/v1/definitions/push_rule.json b/api/client-server/v1/definitions/push_rule.json new file mode 100644 index 00000000..4df93f67 --- /dev/null +++ b/api/client-server/v1/definitions/push_rule.json @@ -0,0 +1,20 @@ +{ + "type": "object", + "properties": { + "default": { + "type": "boolean" + }, + "enabled": { + "type": "boolean" + }, + "rule_id": { + "type": "string" + }, + "actions": { + "items": { + "type": ["object", "string"] + }, + "type": "array" + } + } +} \ No newline at end of file diff --git a/api/client-server/v1/definitions/push_rule.yaml b/api/client-server/v1/definitions/push_rule.yaml deleted file mode 100644 index be4791c8..00000000 --- a/api/client-server/v1/definitions/push_rule.yaml +++ /dev/null @@ -1,12 +0,0 @@ -type: "object" -properties: - rule_id: - type: string - actions: - type: array - items: - type: string - default: - type: boolean - enabled: - type: boolean \ No newline at end of file diff --git a/api/client-server/v1/definitions/push_ruleset.json b/api/client-server/v1/definitions/push_ruleset.json new file mode 100644 index 00000000..e0372701 --- /dev/null +++ b/api/client-server/v1/definitions/push_ruleset.json @@ -0,0 +1,60 @@ +{ + "type": "object", + "properties": { + "content": { + "items": { + "type": "object", + "allOf": [ + { + "$ref": "push_rule.json" + } + ] + }, + "type": "array" + }, + "override": { + "items": { + "type": "object", + "allOf": [ + { + "$ref": "push_rule.json" + } + ] + }, + "type": "array" + }, + "sender": { + "items": { + "type": "object", + "allOf": [ + { + "$ref": "push_rule.json" + } + ] + }, + "type": "array" + }, + "underride": { + "items": { + "type": "object", + "allOf": [ + { + "$ref": "push_rule.json" + } + ] + }, + "type": "array" + }, + "room": { + "items": { + "type": "object", + "allOf": [ + { + "$ref": "push_rule.json" + } + ] + }, + "type": "array" + } + } +} \ No newline at end of file diff --git a/api/client-server/v1/definitions/push_ruleset.yaml b/api/client-server/v1/definitions/push_ruleset.yaml deleted file mode 100644 index 77653b98..00000000 --- a/api/client-server/v1/definitions/push_ruleset.yaml +++ /dev/null @@ -1,27 +0,0 @@ -type: "object" -properties: - content: - type: array - items: - type: object - allOf: [ "$ref": "definitions/push_rule.yaml"] - override: - type: array - items: - type: object - allOf: [ "$ref": "definitions/push_rule.yaml"] - room: - type: array - items: - type: object - allOf: [ "$ref": "definitions/push_rule.yaml"] - sender: - type: array - items: - type: object - allOf: [ "$ref": "definitions/push_rule.yaml"] - underride: - type: array - items: - type: object - allOf: [ "$ref": "definitions/push_rule.yaml"] diff --git a/api/client-server/v1/pushrules.yaml b/api/client-server/v1/pushrules.yaml index 29a8b0cc..17061b2d 100644 --- a/api/client-server/v1/pushrules.yaml +++ b/api/client-server/v1/pushrules.yaml @@ -30,6 +30,7 @@ paths: - accessToken: [] responses: 200: + description: All the push rulesets for this user. schema: type: object required: ["device", "global"] @@ -38,21 +39,20 @@ paths: type: object title: Devices description: A dictionary of devices. - patternProperties: - ".*": + additionalProperties: x-pattern: "$PROFILE_TAG" type: object description: The ruleset for this profile tag. title: Ruleset allOf: [ - "$ref": "definitions/push_ruleset.yaml" + "$ref": "definitions/push_ruleset.json" ] global: type: object description: The global ruleset. title: Ruleset allOf: [ - "$ref": "definitions/push_ruleset.yaml" + "$ref": "definitions/push_ruleset.json" ] examples: application/json: |- @@ -292,14 +292,11 @@ paths: } schema: type: object - required: ["enabled", "rule_id", "actions"] - properties: - enabled: - type: boolean - description: Whether this rule is active or not. - rule_id: - type: string - description: The rule ID from the path. + description: The push rule. + title: PushRule + allOf: [ + "$ref": "definitions/push_rule.json" + ] delete: summary: Delete a push rule. description: |- @@ -330,6 +327,14 @@ paths: x-example: "#spam:example.com" description: | The identifier for the rule. + responses: + 200: + description: The push rule was deleted. + examples: + application/json: |- + {} + schema: + type: object # empty json object put: summary: Add or change a push rule. description: |- From 56ce432399f3dd72614664d8d9450da41afb46f0 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 8 Oct 2015 10:14:05 +0100 Subject: [PATCH 08/23] Get profile tag keys displaying correctly. --- api/client-server/v1/pushrules.yaml | 4 +- specification/modules/push.rst | 81 ------------------- .../matrix_templates/templates/http-api.tmpl | 10 +-- templating/matrix_templates/units.py | 5 +- 4 files changed, 11 insertions(+), 89 deletions(-) diff --git a/api/client-server/v1/pushrules.yaml b/api/client-server/v1/pushrules.yaml index 17061b2d..c9dd777e 100644 --- a/api/client-server/v1/pushrules.yaml +++ b/api/client-server/v1/pushrules.yaml @@ -25,7 +25,7 @@ paths: Retrieve all push rulesets for this user. Clients can "drill-down" on the rulesets by suffixing a ``scope`` to this path e.g. ``/pushrules/global/``. This will return a subset of this data under the - specified key: in this case the ``global`` key. + specified key e.g. the ``global`` key. security: - accessToken: [] responses: @@ -38,7 +38,7 @@ paths: device: type: object title: Devices - description: A dictionary of devices. + description: A dictionary of profile tags to rulesets. additionalProperties: x-pattern: "$PROFILE_TAG" type: object diff --git a/specification/modules/push.rst b/specification/modules/push.rst index 72991565..6411f3df 100644 --- a/specification/modules/push.rst +++ b/specification/modules/push.rst @@ -336,33 +336,6 @@ rules, the rule_id of the rule determines its behaviour. Push Rules: API ~~~~~~~~~~~~~~~ -Rules live under a hierarchy in the REST API that resembles:: - - $PREFIX/pushrules/// - -The component parts are as follows: - -scope - Either 'global' or 'device/' to specify global rules or - device rules for the given profile_tag. -kind - The kind of rule, i.e. 'override', 'underride', 'sender', 'room', 'content'. -rule_id - The identifier for the rule. - -To add or change a rule, a client performs a PUT request to the appropriate URL. -When adding rules of a type that has an ordering, the client can add parameters -that define the priority of the rule: - -before - Use 'before' with a rule_id as its value to make the new rule the next-more - important rule with respect to the given rule. -after - This makes the new rule the next-less important rule relative to the given - rule. - -All requests to the push rules API also require an access_token as a query -parameter. The content of the PUT request is a JSON object with a list of actions under the 'actions' key and either conditions (under the 'conditions' key) or the @@ -391,60 +364,6 @@ To add a custom sound for notifications messages containing the word 'beer' in a curl -X PUT -H "Content-Type: application/json" -d '{ "conditions": [{"kind": "event_match", "key": "content.body", "pattern": "beer" }, {"kind": "room_member_count", "is": "<=10"}], "actions" : ["notify", {"set_sound":"beeroclock.wav"}] }' "http://localhost:8008/_matrix/client/api/v1/pushrules/global/override/U2VlIHlvdSBpbiBUaGUgRHVrZQ?access_token=123456 -To delete rules, a client would just make a DELETE request to the same URL:: - - curl -X DELETE "http://localhost:8008/_matrix/client/api/v1/pushrules/global/room/%23spam%3Amatrix.org?access_token=123456" - - -Retrieving the current ruleset can be done either by fetching individual rules -using the scheme as specified above. This returns the rule in the same format as -would be given in the PUT API with the addition of a rule_id:: - - curl "http://localhost:8008/_matrix/client/api/v1/pushrules/global/room/%23spam%3Amatrix.org?access_token=123456" - -Returns:: - - { - "actions": [ - "dont_notify" - ], - "rule_id": "#spam:matrix.org", - "enabled": true - } - -Clients can also fetch broader sets of rules by removing path components. -Requesting the root level returns a structure as follows:: - - { - "device": { - "exampledevice": { - "content": [], - "override": [], - "room": [ - { - "actions": [ - "dont_notify" - ], - "rule_id": "#spam:matrix.org", - "enabled", true - } - ], - "sender": [], - "underride": [] - } - }, - "global": { - "content": [], - "override": [], - "room": [], - "sender": [], - "underride": [] - } - } - -Adding patch components to the request drills down into this structure to filter -to only the requested set of rules. - Enabling and Disabling Rules ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Rules can be enabled or disabled with a PUT operation to the 'enabled' component diff --git a/templating/matrix_templates/templates/http-api.tmpl b/templating/matrix_templates/templates/http-api.tmpl index f2c3d0b6..33b2cc98 100644 --- a/templating/matrix_templates/templates/http-api.tmpl +++ b/templating/matrix_templates/templates/http-api.tmpl @@ -31,18 +31,18 @@ Response format: {% for table in endpoint.res_tables -%} {{"``"+table.title+"``" if table.title else "" }} -======================= ================= ========================================== - Param Type Description -======================= ================= ========================================== +======================= ========================= ========================================== + Param Type Description +======================= ========================= ========================================== {% for row in table.rows -%} {# -#} {# 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 -#} {# It also needs to then wrap inside the desc col (42 ch width) -#} {# -#} -{{row.key}}{{row.type|indent(24-row.key|length)}}{{row.desc|wrap(40,row.req_str | indent(18 - (row.type|length))) |indent_block(42)}} +{{row.key}}{{row.type|indent(24-row.key|length)}}{{row.desc|wrap(40,row.req_str | indent(26 - (row.type|length))) |indent_block(50)}} {% endfor -%} -======================= ================= ========================================== +======================= ========================= ========================================== {% endfor %} {% endif -%} diff --git a/templating/matrix_templates/units.py b/templating/matrix_templates/units.py index 1b4b8c7d..24e92f5a 100644 --- a/templating/matrix_templates/units.py +++ b/templating/matrix_templates/units.py @@ -86,7 +86,10 @@ def get_json_schema_object_fields(obj, enforce_title=False): props[key_name]["additionalProperties"], enforce_title=True ) - value_type = "{string: %s}" % nested_object[0]["title"] + key = props[key_name]["additionalProperties"].get( + "x-pattern", "string" + ) + value_type = "{%s: %s}" % (key, nested_object[0]["title"]) if not nested_object[0].get("no-table"): tables += nested_object else: From a9618a981b2a861b59acb304c8fc37b3f985cc91 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 8 Oct 2015 11:16:42 +0100 Subject: [PATCH 09/23] Swaggerify the /enabled endpoint --- api/check_examples.py | 2 +- api/client-server/v1/pushrules.yaml | 49 +++++++++++- specification/modules/push.rst | 113 ++++++++++++++++----------- specification/targets.yaml | 2 +- templating/matrix_templates/units.py | 5 ++ 5 files changed, 122 insertions(+), 49 deletions(-) diff --git a/api/check_examples.py b/api/check_examples.py index f08b2dc1..0622bfeb 100755 --- a/api/check_examples.py +++ b/api/check_examples.py @@ -52,7 +52,7 @@ def check_parameter(filepath, request, parameter): jsonschema.validate(example, schema) except Exception as e: raise ValueError("Error validating JSON schema for %r %r" % ( - request, code + request ), e) diff --git a/api/client-server/v1/pushrules.yaml b/api/client-server/v1/pushrules.yaml index c9dd777e..eef0b2c7 100644 --- a/api/client-server/v1/pushrules.yaml +++ b/api/client-server/v1/pushrules.yaml @@ -436,4 +436,51 @@ paths: description: This request was rate-limited. schema: "$ref": "definitions/error.yaml" - + "/pushrules/{scope}/{kind}/{ruleId}/enabled": + put: + summary: "Enable or disable a push rule." + description: |- + This endpoint allows clients to enable or disable the specified push rule. + security: + - accessToken: [] + parameters: + - in: path + type: string + name: scope + required: true + x-example: "global" + description: |- + Either ``global`` or ``device/`` to specify global + rules or device rules for the given ``profile_tag``. + - in: path + type: string + name: kind + required: true + x-example: room + enum: ["override", "underride", "sender", "room", "content"] + description: | + The kind of rule + - in: path + type: string + name: ruleId + required: true + x-example: "#spam:example.com" + description: | + The identifier for the rule. + - in: body + name: + description: | + Whether the push rule is enabled or not. + required: true + schema: + type: boolean + example: |- + true + responses: + 200: + description: The push rule was enabled or disabled. + examples: + application/json: |- + {} + schema: + type: object # empty json object diff --git a/specification/modules/push.rst b/specification/modules/push.rst index 6411f3df..ab3f0bf0 100644 --- a/specification/modules/push.rst +++ b/specification/modules/push.rst @@ -110,7 +110,7 @@ Underride In addition, each kind of rule may be either global or device-specific. Device specific rules only affect delivery of notifications via pushers with a matching -profile_tag. All device-specific rules are higher priority than all global +``profile_tag``. All device-specific rules are higher priority than all global rules. Thusly, the full list of rule kinds, in descending priority order, is as follows: @@ -145,7 +145,7 @@ If no rules match an event, the Home Server should not notify for the message themselves are never alerted for. Predefined Rules -~~~~~~~~~~~~~~~~ +++++++++++++++++ Matrix specifies the following rule IDs for server default rules. Home Servers may define rules as follows with the given IDs. If Home Servers provide rules with these IDs, their semantics should match those given below: @@ -247,8 +247,8 @@ with these IDs, their semantics should match those given below: ], } -Push Rules: Actions: -~~~~~~~~~~~~~~~~~~~~ +Actions ++++++++ All rules have an associated list of 'actions'. An action affects if and how a notification is delivered for a matching event. This standard defines the following actions, although if Home servers wish to support more, they are free @@ -273,8 +273,8 @@ Actions that have no parameters are represented as a string. Otherwise, they are represented as a dictionary with a key equal to their name and other keys as their parameters, e.g. ``{ "set_tweak": "sound", "value": "default" }`` -Push Rules: Actions: Tweaks -~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Tweaks +^^^^^^ The ``set_tweak`` key action is used to add an entry to the 'tweaks' dictionary that is sent in the notification poke. The following tweaks are defined: @@ -295,8 +295,8 @@ notification light on a mobile device. If a kind of tweak that a client understands is not specified in an action, the client may choose a sensible behaviour for the tweak. -Push Rules: Conditions -~~~~~~~~~~~~~~~~~~~~~~ +Conditions +++++++++++ Override, Underride and Default rules have a list of 'conditions'. All conditions must hold true for an event in order for a rule to be applied to an event. A rule with no conditions always matches. Matrix specifies the following @@ -332,44 +332,65 @@ but instead have predefined conditions, the behaviour of which can be configured using parameters named as described above. In the cases of room and sender rules, the rule_id of the rule determines its behaviour. -{{pushrules_http_api}} - Push Rules: API ~~~~~~~~~~~~~~~ -The content of the PUT request is a JSON object with a list of actions under the -'actions' key and either conditions (under the 'conditions' key) or the -appropriate parameters for the rule (under the appropriate key name). - -Examples: - -To create a rule that suppresses notifications for the room with ID '!dj234r78wl45Gh4D:matrix.org':: - - curl -X PUT -H "Content-Type: application/json" -d '{ "actions" : ["dont_notify"] }' "http://localhost:8008/_matrix/client/api/v1/pushrules/global/room/%21dj234r78wl45Gh4D%3Amatrix.org?access_token=123456" - -To suppress notifications for the user '@spambot:matrix.org':: - - curl -X PUT -H "Content-Type: application/json" -d '{ "actions" : ["dont_notify"] }' "http://localhost:8008/_matrix/client/api/v1/pushrules/global/sender/%40spambot%3Amatrix.org?access_token=123456" - -To always notify for messages that contain the work 'cake' and set a specific sound (with a rule_id of 'SSByZWFsbHkgbGlrZSBjYWtl'):: - - curl -X PUT -H "Content-Type: application/json" -d '{ "pattern": "cake", "actions" : ["notify", {"set_sound":"cakealarm.wav"}] }' "http://localhost:8008/_matrix/client/api/v1/pushrules/global/content/SSByZWFsbHkgbGlrZSBjYWtl?access_token=123456" - -To add a rule suppressing notifications for messages starting with 'cake' but ending with 'lie', superseeding the previous rule:: - - curl -X PUT -H "Content-Type: application/json" -d '{ "pattern": "cake*lie", "actions" : ["notify"] }' "http://localhost:8008/_matrix/client/api/v1/pushrules/global/content/U3BvbmdlIGNha2UgaXMgYmVzdA?access_token=123456&before=SSByZWFsbHkgbGlrZSBjYWtl" +Clients can retrieve, add, modify and remove push rules globally or per-device +using the APIs below. -To add a custom sound for notifications messages containing the word 'beer' in any rooms with 10 members or fewer (with greater importance than the room, sender and content rules):: - - curl -X PUT -H "Content-Type: application/json" -d '{ "conditions": [{"kind": "event_match", "key": "content.body", "pattern": "beer" }, {"kind": "room_member_count", "is": "<=10"}], "actions" : ["notify", {"set_sound":"beeroclock.wav"}] }' "http://localhost:8008/_matrix/client/api/v1/pushrules/global/override/U2VlIHlvdSBpbiBUaGUgRHVrZQ?access_token=123456 - - -Enabling and Disabling Rules -~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Rules can be enabled or disabled with a PUT operation to the 'enabled' component -beneath the rule's URI with a content of 'true' or 'false':: +{{pushrules_http_api}} - curl -X PUT -H "Content-Type: application/json" -d 'false' "http://localhost:8008/_matrix/client/api/v1/pushrules/global/sender/%40spambot%3Amatrix.org/enabled?access_token=123456" +Examples +++++++++ + +To create a rule that suppresses notifications for the room with ID +``!dj234r78wl45Gh4D:matrix.org``:: + + curl -X PUT -H "Content-Type: application/json" "http://localhost:8008/_matrix/client/api/v1/pushrules/global/room/%21dj234r78wl45Gh4D%3Amatrix.org?access_token=123456" -d \ + '{ + "actions" : ["dont_notify"] + }' + +To suppress notifications for the user ``@spambot:matrix.org``:: + + curl -X PUT -H "Content-Type: application/json" "http://localhost:8008/_matrix/client/api/v1/pushrules/global/sender/%40spambot%3Amatrix.org?access_token=123456" -d \ + '{ + "actions" : ["dont_notify"] + }' + +To always notify for messages that contain the work 'cake' and set a specific +sound (with a rule_id of ``SSByZWFsbHkgbGlrZSBjYWtl``):: + + curl -X PUT -H "Content-Type: application/json" "http://localhost:8008/_matrix/client/api/v1/pushrules/global/content/SSByZWFsbHkgbGlrZSBjYWtl?access_token=123456" -d \ + '{ + "pattern": "cake", + "actions" : ["notify", {"set_sound":"cakealarm.wav"}] + }' + +To add a rule suppressing notifications for messages starting with 'cake' but +ending with 'lie', superseding the previous rule:: + + curl -X PUT -H "Content-Type: application/json" "http://localhost:8008/_matrix/client/api/v1/pushrules/global/content/U3BvbmdlIGNha2UgaXMgYmVzdA?access_token=123456&before=SSByZWFsbHkgbGlrZSBjYWtl" -d \ + '{ + "pattern": "cake*lie", + "actions" : ["notify"] + }' + +To add a custom sound for notifications messages containing the word 'beer' in +any rooms with 10 members or fewer (with greater importance than the room, +sender and content rules):: + + curl -X PUT -H "Content-Type: application/json" "http://localhost:8008/_matrix/client/api/v1/pushrules/global/override/U2VlIHlvdSBpbiBUaGUgRHVrZQ?access_token=123456" -d \ + '{ + "conditions": [ + {"kind": "event_match", "key": "content.body", "pattern": "beer" }, + {"kind": "room_member_count", "is": "<=10"} + ], + "actions" : [ + "notify", + {"set_sound":"beeroclock.wav"} + ] + }' Server behaviour ---------------- @@ -504,8 +525,11 @@ rejected necessarily be the notification in the request that failed: it could be that a previous notification to the same pushkey failed. -Push: Recommendations for APNS -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Push Gateway behaviour +---------------------- + +Recommendations for APNS +~~~~~~~~~~~~~~~~~~~~~~~~ For sending APNS notifications, the exact format is flexible and up to the client app and its push gateway to agree on (since APNS requires that the sender have a private key owned by the app developer, each app must have its own push @@ -518,9 +542,6 @@ gateway). However, Matrix strongly recommends: gateway before returning and instead to store failures and return 'rejected' responses next time that pushkey is used. -Push Gateway behaviour ----------------------- - Security considerations ----------------------- diff --git a/specification/targets.yaml b/specification/targets.yaml index 8106b7cf..5786ea6b 100644 --- a/specification/targets.yaml +++ b/specification/targets.yaml @@ -24,7 +24,7 @@ groups: # reusable blobs of files when prefixed with 'group:' - modules/history_visibility.rst - modules/push.rst -title_styles: ["=", "-", "~", "+", "^"] +title_styles: ["=", "-", "~", "+", "^", "`"] # The templating system doesn't know the right title style to use when generating # RST. These symbols are 'relative' to say "make a sub-title" (-1), "make a title diff --git a/templating/matrix_templates/units.py b/templating/matrix_templates/units.py index 24e92f5a..c3be2b60 100644 --- a/templating/matrix_templates/units.py +++ b/templating/matrix_templates/units.py @@ -184,6 +184,11 @@ class MatrixUnits(Units): val_type = refType # TODO: Resolve to human-readable. if not val_type and schemaFmt: val_type = schemaFmt + # handle top-level strings/bools + if not val_type and Units.prop(param, "schema/type") == "string": + val_type = "string" + if not val_type and Units.prop(param, "schema/type") == "boolean": + val_type = "boolean" if val_type: endpoint["req_params"].append({ "key": param["name"], From 31ae4b38597f57c6026de29a7fd9044d6e632a61 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 8 Oct 2015 13:08:21 +0100 Subject: [PATCH 10/23] Swaggerify push notification API Edit units.py to support nested JSON request keys --- api/check_examples.py | 2 +- api/client-server/v1/push_notifier.yaml | 194 ++++++++++++++++++ specification/modules/push.rst | 7 +- .../matrix_templates/templates/http-api.tmpl | 12 +- templating/matrix_templates/units.py | 13 ++ 5 files changed, 218 insertions(+), 10 deletions(-) create mode 100644 api/client-server/v1/push_notifier.yaml diff --git a/api/check_examples.py b/api/check_examples.py index 0622bfeb..ee3c773c 100755 --- a/api/check_examples.py +++ b/api/check_examples.py @@ -51,7 +51,7 @@ def check_parameter(filepath, request, parameter): schema['id'] = fileurl jsonschema.validate(example, schema) except Exception as e: - raise ValueError("Error validating JSON schema for %r %r" % ( + raise ValueError("Error validating JSON schema for %r" % ( request ), e) diff --git a/api/client-server/v1/push_notifier.yaml b/api/client-server/v1/push_notifier.yaml new file mode 100644 index 00000000..54576b6c --- /dev/null +++ b/api/client-server/v1/push_notifier.yaml @@ -0,0 +1,194 @@ +swagger: '2.0' +info: + title: "Matrix Push Notification API" + version: "1.0.0" +host: localhost:8008 +schemes: + - https + - http +basePath: /_matrix/push/v1 +consumes: + - application/json +produces: + - application/json +paths: + "/notify": + post: + summary: Notify a push gateway about an event. + description: |- + This endpoint is invoked by HTTP pushers to notify a push gateway about + an event. + *NB: Notifications are send to the URL configured when the pusher is + created. This means that the HTTP path may be different depending on the + push gateway.* + parameters: + - in: body + name: notification + description: Information about the push notification. + required: true + schema: + type: object + example: |- + { + "notification": { + "id": "$3957tyerfgewrf384", + "room_id": "!slw48wfj34rtnrf:example.com", + "type": "m.room.message", + "sender": "@exampleuser:matrix.org", + "sender_display_name": "Major Tom", + "room_name": "Mission Control", + "room_alias": "#exampleroom:matrix.org", + "prio": "high", + "content": { + "msgtype": "m.text", + "body": "I'm floating in a most peculiar way." + } + }, + "counts": { + "unread" : 2, + "missed_calls": 1 + }, + "devices": [ + { + "app_id": "org.matrix.matrixConsole.ios", + "pushkey": "V2h5IG9uIGVhcnRoIGRpZCB5b3UgZGVjb2RlIHRoaXM/", + "pushkey_ts": 12345678, + "data" : {}, + "tweaks": { + "sound": "bing" + } + } + ] + } + required: ["notification", "counts", "devices"] + properties: + notification: + type: object + description: Information about the push notification + required: ["id", "room_id", "type", "sender"] + properties: + id: + type: string + description: |- + An identifier for this notification that may be used to + detect duplicate notification requests. This is not + necessarily the ID of the event that triggered the + notification. + room_id: + type: string + description: The ID of the room in which this event occurred. + type: + type: string + description: The type of the event as in the event's ``type`` field. + sender: + type: string + description: The sender of the event as in the corresponding event field. + sender_display_name: + type: string + description: |- + The current display name of the sender in the room in which + the event occurred. + room_name: + type: string + description: The name of the room in which the event occurred. + room_alias: + type: string + description: An alias to display for the room in which the event occurred. + prio: + type: string + enum: ["high", "low"] + description: |- + The priority of the notification. If omitted, ``high`` is + assumed. This may be used by push gateways to deliver less + time-sensitive notifications in a way that will preserve + battery power on mobile devices. + content: + type: object + title: EventContent + properties: + body: + type: string + description: Message text + description: |- + The ``content`` field from the event, if present. If the + event had no content field, this field is omitted. + counts: + type: object + description: |- + This is a dictionary of the current number of unacknowledged + communications for the recipient user. Counts whose value is + zero are omitted. + properties: + unread: + type: integer + description: |- + The number of unread messages a user has across all of the + rooms they are a member of. + missed_calls: + type: integer + description: |- + The number of unacknowledged missed calls a user has + across all rooms of which they are a member. + devices: + type: array + title: Devices + description: |- + This is an array of devices that the notification should be sent to. + items: + type: object + properties: + app_id: + type: string + description: |- + The app_id given when the pusher was created. + pushkey: + type: string + description: The pushkey given when the pusher was created. + pushkey_ts: + type: integer + description: |- + The unix timestamp (in seconds) when the + pushkey was last updated. + data: + type: object + description: |- + A dictionary of additional pusher-specific data. For + 'http' pushers, this is the data dictionary passed in at + pusher creation minus the ``url`` key. + tweaks: + type: object + description: |- + A dictionary of customisations made to the way this + notification is to be presented. These are added by push rules. + properties: + sound: + type: string + description: |- + Sets the sound file that should be played. + ``default`` means that a default sound should be played. + responses: + 200: + description: A list of rejected push keys. + examples: + application/json: |- + { + "rejected": [ "V2h5IG9uIGVhcnRoIGRpZCB5b3UgZGVjb2RlIHRoaXM/" ] + } + schema: + type: object # empty json object + properties: + rejected: + type: array + description: |- + A list of all pushkeys given in the notification request that + are not valid. These could have been rejected by an upstream + gateway because they have expired or have never been valid. + Homeservers must cease sending notification requests for these + pushkeys and remove the associated pushers. It may not + necessarily be the notification in the request that failed: + it could be that a previous notification to the same pushkey + failed. + items: + type: string + description: A pushkey + diff --git a/specification/modules/push.rst b/specification/modules/push.rst index ab3f0bf0..bc76f5d6 100644 --- a/specification/modules/push.rst +++ b/specification/modules/push.rst @@ -395,12 +395,13 @@ sender and content rules):: Server behaviour ---------------- -HTTP Notification Protocol -~~~~~~~~~~~~~~~~~~~~~~~~~~ - This describes the format used by "HTTP" pushers to send notifications of events. +{{push_notifier_http_api}} + + + Notifications are sent as HTTP POST requests to the URL configured when the pusher is created, but Matrix strongly recommends that the path should be:: diff --git a/templating/matrix_templates/templates/http-api.tmpl b/templating/matrix_templates/templates/http-api.tmpl index 33b2cc98..787f02ca 100644 --- a/templating/matrix_templates/templates/http-api.tmpl +++ b/templating/matrix_templates/templates/http-api.tmpl @@ -13,17 +13,17 @@ Request format: -====================== ================= =========================================== - Parameter Value Description -====================== ================= =========================================== +=================================== ================= =========================================== + Parameter Value Description +=================================== ================= =========================================== {% for loc in endpoint.req_param_by_loc -%} *{{loc}} parameters* ------------------------------------------------------------------------------------- +------------------------------------------------------------------------------------------------- {% for param in endpoint.req_param_by_loc[loc] -%} -{{param.key}}{{param.type|indent(23-param.key|length)}}{{param.desc|indent(18-param.type|length)|wrap(43)|indent_block(41)}} +{{param.key}}{{param.type|indent(36-param.key|length)}}{{param.desc|indent(18-param.type|length)|wrap(43)|indent_block(54)}} {% endfor -%} {% endfor -%} -====================== ================= =========================================== +=================================== ================= =========================================== {% if endpoint.res_tables|length > 0 -%} Response format: diff --git a/templating/matrix_templates/units.py b/templating/matrix_templates/units.py index c3be2b60..558461b9 100644 --- a/templating/matrix_templates/units.py +++ b/templating/matrix_templates/units.py @@ -228,6 +228,19 @@ class MatrixUnits(Units): "type": json_body[key]["type"], "desc": pdesc }) + if json_body[key]["type"] in ["object"]: + req_tables = get_json_schema_object_fields( + json_body[key] + ) + for table in req_tables: + for row in table["rows"]: + endpoint["req_params"].append({ + "key": key + "." + row["key"], + "loc": "JSON body", + "type": row["type"], + "desc": row["req_str"] + row["desc"] + }) + # endfor[param] for row in endpoint["req_params"]: self.log("Request parameter: %s" % row) From 65504db7bb3c4c17e58cff52583699c69e45b9a9 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 8 Oct 2015 13:40:21 +0100 Subject: [PATCH 11/23] Display nested keys on arrays of objects. Make it valid swagger. --- api/client-server/v1/push_notifier.yaml | 5 +++++ api/client-server/v1/pushrules.yaml | 2 ++ templating/matrix_templates/units.py | 30 +++++++++++++++++++------ 3 files changed, 30 insertions(+), 7 deletions(-) diff --git a/api/client-server/v1/push_notifier.yaml b/api/client-server/v1/push_notifier.yaml index 54576b6c..0a0204c0 100644 --- a/api/client-server/v1/push_notifier.yaml +++ b/api/client-server/v1/push_notifier.yaml @@ -151,12 +151,17 @@ paths: pushkey was last updated. data: type: object + title: PusherData description: |- A dictionary of additional pusher-specific data. For 'http' pushers, this is the data dictionary passed in at pusher creation minus the ``url`` key. + properties: + foo: + type: string tweaks: type: object + title: Tweaks description: |- A dictionary of customisations made to the way this notification is to be presented. These are added by push rules. diff --git a/api/client-server/v1/pushrules.yaml b/api/client-server/v1/pushrules.yaml index eef0b2c7..31e84f55 100644 --- a/api/client-server/v1/pushrules.yaml +++ b/api/client-server/v1/pushrules.yaml @@ -413,6 +413,8 @@ paths: always matches. items: type: object + title: conditions + allOf: [ "$ref": "definitions/push_condition.json" ] required: ["actions"] responses: 200: diff --git a/templating/matrix_templates/units.py b/templating/matrix_templates/units.py index 558461b9..83376fba 100644 --- a/templating/matrix_templates/units.py +++ b/templating/matrix_templates/units.py @@ -219,23 +219,39 @@ class MatrixUnits(Units): if Units.prop(param, "schema/required"): required_params = Units.prop(param, "schema/required") for key in json_body: - pdesc = json_body[key]["description"] + req_obj = json_body[key] + pdesc = req_obj["description"] if key in required_params: pdesc = "**Required.** " + pdesc + + is_array = req_obj["type"] == "array" + is_array_of_objects = ( + is_array and req_obj["items"]["type"] == "object" + ) endpoint["req_params"].append({ "key": key, "loc": "JSON body", - "type": json_body[key]["type"], + "type": ( + req_obj["type"] if not is_array else + "array[%s]" % req_obj["items"]["type"] + ), "desc": pdesc }) - if json_body[key]["type"] in ["object"]: - req_tables = get_json_schema_object_fields( - json_body[key] - ) + if not is_array_of_objects and req_obj["type"] == "array": + continue + # Put in request.dot.notation for nested keys + if req_obj["type"] in ["object", "array"]: + if is_array_of_objects: + req_obj = req_obj["items"] + + req_tables = get_json_schema_object_fields(req_obj) + key_sep = "[0]." if is_array else "." for table in req_tables: + if table.get("no-table"): + continue for row in table["rows"]: endpoint["req_params"].append({ - "key": key + "." + row["key"], + "key": key + key_sep + row["key"], "loc": "JSON body", "type": row["type"], "desc": row["req_str"] + row["desc"] From befa23624e0a9d41ba9bfe56acb6da5445728370 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 8 Oct 2015 13:41:47 +0100 Subject: [PATCH 12/23] It's dangerous to go alone, take this. --- api/client-server/v1/definitions/push_condition.json | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 api/client-server/v1/definitions/push_condition.json diff --git a/api/client-server/v1/definitions/push_condition.json b/api/client-server/v1/definitions/push_condition.json new file mode 100644 index 00000000..1d84955c --- /dev/null +++ b/api/client-server/v1/definitions/push_condition.json @@ -0,0 +1,9 @@ +{ + "type": "object", + "properties": { + "kind": { + "type": "string", + "enum": ["event_match", "profile_tag", "contains_display_name", "room_member_count"] + } + } +} \ No newline at end of file From 9c95ee5c1f27eb88a414207e4038292ee6dba5bd Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 8 Oct 2015 15:36:03 +0100 Subject: [PATCH 13/23] Modify wording and formatting --- api/client-server/v1/push_notifier.yaml | 6 + specification/modules/push.rst | 458 +++++++++--------------- 2 files changed, 174 insertions(+), 290 deletions(-) diff --git a/api/client-server/v1/push_notifier.yaml b/api/client-server/v1/push_notifier.yaml index 0a0204c0..07c93f3b 100644 --- a/api/client-server/v1/push_notifier.yaml +++ b/api/client-server/v1/push_notifier.yaml @@ -94,6 +94,12 @@ paths: room_alias: type: string description: An alias to display for the room in which the event occurred. + user_is_target: + type: boolean + description: |- + This is true if the user receiving the notification is the + subject of a member event (i.e. the ``state_key`` of the + member event is equal to the user's Matrix ID). prio: type: string enum: ["high", "low"] diff --git a/specification/modules/push.rst b/specification/modules/push.rst index bc76f5d6..ac156dcc 100644 --- a/specification/modules/push.rst +++ b/specification/modules/push.rst @@ -27,92 +27,101 @@ Push Notifications Mobile Device or Client -Matrix supports push notifications as a first class citizen. Home Servers send -notifications of user events to user-configured HTTP endpoints. User may also -configure a number of rules that determine what events generate notifications. -These are all stored and managed by the users home server such that settings can -be reused between client apps as appropriate. +This module adds support for push notifications. Homeservers send notifications +of user events to user-configured HTTP endpoints. Users may also configure a +number of rules that determine which events generate notifications. These are +all stored and managed by the user's homeserver. This allows user-specific push +settings to be reused between client applications. The above diagram shows the flow of push notifications being sent to a handset where push notifications are submitted via the handset vendor, such as Apple's APNS or Google's GCM. This happens as follows: - 1. The client app signs in to a Matrix Home Server - 2. The client app registers with its vendor's Push Notification provider and + 1. The client app signs in to a homeserver. + 2. The client app registers with its vendor's Push Provider and obtains a routing token of some kind. - 3. The mobile app, uses the Matrix client/server API to add a 'pusher', - providing the URL of a specific Push Gateway which is configured for that + 3. The mobile app uses the Client/Server API to add a 'pusher', providing the + URL of a specific Push Gateway which is configured for that application. It also provides the routing token it has acquired from the - Push Notification Provider. - 4. The Home Server starts sending notification HTTP requests to the Push - Gateway using the supplied URL. The Push Gateway relays this notification to - the Push Notification Provider, passing the routing token along with any + Push Provider. + 4. The homeserver starts sending HTTP requests to the Push Gateway using the + supplied URL. The Push Gateway relays this notification to + the Push Provider, passing the routing token along with any necessary private credentials the provider requires to send push notifications. - 5. The Push Notification provider sends the notification to the device. + 5. The Push Provider sends the notification to the device. Definitions for terms used in this section are below: -Pusher - A 'pusher' is an activity in the Home Server that manages the sending - of HTTP notifications for a single device of a single user. - -Push Rules - A push rule is a single rule, configured by a matrix user, that gives - instructions to the Home Server about whether an event should be notified - about and how given a set of conditions. Matrix clients allow the user to - configure these. They create and view them via the Client to Server REST API. +Push Provider + A push provider is a service managed by the device vendor which can send + notifications directly to the device. Google Cloud Messaging (GCM) and Apple + Push Notification Service (APNS) are two examples of push providers. Push Gateway - A push gateway is a server that receives HTTP event notifications from Home - Servers and passes them on to a different protocol such as APNS for iOS - devices or GCM for Android devices. Matrix.org provides a reference push - gateway, 'sygnal'. A client app tells a Home Server what push gateway - to send notifications to when it sets up a pusher. + A push gateway is a server that receives HTTP event notifications from + homeservers and passes them on to a different protocol such as APNS for iOS + devices or GCM for Android devices. Clients inform the homeserver which + Push Gateway to send notifications to when it sets up a Pusher. -For information on the client-server API for setting pushers and push rules, see -the Client Server API section. For more information on the format of HTTP -notifications, see the HTTP Notification Protocol section. +Pusher + A pusher is a worker on the homeserver that manages the sending + of HTTP notifications for a user. A user can have multiple pushers: one per + device. + +Push Rule + A push rule is a single rule that states under what *conditions* an event should + be passed onto a push gateway and *how* the notification should be presented. + These rules are stored on the user's homeserver. They are manually configured + by the user, who can create and view them via the Client/Server API. + +Push Ruleset + A push ruleset *scopes a set of rules according to some criteria*. For example, + some rules may only be applied for messages from a particular sender, + a particular room, or by default. The push ruleset contains the entire set + of scopes and rules. Client behaviour ---------------- -To receive any notification pokes at all, it is necessary to configure a -'pusher' on the Home Server that you wish to receive notifications from. There -is a single API endpoint for this, as described below. +Clients MUST configure a Pusher before they will receive push notifications. +There is a single API endpoint for this, as described below. {{pusher_http_api}} Push Rules ~~~~~~~~~~ -Homeservers have an interface to configure what events trigger notifications. -This behaviour is configured through "Push Rules". Push Rules come in a variety -of different kinds and each kind of rule has an associated priority. The -different kinds of rule, in descending order of priority, are: - -Override Rules +A push rule is a single rule that states under what *conditions* an event should +be passed onto a push gateway and *how* the notification should be presented. +There are different "kinds" of push rules and each rule has an associated +priority. Every push rule MUST have a ``kind`` and ``rule_id``. The ``rule_id`` +is a unique string within the kind of rule and its' scope: ``rule_ids`` do not +need to be unique between rules of the same kind on different devices. Rules may +have extra keys depending on the value of ``kind``.The different kinds of rule +in descending order of priority are: + +Override Rules ``override`` The highest priority rules are user-configured overrides. -Content Rules +Content-specific Rules ``content`` These configure behaviour for (unencrypted) messages that match certain - patterns. Content rules take one parameter, 'pattern', that gives the pattern - to match against. This is treated in the same way as pattern for event_match - conditions, below. -Room Rules - These change the behaviour of all messages to a given room. The rule_id of a - room rule is always the ID of the room that it affects. -Sender - These rules configure notification behaviour for messages from a specific, - named Matrix user ID. The rule_id of Sender rules is always the Matrix user + patterns. Content rules take one parameter: ``pattern``, that gives the glob + pattern to match against. This is treated in the same way as pattern for + ``event_match`` conditions, below. +Room-specific Rules ``room`` + These rules change the behaviour of all messages for a given room. The + ``rule_id`` of a room rule is always the ID of the room that it affects. +Sender-specific rules ``sender`` + These rules configure notification behaviour for messages from a specific + Matrix user ID. The ``rule_id`` of Sender rules is always the Matrix user ID of the user whose messages they'd apply to. -Underride - These are identical to override rules, but have a lower priority than content, - room and sender rules. +Underride rules ``underride`` + These are identical to ``override`` rules, but have a lower priority than + ``content``, ``room`` and ``sender`` rules. -In addition, each kind of rule may be either global or device-specific. Device -specific rules only affect delivery of notifications via pushers with a matching -``profile_tag``. All device-specific rules are higher priority than all global -rules. Thusly, the full list of rule kinds, in descending priority order, is as -follows: +Push rules may be either global or device-specific. Device specific rules only +affect delivery of notifications via pushers with a matching ``profile_tag``. +All device-specific rules have a higher priority than global rules. This means +that the full list of rule kinds, in descending priority order, is as follows: * Device-specific Override * Device-specific Content @@ -125,36 +134,30 @@ follows: * Global Sender * Global Underride -For some kinds of rule, rules of the same kind also have an ordering with -respect to one another. The kinds that do not are room and sender rules where -the rules are mutually exclusive by definition and therefore an ordering would -be redundant. Actions for the highest priority rule and only that rule apply -(for example, a set_tweak action in a lower priority rule will not apply if a -higher priority rule matches, even if that rule does not specify any tweaks). - -Rules also have an identifier, ``rule_id``, which is a string. The ``rule_id`` -is unique within the kind of rule and scope: ``rule_ids`` need not be unique -between rules of the same kind on different devices. A home server may also have -server default rules of each kind and in each scope. Server default rules are -lower priority than user-defined rules in each scope. Server default rules (and -only server default rules) begin with a dot ('.') character. In addition, all -rules may be enabled or disabled. Disabled rules never match. - -If no rules match an event, the Home Server should not notify for the message -(that is to say, the default action is "dont-notify"). Events that the user sent -themselves are never alerted for. +Rules with the same ``kind`` can specify an ordering priority. This determines +which rule is selected in the event of multiple matches. For example, a rule +matching "tea" and a separate rule matching "time" would both match the sentence +"It's time for tea". The ordering of the rules would then resolve the tiebreak +to determine which rule is executed. Only ``actions`` for highest priority rule +will be sent to the Push Gateway. + +Each rule can be enabled or disabled. Disabled rules never match. If no rules +match an event, the homeserver MUST NOT notify the Push Gateway for that event. +Homeservers MUST NOT notify the Push Gateway for events that the user has sent +themselves. Predefined Rules ++++++++++++++++ -Matrix specifies the following rule IDs for server default rules. Home Servers -may define rules as follows with the given IDs. If Home Servers provide rules -with these IDs, their semantics should match those given below: +Homeservers can specify "server-default rules" which operate at a lower priority +than "user-defined rules". The ``rule_id`` for all server-default rules MUST +start with a dot (".") to identify them as "server-default". The following +server-default rules are specified: -.m.rule.contains_user_name +``.m.rule.contains_user_name`` Matches any message whose content is unencrypted and contains the local part of the user's Matrix ID, separated by word boundaries. - Definition (as a content rule):: + Definition (as a ``content`` rule):: { "rule_id": ".m.rule.contains_user_name" @@ -168,11 +171,11 @@ with these IDs, their semantics should match those given below: ], } -.m.rule.contains_display_name +``.m.rule.contains_display_name`` Matches any message whose content is unencrypted and contains the user's current display name in the room in which it was sent. - Definition (this rule can only be an override or underride rule):: + Definition (this rule can only be an ``override`` or ``underride`` rule):: { "rule_id": ".m.rule.contains_display_name" @@ -190,10 +193,10 @@ with these IDs, their semantics should match those given below: ], } -.m.rule.room_one_to_one +``.m.rule.room_one_to_one`` Matches any message sent in a room with exactly two members. - Definition (this rule can only be an override or underride rule):: + Definition (this rule can only be an ``override`` or ``underride`` rule):: { "rule_id": ".m.rule.room_two_members" @@ -212,9 +215,10 @@ with these IDs, their semantics should match those given below: ], } -.m.rule.suppress_notices - Matches messages with 'msgtype' of 'notice'. This should be an override rule - such that, when enabled, it takes priority over content / sender / room rules. +``.m.rule.suppress_notices`` + Matches messages with a ``msgtype`` of ``notice``. This should be an + ``override`` rule so that it takes priority over ``content`` / ``sender`` / + ``room`` rules. Definition:: @@ -232,10 +236,10 @@ with these IDs, their semantics should match those given below: ] } -.m.rule.fallback +``.m.rule.fallback`` Matches any message. Used to define the behaviour of messages that match no - other rules. Therefore, if Home Servers define this, it should be the lowest - priority underride rule. + other rules. If homeservers define this it should be the lowest priority + ``underride`` rule. Definition:: @@ -249,24 +253,22 @@ with these IDs, their semantics should match those given below: Actions +++++++ -All rules have an associated list of 'actions'. An action affects if and how a -notification is delivered for a matching event. This standard defines the -following actions, although if Home servers wish to support more, they are free -to do so: +All rules have an associated list of ``actions``. An action affects if and how a +notification is delivered for a matching event. The following actions are defined: -notify +``notify`` This causes each matching event to generate a notification. -dont_notify - Prevents this event from generating a notification -coalesce - This enables notifications for matching events but activates Home Server +``dont_notify`` + This prevents this event from generating a notification +``coalesce`` + This enables notifications for matching events but activates homeserver specific behaviour to intelligently coalesce multiple events into a single - notification. Not all Home Servers may support this. Those that do not should - treat it as the 'notify' action. -set_tweak - Sets an entry in the 'tweaks' dictionary key that is sent in the notification - poke. This takes the form of a dictionary with a 'set_tweak' key whose value - is the name of the tweak to set. It may also have a 'value' key which is + notification. Not all homeservers may support this. Those that do not support + it should treat it as the ``notify`` action. +``set_tweak`` + Sets an entry in the ``tweaks`` dictionary key that is sent in the notification + request. This takes the form of a dictionary with a ``set_tweak`` key whose value + is the name of the tweak to set. It may also have a ``value`` key which is the value to which it should be set. Actions that have no parameters are represented as a string. Otherwise, they are @@ -275,62 +277,60 @@ their parameters, e.g. ``{ "set_tweak": "sound", "value": "default" }`` Tweaks ^^^^^^ -The ``set_tweak`` key action is used to add an entry to the 'tweaks' dictionary -that is sent in the notification poke. The following tweaks are defined: - -sound - A sound to be played when this notification arrives. 'default' means to - play a default sound. -highlight - Whether or not this message should be highlighted in the UI. This will - normally take the form of presenting the message in a different colour and/or - weight. The UI might also be adjusted to draw particular attention to the room - in which the event occurred. The value may be omitted from the highlight - tweak, in which case it should be read as if it had a value of true. - -Tweaks are passed transparently through the Home Server so client applications -and push gateways may agree on additional tweaks, for example, how to flash the -notification light on a mobile device. - -If a kind of tweak that a client understands is not specified in an action, the -client may choose a sensible behaviour for the tweak. +The ``set_tweak`` action is used to add an entry to the 'tweaks' dictionary +that is sent in the notification request. The following tweaks are defined: + +``sound`` + A string representing the sound to be played when this notification arrives. + A value of ``default`` means to play a default sound. +``highlight`` + A boolean representing whether or not this message should be highlighted in + the UI. This will normally take the form of presenting the message in a + different colour and/or style. The UI might also be adjusted to draw + particular attention to the room in which the event occurred. The ``value`` + may be omitted from the highlight tweak, in which case it should default to + ``true``. + +Tweaks are passed transparently through the homeserver so client applications +and Push Gateways may agree on additional tweaks. For example, a tweak may be +added to specify how to flash the notification light on a mobile device. Conditions ++++++++++ -Override, Underride and Default rules have a list of 'conditions'. All -conditions must hold true for an event in order for a rule to be applied to an -event. A rule with no conditions always matches. Matrix specifies the following -conditions, although if Home Servers wish to support others, they are free to -do so: -event_match +Override, Underride and Default Rules MAY have a list of 'conditions'. +All conditions must hold true for an event in order to apply the ``action`` for +the event. A rule with no conditions always matches. Room, Sender, User and +Content rules do not have conditions in the same way, but instead have +predefined conditions. These conditions can be configured using the parameters +outlined below. In the cases of room and sender rules, the ``rule_id`` of the +rule determines its behaviour. The following conditions are defined: + +``event_match`` This is a glob pattern match on a field of the event. Parameters: - * 'key': The dot-separated field of the event to match, e.g. content.body - * 'pattern': The glob-style pattern to match against. Patterns with no - special glob characters should be treated as having asterisks - prepended and appended when testing the condition. -profile_tag - Matches the profile_tag of the device that the notification would be + * ``key``: The dot-separated field of the event to match, e.g. ``content.body`` + * ``pattern``: The glob-style pattern to match against. Patterns with no + special glob characters should be treated as having asterisks + prepended and appended when testing the condition. + +``profile_tag`` + Matches the ``profile_tag`` of the device that the notification would be delivered to. Parameters: - * 'profile_tag': The profile_tag to match with. -contains_display_name - This matches unencrypted messages where content.body contains the owner's + * ``profile_tag``: The profile_tag to match with. + +``contains_display_name`` + This matches unencrypted messages where ``content.body`` contains the owner's display name in that room. This is a separate rule because display names may change and as such it would be hard to maintain a rule that matched the user's display name. This condition has no parameters. -room_member_count - This matches the current number of members in the room. - * 'is': A decimal integer optionally prefixed by one of, '==', '<', '>', - '>=' or '<='. A prefix of '<' matches rooms where the member count is - strictly less than the given number and so forth. If no prefix is present, - this matches rooms where the member count is exactly equal to the given - number (i.e. the same as '=='). - -Room, Sender, User and Content rules do not have conditions in the same way, -but instead have predefined conditions, the behaviour of which can be configured -using parameters named as described above. In the cases of room and sender -rules, the rule_id of the rule determines its behaviour. + +``room_member_count`` + This matches the current number of members in the room. Parameters: + * ``is``: A decimal integer optionally prefixed by one of, ``==``, ``<``, + ``>``, ``>=`` or ``<=``. A prefix of ``<`` matches rooms where the member + count is strictly less than the given number and so forth. If no prefix is + present, this parameter defaults to ``==``. Push Rules: API ~~~~~~~~~~~~~~~ @@ -396,158 +396,36 @@ Server behaviour ---------------- This describes the format used by "HTTP" pushers to send notifications of -events. +events. If the endpoint returns an HTTP error code, the homeserver should retry +for a reasonable amount of time with a reasonable back-off scheme. {{push_notifier_http_api}} - - -Notifications are sent as HTTP POST requests to the URL configured when the -pusher is created, but Matrix strongly recommends that the path should be:: - - /_matrix/push/v1/notify - -The body of the POST request is a JSON dictionary. The format -is as follows:: - - { - "notification": { - "id": "$3957tyerfgewrf384", - "room_id": "!slw48wfj34rtnrf:example.com", - "type": "m.room.message", - "sender": "@exampleuser:matrix.org", - "sender_display_name": "Major Tom", - "room_name": "Mission Control", - "room_alias": "#exampleroom:matrix.org", - "prio": "high", - "content": { - "msgtype": "m.text", - "body": "I'm floating in a most peculiar way." - } - }, - "counts": { - "unread" : 2, - "missed_calls": 1 - } - "devices": [ - { - "app_id": "org.matrix.matrixConsole.ios", - "pushkey": "V2h5IG9uIGVhcnRoIGRpZCB5b3UgZGVjb2RlIHRoaXM/", - "pushkey_ts": 12345678, - "data" : { - }, - "tweaks": { - "sound": "bing" - } - } - ] - } - } - -The contents of this dictionary are defined as follows: - -id - An identifier for this notification that may be used to detect duplicate - notification requests. This is not necessarily the ID of the event that - triggered the notification. -room_id - The ID of the room in which this event occurred. -type - The type of the event as in the event's 'type' field. -sender - The sender of the event as in the corresponding event field. -sender_display_name - The current display name of the sender in the room in which the event - occurred. -room_name - The name of the room in which the event occurred. -room_alias - An alias to display for the room in which the event occurred. -prio - The priority of the notification. Acceptable values are 'high' or 'low. If - omitted, 'high' is assumed. This may be used by push gateways to deliver less - time-sensitive notifications in a way that will preserve battery power on - mobile devices. -content - The 'content' field from the event, if present. If the event had no content - field, this field is omitted. -counts - This is a dictionary of the current number of unacknowledged communications - for the recipient user. Counts whose value is zero are omitted. -unread - The number of unread messages a user has across all of the rooms they are a - member of. -missed_calls - The number of unacknowledged missed calls a user has across all rooms of - which they are a member. -device - This is an array of devices that the notification should be sent to. -app_id - The app_id given when the pusher was created. -pushkey - The pushkey given when the pusher was created. -pushkey_ts - The unix timestamp (in seconds) when the pushkey was last updated. -data - A dictionary of additional pusher-specific data. For 'http' pushers, this is - the data dictionary passed in at pusher creation minus the 'url' key. -tweaks - A dictionary of customisations made to the way this notification is to be - presented. These are added by push rules. -sound - Sets the sound file that should be played. 'default' means that a default - sound should be played. - -And additional key is defined but only present on member events: - -user_is_target - This is true if the user receiving the notification is the subject of a member - event (i.e. the state_key of the member event is equal to the user's Matrix - ID). - -The recipient of an HTTP notification should respond with an HTTP 2xx response -when the notification has been processed. If the endpoint returns an HTTP error -code, the Home Server should retry for a reasonable amount of time with a -reasonable back-off scheme. - -The endpoint should return a JSON dictionary as follows:: - - { - "rejected": [ "V2h5IG9uIGVhcnRoIGRpZCB5b3UgZGVjb2RlIHRoaXM/" ] - } - -Whose keys are: - -rejected - A list of all pushkeys given in the notification request that are not valid. - These could have been rejected by an upstream gateway because they have - expired or have never been valid. Home Servers must cease sending notification - requests for these pushkeys and remove the associated pushers. It may not - necessarily be the notification in the request that failed: it could be that - a previous notification to the same pushkey failed. - Push Gateway behaviour ---------------------- Recommendations for APNS ~~~~~~~~~~~~~~~~~~~~~~~~ -For sending APNS notifications, the exact format is flexible and up to the -client app and its push gateway to agree on (since APNS requires that the sender -have a private key owned by the app developer, each app must have its own push -gateway). However, Matrix strongly recommends: +The exact format for sending APNS notifications is flexible and up to the +client app and its' push gateway to agree on. As APNS requires that the sender +has a private key owned by the app developer, each app must have its own push +gateway. It is recommended that: - * That the APNS token be base64 encoded and used as the pushkey. - * That a different app_id be used for apps on the production and sandbox + * The APNS token be base64 encoded and used as the pushkey. + * A different app_id be used for apps on the production and sandbox APS environments. - * That APNS push gateways do not attempt to wait for errors from the APNS + * APNS push gateways do not attempt to wait for errors from the APNS gateway before returning and instead to store failures and return 'rejected' responses next time that pushkey is used. Security considerations ----------------------- -- Message content shouldn't be sent in the push itself as it will pass through - the Push Provider (Google/Apple). Instead, send a ping to tell the client to - sync. -- HTTPS should be used on the Matrix HTTP Notification Protocol. +Clients specify the Push Gateway URL to use to send event notifications to. This +URL should be over HTTPS and *never* over HTTP. + +As push notifications will pass through a Push Provider, message content +shouldn't be sent in the push itself where possible. Instead, Push Gateways +should send a "sync" command to instruct the client to get new events from the +homeserver directly. From f2a6950cc3e32193363360653073cf773a5b9de0 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 8 Oct 2015 16:21:26 +0100 Subject: [PATCH 14/23] Minor tweaks; allow objects without props/parents if a title is set This allows us to do things like {Tweaks} where Tweaks is defined somewhere else. --- api/client-server/v1/push_notifier.yaml | 15 +-- api/client-server/v1/pusher.yaml | 2 +- specification/modules/push.rst | 139 ++++++++++++------------ templating/matrix_templates/units.py | 7 ++ 4 files changed, 80 insertions(+), 83 deletions(-) diff --git a/api/client-server/v1/push_notifier.yaml b/api/client-server/v1/push_notifier.yaml index 07c93f3b..be3b5f74 100644 --- a/api/client-server/v1/push_notifier.yaml +++ b/api/client-server/v1/push_notifier.yaml @@ -18,7 +18,7 @@ paths: description: |- This endpoint is invoked by HTTP pushers to notify a push gateway about an event. - *NB: Notifications are send to the URL configured when the pusher is + *NB: Notifications are sent to the URL configured when the pusher is created. This means that the HTTP path may be different depending on the push gateway.* parameters: @@ -111,10 +111,6 @@ paths: content: type: object title: EventContent - properties: - body: - type: string - description: Message text description: |- The ``content`` field from the event, if present. If the event had no content field, this field is omitted. @@ -162,21 +158,12 @@ paths: A dictionary of additional pusher-specific data. For 'http' pushers, this is the data dictionary passed in at pusher creation minus the ``url`` key. - properties: - foo: - type: string tweaks: type: object title: Tweaks description: |- A dictionary of customisations made to the way this notification is to be presented. These are added by push rules. - properties: - sound: - type: string - description: |- - Sets the sound file that should be played. - ``default`` means that a default sound should be played. responses: 200: description: A list of rejected push keys. diff --git a/api/client-server/v1/pusher.yaml b/api/client-server/v1/pusher.yaml index 3c9ffe8c..99a70ee7 100644 --- a/api/client-server/v1/pusher.yaml +++ b/api/client-server/v1/pusher.yaml @@ -69,7 +69,7 @@ paths: description: |- This is a string that determines what set of device rules will be matched when evaluating push rules for this pusher. It is - an arbitrary string. Multiple devices maybe use the same + an arbitrary string. Multiple devices may use the same ``profile_tag``. It is advised that when an app's data is copied or restored to a different device, this value remain the same. Client apps should offer ways to change the diff --git a/specification/modules/push.rst b/specification/modules/push.rst index ac156dcc..7948475c 100644 --- a/specification/modules/push.rst +++ b/specification/modules/push.rst @@ -5,21 +5,21 @@ Push Notifications :: - +--------------------+ +-------------------+ - Matrix HTTP | | | | - Notification Protocol | App Developer | | Device Vendor | - | | | | - +-------------------+ | +----------------+ | | +---------------+ | - | | | | | | | | | | - | Matrix Home Server+-----> Push Gateway | +---> Push Provider | | - | | | | | | | | | | - +-^-----------------+ | +----------------+ | | +----+----------+ | - | | | | | | - Matrix | | | | | | - Client/Server API + | | | | | - | | +--------------------+ +-------------------+ - | +--+-+ | - | | <------------------------------------------+ + +--------------------+ +-------------------+ + Matrix HTTP | | | | + Notification Protocol | App Developer | | Device Vendor | + | | | | + +-------------------+ | +----------------+ | | +---------------+ | + | | | | | | | | | | + | Matrix Home Server+-----> Push Gateway +------> Push Provider | | + | | | | | | | | | | + +-^-----------------+ | +----------------+ | | +----+----------+ | + | | | | | | + Matrix | | | | | | + Client/Server API + | | | | | + | | +--------------------+ +-------------------+ + | +--+-+ | + | | <-------------------------------------------+ +---+ | | | Provider Push Protocol +----+ @@ -28,7 +28,7 @@ Push Notifications This module adds support for push notifications. Homeservers send notifications -of user events to user-configured HTTP endpoints. Users may also configure a +of events to user-configured HTTP endpoints. Users may also configure a number of rules that determine which events generate notifications. These are all stored and managed by the user's homeserver. This allows user-specific push settings to be reused between client applications. @@ -105,8 +105,8 @@ Override Rules ``override`` Content-specific Rules ``content`` These configure behaviour for (unencrypted) messages that match certain patterns. Content rules take one parameter: ``pattern``, that gives the glob - pattern to match against. This is treated in the same way as pattern for - ``event_match`` conditions, below. + pattern to match against. This is treated in the same way as ``pattern`` for + ``event_match``. Room-specific Rules ``room`` These rules change the behaviour of all messages for a given room. The ``rule_id`` of a room rule is always the ID of the room that it affects. @@ -144,7 +144,52 @@ will be sent to the Push Gateway. Each rule can be enabled or disabled. Disabled rules never match. If no rules match an event, the homeserver MUST NOT notify the Push Gateway for that event. Homeservers MUST NOT notify the Push Gateway for events that the user has sent -themselves. +themselves. + +Actions ++++++++ +All rules have an associated list of ``actions``. An action affects if and how a +notification is delivered for a matching event. The following actions are defined: + +``notify`` + This causes each matching event to generate a notification. +``dont_notify`` + This prevents each matching event from generating a notification +``coalesce`` + This enables notifications for matching events but activates homeserver + specific behaviour to intelligently coalesce multiple events into a single + notification. Not all homeservers may support this. Those that do not support + it should treat it as the ``notify`` action. +``set_tweak`` + Sets an entry in the ``tweaks`` dictionary key that is sent in the notification + request to the Push Gateway. This takes the form of a dictionary with a + ``set_tweak`` key whose value is the name of the tweak to set. It may also + have a ``value`` key which is the value to which it should be set. + +Actions that have no parameters are represented as a string. Otherwise, they are +represented as a dictionary with a key equal to their name and other keys as +their parameters, e.g. ``{ "set_tweak": "sound", "value": "default" }`` + +Tweaks +^^^^^^ +The ``set_tweak`` action is used to add an entry to the 'tweaks' dictionary +that is sent in the notification request to the Push Gateway. The following +tweaks are defined: + +``sound`` + A string representing the sound to be played when this notification arrives. + A value of ``default`` means to play a default sound. +``highlight`` + A boolean representing whether or not this message should be highlighted in + the UI. This will normally take the form of presenting the message in a + different colour and/or style. The UI might also be adjusted to draw + particular attention to the room in which the event occurred. The ``value`` + may be omitted from the highlight tweak, in which case it should default to + ``true``. + +Tweaks are passed transparently through the homeserver so client applications +and Push Gateways may agree on additional tweaks. For example, a tweak may be +added to specify how to flash the notification light on a mobile device. Predefined Rules ++++++++++++++++ @@ -251,49 +296,7 @@ server-default rules are specified: ], } -Actions -+++++++ -All rules have an associated list of ``actions``. An action affects if and how a -notification is delivered for a matching event. The following actions are defined: - -``notify`` - This causes each matching event to generate a notification. -``dont_notify`` - This prevents this event from generating a notification -``coalesce`` - This enables notifications for matching events but activates homeserver - specific behaviour to intelligently coalesce multiple events into a single - notification. Not all homeservers may support this. Those that do not support - it should treat it as the ``notify`` action. -``set_tweak`` - Sets an entry in the ``tweaks`` dictionary key that is sent in the notification - request. This takes the form of a dictionary with a ``set_tweak`` key whose value - is the name of the tweak to set. It may also have a ``value`` key which is - the value to which it should be set. - -Actions that have no parameters are represented as a string. Otherwise, they are -represented as a dictionary with a key equal to their name and other keys as -their parameters, e.g. ``{ "set_tweak": "sound", "value": "default" }`` - -Tweaks -^^^^^^ -The ``set_tweak`` action is used to add an entry to the 'tweaks' dictionary -that is sent in the notification request. The following tweaks are defined: -``sound`` - A string representing the sound to be played when this notification arrives. - A value of ``default`` means to play a default sound. -``highlight`` - A boolean representing whether or not this message should be highlighted in - the UI. This will normally take the form of presenting the message in a - different colour and/or style. The UI might also be adjusted to draw - particular attention to the room in which the event occurred. The ``value`` - may be omitted from the highlight tweak, in which case it should default to - ``true``. - -Tweaks are passed transparently through the homeserver so client applications -and Push Gateways may agree on additional tweaks. For example, a tweak may be -added to specify how to flash the notification light on a mobile device. Conditions ++++++++++ @@ -349,14 +352,14 @@ To create a rule that suppresses notifications for the room with ID curl -X PUT -H "Content-Type: application/json" "http://localhost:8008/_matrix/client/api/v1/pushrules/global/room/%21dj234r78wl45Gh4D%3Amatrix.org?access_token=123456" -d \ '{ "actions" : ["dont_notify"] - }' + }' To suppress notifications for the user ``@spambot:matrix.org``:: curl -X PUT -H "Content-Type: application/json" "http://localhost:8008/_matrix/client/api/v1/pushrules/global/sender/%40spambot%3Amatrix.org?access_token=123456" -d \ '{ "actions" : ["dont_notify"] - }' + }' To always notify for messages that contain the work 'cake' and set a specific sound (with a rule_id of ``SSByZWFsbHkgbGlrZSBjYWtl``):: @@ -365,7 +368,7 @@ sound (with a rule_id of ``SSByZWFsbHkgbGlrZSBjYWtl``):: '{ "pattern": "cake", "actions" : ["notify", {"set_sound":"cakealarm.wav"}] - }' + }' To add a rule suppressing notifications for messages starting with 'cake' but ending with 'lie', superseding the previous rule:: @@ -374,7 +377,7 @@ ending with 'lie', superseding the previous rule:: '{ "pattern": "cake*lie", "actions" : ["notify"] - }' + }' To add a custom sound for notifications messages containing the word 'beer' in any rooms with 10 members or fewer (with greater importance than the room, @@ -390,14 +393,14 @@ sender and content rules):: "notify", {"set_sound":"beeroclock.wav"} ] - }' + }' Server behaviour ---------------- This describes the format used by "HTTP" pushers to send notifications of -events. If the endpoint returns an HTTP error code, the homeserver should retry -for a reasonable amount of time with a reasonable back-off scheme. +events to Push Gateways. If the endpoint returns an HTTP error code, the +homeserver SHOULD retry for a reasonable amount of time using exponential-backoff. {{push_notifier_http_api}} diff --git a/templating/matrix_templates/units.py b/templating/matrix_templates/units.py index 83376fba..bbfa8423 100644 --- a/templating/matrix_templates/units.py +++ b/templating/matrix_templates/units.py @@ -61,6 +61,13 @@ def get_json_schema_object_fields(obj, enforce_title=False): if pretty_key: props[pretty_key] = props[key_name] del props[key_name] + if not props and not parents: + # Sometimes you just want to specify that a thing is an object without + # doing all the keys. Allow people to do that if they set a 'title'. + if obj.get("title"): + parents = [{ + "$ref": obj.get("title") + }] if not props and not parents: raise Exception( "Object %s has no properties or parents." % obj From 213cb252900ea43542890fa87bb6a81d9c6e0c27 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Thu, 8 Oct 2015 16:38:41 +0100 Subject: [PATCH 15/23] Wrap correctly --- templating/matrix_templates/templates/http-api.tmpl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templating/matrix_templates/templates/http-api.tmpl b/templating/matrix_templates/templates/http-api.tmpl index 787f02ca..d1633513 100644 --- a/templating/matrix_templates/templates/http-api.tmpl +++ b/templating/matrix_templates/templates/http-api.tmpl @@ -40,7 +40,7 @@ Response format: {# Desc needs to prepend the required text (maybe) and prepend spaces too -#} {# It also needs to then wrap inside the desc col (42 ch width) -#} {# -#} -{{row.key}}{{row.type|indent(24-row.key|length)}}{{row.desc|wrap(40,row.req_str | indent(26 - (row.type|length))) |indent_block(50)}} +{{row.key}}{{row.type|indent(24-row.key|length)}}{{row.desc|wrap(42,row.req_str | indent(26 - (row.type|length))) |indent_block(50)}} {% endfor -%} ======================= ========================= ========================================== From 241096dc811cbbaa544d4a4aac73acdeb548aca4 Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Thu, 8 Oct 2015 17:25:38 +0100 Subject: [PATCH 16/23] Add a flag to initial sync to indicate we want rooms that the user has left --- api/client-server/v1/sync.yaml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/api/client-server/v1/sync.yaml b/api/client-server/v1/sync.yaml index 8fe30056..de8dfec9 100644 --- a/api/client-server/v1/sync.yaml +++ b/api/client-server/v1/sync.yaml @@ -39,6 +39,16 @@ paths: description: The maximum time in milliseconds to wait for an event. required: false x-example: "35000" + - in: query + type: string + name: archived + description: |- + Whether to include rooms that the user has left. If absent then + only rooms that the user has been invited to or has joined are + included. If set to "1" then rooms that the user has left are + included as well. + required: false + x-example: "1" responses: 200: description: "The events received, which may be none." From d42c3195e6f709b0d27e42367b7e0635f00f626f Mon Sep 17 00:00:00 2001 From: Mark Haines Date: Thu, 8 Oct 2015 18:06:52 +0100 Subject: [PATCH 17/23] Use 'true' rather than '1' for archived flag --- api/client-server/v1/sync.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/api/client-server/v1/sync.yaml b/api/client-server/v1/sync.yaml index de8dfec9..7c1d43f3 100644 --- a/api/client-server/v1/sync.yaml +++ b/api/client-server/v1/sync.yaml @@ -45,10 +45,10 @@ paths: description: |- Whether to include rooms that the user has left. If absent then only rooms that the user has been invited to or has joined are - included. If set to "1" then rooms that the user has left are + included. If set to "true" then rooms that the user has left are included as well. required: false - x-example: "1" + x-example: "true" responses: 200: description: "The events received, which may be none." From 51ab51ae26ba9e5e469e4594e7a579f8fe434c09 Mon Sep 17 00:00:00 2001 From: Oddvar Lovaas Date: Thu, 8 Oct 2015 19:27:08 +0100 Subject: [PATCH 18/23] Only documents in matrix-doc! --- supporting-docs/_config.yml | 16 - supporting-docs/_includes/footer.html | 25 - supporting-docs/_includes/head.html | 31 -- supporting-docs/_includes/nav.html | 33 -- supporting-docs/_layouts/default.html | 23 - supporting-docs/_layouts/page.html | 14 - supporting-docs/_layouts/post.html | 6 - .../_plugins/jekyll-rst-master/.gitignore | 1 - .../_plugins/jekyll-rst-master/LICENSE.txt | 20 - .../_plugins/jekyll-rst-master/README.rst | 97 ---- .../_plugins/jekyll-rst-master/converter.rb | 30 - .../_plugins/jekyll-rst-master/directives.py | 97 ---- .../_plugins/jekyll-rst-master/rst2html.py | 39 -- .../_plugins/jekyll-rst-master/transform.py | 42 -- .../_plugins/project_version_tag.rb | 51 -- supporting-docs/_posts/index.html | 18 - supporting-docs/_sass/_base.scss | 204 ------- supporting-docs/_sass/_layout.scss | 236 -------- .../_sass/_syntax-highlighting.scss | 67 --- supporting-docs/about.md | 11 - supporting-docs/css/basic.css | 512 ------------------ supporting-docs/css/faq.css | 40 -- supporting-docs/css/main.scss | 52 -- supporting-docs/css/nature.css | 285 ---------- supporting-docs/css/site_overrides.css | 62 --- supporting-docs/feed.xml | 30 - .../2015-08-10-client-server.rst | 0 .../2015-08-14-getting_involved.md | 0 .../{_posts => guides}/2015-08-19-faq.md | 0 .../2015-08-21-application_services.md | 0 supporting-docs/index.html | 14 - 31 files changed, 2056 deletions(-) delete mode 100644 supporting-docs/_config.yml delete mode 100644 supporting-docs/_includes/footer.html delete mode 100644 supporting-docs/_includes/head.html delete mode 100644 supporting-docs/_includes/nav.html delete mode 100644 supporting-docs/_layouts/default.html delete mode 100644 supporting-docs/_layouts/page.html delete mode 100644 supporting-docs/_layouts/post.html delete mode 100644 supporting-docs/_plugins/jekyll-rst-master/.gitignore delete mode 100644 supporting-docs/_plugins/jekyll-rst-master/LICENSE.txt delete mode 100644 supporting-docs/_plugins/jekyll-rst-master/README.rst delete mode 100644 supporting-docs/_plugins/jekyll-rst-master/converter.rb delete mode 100644 supporting-docs/_plugins/jekyll-rst-master/directives.py delete mode 100644 supporting-docs/_plugins/jekyll-rst-master/rst2html.py delete mode 100644 supporting-docs/_plugins/jekyll-rst-master/transform.py delete mode 100644 supporting-docs/_plugins/project_version_tag.rb delete mode 100644 supporting-docs/_posts/index.html delete mode 100644 supporting-docs/_sass/_base.scss delete mode 100644 supporting-docs/_sass/_layout.scss delete mode 100644 supporting-docs/_sass/_syntax-highlighting.scss delete mode 100644 supporting-docs/about.md delete mode 100644 supporting-docs/css/basic.css delete mode 100644 supporting-docs/css/faq.css delete mode 100755 supporting-docs/css/main.scss delete mode 100644 supporting-docs/css/nature.css delete mode 100644 supporting-docs/css/site_overrides.css delete mode 100644 supporting-docs/feed.xml rename supporting-docs/{_posts => guides}/2015-08-10-client-server.rst (100%) rename supporting-docs/{_posts => guides}/2015-08-14-getting_involved.md (100%) rename supporting-docs/{_posts => guides}/2015-08-19-faq.md (100%) rename supporting-docs/{_posts => guides}/2015-08-21-application_services.md (100%) delete mode 100644 supporting-docs/index.html diff --git a/supporting-docs/_config.yml b/supporting-docs/_config.yml deleted file mode 100644 index 1b3ea192..00000000 --- a/supporting-docs/_config.yml +++ /dev/null @@ -1,16 +0,0 @@ -# Site settings -title: Matrix -email: webmaster@matrix.org -description: > # this means to ignore newlines until "baseurl:" - Matrix.org documentation -baseurl: "/docs/guides" # the subpath of your site, e.g. /blog/ -url: "http://matrix.org" # the base hostname & protocol for your site -twitter_username: matrixdotorg -github_username: matrix-org - -# Build settings -markdown: kramdown - -#defaults: -#permalink: /:categories/:title.html # can use this when/if we use jekyll for all docs -permalink: :title.html diff --git a/supporting-docs/_includes/footer.html b/supporting-docs/_includes/footer.html deleted file mode 100644 index 3e020c64..00000000 --- a/supporting-docs/_includes/footer.html +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - diff --git a/supporting-docs/_includes/head.html b/supporting-docs/_includes/head.html deleted file mode 100644 index 213e1796..00000000 --- a/supporting-docs/_includes/head.html +++ /dev/null @@ -1,31 +0,0 @@ - - - - - {% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %} - - - - - - - - - - - - - - - - - - diff --git a/supporting-docs/_includes/nav.html b/supporting-docs/_includes/nav.html deleted file mode 100644 index b7e2d629..00000000 --- a/supporting-docs/_includes/nav.html +++ /dev/null @@ -1,33 +0,0 @@ -
-
- - - -
- - - -
-
-
diff --git a/supporting-docs/_layouts/default.html b/supporting-docs/_layouts/default.html deleted file mode 100644 index da18483e..00000000 --- a/supporting-docs/_layouts/default.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - {% include head.html %} - - - - -
- {% include nav.html %} -
- -
-
- {{ content }} -
-
-
-
- {% include footer.html %} - - - diff --git a/supporting-docs/_layouts/page.html b/supporting-docs/_layouts/page.html deleted file mode 100644 index 74c1a118..00000000 --- a/supporting-docs/_layouts/page.html +++ /dev/null @@ -1,14 +0,0 @@ ---- -layout: default ---- -
- -
-

{{ page.title }}

-
- -
- {{ content }} -
- -
diff --git a/supporting-docs/_layouts/post.html b/supporting-docs/_layouts/post.html deleted file mode 100644 index 64fafcbc..00000000 --- a/supporting-docs/_layouts/post.html +++ /dev/null @@ -1,6 +0,0 @@ ---- -layout: default ---- - - {{ content }} - diff --git a/supporting-docs/_plugins/jekyll-rst-master/.gitignore b/supporting-docs/_plugins/jekyll-rst-master/.gitignore deleted file mode 100644 index 7e99e367..00000000 --- a/supporting-docs/_plugins/jekyll-rst-master/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.pyc \ No newline at end of file diff --git a/supporting-docs/_plugins/jekyll-rst-master/LICENSE.txt b/supporting-docs/_plugins/jekyll-rst-master/LICENSE.txt deleted file mode 100644 index 988ac9eb..00000000 --- a/supporting-docs/_plugins/jekyll-rst-master/LICENSE.txt +++ /dev/null @@ -1,20 +0,0 @@ -The MIT License (MIT) -Copyright (c) 2011 Greg Thornton, http://xdissent.com - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -THE SOFTWARE. \ No newline at end of file diff --git a/supporting-docs/_plugins/jekyll-rst-master/README.rst b/supporting-docs/_plugins/jekyll-rst-master/README.rst deleted file mode 100644 index 48c21f42..00000000 --- a/supporting-docs/_plugins/jekyll-rst-master/README.rst +++ /dev/null @@ -1,97 +0,0 @@ -Overview -======== - -This plugin adds `ReStructuredText`_ support to `Jekyll`_ and `Octopress`_. -It renders ReST in posts and pages, and provides a custom directive to -support Octopress-compatible syntax highlighting. - -Requirements -============ - -* Jekyll *or* Octopress >= 2.0 -* Docutils -* Pygments -* `RbST`_ - -Installation -============ - -1. Install Docutils and Pygments. - - The most convenient way is to use virtualenv_burrito: - - :: - - $ curl -s https://raw.github.com/brainsik/virtualenv-burrito/master/virtualenv-burrito.sh | bash - $ source /Users/xdissent/.venvburrito/startup.sh - $ mkvirtualenv jekyll-rst - $ pip install docutils pygments - -2. Install RbST. - - If you use `bundler`_ with Octopress, add ``gem 'RbST'`` to - your ``Gemfile`` in the ``development`` group, then run - ``bundle install``. Otherwise, ``gem install RbST``. - -3. Install the plugin. - - For Jekyll: - - :: - - $ cd - $ git submodule add https://github.com/xdissent/jekyll-rst.git _plugins/jekyll-rst - - For Octopress: - - :: - - $ cd - $ git submodule add https://github.com/xdissent/jekyll-rst.git plugins/jekyll-rst - -4. Start blogging in ReStructuredText. Any file with the ``.rst`` extension - will be parsed as ReST and rendered into HTML. - - .. note:: Be sure to activate the ``jekyll-rst`` virtualenv before generating - the site by issuing a ``workon jekyll-rst``. I suggest you follow `Harry - Marr's advice`_ and create a ``.venv`` file that will automatically - activate the ``jekyll-rst`` virtualenv when you ``cd`` into your project. - -Source Code Highlighting -======================== - -A ``code-block`` ReST directive is registered and aliased as ``sourcecode``. -It adds syntax highlighting to code blocks in your documents:: - - .. code-block:: ruby - - # Output "I love ReST" - say = "I love ReST" - puts say - -Optional arguments exist to supply a caption, link, and link title:: - - .. code-block:: console - :caption: Read Hacker News on a budget - :url: http://news.ycombinator.com - :title: Hacker News - - $ curl http://news.ycombinator.com | less - -Octopress already includes style sheets for syntax highlighting, but you'll -need to generate one yourself if using Jekyll:: - - $ pygmentize -S default -f html > css/pygments.css - -Octopress Tips -============== - -* Use ``.. more`` in your ReST documents to indicate where Octopress's - ``excerpt`` tag should split your content for summary views. - -.. _ReStructuredText: http://docutils.sourceforge.net/rst.html -.. _Jekyll: http://jekyllrb.com/ -.. _Octopress: http://octopress.com/ -.. _RbST: http://rubygems.org/gems/RbST -.. _bundler: http://gembundler.com/ -.. _Harry Marr's advice: http://hmarr.com/2010/jan/19/making-virtualenv-play-nice-with-git/ \ No newline at end of file diff --git a/supporting-docs/_plugins/jekyll-rst-master/converter.rb b/supporting-docs/_plugins/jekyll-rst-master/converter.rb deleted file mode 100644 index 64b639cc..00000000 --- a/supporting-docs/_plugins/jekyll-rst-master/converter.rb +++ /dev/null @@ -1,30 +0,0 @@ -require 'rbst' - -module Jekyll - class RestConverter < Converter - safe true - - priority :low - - def matches(ext) - ext =~ /rst/i - end - - def output_ext(ext) - ".html" - end - - def convert(content) - RbST.executables = {:html => "#{File.expand_path(File.dirname(__FILE__))}/rst2html.py"} - RbST.new(content).to_html(:part => :fragment, :initial_header_level => 2) - end - end - - module Filters - def restify(input) - site = @context.registers[:site] - converter = site.getConverterImpl(Jekyll::RestConverter) - converter.convert(input) - end - end -end \ No newline at end of file diff --git a/supporting-docs/_plugins/jekyll-rst-master/directives.py b/supporting-docs/_plugins/jekyll-rst-master/directives.py deleted file mode 100644 index bfd2b78b..00000000 --- a/supporting-docs/_plugins/jekyll-rst-master/directives.py +++ /dev/null @@ -1,97 +0,0 @@ -# Define a new directive `code-block` (aliased as `sourcecode`) that uses the -# `pygments` source highlighter to render code in color. -# -# Incorporates code from the `Pygments`_ documentation for `Using Pygments in -# ReST documents`_ and `Octopress`_. -# -# .. _Pygments: http://pygments.org/ -# .. _Using Pygments in ReST documents: http://pygments.org/docs/rstdirective/ -# .. _Octopress: http://octopress.org/ - -import re -import os -import md5 -import __main__ - -# Absolute path to pygments cache dir -PYGMENTS_CACHE_DIR = os.path.abspath(os.path.join(os.path.dirname(__main__.__file__), '../../.pygments-cache')) - -# Ensure cache dir exists -if not os.path.exists(PYGMENTS_CACHE_DIR): - os.makedirs(PYGMENTS_CACHE_DIR) - -from pygments.formatters import HtmlFormatter - -from docutils import nodes -from docutils.parsers.rst import directives, Directive - -from pygments import highlight -from pygments.lexers import get_lexer_by_name, TextLexer - -class Pygments(Directive): - """ Source code syntax hightlighting. - """ - required_arguments = 1 - optional_arguments = 0 - final_argument_whitespace = True - string_opts = ['title', 'url', 'caption'] - option_spec = dict([(key, directives.unchanged) for key in string_opts]) - has_content = True - - def run(self): - self.assert_has_content() - try: - lexer_name = self.arguments[0] - lexer = get_lexer_by_name(lexer_name) - except ValueError: - # no lexer found - use the text one instead of an exception - lexer_name = 'text' - lexer = TextLexer() - formatter = HtmlFormatter() - - # Construct cache filename - cache_file = None - content_text = u'\n'.join(self.content) - cache_file_name = '%s-%s.html' % (lexer_name, md5.new(content_text).hexdigest()) - cached_path = os.path.join(PYGMENTS_CACHE_DIR, cache_file_name) - - # Look for cached version, otherwise parse - if os.path.exists(cached_path): - cache_file = open(cached_path, 'r') - parsed = cache_file.read() - else: - parsed = highlight(content_text, lexer, formatter) - - # Strip pre tag and everything outside it - pres = re.compile("
(.+)<\/pre>", re.S)
-        stripped = pres.search(parsed).group(1)
-
-        # Create tabular code with line numbers
-        table = '
'
-        lined = ''
-        for idx, line in enumerate(stripped.splitlines(True)):
-            table += '%d\n' % (idx + 1)
-            lined  += '%s' % line
-        table += '
%s
' % (lexer_name, lined) - - # Add wrapper with optional caption and link - code = '
' - if self.options: - caption = ('%s' % self.options['caption']) if 'caption' in self.options else '' - title = self.options['title'] if 'title' in self.options else 'link' - link = ('%s' % (self.options['url'], title)) if 'url' in self.options else '' - - if caption or link: - code += '
%s %s
' % (caption, link) - code += '%s
' % table - - # Write cache - if cache_file is None: - cache_file = open(cached_path, 'w') - cache_file.write(parsed) - cache_file.close() - - return [nodes.raw('', code, format='html')] - -directives.register_directive('code-block', Pygments) -directives.register_directive('sourcecode', Pygments) \ No newline at end of file diff --git a/supporting-docs/_plugins/jekyll-rst-master/rst2html.py b/supporting-docs/_plugins/jekyll-rst-master/rst2html.py deleted file mode 100644 index 0190da05..00000000 --- a/supporting-docs/_plugins/jekyll-rst-master/rst2html.py +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python - -# :Author: David Goodger, the Pygments team, Guenter Milde -# :Date: $Date: $ -# :Copyright: This module has been placed in the public domain. - -# This is a merge of the `Docutils`_ `rst2html` front end with an extension -# suggestion taken from the `Pygments`_ documentation, reworked specifically -# for `Octopress`_. -# -# .. _Pygments: http://pygments.org/ -# .. _Docutils: http://docutils.sourceforge.net/ -# .. _Octopress: http://octopress.org/ - -""" -A front end to docutils, producing HTML with syntax colouring using pygments -""" - -try: - import locale - locale.setlocale(locale.LC_ALL, '') -except: - pass - -from transform import transform -from docutils.writers.html4css1 import Writer -from docutils.core import default_description -from directives import Pygments - -description = ('Generates (X)HTML documents from standalone reStructuredText ' - 'sources. Uses `pygments` to colorize the content of' - '"code-block" directives. Needs an adapted stylesheet' - + default_description) - -def main(): - return transform(writer=Writer(), part='html_body') - -if __name__ == '__main__': - print(main()) diff --git a/supporting-docs/_plugins/jekyll-rst-master/transform.py b/supporting-docs/_plugins/jekyll-rst-master/transform.py deleted file mode 100644 index 51ad4ef6..00000000 --- a/supporting-docs/_plugins/jekyll-rst-master/transform.py +++ /dev/null @@ -1,42 +0,0 @@ -import sys -from docutils.core import publish_parts -from optparse import OptionParser -from docutils.frontend import OptionParser as DocutilsOptionParser -from docutils.parsers.rst import Parser - -def transform(writer=None, part=None): - p = OptionParser(add_help_option=False) - - # Collect all the command line options - docutils_parser = DocutilsOptionParser(components=(writer, Parser())) - for group in docutils_parser.option_groups: - p.add_option_group(group.title, None).add_options(group.option_list) - - p.add_option('--part', default=part) - - opts, args = p.parse_args() - - settings = dict({ - 'file_insertion_enabled': False, - 'raw_enabled': False, - 'doctitle_xform': False, - }) - - if len(args) == 1: - try: - content = open(args[0], 'r').read() - except IOError: - content = args[0] - else: - content = sys.stdin.read() - - parts = publish_parts( - source=content, - writer=writer, - settings_overrides=settings - ) - if 'html_body' in parts: - return parts['html_body'] - if opts.part in parts: - return parts[opts.part] - return '' diff --git a/supporting-docs/_plugins/project_version_tag.rb b/supporting-docs/_plugins/project_version_tag.rb deleted file mode 100644 index c647eef8..00000000 --- a/supporting-docs/_plugins/project_version_tag.rb +++ /dev/null @@ -1,51 +0,0 @@ -module Jekyll - class ProjectVersionTag < Liquid::Tag - NO_GIT_MESSAGE = 'Oops, are you sure this is a git project?' - UNABLE_TO_PARSE_MESSAGE = 'Sorry, could not read project version at the moment' - - def render(context) - if git_repo? - current_version.chomp - else - NO_GIT_MESSAGE - end - end - - private - - def current_version - @_current_version ||= begin - # attempt to find the latest tag, falling back to last commit - version = git_describe || parse_head - - version || UNABLE_TO_PARSE_MESSAGE - end - end - - def git_describe - tagged_version = %x{ git describe --tags --always } - - if command_succeeded? - tagged_version - end - end - - def parse_head - head_commitish = %x{ git rev-parse --short HEAD } - - if command_succeeded? - head_commitish - end - end - - def command_succeeded? - !$?.nil? && $?.success? - end - - def git_repo? - system('git rev-parse') - end - end -end - -Liquid::Template.register_tag('project_version', Jekyll::ProjectVersionTag) diff --git a/supporting-docs/_posts/index.html b/supporting-docs/_posts/index.html deleted file mode 100644 index 15c7d5c2..00000000 --- a/supporting-docs/_posts/index.html +++ /dev/null @@ -1,18 +0,0 @@ ---- -layout: default ---- - {% include basic.css %} - {% include nature.css %} - -
- -
-
{{ page.title }}
- -
- -
- {{ content }} -
- -
diff --git a/supporting-docs/_sass/_base.scss b/supporting-docs/_sass/_base.scss deleted file mode 100644 index e5fd0fd8..00000000 --- a/supporting-docs/_sass/_base.scss +++ /dev/null @@ -1,204 +0,0 @@ -/** - * Reset some basic elements - */ -body, h1, h2, h3, h4, h5, h6, -p, blockquote, pre, hr, -dl, dd, ol, ul, figure { - margin: 0; - padding: 0; -} - - - -/** - * Basic styling - */ -body { - font-family: $base-font-family; - font-size: $base-font-size; - line-height: $base-line-height; - font-weight: 300; - color: $text-color; - background-color: $background-color; - -webkit-text-size-adjust: 100%; -} - - - -/** - * Set `margin-bottom` to maintain vertical rhythm - */ -h1, h2, h3, h4, h5, h6, -p, blockquote, pre, -ul, ol, dl, figure, -%vertical-rhythm { - margin-bottom: $spacing-unit / 2; -} - - - -/** - * Images - */ -img { - max-width: 100%; - vertical-align: middle; -} - - - -/** - * Figures - */ -figure > img { - display: block; -} - -figcaption { - font-size: $small-font-size; -} - - - -/** - * Lists - */ -ul, ol { - margin-left: $spacing-unit; -} - -li { - > ul, - > ol { - margin-bottom: 0; - } -} - - - -/** - * Headings - */ -h1, h2, h3, h4, h5, h6 { - font-weight: 300; -} - - - -/** - * Links - */ -a { - color: $brand-color; - text-decoration: none; - - &:visited { - color: darken($brand-color, 15%); - } - - &:hover { - color: $text-color; - text-decoration: underline; - } -} - - - -/** - * Blockquotes - */ -blockquote { - color: $grey-color; - border-left: 4px solid $grey-color-light; - padding-left: $spacing-unit / 2; - font-size: 18px; - letter-spacing: -1px; - font-style: italic; - - > :last-child { - margin-bottom: 0; - } -} - - - -/** - * Code formatting - */ -pre, -code { - font-size: 15px; - border: 1px solid $grey-color-light; - border-radius: 3px; - background-color: #eef; -} - -code { - padding: 1px 5px; -} - -pre { - padding: 8px 12px; - overflow-x: scroll; - - > code { - border: 0; - padding-right: 0; - padding-left: 0; - } -} - - - -/** - * Wrapper - */ -.wrapper { - max-width: -webkit-calc(#{$content-width} - (#{$spacing-unit} * 2)); - max-width: calc(#{$content-width} - (#{$spacing-unit} * 2)); - margin-right: auto; - margin-left: auto; - padding-right: $spacing-unit; - padding-left: $spacing-unit; - @extend %clearfix; - - @include media-query($on-laptop) { - max-width: -webkit-calc(#{$content-width} - (#{$spacing-unit})); - max-width: calc(#{$content-width} - (#{$spacing-unit})); - padding-right: $spacing-unit / 2; - padding-left: $spacing-unit / 2; - } -} - - - -/** - * Clearfix - */ -%clearfix { - - &:after { - content: ""; - display: table; - clear: both; - } -} - - - -/** - * Icons - */ -.icon { - - > svg { - display: inline-block; - width: 16px; - height: 16px; - vertical-align: middle; - - path { - fill: $grey-color; - } - } -} diff --git a/supporting-docs/_sass/_layout.scss b/supporting-docs/_sass/_layout.scss deleted file mode 100644 index def56f89..00000000 --- a/supporting-docs/_sass/_layout.scss +++ /dev/null @@ -1,236 +0,0 @@ -/** - * Site header - */ -.site-header { - border-top: 5px solid $grey-color-dark; - border-bottom: 1px solid $grey-color-light; - min-height: 56px; - - // Positioning context for the mobile navigation icon - position: relative; -} - -.site-title { - font-size: 26px; - line-height: 56px; - letter-spacing: -1px; - margin-bottom: 0; - float: left; - - &, - &:visited { - color: $grey-color-dark; - } -} - -.site-nav { - float: right; - line-height: 56px; - - .menu-icon { - display: none; - } - - .page-link { - color: $text-color; - line-height: $base-line-height; - - // Gaps between nav items, but not on the first one - &:not(:first-child) { - margin-left: 20px; - } - } - - @include media-query($on-palm) { - position: absolute; - top: 9px; - right: 30px; - background-color: $background-color; - border: 1px solid $grey-color-light; - border-radius: 5px; - text-align: right; - - .menu-icon { - display: block; - float: right; - width: 36px; - height: 26px; - line-height: 0; - padding-top: 10px; - text-align: center; - - > svg { - width: 18px; - height: 15px; - - path { - fill: $grey-color-dark; - } - } - } - - .trigger { - clear: both; - display: none; - } - - &:hover .trigger { - display: block; - padding-bottom: 5px; - } - - .page-link { - display: block; - padding: 5px 10px; - } - } -} - - - -/** - * Site footer - */ -.site-footer { - border-top: 1px solid $grey-color-light; - padding: $spacing-unit 0; -} - -.footer-heading { - font-size: 18px; - margin-bottom: $spacing-unit / 2; -} - -.contact-list, -.social-media-list { - list-style: none; - margin-left: 0; -} - -.footer-col-wrapper { - font-size: 15px; - color: $grey-color; - margin-left: -$spacing-unit / 2; - @extend %clearfix; -} - -.footer-col { - float: left; - margin-bottom: $spacing-unit / 2; - padding-left: $spacing-unit / 2; -} - -.footer-col-1 { - width: -webkit-calc(35% - (#{$spacing-unit} / 2)); - width: calc(35% - (#{$spacing-unit} / 2)); -} - -.footer-col-2 { - width: -webkit-calc(20% - (#{$spacing-unit} / 2)); - width: calc(20% - (#{$spacing-unit} / 2)); -} - -.footer-col-3 { - width: -webkit-calc(45% - (#{$spacing-unit} / 2)); - width: calc(45% - (#{$spacing-unit} / 2)); -} - -@include media-query($on-laptop) { - .footer-col-1, - .footer-col-2 { - width: -webkit-calc(50% - (#{$spacing-unit} / 2)); - width: calc(50% - (#{$spacing-unit} / 2)); - } - - .footer-col-3 { - width: -webkit-calc(100% - (#{$spacing-unit} / 2)); - width: calc(100% - (#{$spacing-unit} / 2)); - } -} - -@include media-query($on-palm) { - .footer-col { - float: none; - width: -webkit-calc(100% - (#{$spacing-unit} / 2)); - width: calc(100% - (#{$spacing-unit} / 2)); - } -} - - - -/** - * Page content - */ -.page-content { - padding: $spacing-unit 0; -} - -.page-heading { - font-size: 20px; -} - -.post-list { - margin-left: 0; - list-style: none; - - > li { - margin-bottom: $spacing-unit; - } -} - -.post-meta { - font-size: $small-font-size; - color: $grey-color; -} - -.post-link { - display: block; - font-size: 24px; -} - - - -/** - * Posts - */ -.post-header { - margin-bottom: $spacing-unit; -} - -.post-title { - font-size: 42px; - letter-spacing: -1px; - line-height: 1; - - @include media-query($on-laptop) { - font-size: 36px; - } -} - -.post-content { - margin-bottom: $spacing-unit; - - h2 { - font-size: 32px; - - @include media-query($on-laptop) { - font-size: 28px; - } - } - - h3 { - font-size: 26px; - - @include media-query($on-laptop) { - font-size: 22px; - } - } - - h4 { - font-size: 20px; - - @include media-query($on-laptop) { - font-size: 18px; - } - } -} diff --git a/supporting-docs/_sass/_syntax-highlighting.scss b/supporting-docs/_sass/_syntax-highlighting.scss deleted file mode 100644 index e36627da..00000000 --- a/supporting-docs/_sass/_syntax-highlighting.scss +++ /dev/null @@ -1,67 +0,0 @@ -/** - * Syntax highlighting styles - */ -.highlight { - background: #fff; - @extend %vertical-rhythm; - - .c { color: #998; font-style: italic } // Comment - .err { color: #a61717; background-color: #e3d2d2 } // Error - .k { font-weight: bold } // Keyword - .o { font-weight: bold } // Operator - .cm { color: #998; font-style: italic } // Comment.Multiline - .cp { color: #999; font-weight: bold } // Comment.Preproc - .c1 { color: #998; font-style: italic } // Comment.Single - .cs { color: #999; font-weight: bold; font-style: italic } // Comment.Special - .gd { color: #000; background-color: #fdd } // Generic.Deleted - .gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific - .ge { font-style: italic } // Generic.Emph - .gr { color: #a00 } // Generic.Error - .gh { color: #999 } // Generic.Heading - .gi { color: #000; background-color: #dfd } // Generic.Inserted - .gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific - .go { color: #888 } // Generic.Output - .gp { color: #555 } // Generic.Prompt - .gs { font-weight: bold } // Generic.Strong - .gu { color: #aaa } // Generic.Subheading - .gt { color: #a00 } // Generic.Traceback - .kc { font-weight: bold } // Keyword.Constant - .kd { font-weight: bold } // Keyword.Declaration - .kp { font-weight: bold } // Keyword.Pseudo - .kr { font-weight: bold } // Keyword.Reserved - .kt { color: #458; font-weight: bold } // Keyword.Type - .m { color: #099 } // Literal.Number - .s { color: #d14 } // Literal.String - .na { color: #008080 } // Name.Attribute - .nb { color: #0086B3 } // Name.Builtin - .nc { color: #458; font-weight: bold } // Name.Class - .no { color: #008080 } // Name.Constant - .ni { color: #800080 } // Name.Entity - .ne { color: #900; font-weight: bold } // Name.Exception - .nf { color: #900; font-weight: bold } // Name.Function - .nn { color: #555 } // Name.Namespace - .nt { color: #000080 } // Name.Tag - .nv { color: #008080 } // Name.Variable - .ow { font-weight: bold } // Operator.Word - .w { color: #bbb } // Text.Whitespace - .mf { color: #099 } // Literal.Number.Float - .mh { color: #099 } // Literal.Number.Hex - .mi { color: #099 } // Literal.Number.Integer - .mo { color: #099 } // Literal.Number.Oct - .sb { color: #d14 } // Literal.String.Backtick - .sc { color: #d14 } // Literal.String.Char - .sd { color: #d14 } // Literal.String.Doc - .s2 { color: #d14 } // Literal.String.Double - .se { color: #d14 } // Literal.String.Escape - .sh { color: #d14 } // Literal.String.Heredoc - .si { color: #d14 } // Literal.String.Interpol - .sx { color: #d14 } // Literal.String.Other - .sr { color: #009926 } // Literal.String.Regex - .s1 { color: #d14 } // Literal.String.Single - .ss { color: #990073 } // Literal.String.Symbol - .bp { color: #999 } // Name.Builtin.Pseudo - .vc { color: #008080 } // Name.Variable.Class - .vg { color: #008080 } // Name.Variable.Global - .vi { color: #008080 } // Name.Variable.Instance - .il { color: #099 } // Literal.Number.Integer.Long -} diff --git a/supporting-docs/about.md b/supporting-docs/about.md deleted file mode 100644 index 3ed64bb6..00000000 --- a/supporting-docs/about.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -layout: page -title: About -permalink: /about/ ---- - -This is the base Jekyll theme. You can find out more info about customizing your Jekyll theme, as well as basic Jekyll usage documentation at [jekyllrb.com](http://jekyllrb.com/) - -You can find the source code for the Jekyll new theme at: [github.com/jglovier/jekyll-new](https://github.com/jglovier/jekyll-new) - -You can find the source code for Jekyll at [github.com/jekyll/jekyll](https://github.com/jekyll/jekyll) diff --git a/supporting-docs/css/basic.css b/supporting-docs/css/basic.css deleted file mode 100644 index bf8f4712..00000000 --- a/supporting-docs/css/basic.css +++ /dev/null @@ -1,512 +0,0 @@ -/* - * basic.css - * ~~~~~~~~~ - * - * Sphinx stylesheet -- basic theme. - * - * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- main layout ----------------------------------------------------------- */ - -div.clearer { - clear: both; -} - -/* -- relbar ---------------------------------------------------------------- */ - -div.related { - width: 100%; - font-size: 90%; -} - -div.related h3 { - display: none; -} - -div.related ul { - margin: 0; - padding: 0 0 0 10px; - list-style: none; -} - -div.related li { - display: inline; -} - -div.related li.right { - float: right; - margin-right: 5px; -} - -/* -- sidebar --------------------------------------------------------------- */ - -div.sphinxsidebarwrapper { - padding: 10px 5px 0 10px; -} - -div.sphinxsidebar { - float: left; - width: 230px; - margin-left: -100%; - font-size: 90%; -} - -div.sphinxsidebar ul { - list-style: none; -} - -div.sphinxsidebar ul ul, -div.sphinxsidebar ul.want-points { - margin-left: 20px; - list-style: square; -} - -div.sphinxsidebar ul ul { - margin-top: 0; - margin-bottom: 0; -} - -div.sphinxsidebar form { - margin-top: 10px; -} - -div.sphinxsidebar input { - border: 1px solid #98dbcc; - font-family: sans-serif; - font-size: 1em; -} - -img { - border: 0; -} - -/* -- search page ----------------------------------------------------------- */ - -ul.search { - margin: 10px 0 0 20px; - padding: 0; -} - -ul.search li { - padding: 5px 0 5px 20px; - background-image: url(file.png); - background-repeat: no-repeat; - background-position: 0 7px; -} - -ul.search li a { - font-weight: bold; -} - -ul.search li div.context { - color: #888; - margin: 2px 0 0 30px; - text-align: left; -} - -ul.keywordmatches li.goodmatch a { - font-weight: bold; -} - -/* -- index page ------------------------------------------------------------ */ - -table.contentstable { - width: 90%; -} - -table.contentstable p.biglink { - line-height: 150%; -} - -a.biglink { - font-size: 1.3em; -} - -span.linkdescr { - font-style: italic; - padding-top: 5px; - font-size: 90%; -} - -/* -- general index --------------------------------------------------------- */ - -table.indextable { - width: 100%; -} - -table.indextable td { - text-align: left; - vertical-align: top; -} - -table.indextable dl, table.indextable dd { - margin-top: 0; - margin-bottom: 0; -} - -table.indextable tr.pcap { - height: 10px; -} - -table.indextable tr.cap { - margin-top: 10px; - background-color: #f2f2f2; -} - -img.toggler { - margin-right: 3px; - margin-top: 3px; - cursor: pointer; -} - -div.modindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -div.genindex-jumpbox { - border-top: 1px solid #ddd; - border-bottom: 1px solid #ddd; - margin: 1em 0 1em 0; - padding: 0.4em; -} - -/* -- general body styles --------------------------------------------------- */ - -a.headerlink { - visibility: hidden; -} - -h1:hover > a.headerlink, -h2:hover > a.headerlink, -h3:hover > a.headerlink, -h4:hover > a.headerlink, -h5:hover > a.headerlink, -h6:hover > a.headerlink, -dt:hover > a.headerlink { - visibility: visible; -} - -div.document p.caption { - text-align: inherit; -} - -div.document td { - text-align: left; -} - -.field-list ul { - padding-left: 1em; -} - -.first { - margin-top: 0 !important; -} - -p.rubric { - margin-top: 30px; - font-weight: bold; -} - -.align-left { - text-align: left; -} - -.align-center { - clear: both; - text-align: center; -} - -.align-right { - text-align: right; -} - -/* -- sidebars -------------------------------------------------------------- */ - -div.sidebar { - margin: 0 0 0.5em 1em; - border: 1px solid #ddb; - padding: 7px 7px 0 7px; - background-color: #ffe; - width: 40%; - float: right; -} - -p.sidebar-title { - font-weight: bold; -} - -/* -- topics ---------------------------------------------------------------- */ - -div.topic { - border: 1px solid #ccc; - padding: 7px 7px 0 7px; - margin: 10px 0 10px 0; -} - -p.topic-title { - font-size: 1.1em; - font-weight: bold; - margin-top: 10px; -} - -/* -- admonitions ----------------------------------------------------------- */ - -div.admonition { - margin-top: 10px; - margin-bottom: 10px; - padding: 7px; -} - -div.admonition dt { - font-weight: bold; -} - -div.admonition dl { - margin-bottom: 0; -} - -p.admonition-title { - margin: 0px 10px 5px 0px; - font-weight: bold; -} - -div.document p.centered { - text-align: center; - margin-top: 25px; -} - -/* -- tables ---------------------------------------------------------------- */ - -table.docutils { - border: 0; - border-collapse: collapse; -} - -table.docutils td, table.docutils th { - padding: 1px 8px 1px 5px; - border-top: 0; - border-left: 0; - border-right: 0; - border-bottom: 1px solid #aaa; -} - -table.field-list td, table.field-list th { - border: 0 !important; -} - -table.footnote td, table.footnote th { - border: 0 !important; -} - -th { - text-align: left; - padding-right: 5px; -} - -table.citation { - border-left: solid 1px gray; - margin-left: 1px; -} - -table.citation td { - border-bottom: none; -} - -/* -- other body styles ----------------------------------------------------- */ - -ol.arabic { - list-style: decimal; -} - -ol.loweralpha { - list-style: lower-alpha; -} - -ol.upperalpha { - list-style: upper-alpha; -} - -ol.lowerroman { - list-style: lower-roman; -} - -ol.upperroman { - list-style: upper-roman; -} - -dl { - margin-bottom: 15px; -} - -dd p { - margin-top: 0px; -} - -dd ul, dd table { - margin-bottom: 10px; -} - -dd { - margin-top: 3px; - margin-bottom: 10px; - margin-left: 30px; -} - -dt:target, .highlighted { - background-color: #fbe54e; -} - -dl.glossary dt { - font-weight: bold; - font-size: 1.1em; -} - -.field-list ul { - margin: 0; - padding-left: 1em; -} - -.field-list p { - margin: 0; -} - -.refcount { - color: #060; -} - -.optional { - font-size: 1.3em; -} - -.versionmodified { - font-style: italic; -} - -.system-message { - background-color: #fda; - padding: 5px; - border: 3px solid red; -} - -.footnote:target { - background-color: #ffa -} - -.line-block { - display: block; - margin-top: 1em; - margin-bottom: 1em; -} - -.line-block .line-block { - margin-top: 0; - margin-bottom: 0; - margin-left: 1.5em; -} - -.guilabel, .menuselection { - font-family: sans-serif; -} - -.accelerator { - text-decoration: underline; -} - -.classifier { - font-style: oblique; -} - -/* -- code displays --------------------------------------------------------- */ - -pre { - overflow: auto; - font-size: 1.1em; - -} - -td.linenos pre { - padding: 5px 0px; - border: 0; - background-color: transparent; - color: #aaa; -} - -table.highlighttable { - margin-left: 0.5em; -} - -table.highlighttable td { - padding: 0 0.5em 0 0.5em; -} - -tt.descname { - background-color: transparent; - font-weight: bold; - font-size: 1.2em; -} - -tt.descclassname { - background-color: transparent; -} - -tt.xref, a tt { - background-color: transparent; - font-weight: bold; -} - -h1 tt, h2 tt, h3 tt, h4 tt, h5 tt, h6 tt { - background-color: transparent; -} - -.viewcode-link { - float: right; -} - -.viewcode-back { - float: right; - font-family: sans-serif; -} - -div.viewcode-block:target { - margin: -1px -10px; - padding: 0 10px; -} - -/* -- math display ---------------------------------------------------------- */ - -img.math { - vertical-align: middle; -} - -div.document div.math p { - text-align: center; -} - -span.eqno { - float: right; -} - -/* -- printout stylesheet --------------------------------------------------- */ - -@media print { - div.document, - div.documentwrapper, - div.bodywrapper { - margin: 0 !important; - width: 100%; - } - - div.sphinxsidebar, - div.related, - div.footer, - #top-link { - display: none; - } -} - diff --git a/supporting-docs/css/faq.css b/supporting-docs/css/faq.css deleted file mode 100644 index 9730efa3..00000000 --- a/supporting-docs/css/faq.css +++ /dev/null @@ -1,40 +0,0 @@ -.toc { - background: #f9f9f9; - border: 1px solid #aaaaaa; - display: table; - padding-top: 16px; - padding-right: 16px; - padding-bottom: 16px; - list-style: none; - color: #2EA3F2; -} - -ul { - padding-left: 30px; -} - -p { - padding-left: 30px; - color: #666; - -} - -h3 { - padding-top: 48px; - color: #333; -} - -h4, h5 { - border-top: 40px solid transparent; - margin-top: -40px; - -webkit-background-clip: padding-box; - -moz-background-clip: padding; - background-clip: padding-box; - font-style: italic; - font-size: 16px; - padding-top: 16px; - color: #333; - -} - - diff --git a/supporting-docs/css/main.scss b/supporting-docs/css/main.scss deleted file mode 100755 index b8a3e2be..00000000 --- a/supporting-docs/css/main.scss +++ /dev/null @@ -1,52 +0,0 @@ ---- -# Only the main Sass file needs front matter (the dashes are enough) ---- -@charset "utf-8"; - - - -// Our variables -$base-font-family: Helvetica, Arial, sans-serif; -$base-font-size: 16px; -$small-font-size: $base-font-size * 0.875; -$base-line-height: 1.5; - -$spacing-unit: 30px; - -$text-color: #111; -$background-color: #fdfdfd; -$brand-color: #2a7ae2; - -$grey-color: #828282; -$grey-color-light: lighten($grey-color, 40%); -$grey-color-dark: darken($grey-color, 25%); - -// Width of the content area -$content-width: 1340px; - -$on-palm: 600px; -$on-laptop: 800px; - - - -// Using media queries with like this: -// @include media-query($on-palm) { -// .wrapper { -// padding-right: $spacing-unit / 2; -// padding-left: $spacing-unit / 2; -// } -// } -@mixin media-query($device) { - @media screen and (max-width: $device) { - @content; - } -} - - - -// Import partials from `sass_dir` (defaults to `_sass`) -@import - "base", - "layout", - "syntax-highlighting" -; diff --git a/supporting-docs/css/nature.css b/supporting-docs/css/nature.css deleted file mode 100644 index 9bf583be..00000000 --- a/supporting-docs/css/nature.css +++ /dev/null @@ -1,285 +0,0 @@ -/* - * nature.css_t - * ~~~~~~~~~~~~ - * - * Sphinx stylesheet -- nature theme. - * - * :copyright: Copyright 2007-2010 by the Sphinx team, see AUTHORS. - * :license: BSD, see LICENSE for details. - * - */ - -/* -- page layout ----------------------------------------------------------- */ - -body { - font-family: Arial, sans-serif; - font-size: 100%; - /*background-color: #111;*/ - color: #555; - margin: 0; - padding: 0; -} - -div.documentwrapper { - float: left; - width: 100%; -} - -div.bodywrapper { - margin: 0 0 0 230px; -} - -hr { - border: 1px solid #B1B4B6; -} - -/* -div.document { - background-color: #eee; -} -*/ - -div.document { - background-color: #ffffff; - color: #3E4349; - padding: 0 30px 30px 30px; - font-size: 0.9em; -} - -div.footer { - color: #555; - width: 100%; - padding: 13px 0; - text-align: center; - font-size: 75%; -} - -div.footer a { - color: #444; - text-decoration: underline; -} - -div.related { - background-color: #6BA81E; - line-height: 32px; - color: #fff; - text-shadow: 0px 1px 0 #444; - font-size: 0.9em; -} - -div.related a { - color: #E2F3CC; -} - -div.sphinxsidebar { - font-size: 0.75em; - line-height: 1.5em; -} - -div.sphinxsidebarwrapper{ - padding: 20px 0; -} - -div.sphinxsidebar h3, -div.sphinxsidebar h4 { - font-family: Arial, sans-serif; - color: #222; - font-size: 1.2em; - font-weight: normal; - margin: 0; - padding: 5px 10px; - background-color: #ddd; - text-shadow: 1px 1px 0 white -} - -div.sphinxsidebar h4{ - font-size: 1.1em; -} - -div.sphinxsidebar h3 a { - color: #444; -} - - -div.sphinxsidebar p { - color: #888; - padding: 5px 20px; -} - -div.sphinxsidebar p.topless { -} - -div.sphinxsidebar ul { - margin: 10px 20px; - padding: 0; - color: #000; -} - -div.sphinxsidebar a { - color: #444; -} - -div.sphinxsidebar input { - border: 1px solid #ccc; - font-family: sans-serif; - font-size: 1em; -} - -div.sphinxsidebar input[type=text]{ - margin-left: 20px; -} - -/* -- body styles ----------------------------------------------------------- */ - -a { - color: #005B81; - text-decoration: none; -} - -a:hover { - color: #E32E00; - text-decoration: underline; -} - -div.document h1, -div.document h2, -div.document h3, -div.document h4, -div.document h5, -div.document h6 { - font-family: Arial, sans-serif; - background-color: #BED4EB; - font-weight: normal; - color: #212224; - margin: 30px 0px 10px 0px; - padding: 5px 0 5px 10px; - text-shadow: 0px 1px 0 white -} - -div.document h1 { border-top: 20px solid white; margin-top: 0; font-size: 200%; } -div.document h2 { font-size: 150%; background-color: #C8D5E3; } -div.document h3 { font-size: 120%; background-color: #D8DEE3; } -div.document h4 { font-size: 110%; background-color: #D8DEE3; } -div.document h5 { font-size: 100%; background-color: #D8DEE3; } -div.document h6 { font-size: 100%; background-color: #D8DEE3; } - -a.headerlink { - color: #c60f0f; - font-size: 0.8em; - padding: 0 4px 0 4px; - text-decoration: none; -} - -a.headerlink:hover { - background-color: #c60f0f; - color: white; -} - -div.document p, div.document dd, div.document li { - line-height: 1.5em; -} - -div.admonition p.admonition-title + p { - display: inline; -} - -div.highlight{ - background-color: white; -} - -div.note { - background-color: #eee; - border: 1px solid #ccc; -} - -div.seealso { - background-color: #ffc; - border: 1px solid #ff6; -} - -div.topic { - background-color: #eee; -} - -div.warning { - background-color: #ffe4e4; - border: 1px solid #f66; -} - -p.admonition-title { - display: inline; -} - -p.admonition-title:after { - content: ":"; -} - -pre { - padding: 10px; - background-color: White; - color: #222; - line-height: 1.2em; - border: 1px solid #C6C9CB; - font-size: 1.1em; - margin: 1.5em 0 1.5em 0; - -webkit-box-shadow: 1px 1px 1px #d8d8d8; - -moz-box-shadow: 1px 1px 1px #d8d8d8; -} - -tt { - background-color: #ecf0f3; - color: #222; - /* padding: 1px 2px; */ - font-size: 1.1em; - font-family: monospace; -} - -.viewcode-back { - font-family: Arial, sans-serif; -} - -div.viewcode-block:target { - background-color: #f4debf; - border-top: 1px solid #ac9; - border-bottom: 1px solid #ac9; -} - -p { - margin: 0; -} - -ul li dd { - margin-top: 0; -} - -ul li dl { - margin-bottom: 0; -} - -li dl dd { - margin-bottom: 0; -} - -dd ul { - padding-left: 0; -} - -li dd ul { - margin-bottom: 0; -} - -table { - margin-top: 10px; - margin-bottom: 10px; - border: 0; - border-collapse: collapse; -} - -td[colspan]:not([colspan="1"]) { - background: #eeeeee; -} - -thead { - background: #eeeeee; -} - diff --git a/supporting-docs/css/site_overrides.css b/supporting-docs/css/site_overrides.css deleted file mode 100644 index f7640e1c..00000000 --- a/supporting-docs/css/site_overrides.css +++ /dev/null @@ -1,62 +0,0 @@ -p { - line-height: 1.5; - color: #666; -} - -a.anchor { - display: block; - position: relative; - top: -50px; - visibility: hidden; -} - -a:link { - color: #2EA3F2; - text-decoration: none; -} - -a:visited { - color: #2EA3F2; - text-decoration: none; -} - -a:active { - color: #2EA3F2; - text-decoration: none; -} - -a:hover { - color: #2EA3F2; - text-decoration: underline; -} - -h1,h2,h3,h4,h5 { - color: #333; -} - -.page-content { - min-height: 100%; - height: auto !important; /* This line and the next line are not necessary unless you need IE6 support */ - height: 100%; - margin: 0 auto -33px; /* the bottom margin is the negative value of the footer's height */ - padding-bottom: 0; - padding-top: 0; -} - -.push { - height: 33px; -} - -#page { - margin-bottom: -33px; -} - -#document { - margin-top: 10px; /* We want a little whitespace before the page content starts */ - width: 1080px; -} - -#wrapper { - max-width: 1080px; -} - diff --git a/supporting-docs/feed.xml b/supporting-docs/feed.xml deleted file mode 100644 index a6628bd8..00000000 --- a/supporting-docs/feed.xml +++ /dev/null @@ -1,30 +0,0 @@ ---- -layout: null ---- - - - - {{ site.title | xml_escape }} - {{ site.description | xml_escape }} - {{ site.url }}{{ site.baseurl }}/ - - {{ site.time | date_to_rfc822 }} - {{ site.time | date_to_rfc822 }} - Jekyll v{{ jekyll.version }} - {% for post in site.posts limit:10 %} - - {{ post.title | xml_escape }} - {{ post.content | xml_escape }} - {{ post.date | date_to_rfc822 }} - {{ post.url | prepend: site.baseurl | prepend: site.url }} - {{ post.url | prepend: site.baseurl | prepend: site.url }} - {% for tag in post.tags %} - {{ tag | xml_escape }} - {% endfor %} - {% for cat in post.categories %} - {{ cat | xml_escape }} - {% endfor %} - - {% endfor %} - - diff --git a/supporting-docs/_posts/2015-08-10-client-server.rst b/supporting-docs/guides/2015-08-10-client-server.rst similarity index 100% rename from supporting-docs/_posts/2015-08-10-client-server.rst rename to supporting-docs/guides/2015-08-10-client-server.rst diff --git a/supporting-docs/_posts/2015-08-14-getting_involved.md b/supporting-docs/guides/2015-08-14-getting_involved.md similarity index 100% rename from supporting-docs/_posts/2015-08-14-getting_involved.md rename to supporting-docs/guides/2015-08-14-getting_involved.md diff --git a/supporting-docs/_posts/2015-08-19-faq.md b/supporting-docs/guides/2015-08-19-faq.md similarity index 100% rename from supporting-docs/_posts/2015-08-19-faq.md rename to supporting-docs/guides/2015-08-19-faq.md diff --git a/supporting-docs/_posts/2015-08-21-application_services.md b/supporting-docs/guides/2015-08-21-application_services.md similarity index 100% rename from supporting-docs/_posts/2015-08-21-application_services.md rename to supporting-docs/guides/2015-08-21-application_services.md diff --git a/supporting-docs/index.html b/supporting-docs/index.html deleted file mode 100644 index 5a874f06..00000000 --- a/supporting-docs/index.html +++ /dev/null @@ -1,14 +0,0 @@ ---- -layout: default ---- -
- -

Guides

- -

Here is a collection of guides that might help you get involved with Matrix.

-

First, there is the Getting Involved guide, which explains various ways of getting started with Matrix.

-

The Client-Server API guide explains in detail how to use the CS API, which is useful if you want to write a client (or modify an existing one) - or if you're just interested in how it works "under the hood".

-

The Application services guide introduces and explains Application services, and what they can be used for. -

Finally there is the FAQ, which tries to answer all your questions relating to Matrix!

- -
From a0cf4859190efc4b8ce02c34ba68a42508a0dbd6 Mon Sep 17 00:00:00 2001 From: Daniel Wagner-Hall Date: Fri, 9 Oct 2015 10:43:27 +0100 Subject: [PATCH 19/23] speculator: Specify merge target --- scripts/speculator/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/speculator/main.go b/scripts/speculator/main.go index 842d20b7..d807bf78 100644 --- a/scripts/speculator/main.go +++ b/scripts/speculator/main.go @@ -86,7 +86,7 @@ func gitFetchAndMerge(path string) error { if err := runGitCommand(path, []string{"fetch"}); err != nil { return err } - return runGitCommand(path, []string{"merge"}) + return runGitCommand(path, []string{"merge", "origin/master"}) } func runGitCommand(path string, args []string) error { From 0dbc6d82770b59a329f356e118762fe2e117be7b Mon Sep 17 00:00:00 2001 From: Daniel Wagner-Hall Date: Fri, 9 Oct 2015 10:59:26 +0100 Subject: [PATCH 20/23] Checkout SHA of origin/master rather than merging --- scripts/speculator/main.go | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/scripts/speculator/main.go b/scripts/speculator/main.go index d807bf78..ad0a897b 100644 --- a/scripts/speculator/main.go +++ b/scripts/speculator/main.go @@ -82,11 +82,8 @@ func gitCheckout(path, sha string) error { return runGitCommand(path, []string{"checkout", sha}) } -func gitFetchAndMerge(path string) error { - if err := runGitCommand(path, []string{"fetch"}); err != nil { - return err - } - return runGitCommand(path, []string{"merge", "origin/master"}) +func gitFetch(path string) error { + return runGitCommand(path, []string{"fetch"}) } func runGitCommand(path string, args []string) error { @@ -145,7 +142,7 @@ type server struct { // generateAt generates spec from repo at sha. // Returns the path where the generation was done. func (s *server) generateAt(sha string) (dst string, err error) { - err = gitFetchAndMerge(s.matrixDocCloneURL) + err = gitFetch(s.matrixDocCloneURL) if err != nil { return } @@ -162,11 +159,27 @@ func (s *server) generateAt(sha string) (dst string, err error) { return } +func (s *server) getSHAOf(ref string) (string, error) { + cmd := exec.Command("git", "rev-list", ref, "-n1") + cmd.Dir = path.Join(s.matrixDocCloneURL) + var b bytes.Buffer + cmd.Stdout = &b + err := cmd.Run() + if err != nil { + return "", fmt.Errorf("error generating spec: %v\nOutput from gendoc:\n%v", err, b.String()) + } + return strings.TrimSpace(b.String()), nil +} + func (s *server) serveSpec(w http.ResponseWriter, req *http.Request) { var sha string if strings.ToLower(req.URL.Path) == "/spec/head" { - sha = "HEAD" + originHead, err := s.getSHAOf("origin/master") + if err != nil { + writeError(w, 500, err) + } + sha = originHead } else { pr, err := lookupPullRequest(*req.URL, "/spec") if err != nil { From 481298db83d257466aa24d7433798da8240e58c1 Mon Sep 17 00:00:00 2001 From: Daniel Wagner-Hall Date: Fri, 9 Oct 2015 11:01:35 +0100 Subject: [PATCH 21/23] Revert "Checkout SHA of origin/master rather than merging" This reverts commit 0dbc6d82770b59a329f356e118762fe2e117be7b. --- scripts/speculator/main.go | 27 +++++++-------------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/scripts/speculator/main.go b/scripts/speculator/main.go index ad0a897b..d807bf78 100644 --- a/scripts/speculator/main.go +++ b/scripts/speculator/main.go @@ -82,8 +82,11 @@ func gitCheckout(path, sha string) error { return runGitCommand(path, []string{"checkout", sha}) } -func gitFetch(path string) error { - return runGitCommand(path, []string{"fetch"}) +func gitFetchAndMerge(path string) error { + if err := runGitCommand(path, []string{"fetch"}); err != nil { + return err + } + return runGitCommand(path, []string{"merge", "origin/master"}) } func runGitCommand(path string, args []string) error { @@ -142,7 +145,7 @@ type server struct { // generateAt generates spec from repo at sha. // Returns the path where the generation was done. func (s *server) generateAt(sha string) (dst string, err error) { - err = gitFetch(s.matrixDocCloneURL) + err = gitFetchAndMerge(s.matrixDocCloneURL) if err != nil { return } @@ -159,27 +162,11 @@ func (s *server) generateAt(sha string) (dst string, err error) { return } -func (s *server) getSHAOf(ref string) (string, error) { - cmd := exec.Command("git", "rev-list", ref, "-n1") - cmd.Dir = path.Join(s.matrixDocCloneURL) - var b bytes.Buffer - cmd.Stdout = &b - err := cmd.Run() - if err != nil { - return "", fmt.Errorf("error generating spec: %v\nOutput from gendoc:\n%v", err, b.String()) - } - return strings.TrimSpace(b.String()), nil -} - func (s *server) serveSpec(w http.ResponseWriter, req *http.Request) { var sha string if strings.ToLower(req.URL.Path) == "/spec/head" { - originHead, err := s.getSHAOf("origin/master") - if err != nil { - writeError(w, 500, err) - } - sha = originHead + sha = "HEAD" } else { pr, err := lookupPullRequest(*req.URL, "/spec") if err != nil { From 89426c93224d005a30538f14d13ae8bd7b3370f2 Mon Sep 17 00:00:00 2001 From: Oddvar Lovaas Date: Fri, 9 Oct 2015 17:43:46 +0100 Subject: [PATCH 22/23] typos and fixes --- supporting-docs/guides/2015-08-19-faq.md | 6 +++--- supporting-docs/guides/2015-08-21-application_services.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/supporting-docs/guides/2015-08-19-faq.md b/supporting-docs/guides/2015-08-19-faq.md index ce58c158..ff30827c 100644 --- a/supporting-docs/guides/2015-08-19-faq.md +++ b/supporting-docs/guides/2015-08-19-faq.md @@ -204,7 +204,7 @@ on: - Disruptive net-splits - Non-extensible -[IRCv3](http://ircv3.net) exists and is addressing some of issues; +[IRCv3](http://ircv3.net) exists and is addressing some of these issues; this is great news and we wish them well. It's almost a contradiction in terms to get competitive between openly interoperable communication projects - we look forward to increasing the richness of Matrix\<-\>IRC @@ -519,8 +519,8 @@ Follow the instructions for the homeserver you want to run. If you want to run S ##### Can I run my own identity server? Yes - the reference implementation is -[sydent](https://github.com/matrix-org/sydent) and you can run your own -ID server cluster that tracks 3rd party to Matrix ID mappings. This won't be very useful right now, though, and we don't recommend it. +[sydent](https://github.com/matrix-org/sydent) and you can run your own ID server cluster that tracks 3rd party to Matrix ID mappings. This won't be very useful right now, though, and we don't recommend it. + If you want your server to participate in the global replicated Matrix ID service then please get in touch with us. Meanwhile, we are looking at ways of decentralising the 'official' Matrix identity service so that diff --git a/supporting-docs/guides/2015-08-21-application_services.md b/supporting-docs/guides/2015-08-21-application_services.md index bd0453e8..dd532d42 100644 --- a/supporting-docs/guides/2015-08-21-application_services.md +++ b/supporting-docs/guides/2015-08-21-application_services.md @@ -17,7 +17,7 @@ One of the main use cases for application services is protocol bridges. Our Matr ### Some of the features of the IRC application service we have since implemented include: - Specific channel-to-matrix room bridging : This is what the original IRC bot did. You can specify specific channels and specific room IDs, and messages will be bridged. -- Dynamic channel-to-matrix room bridging> : This allows Matrix users to join any channel on an IRC network, rather than being forced to use one of the specific channels configured. +- Dynamic channel-to-matrix room bridging : This allows Matrix users to join any channel on an IRC network, rather than being forced to use one of the specific channels configured. - Two-way PM support : IRC users can PM the virtual "M-" users and private Matrix rooms will be created. Likewise, Matrix users can invite the virtual "@irc_Nick:domain" user IDs to a room and a PM to the IRC nick will be made. - IRC nick changing support: Matrix users are no longer forced to use "M-" nicks and can change them by sending "!nick" messages directly to the bridge. - Ident support: This allows usernames to be authenticated for virtual IRC clients, which means IRC bans can be targeted at the Matrix user rather than the entire application service. From 8f5c796884bd0312318f6046faa4c9599be9dc37 Mon Sep 17 00:00:00 2001 From: Kegan Dougal Date: Mon, 12 Oct 2015 17:50:46 +0100 Subject: [PATCH 23/23] Linkify 'pushers' --- api/client-server/v1/pusher.yaml | 2 +- specification/modules/push.rst | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/api/client-server/v1/pusher.yaml b/api/client-server/v1/pusher.yaml index 99a70ee7..8c243f2b 100644 --- a/api/client-server/v1/pusher.yaml +++ b/api/client-server/v1/pusher.yaml @@ -22,7 +22,7 @@ paths: post: summary: Modify a pusher for this user on the homeserver. description: |- - This endpoint allows the creation, modification and deletion of pushers + This endpoint allows the creation, modification and deletion of `pushers`_ for this user ID. The behaviour of this endpoint varies depending on the values in the JSON body. security: diff --git a/specification/modules/push.rst b/specification/modules/push.rst index 7948475c..6e9c8536 100644 --- a/specification/modules/push.rst +++ b/specification/modules/push.rst @@ -64,6 +64,8 @@ Push Gateway devices or GCM for Android devices. Clients inform the homeserver which Push Gateway to send notifications to when it sets up a Pusher. +.. _def:pushers: + Pusher A pusher is a worker on the homeserver that manages the sending of HTTP notifications for a user. A user can have multiple pushers: one per @@ -89,6 +91,8 @@ There is a single API endpoint for this, as described below. {{pusher_http_api}} +.. _pushers: `def:pushers`_ + Push Rules ~~~~~~~~~~ A push rule is a single rule that states under what *conditions* an event should