More docs
This commit is contained in:
		
							parent
							
								
									c5ec3b48b4
								
							
						
					
					
						commit
						a779434bab
					
				
					 7 changed files with 1776 additions and 1045 deletions
				
			
		
							
								
								
									
										838
									
								
								docs/publish.md
									
										
									
									
									
								
							
							
						
						
									
										838
									
								
								docs/publish.md
									
										
									
									
									
								
							|  | @ -821,11 +821,13 @@ Here's an example of what that a notification with actions can look like: | ||||||
|   <figcaption>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</figcaption> |   <figcaption>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</figcaption> | ||||||
| </figure> | </figure> | ||||||
| 
 | 
 | ||||||
| To define the user actions, you can either pass the `actions` field as part of the JSON body (if you're  | You can set up to three user actions in your notifications, using either of the following methods: | ||||||
| [publishing via JSON](#publish-as-json)), or use the `X-Actions` header (or any of its aliases: `Actions`, `Action`). |  | ||||||
| 
 | 
 | ||||||
| Using the `X-Actions` header and the **simple format** (details see below), you can create the above notification like  | * In the `X-Actions` header, using the **simple format** | ||||||
| this. This format is much **easier to write, but less powerful**: | * As a **JSON array** in the `actions` key, when [publishing as JSON](#publish-as-json)  | ||||||
|  | 
 | ||||||
|  | Using the `X-Actions` header (or any of its aliases: `Actions`, `Action`) and the **simple format** (details see below), you  | ||||||
|  | can create the above notification like this.  | ||||||
| 
 | 
 | ||||||
| === "Command line (curl)" | === "Command line (curl)" | ||||||
|     ``` |     ``` | ||||||
|  | @ -900,39 +902,28 @@ this. This format is much **easier to write, but less powerful**: | ||||||
|     ])); |     ])); | ||||||
|     ``` |     ``` | ||||||
|   |   | ||||||
| The `X-Actions` header (including above-mentioned aliases) supports the following formats: | Here's the generic definition of the simple format:  | ||||||
| 
 | 
 | ||||||
| === "Simple format (long)" | === "Simple format (long)" | ||||||
|     ``` |     ``` | ||||||
|     X-Actions: action=<action>, label=<label>, param1=..., param2=..., ... |     action=<action1>, label=<label1>, paramN=...[; action=<action2>, label=<label2>, ...] | ||||||
|     ``` |  | ||||||
|     Simple format examples: |  | ||||||
|     ``` |  | ||||||
|     X-Actions: action=view, label=Play video, url=https://www.youtube.com/watch?v=EmL3lS0-Sr8 |  | ||||||
|     X-Actions: action=broadcast, label=Turn of flashlight, extras.cmd=flashlight-on |  | ||||||
|     X-Actions: action=http, label=Change temperature, url=https://api.nest.com/device/XZ1D2, body=target_temp_f=65 |  | ||||||
|     ``` |     ``` | ||||||
| 
 | 
 | ||||||
| === "Simple format (short)" | === "Simple format (short)" | ||||||
|     ``` |     ``` | ||||||
|     Actions: <action>, <label>, param1=..., param2=..., ... |     <action1>, <label1>, paramN=...[; <action2>, <label2>, ...] | ||||||
|     ``` |     ``` | ||||||
| 
 | 
 | ||||||
| An `action` is either [`view`](#open-websiteapp), [`broadcast`](#send-android-broadcast), or [`http`](#send-http-request), | `action=` and `label=` are optional in all actions, and `url=` is optional in the `view` and `http` action. | ||||||
| and the `label` defines the button text. The other parameters depend on the action itself. Please refer to this table |  | ||||||
| for all available parameters: |  | ||||||
| 
 | 
 | ||||||
| | Field     | Required | Type                           | Example               | Applies to action | Description                                                  | | Simple format examples: | ||||||
| |-----------|----------|--------------------------------|-----------------------|-------------------|--------------------------------------------------------------| |  | ||||||
| | `action`  | ✔️       | *view, broadcast, or http*     | `view`                | *all actions*     | Action type                                                  | |  | ||||||
| | `label`   | ✔️       | *string*                       | `Turn on light`       | *all actions*     | Label of the action button in the notification               | |  | ||||||
| | `url`     | -️       | *URL*                          | `https://example.com` | `view`, `http`    | URL to open or send a HTTP request to                        | |  | ||||||
| | `method`  | -️       | *HTTP method (GET, POST, ...)* | `GET`                 | `http`            | HTTP method to use for HTTP request (**default is `POST`**!) | |  | ||||||
| | `headers` | -️       | *HTTP method (GET, POST, ...)* | `GET`                 | `http`            | HTTP method to use for HTTP request (**default is `POST`**!) | |  | ||||||
| | `method`  | -️       | *HTTP method (GET, POST, ...)* | `GET`                 | `http`            | HTTP method to use for HTTP request (**default is `POST`**!) | |  | ||||||
| 
 | 
 | ||||||
|  | ``` | ||||||
|  | http, Change temp, https://api.nest.com/XZ1D2, body=target_temp=65 | ||||||
|  | action=view, label=Open site, url=https://ntfy.sh; action=broadcast, label=Turn off, extras.cmd=turn-off | ||||||
|  | ``` | ||||||
| 
 | 
 | ||||||
| Alternatively, you can define actions as **JSON array** (details see below), and pass them as part of the JSON body  | Alternatively, the same actions can be defined as **JSON array** (details see below), if the notification is defined as part of the JSON body  | ||||||
| (see [publish as JSON](#publish-as-json)): | (see [publish as JSON](#publish-as-json)): | ||||||
| 
 | 
 | ||||||
| === "Command line (curl)" | === "Command line (curl)" | ||||||
|  | @ -1127,15 +1118,241 @@ Alternatively, you can define actions as **JSON array** (details see below), and | ||||||
|     ])); |     ])); | ||||||
|     ``` |     ``` | ||||||
| 
 | 
 | ||||||
| XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXx |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| ### Open website/app | ### Open website/app | ||||||
| The `view` action opens a website or app when the action button is tapped, e.g. a browser, a Google Maps location, or | The `view` action opens a website or app when the action button is tapped, e.g. a browser, a Google Maps location, or | ||||||
| even a deep link into Twitter or a show ntfy topic. | even a deep link into Twitter or a show ntfy topic. | ||||||
| 
 | 
 | ||||||
| XXXXXXXXXXXXXXXXXXx | Examples: | ||||||
| 
 | 
 | ||||||
|  | * `http://` or `https://` will open your browser (or an app if it registered for a URL) | ||||||
|  | * `mailto:` links will open your mail app, e.g. `mailto:phil@example.com` | ||||||
|  | * `geo:` links will open Google Maps, e.g. `geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+CA` | ||||||
|  | * `ntfy://` links will open ntfy (see [ntfy:// links](subscribe/phone.md#ntfy-links)), e.g. `ntfy://ntfy.sh/stats` | ||||||
|  | * ... | ||||||
|  | 
 | ||||||
|  | Here's an example using the simple format: | ||||||
|  | 
 | ||||||
|  | === "Command line (curl)" | ||||||
|  |     ``` | ||||||
|  |     curl \ | ||||||
|  |         -d "You left the house. Turn down the A/C?" \ | ||||||
|  |         -H "Actions: view, Open portal, https://home.nest.com/" \ | ||||||
|  |     ntfy.sh/myhome | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "ntfy CLI" | ||||||
|  |     ``` | ||||||
|  |     ntfy publish \ | ||||||
|  |         --actions="view, Open portal, https://home.nest.com/" \ | ||||||
|  |         myhome \ | ||||||
|  |         "You left the house. Turn down the A/C?" | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "HTTP" | ||||||
|  |     ``` http | ||||||
|  |     POST /myhome HTTP/1.1 | ||||||
|  |     Host: ntfy.sh | ||||||
|  |     Actions: view, Open portal, https://home.nest.com/ | ||||||
|  | 
 | ||||||
|  |     You left the house. Turn down the A/C? | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "JavaScript" | ||||||
|  |     ``` javascript | ||||||
|  |     fetch('https://ntfy.sh/myhome', { | ||||||
|  |         method: 'POST', | ||||||
|  |         body: 'You left the house. Turn down the A/C?', | ||||||
|  |         headers: {  | ||||||
|  |             'Actions': 'view, Open portal, https://home.nest.com/'  | ||||||
|  |         } | ||||||
|  |     }) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "Go" | ||||||
|  |     ``` go | ||||||
|  |     req, _ := http.NewRequest("POST", "https://ntfy.sh/myhome", strings.NewReader("You left the house. Turn down the A/C?")) | ||||||
|  |     req.Header.Set("Actions", "view, Open portal, https://home.nest.com/") | ||||||
|  |     http.DefaultClient.Do(req) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "PowerShell" | ||||||
|  |     ``` powershell | ||||||
|  |     $uri = "https://ntfy.sh/myhome" | ||||||
|  |     $headers = @{ Actions="view, Open portal, https://home.nest.com/" } | ||||||
|  |     $body = "You left the house. Turn down the A/C?" | ||||||
|  |     Invoke-RestMethod -Method 'Post' -Uri $uri -Headers $headers -Body $body -UseBasicParsing | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "Python" | ||||||
|  |     ``` python | ||||||
|  |     requests.post("https://ntfy.sh/myhome", | ||||||
|  |         data="You left the house. Turn down the A/C?", | ||||||
|  |         headers={ "Actions": "view, Open portal, https://home.nest.com/" }) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "PHP" | ||||||
|  |     ``` php-inline | ||||||
|  |     file_get_contents('https://ntfy.sh/reddit_alerts', false, stream_context_create([ | ||||||
|  |         'http' => [ | ||||||
|  |             'method' => 'POST', | ||||||
|  |             'header' => | ||||||
|  |                 "Content-Type: text/plain\r\n" . | ||||||
|  |                 "Actions: view, Open portal, https://home.nest.com/", | ||||||
|  |             'content' => 'You left the house. Turn down the A/C?' | ||||||
|  |         ] | ||||||
|  |     ])); | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | And the same example using [JSON publishing](#publish-as-json): | ||||||
|  | 
 | ||||||
|  | === "Command line (curl)" | ||||||
|  |     ``` | ||||||
|  |     curl ntfy.sh \ | ||||||
|  |       -d '{ | ||||||
|  |         "topic": "myhome", | ||||||
|  |         "message": "You left the house. Turn down the A/C?", | ||||||
|  |         "actions": [ | ||||||
|  |           { | ||||||
|  |             "action": "view", | ||||||
|  |             "label": "Open portal", | ||||||
|  |             "url": "https://home.nest.com/" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       }' | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "ntfy CLI" | ||||||
|  |     ``` | ||||||
|  |     ntfy publish \ | ||||||
|  |         --actions '[ | ||||||
|  |             { | ||||||
|  |                 "action": "view", | ||||||
|  |                 "label": "Open portal", | ||||||
|  |                 "url": "https://home.nest.com/" | ||||||
|  |             } | ||||||
|  |         ]' \ | ||||||
|  |         myhome \ | ||||||
|  |         "You left the house. Turn down the A/C?" | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "HTTP" | ||||||
|  |     ``` http | ||||||
|  |     POST / HTTP/1.1 | ||||||
|  |     Host: ntfy.sh | ||||||
|  | 
 | ||||||
|  |     { | ||||||
|  |         "topic": "myhome", | ||||||
|  |         "message": "You left the house. Turn down the A/C?", | ||||||
|  |         "actions": [ | ||||||
|  |           { | ||||||
|  |             "action": "view", | ||||||
|  |             "label": "Open portal", | ||||||
|  |             "url": "https://home.nest.com/" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |     } | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "JavaScript" | ||||||
|  |     ``` javascript | ||||||
|  |     fetch('https://ntfy.sh', { | ||||||
|  |         method: 'POST', | ||||||
|  |         body: JSON.stringify({ | ||||||
|  |             topic: "myhome", | ||||||
|  |             message": "You left the house. Turn down the A/C?", | ||||||
|  |             actions: [ | ||||||
|  |                 { | ||||||
|  |                     action: "view", | ||||||
|  |                     label: "Open portal", | ||||||
|  |                     url: "https://home.nest.com/" | ||||||
|  |                 } | ||||||
|  |             ] | ||||||
|  |         }) | ||||||
|  |     }) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "Go" | ||||||
|  |     ``` go | ||||||
|  |     // You should probably use json.Marshal() instead and make a proper struct, | ||||||
|  |     // but for the sake of the example, this is easier. | ||||||
|  |      | ||||||
|  |     body := `{ | ||||||
|  |         "topic": "myhome", | ||||||
|  |         "message": "You left the house. Turn down the A/C?", | ||||||
|  |         "actions": [ | ||||||
|  |           { | ||||||
|  |             "action": "view", | ||||||
|  |             "label": "Open portal", | ||||||
|  |             "url": "https://home.nest.com/" | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |     }` | ||||||
|  |     req, _ := http.NewRequest("POST", "https://ntfy.sh/", strings.NewReader(body)) | ||||||
|  |     http.DefaultClient.Do(req) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "PowerShell" | ||||||
|  |     ``` powershell | ||||||
|  |     $uri = "https://ntfy.sh" | ||||||
|  |     $body = @{ | ||||||
|  |         "topic"="myhome" | ||||||
|  |         "message"="You left the house. Turn down the A/C?" | ||||||
|  |         "actions"=@( | ||||||
|  |             @{ | ||||||
|  |                 "action"="view" | ||||||
|  |                 "label"="Open portal" | ||||||
|  |                 "url"="https://home.nest.com/" | ||||||
|  |             } | ||||||
|  |         ) | ||||||
|  |     } | ConvertTo-Json | ||||||
|  |     Invoke-RestMethod -Method 'Post' -Uri $uri -Body $body -ContentType "application/json" -UseBasicParsing | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "Python" | ||||||
|  |     ``` python | ||||||
|  |     requests.post("https://ntfy.sh/", | ||||||
|  |         data=json.dumps({ | ||||||
|  |             "topic": "myhome", | ||||||
|  |             "message": "You left the house. Turn down the A/C?", | ||||||
|  |             "actions": [ | ||||||
|  |                 { | ||||||
|  |                     "action": "view", | ||||||
|  |                     "label": "Open portal", | ||||||
|  |                     "url": "https://home.nest.com/" | ||||||
|  |                 } | ||||||
|  |             ] | ||||||
|  |         }) | ||||||
|  |     ) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "PHP" | ||||||
|  |     ``` php-inline | ||||||
|  |     file_get_contents('https://ntfy.sh/', false, stream_context_create([ | ||||||
|  |         'http' => [ | ||||||
|  |             'method' => 'POST', | ||||||
|  |             'header' => "Content-Type: application/json", | ||||||
|  |             'content' => json_encode([ | ||||||
|  |                 "topic": "myhome", | ||||||
|  |                 "message": "You left the house. Turn down the A/C?", | ||||||
|  |                 "actions": [ | ||||||
|  |                     [ | ||||||
|  |                         "action": "view", | ||||||
|  |                         "label": "Open portal", | ||||||
|  |                         "url": "https://home.nest.com/" | ||||||
|  |                     ] | ||||||
|  |                 ] | ||||||
|  |             ]) | ||||||
|  |         ] | ||||||
|  |     ])); | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | The `view` action supports the following fields: | ||||||
|  | 
 | ||||||
|  | | Field    | Required | Type     | Example               | Description                                    | | ||||||
|  | |----------|----------|----------|-----------------------|------------------------------------------------| | ||||||
|  | | `action` | ✔️       | *string* | `view`                | Action type (**must be `view`**)               | | ||||||
|  | | `label`  | ✔️       | *string* | `Turn on light`       | Label of the action button in the notification | | ||||||
|  | | `url`    | ✔️       | *URL*    | `https://example.com` | URL to open when action is tapped              | | ||||||
| 
 | 
 | ||||||
| ### Send Android broadcast | ### Send Android broadcast | ||||||
| The `broadcast` action sends an [Android broadcast](https://developer.android.com/guide/components/broadcasts) intent | The `broadcast` action sends an [Android broadcast](https://developer.android.com/guide/components/broadcasts) intent | ||||||
|  | @ -1144,107 +1361,510 @@ or [Tasker](https://play.google.com/store/apps/details?id=net.dinglisch.android. | ||||||
| you can do everything your phone is capable of. Examples include taking pictures, launching/killing apps, change device | you can do everything your phone is capable of. Examples include taking pictures, launching/killing apps, change device | ||||||
| settings, write/read files, etc. | settings, write/read files, etc. | ||||||
| 
 | 
 | ||||||
| XXXXXXXXXXXXXXxx | Here's an example using the simple format: | ||||||
| 
 | 
 | ||||||
|  | === "Command line (curl)" | ||||||
|  |     ``` | ||||||
|  |     curl \ | ||||||
|  |         -d "Your wife requested you send a picture of yourself." \ | ||||||
|  |         -H "Actions: broadcast, Take picture, extras.cmd=pic, extras.camera=front" \ | ||||||
|  |     ntfy.sh/wifey | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "ntfy CLI" | ||||||
|  |     ``` | ||||||
|  |     ntfy publish \ | ||||||
|  |         --actions="broadcast, Take picture, extras.cmd=pic, extras.camera=front" \ | ||||||
|  |         wifey \ | ||||||
|  |         "Your wife requested you send a picture of yourself." | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "HTTP" | ||||||
|  |     ``` http | ||||||
|  |     POST /wifey HTTP/1.1 | ||||||
|  |     Host: ntfy.sh | ||||||
|  |     Actions: broadcast, Take picture, extras.cmd=pic, extras.camera=front | ||||||
|  | 
 | ||||||
|  |     Your wife requested you send a picture of yourself. | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "JavaScript" | ||||||
|  |     ``` javascript | ||||||
|  |     fetch('https://ntfy.sh/wifey', { | ||||||
|  |         method: 'POST', | ||||||
|  |         body: 'Your wife requested you send a picture of yourself.', | ||||||
|  |         headers: {  | ||||||
|  |             'Actions': 'broadcast, Take picture, extras.cmd=pic, extras.camera=front'  | ||||||
|  |         } | ||||||
|  |     }) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "Go" | ||||||
|  |     ``` go | ||||||
|  |     req, _ := http.NewRequest("POST", "https://ntfy.sh/wifey", strings.NewReader("Your wife requested you send a picture of yourself.")) | ||||||
|  |     req.Header.Set("Actions", "broadcast, Take picture, extras.cmd=pic, extras.camera=front") | ||||||
|  |     http.DefaultClient.Do(req) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "PowerShell" | ||||||
|  |     ``` powershell | ||||||
|  |     $uri = "https://ntfy.sh/wifey" | ||||||
|  |     $headers = @{ Actions="broadcast, Take picture, extras.cmd=pic, extras.camera=front" } | ||||||
|  |     $body = "Your wife requested you send a picture of yourself." | ||||||
|  |     Invoke-RestMethod -Method 'Post' -Uri $uri -Headers $headers -Body $body -UseBasicParsing | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "Python" | ||||||
|  |     ``` python | ||||||
|  |     requests.post("https://ntfy.sh/wifey", | ||||||
|  |         data="Your wife requested you send a picture of yourself.", | ||||||
|  |         headers={ "Actions": "broadcast, Take picture, extras.cmd=pic, extras.camera=front" }) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "PHP" | ||||||
|  |     ``` php-inline | ||||||
|  |     file_get_contents('https://ntfy.sh/wifey', false, stream_context_create([ | ||||||
|  |         'http' => [ | ||||||
|  |             'method' => 'POST', | ||||||
|  |             'header' => | ||||||
|  |                 "Content-Type: text/plain\r\n" . | ||||||
|  |                 "Actions: broadcast, Take picture, extras.cmd=pic, extras.camera=front", | ||||||
|  |             'content' => 'Your wife requested you send a picture of yourself.' | ||||||
|  |         ] | ||||||
|  |     ])); | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | And the same example using [JSON publishing](#publish-as-json): | ||||||
|  | 
 | ||||||
|  | === "Command line (curl)" | ||||||
|  |     ``` | ||||||
|  |     curl ntfy.sh \ | ||||||
|  |       -d '{ | ||||||
|  |         "topic": "wifey", | ||||||
|  |         "message": "Your wife requested you send a picture of yourself.", | ||||||
|  |         "actions": [ | ||||||
|  |           { | ||||||
|  |             "action": "broadcast", | ||||||
|  |             "label": "Take picture", | ||||||
|  |             "extras": { | ||||||
|  |                 "cmd": "pic", | ||||||
|  |                 "camera": "front" | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       }' | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "ntfy CLI" | ||||||
|  |     ``` | ||||||
|  |     ntfy publish \ | ||||||
|  |         --actions '[ | ||||||
|  |             { | ||||||
|  |                 "action": "broadcast", | ||||||
|  |                 "label": "Take picture", | ||||||
|  |                 "extras": { | ||||||
|  |                     "cmd": "pic", | ||||||
|  |                     "camera": "front" | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         ]' \ | ||||||
|  |         wifey \ | ||||||
|  |         "Your wife requested you send a picture of yourself." | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "HTTP" | ||||||
|  |     ``` http | ||||||
|  |     POST / HTTP/1.1 | ||||||
|  |     Host: ntfy.sh | ||||||
|  | 
 | ||||||
|  |     { | ||||||
|  |         "topic": "wifey", | ||||||
|  |         "message": "Your wife requested you send a picture of yourself.", | ||||||
|  |         "actions": [ | ||||||
|  |           { | ||||||
|  |             "action": "broadcast", | ||||||
|  |             "label": "Take picture", | ||||||
|  |             "extras": { | ||||||
|  |                 "cmd": "pic", | ||||||
|  |                 "camera": "front" | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |     } | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "JavaScript" | ||||||
|  |     ``` javascript | ||||||
|  |     fetch('https://ntfy.sh', { | ||||||
|  |         method: 'POST', | ||||||
|  |         body: JSON.stringify({ | ||||||
|  |             topic: "wifey", | ||||||
|  |             message": "Your wife requested you send a picture of yourself.", | ||||||
|  |             actions: [ | ||||||
|  |                 { | ||||||
|  |                     "action": "broadcast", | ||||||
|  |                     "label": "Take picture", | ||||||
|  |                     "extras": { | ||||||
|  |                         "cmd": "pic", | ||||||
|  |                         "camera": "front" | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             ] | ||||||
|  |         }) | ||||||
|  |     }) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "Go" | ||||||
|  |     ``` go | ||||||
|  |     // You should probably use json.Marshal() instead and make a proper struct, | ||||||
|  |     // but for the sake of the example, this is easier. | ||||||
|  |      | ||||||
|  |     body := `{ | ||||||
|  |         "topic": "wifey", | ||||||
|  |         "message": "Your wife requested you send a picture of yourself.", | ||||||
|  |         "actions": [ | ||||||
|  |           { | ||||||
|  |             "action": "broadcast", | ||||||
|  |             "label": "Take picture", | ||||||
|  |             "extras": { | ||||||
|  |                 "cmd": "pic", | ||||||
|  |                 "camera": "front" | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |     }` | ||||||
|  |     req, _ := http.NewRequest("POST", "https://ntfy.sh/", strings.NewReader(body)) | ||||||
|  |     http.DefaultClient.Do(req) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "PowerShell" | ||||||
|  |     ``` powershell | ||||||
|  |     $uri = "https://ntfy.sh" | ||||||
|  |     $body = @{ | ||||||
|  |         "topic"="wifey" | ||||||
|  |         "message"="Your wife requested you send a picture of yourself." | ||||||
|  |         "actions"=@( | ||||||
|  |             @{ | ||||||
|  |                 "action"="broadcast" | ||||||
|  |                 "label"="Take picture" | ||||||
|  |                 "extras"=@{ | ||||||
|  |                     "cmd"="pic" | ||||||
|  |                     "camera"="front" | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |         ) | ||||||
|  |     } | ConvertTo-Json | ||||||
|  |     Invoke-RestMethod -Method 'Post' -Uri $uri -Body $body -ContentType "application/json" -UseBasicParsing | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "Python" | ||||||
|  |     ``` python | ||||||
|  |     requests.post("https://ntfy.sh/", | ||||||
|  |         data=json.dumps({ | ||||||
|  |             "topic": "wifey", | ||||||
|  |             "message": "Your wife requested you send a picture of yourself.", | ||||||
|  |             "actions": [ | ||||||
|  |                 { | ||||||
|  |                     "action": "broadcast", | ||||||
|  |                     "label": "Take picture", | ||||||
|  |                     "extras": { | ||||||
|  |                         "cmd": "pic", | ||||||
|  |                         "camera": "front" | ||||||
|  |                     } | ||||||
|  |                 } | ||||||
|  |             ] | ||||||
|  |         }) | ||||||
|  |     ) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "PHP" | ||||||
|  |     ``` php-inline | ||||||
|  |     file_get_contents('https://ntfy.sh/', false, stream_context_create([ | ||||||
|  |         'http' => [ | ||||||
|  |             'method' => 'POST', | ||||||
|  |             'header' => "Content-Type: application/json", | ||||||
|  |             'content' => json_encode([ | ||||||
|  |                 "topic": "wifey", | ||||||
|  |                 "message": "Your wife requested you send a picture of yourself.", | ||||||
|  |                 "actions": [ | ||||||
|  |                     [ | ||||||
|  |                     "action": "broadcast", | ||||||
|  |                     "label": "Take picture", | ||||||
|  |                     "extras": [ | ||||||
|  |                         "cmd": "pic", | ||||||
|  |                         "camera": "front" | ||||||
|  |                     ] | ||||||
|  |                 ] | ||||||
|  |             ]) | ||||||
|  |         ] | ||||||
|  |     ])); | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | The `broadcast` action supports the following fields: | ||||||
|  | 
 | ||||||
|  | | Field    | Required | Type             | Example                 | Description                                                                                                                                                                            | | ||||||
|  | |----------|----------|------------------|-------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ||||||
|  | | `action` | ✔️       | *string*         | `broadcast`             | Action type (**must be `broadcast`**)                                                                                                                                                  | | ||||||
|  | | `label`  | ✔️       | *string*         | `Turn on light`         | Label of the action button in the notification                                                                                                                                         | | ||||||
|  | | `intent` | -️       | *string*         | `com.example.AN_INTENT` | Android intent name, **default is `io.heckel.ntfy.USER_ACTION`**                                                                                                                       | | ||||||
|  | | `extras` | -️       | *map of strings* | *see above*             | Android intent extras. Currently, only string extras are supported. When publishing as JSON, extras are passed as a map. When the simple format is used, use `extras.<param>=<value>`. | | ||||||
| 
 | 
 | ||||||
| ### Send HTTP request | ### Send HTTP request | ||||||
| The `http` action sends a HTTP POST/GET/PUT request when the action button is tapped. You can use this to trigger REST APIs | The `http` action sends a HTTP POST/GET/PUT request when the action button is tapped. You can use this to trigger REST APIs | ||||||
| for whatever systems you have, e.g. opening the garage door, or turning on/off lights. | for whatever systems you have, e.g. opening the garage door, or turning on/off lights. | ||||||
| 
 | 
 | ||||||
| XXXXXXXXXXXXXXXXXXXXx | Here's an example using the simple format: | ||||||
| 
 | 
 | ||||||
| === "`view` action" | === "Command line (curl)" | ||||||
|     ``` json |     ``` | ||||||
|     {  |     curl \ | ||||||
|       "action": "view",  |         -d "Garage door has been open for 15 minutes. Close it?" \ | ||||||
|       "label": "Open bing.com",  |         -H "Actions: http, Cloor door, https://mygarage.lan/close, headers.Authorization=Bearer zAzsx1sk.." \ | ||||||
|       "url": "https://bing.com" |         ntfy.sh/myhome | ||||||
|     } |  | ||||||
|     ``` |     ``` | ||||||
| 
 | 
 | ||||||
| === "`broadcast` action" | === "ntfy CLI" | ||||||
|     ``` json |     ``` | ||||||
|     {  |     ntfy publish \ | ||||||
|       "action": "broadcast",  |         --actions="http, Cloor door, https://mygarage.lan/close, headers.Authorization=Bearer zAzsx1sk.." \ | ||||||
|       "label": "Send broadcast",  |         myhome \ | ||||||
|       "intent": "io.heckel.ntfy.USER_ACTION", |         "Garage door has been open for 15 minutes. Close it?" | ||||||
|       "extras": { |  | ||||||
|         "param": "this is a param", |  | ||||||
|         "anotherparam": "this is another one" |  | ||||||
|       } |  | ||||||
|     } |  | ||||||
|     ``` |     ``` | ||||||
| 
 | 
 | ||||||
| === "`http` action" | === "HTTP" | ||||||
|     ``` json |     ``` http | ||||||
|  |     POST /myhome HTTP/1.1 | ||||||
|  |     Host: ntfy.sh | ||||||
|  |     Actions: http, Cloor door, https://mygarage.lan/close, headers.Authorization=Bearer zAzsx1sk.. | ||||||
|  | 
 | ||||||
|  |     Garage door has been open for 15 minutes. Close it? | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "JavaScript" | ||||||
|  |     ``` javascript | ||||||
|  |     fetch('https://ntfy.sh/myhome', { | ||||||
|  |         method: 'POST', | ||||||
|  |         body: 'Garage door has been open for 15 minutes. Close it?', | ||||||
|  |         headers: {  | ||||||
|  |             'Actions': 'http, Cloor door, https://mygarage.lan/close, headers.Authorization=Bearer zAzsx1sk..'  | ||||||
|  |         } | ||||||
|  |     }) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "Go" | ||||||
|  |     ``` go | ||||||
|  |     req, _ := http.NewRequest("POST", "https://ntfy.sh/myhome", strings.NewReader("Garage door has been open for 15 minutes. Close it?")) | ||||||
|  |     req.Header.Set("Actions", "http, Cloor door, https://mygarage.lan/close, headers.Authorization=Bearer zAzsx1sk..") | ||||||
|  |     http.DefaultClient.Do(req) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "PowerShell" | ||||||
|  |     ``` powershell | ||||||
|  |     $uri = "https://ntfy.sh/myhome" | ||||||
|  |     $headers = @{ Actions="http, Cloor door, https://mygarage.lan/close, headers.Authorization=Bearer zAzsx1sk.." } | ||||||
|  |     $body = "Garage door has been open for 15 minutes. Close it?" | ||||||
|  |     Invoke-RestMethod -Method 'Post' -Uri $uri -Headers $headers -Body $body -UseBasicParsing | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "Python" | ||||||
|  |     ``` python | ||||||
|  |     requests.post("https://ntfy.sh/myhome", | ||||||
|  |         data="Garage door has been open for 15 minutes. Close it?", | ||||||
|  |         headers={ "Actions": "http, Cloor door, https://mygarage.lan/close, headers.Authorization=Bearer zAzsx1sk.." }) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "PHP" | ||||||
|  |     ``` php-inline | ||||||
|  |     file_get_contents('https://ntfy.sh/reddit_alerts', false, stream_context_create([ | ||||||
|  |         'http' => [ | ||||||
|  |             'method' => 'POST', | ||||||
|  |             'header' => | ||||||
|  |                 "Content-Type: text/plain\r\n" . | ||||||
|  |                 "Actions: http, Cloor door, https://mygarage.lan/close, headers.Authorization=Bearer zAzsx1sk..", | ||||||
|  |             'content' => 'Garage door has been open for 15 minutes. Close it?' | ||||||
|  |         ] | ||||||
|  |     ])); | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | And the same example using [JSON publishing](#publish-as-json): | ||||||
|  | 
 | ||||||
|  | === "Command line (curl)" | ||||||
|  |     ``` | ||||||
|  |     curl ntfy.sh \ | ||||||
|  |       -d '{ | ||||||
|  |         "topic": "myhome", | ||||||
|  |         "message": "Garage door has been open for 15 minutes. Close it?", | ||||||
|  |         "actions": [ | ||||||
|           { |           { | ||||||
|             "action": "http", |             "action": "http", | ||||||
|       "label": "Take picture",  |             "label": "Close door", | ||||||
|       "method": "POST", |             "url": "https://mygarage.lan/close", | ||||||
|       "url": "https://homecam.lan/capture", |  | ||||||
|             "headers": { |             "headers": { | ||||||
|         "Authorization": "..." |                 "Authorization": "Bearer zAzsx1sk.." | ||||||
|       }, |  | ||||||
|       "body": "this is a message" |  | ||||||
|             } |             } | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |       }' | ||||||
|     ``` |     ``` | ||||||
| 
 | 
 | ||||||
| Examples: | === "ntfy CLI" | ||||||
| 
 |  | ||||||
| === "Open a website" |  | ||||||
|     ``` json |  | ||||||
|     {  |  | ||||||
|       "action": "view",  |  | ||||||
|       "label": "Open bing.com",  |  | ||||||
|       "url": "https://bing.com" |  | ||||||
|     } |  | ||||||
|     ``` |     ``` | ||||||
| 
 |     ntfy publish \ | ||||||
| === "Open location in Google Maps" |         --actions '[ | ||||||
|     ``` json |  | ||||||
|     {  |  | ||||||
|       "action": "view",  |  | ||||||
|       "label": "Show map",  |  | ||||||
|       "url": "geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California" |  | ||||||
|     } |  | ||||||
|     ``` |  | ||||||
| 
 |  | ||||||
| === "Open a ntfy topic (deep link)" |  | ||||||
|     ``` json |  | ||||||
|     { |  | ||||||
|       "action": "view", |  | ||||||
|       "label": "Show stats", |  | ||||||
|       "url": "ntfy://ntfy.sh/stats" |  | ||||||
|     } |  | ||||||
|     ``` |  | ||||||
| 
 |  | ||||||
| === "Send broadcast" |  | ||||||
|     ``` json |  | ||||||
|     { |  | ||||||
|       "action": "broadcast", |  | ||||||
|       "label": "Send broadcast", |  | ||||||
|       "intent": "my.custom.intent", |  | ||||||
|       "extras": { |  | ||||||
|         "message": "whats up, hello" |  | ||||||
|       } |  | ||||||
|     }   |  | ||||||
|     ``` |  | ||||||
| 
 |  | ||||||
| === "Send a ntfy message" |  | ||||||
|     ``` json |  | ||||||
|             { |             { | ||||||
|               "action": "http", |               "action": "http", | ||||||
|       "label": "Send message",  |               "label": "Close door", | ||||||
|       "method": "POST", |               "url": "https://mygarage.lan/close", | ||||||
|       "url": "http://ntfy.example.com/mytopic", |  | ||||||
|               "headers": { |               "headers": { | ||||||
|         "Title": "another message", |                 "Authorization": "Bearer zAzsx1sk.." | ||||||
|         "Tags": "tag1, tag2" |               } | ||||||
|       }, |             } | ||||||
|       "body": "this is a message" |         ]' \ | ||||||
|  |         myhome \ | ||||||
|  |         "Garage door has been open for 15 minutes. Close it?" | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "HTTP" | ||||||
|  |     ``` http | ||||||
|  |     POST / HTTP/1.1 | ||||||
|  |     Host: ntfy.sh | ||||||
|  | 
 | ||||||
|  |     { | ||||||
|  |         "topic": "myhome", | ||||||
|  |         "message": "Garage door has been open for 15 minutes. Close it?", | ||||||
|  |         "actions": [ | ||||||
|  |           { | ||||||
|  |             "action": "http", | ||||||
|  |             "label": "Close door", | ||||||
|  |             "url": "https://mygarage.lan/close", | ||||||
|  |             "headers": { | ||||||
|  |               "Authorization": "Bearer zAzsx1sk.." | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|     } |     } | ||||||
|     ``` |     ``` | ||||||
| 
 | 
 | ||||||
|  | === "JavaScript" | ||||||
|  |     ``` javascript | ||||||
|  |     fetch('https://ntfy.sh', { | ||||||
|  |         method: 'POST', | ||||||
|  |         body: JSON.stringify({ | ||||||
|  |             topic: "myhome", | ||||||
|  |             message": "Garage door has been open for 15 minutes. Close it?", | ||||||
|  |             actions: [ | ||||||
|  |               { | ||||||
|  |                 "action": "http", | ||||||
|  |                 "label": "Close door", | ||||||
|  |                 "url": "https://mygarage.lan/close", | ||||||
|  |                 "headers": { | ||||||
|  |                   "Authorization": "Bearer zAzsx1sk.." | ||||||
|  |                 } | ||||||
|  |               } | ||||||
|  |             ] | ||||||
|  |         }) | ||||||
|  |     }) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "Go" | ||||||
|  |     ``` go | ||||||
|  |     // You should probably use json.Marshal() instead and make a proper struct, | ||||||
|  |     // but for the sake of the example, this is easier. | ||||||
|  |      | ||||||
|  |     body := `{ | ||||||
|  |         "topic": "myhome", | ||||||
|  |         "message": "Garage door has been open for 15 minutes. Close it?", | ||||||
|  |         "actions": [ | ||||||
|  |           { | ||||||
|  |             "action": "http", | ||||||
|  |             "label": "Close door", | ||||||
|  |             "url": "https://mygarage.lan/close", | ||||||
|  |             "headers": { | ||||||
|  |               "Authorization": "Bearer zAzsx1sk.." | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         ] | ||||||
|  |     }` | ||||||
|  |     req, _ := http.NewRequest("POST", "https://ntfy.sh/", strings.NewReader(body)) | ||||||
|  |     http.DefaultClient.Do(req) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "PowerShell" | ||||||
|  |     ``` powershell | ||||||
|  |     $uri = "https://ntfy.sh" | ||||||
|  |     $body = @{ | ||||||
|  |         "topic"="myhome" | ||||||
|  |         "message"="Garage door has been open for 15 minutes. Close it?" | ||||||
|  |         "actions"=@( | ||||||
|  |             @{ | ||||||
|  |                 "action"="http", | ||||||
|  |                 "label"="Close door" | ||||||
|  |                 "url"="https://mygarage.lan/close" | ||||||
|  |                 "headers"=@{ | ||||||
|  |                   "Authorization"="Bearer zAzsx1sk.." | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |           } | ||||||
|  |         ) | ||||||
|  |     } | ConvertTo-Json | ||||||
|  |     Invoke-RestMethod -Method 'Post' -Uri $uri -Body $body -ContentType "application/json" -UseBasicParsing | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "Python" | ||||||
|  |     ``` python | ||||||
|  |     requests.post("https://ntfy.sh/", | ||||||
|  |         data=json.dumps({ | ||||||
|  |             "topic": "myhome", | ||||||
|  |             "message": "Garage door has been open for 15 minutes. Close it?", | ||||||
|  |             "actions": [ | ||||||
|  |                 { | ||||||
|  |                   "action": "http", | ||||||
|  |                   "label": "Close door", | ||||||
|  |                   "url": "https://mygarage.lan/close", | ||||||
|  |                   "headers": { | ||||||
|  |                     "Authorization": "Bearer zAzsx1sk.." | ||||||
|  |                   } | ||||||
|  |                 } | ||||||
|  |             ] | ||||||
|  |         }) | ||||||
|  |     ) | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | === "PHP" | ||||||
|  |     ``` php-inline | ||||||
|  |     file_get_contents('https://ntfy.sh/', false, stream_context_create([ | ||||||
|  |         'http' => [ | ||||||
|  |             'method' => 'POST', | ||||||
|  |             'header' => "Content-Type: application/json", | ||||||
|  |             'content' => json_encode([ | ||||||
|  |                 "topic": "myhome", | ||||||
|  |                 "message": "Garage door has been open for 15 minutes. Close it?", | ||||||
|  |                 "actions": [ | ||||||
|  |                     [ | ||||||
|  |                         "action": "http", | ||||||
|  |                         "label": "Close door", | ||||||
|  |                         "url": "https://mygarage.lan/close", | ||||||
|  |                         "headers": [ | ||||||
|  |                             "Authorization": "Bearer zAzsx1sk.." | ||||||
|  |                          ] | ||||||
|  |                     ] | ||||||
|  |                 ] | ||||||
|  |             ]) | ||||||
|  |         ] | ||||||
|  |     ])); | ||||||
|  |     ``` | ||||||
|  | 
 | ||||||
|  | The `http` action supports the following fields: | ||||||
|  | 
 | ||||||
|  | | Field     | Required | Type               | Example                   | Description                                                                                                                                             | | ||||||
|  | |-----------|----------|--------------------|---------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------| | ||||||
|  | | `action`  | ✔️       | *string*           | `http`                    | Action type (**must be `http`**)                                                                                                                        | | ||||||
|  | | `label`   | ✔️       | *string*           | `Open garage door`        | Label of the action button in the notification                                                                                                          | | ||||||
|  | | `url`     | ✔️       | *string*           | `https://ntfy.sh/mytopic` | URL to which the HTTP request will be sent                                                                                                              | | ||||||
|  | | `method`  | -️       | *GET/POST/PUT/...* | `GET`                     | HTTP method to use for request, **default is POST (!)**                                                                                                 | | ||||||
|  | | `headers` | -️       | *map of strings*   | *see above*               | HTTP headers to pass in request. When publishing as JSON, headers are passed as a map. When the simple format is used, use `headers.<header1>=<value>`. | | ||||||
|  | | `method`  | -️       | *string*           | `some body, somebody?`    | HTTP body                                                                                                                                               | | ||||||
|  | 
 | ||||||
| ## Click action | ## Click action | ||||||
| You can define which URL to open when a notification is clicked. This may be useful if your notification is related  | You can define which URL to open when a notification is clicked. This may be useful if your notification is related  | ||||||
| to a Zabbix alert or a transaction that you'd like to provide the deep-link for. Tapping the notification will open | to a Zabbix alert or a transaction that you'd like to provide the deep-link for. Tapping the notification will open | ||||||
|  | @ -1257,9 +1877,9 @@ by another app, the responsible app may open. | ||||||
| Examples: | Examples: | ||||||
| 
 | 
 | ||||||
| * `http://` or `https://` will open your browser (or an app if it registered for a URL) | * `http://` or `https://` will open your browser (or an app if it registered for a URL) | ||||||
| * `mailto:` links will open your mail app | * `mailto:` links will open your mail app, e.g. `mailto:phil@example.com` | ||||||
| * `geo:` links will open Google Maps (or your maps application) | * `geo:` links will open Google Maps, e.g. `geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+CA` | ||||||
| * `ntfy://` links will open ntfy (see [ntfy:// links](subscribe/phone.md#ntfy-links)) | * `ntfy://` links will open ntfy (see [ntfy:// links](subscribe/phone.md#ntfy-links)), e.g. `ntfy://ntfy.sh/stats` | ||||||
| * ... | * ... | ||||||
| 
 | 
 | ||||||
| Here's an example that will open Reddit when the notification is clicked: | Here's an example that will open Reddit when the notification is clicked: | ||||||
|  |  | ||||||
							
								
								
									
										27
									
								
								go.mod
									
										
									
									
									
								
							
							
						
						
									
										27
									
								
								go.mod
									
										
									
									
									
								
							|  | @ -4,7 +4,7 @@ go 1.17 | ||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
| 	cloud.google.com/go/firestore v1.6.1 // indirect | 	cloud.google.com/go/firestore v1.6.1 // indirect | ||||||
| 	cloud.google.com/go/storage v1.21.0 // indirect | 	cloud.google.com/go/storage v1.22.0 // indirect | ||||||
| 	firebase.google.com/go v3.13.0+incompatible | 	firebase.google.com/go v3.13.0+incompatible | ||||||
| 	github.com/BurntSushi/toml v1.1.0 // indirect | 	github.com/BurntSushi/toml v1.1.0 // indirect | ||||||
| 	github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect | 	github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect | ||||||
|  | @ -15,20 +15,20 @@ require ( | ||||||
| 	github.com/olebedev/when v0.0.0-20211212231525-59bd4edcf9d6 | 	github.com/olebedev/when v0.0.0-20211212231525-59bd4edcf9d6 | ||||||
| 	github.com/stretchr/testify v1.7.0 | 	github.com/stretchr/testify v1.7.0 | ||||||
| 	github.com/urfave/cli/v2 v2.4.0 | 	github.com/urfave/cli/v2 v2.4.0 | ||||||
| 	golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 | 	golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 | ||||||
| 	golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a // indirect | 	golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 // indirect | ||||||
| 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c | 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c | ||||||
| 	golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 | 	golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 | ||||||
| 	golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 | 	golang.org/x/time v0.0.0-20220411224347-583f2d630306 | ||||||
| 	google.golang.org/api v0.74.0 | 	google.golang.org/api v0.75.0 | ||||||
| 	gopkg.in/yaml.v2 v2.4.0 | 	gopkg.in/yaml.v2 v2.4.0 | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| require github.com/pkg/errors v0.9.1 | require github.com/pkg/errors v0.9.1 | ||||||
| 
 | 
 | ||||||
| require ( | require ( | ||||||
| 	cloud.google.com/go v0.100.2 // indirect | 	cloud.google.com/go v0.101.0 // indirect | ||||||
| 	cloud.google.com/go/compute v1.5.0 // indirect | 	cloud.google.com/go/compute v1.6.0 // indirect | ||||||
| 	cloud.google.com/go/iam v0.3.0 // indirect | 	cloud.google.com/go/iam v0.3.0 // indirect | ||||||
| 	github.com/AlekSi/pointer v1.2.0 // indirect | 	github.com/AlekSi/pointer v1.2.0 // indirect | ||||||
| 	github.com/davecgh/go-spew v1.1.1 // indirect | 	github.com/davecgh/go-spew v1.1.1 // indirect | ||||||
|  | @ -36,16 +36,17 @@ require ( | ||||||
| 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect | 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect | ||||||
| 	github.com/golang/protobuf v1.5.2 // indirect | 	github.com/golang/protobuf v1.5.2 // indirect | ||||||
| 	github.com/google/go-cmp v0.5.7 // indirect | 	github.com/google/go-cmp v0.5.7 // indirect | ||||||
| 	github.com/googleapis/gax-go/v2 v2.2.0 // indirect | 	github.com/googleapis/gax-go/v2 v2.3.0 // indirect | ||||||
|  | 	github.com/googleapis/go-type-adapters v1.0.0 // indirect | ||||||
| 	github.com/pmezard/go-difflib v1.0.0 // indirect | 	github.com/pmezard/go-difflib v1.0.0 // indirect | ||||||
| 	github.com/russross/blackfriday/v2 v2.1.0 // indirect | 	github.com/russross/blackfriday/v2 v2.1.0 // indirect | ||||||
| 	go.opencensus.io v0.23.0 // indirect | 	go.opencensus.io v0.23.0 // indirect | ||||||
| 	golang.org/x/net v0.0.0-20220403103023-749bd193bc2b // indirect | 	golang.org/x/net v0.0.0-20220420153159-1850ba15e1be // indirect | ||||||
| 	golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 // indirect | 	golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect | ||||||
| 	golang.org/x/text v0.3.7 // indirect | 	golang.org/x/text v0.3.7 // indirect | ||||||
| 	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect | 	golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f // indirect | ||||||
| 	google.golang.org/appengine v1.6.7 // indirect | 	google.golang.org/appengine v1.6.7 // indirect | ||||||
| 	google.golang.org/genproto v0.0.0-20220405205423-9d709892a2bf // indirect | 	google.golang.org/genproto v0.0.0-20220420195807-44278fea765b // indirect | ||||||
| 	google.golang.org/grpc v1.45.0 // indirect | 	google.golang.org/grpc v1.45.0 // indirect | ||||||
| 	google.golang.org/protobuf v1.28.0 // indirect | 	google.golang.org/protobuf v1.28.0 // indirect | ||||||
| 	gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect | 	gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect | ||||||
|  |  | ||||||
							
								
								
									
										35
									
								
								go.sum
									
										
									
									
									
								
							
							
						
						
									
										35
									
								
								go.sum
									
										
									
									
									
								
							|  | @ -29,6 +29,8 @@ cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2Z | ||||||
| cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= | cloud.google.com/go v0.100.1/go.mod h1:fs4QogzfH5n2pBXBP9vRiU+eCny7lD2vmFZy79Iuw1U= | ||||||
| cloud.google.com/go v0.100.2 h1:t9Iw5QH5v4XtlEQaCtUY7x6sCABps8sW0acw7e2WQ6Y= | cloud.google.com/go v0.100.2 h1:t9Iw5QH5v4XtlEQaCtUY7x6sCABps8sW0acw7e2WQ6Y= | ||||||
| cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= | cloud.google.com/go v0.100.2/go.mod h1:4Xra9TjzAeYHrl5+oeLlzbM2k3mjVhZh4UqTZ//w99A= | ||||||
|  | cloud.google.com/go v0.101.0 h1:g+LL+JvpvdyGtcaD2xw2mSByE/6F9s471eJSoaysM84= | ||||||
|  | cloud.google.com/go v0.101.0/go.mod h1:hEiddgDb77jDQ+I80tURYNJEnuwPzFU8awCFFRLKjW0= | ||||||
| cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= | cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= | ||||||
| cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= | cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= | ||||||
| cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= | cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc= | ||||||
|  | @ -40,6 +42,8 @@ cloud.google.com/go/compute v1.2.0/go.mod h1:xlogom/6gr8RJGBe7nT2eGsQYAFUbbv8dbC | ||||||
| cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= | cloud.google.com/go/compute v1.3.0/go.mod h1:cCZiE1NHEtai4wiufUhW8I8S1JKkAnhnQJWM7YD99wM= | ||||||
| cloud.google.com/go/compute v1.5.0 h1:b1zWmYuuHz7gO9kDcM/EpHGr06UgsYNRpNJzI2kFiLM= | cloud.google.com/go/compute v1.5.0 h1:b1zWmYuuHz7gO9kDcM/EpHGr06UgsYNRpNJzI2kFiLM= | ||||||
| cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= | cloud.google.com/go/compute v1.5.0/go.mod h1:9SMHyhJlzhlkJqrPAc839t2BZFTSk6Jdj6mkzQJeu0M= | ||||||
|  | cloud.google.com/go/compute v1.6.0 h1:XdQIN5mdPTSBVwSIVDuY5e8ZzVAccsHvD3qTEz4zIps= | ||||||
|  | cloud.google.com/go/compute v1.6.0/go.mod h1:T29tfhtVbq1wvAPo0E3+7vhgmkOYeXjhFvz/FMzPu0s= | ||||||
| cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= | cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= | ||||||
| cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= | cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk= | ||||||
| cloud.google.com/go/firestore v1.6.1 h1:8rBq3zRjnHx8UtBvaOWqBB1xq9jH6/wltfQLlTMh2Fw= | cloud.google.com/go/firestore v1.6.1 h1:8rBq3zRjnHx8UtBvaOWqBB1xq9jH6/wltfQLlTMh2Fw= | ||||||
|  | @ -58,6 +62,8 @@ cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RX | ||||||
| cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= | cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= | ||||||
| cloud.google.com/go/storage v1.21.0 h1:HwnT2u2D309SFDHQII6m18HlrCi3jAXhUMTLOWXYH14= | cloud.google.com/go/storage v1.21.0 h1:HwnT2u2D309SFDHQII6m18HlrCi3jAXhUMTLOWXYH14= | ||||||
| cloud.google.com/go/storage v1.21.0/go.mod h1:XmRlxkgPjlBONznT2dDUU/5XlpU2OjMnKuqnZI01LAA= | cloud.google.com/go/storage v1.21.0/go.mod h1:XmRlxkgPjlBONznT2dDUU/5XlpU2OjMnKuqnZI01LAA= | ||||||
|  | cloud.google.com/go/storage v1.22.0 h1:NUV0NNp9nkBuW66BFRLuMgldN60C57ET3dhbwLIYio8= | ||||||
|  | cloud.google.com/go/storage v1.22.0/go.mod h1:GbaLEoMqbVm6sx3Z0R++gSiBlgMv6yUi2q1DeGFKQgE= | ||||||
| dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= | dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= | ||||||
| firebase.google.com/go v3.13.0+incompatible h1:3TdYC3DDi6aHn20qoRkxwGqNgdjtblwVAyRLQwGn/+4= | firebase.google.com/go v3.13.0+incompatible h1:3TdYC3DDi6aHn20qoRkxwGqNgdjtblwVAyRLQwGn/+4= | ||||||
| firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs= | firebase.google.com/go v3.13.0+incompatible/go.mod h1:xlah6XbEyW6tbfSklcfe5FHJIwjt8toICdV5Wh9ptHs= | ||||||
|  | @ -166,6 +172,8 @@ github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIG | ||||||
| github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= | github.com/google/martian/v3 v3.1.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0= | ||||||
| github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ= | github.com/google/martian/v3 v3.2.1 h1:d8MncMlErDFTwQGBK1xhv026j9kqhvw1Qv9IbWT1VLQ= | ||||||
| github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= | github.com/google/martian/v3 v3.2.1/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= | ||||||
|  | github.com/google/martian/v3 v3.3.2 h1:IqNFLAmvJOgVlpdEBiQbDc2EwKW77amAycfTuWKdfvw= | ||||||
|  | github.com/google/martian/v3 v3.3.2/go.mod h1:oBOf6HBosgwRXnUGWUB05QECsc6uvmMiJ3+6W4l/CUk= | ||||||
| github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= | github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= | ||||||
| github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= | github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= | ||||||
| github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= | github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= | ||||||
|  | @ -188,6 +196,10 @@ github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pf | ||||||
| github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= | github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM= | ||||||
| github.com/googleapis/gax-go/v2 v2.2.0 h1:s7jOdKSaksJVOxE0Y/S32otcfiP+UQ0cL8/GTKaONwE= | github.com/googleapis/gax-go/v2 v2.2.0 h1:s7jOdKSaksJVOxE0Y/S32otcfiP+UQ0cL8/GTKaONwE= | ||||||
| github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= | github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/OthfcblKl4IGNaM= | ||||||
|  | github.com/googleapis/gax-go/v2 v2.3.0 h1:nRJtk3y8Fm770D42QV6T90ZnvFZyk7agSo3Q+Z9p3WI= | ||||||
|  | github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM= | ||||||
|  | github.com/googleapis/go-type-adapters v1.0.0 h1:9XdMn+d/G57qq1s8dNc5IesGCXHf6V2HZ2JwRxfA2tA= | ||||||
|  | github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4= | ||||||
| github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= | github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= | ||||||
| github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= | github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= | ||||||
| github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= | github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw= | ||||||
|  | @ -248,6 +260,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U | ||||||
| golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||||||
| golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o= | golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29 h1:tkVvjkPTB7pnW3jnid7kNyAMPVWllTNOf/qKDze4p9o= | ||||||
| golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | golang.org/x/crypto v0.0.0-20220331220935-ae2d96664a29/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | ||||||
|  | golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 h1:kUhD7nTDoI3fVd9G4ORWrbV5NY0liEs/Jg2pv5f+bBA= | ||||||
|  | golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= | ||||||
| golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | ||||||
| golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | ||||||
| golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= | golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= | ||||||
|  | @ -325,6 +339,9 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su | ||||||
| golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= | golang.org/x/net v0.0.0-20220325170049-de3da57026de/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= | ||||||
| golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0= | golang.org/x/net v0.0.0-20220403103023-749bd193bc2b h1:vI32FkLJNAWtGD4BwkThwEy6XS7ZLLMHkSkYfF8M0W0= | ||||||
| golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= | golang.org/x/net v0.0.0-20220403103023-749bd193bc2b/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= | ||||||
|  | golang.org/x/net v0.0.0-20220412020605-290c469a71a5/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= | ||||||
|  | golang.org/x/net v0.0.0-20220420153159-1850ba15e1be h1:yx80W7nvY5ySWpaU8UWaj5o9e23YgO9BRhQol7Lc+JI= | ||||||
|  | golang.org/x/net v0.0.0-20220420153159-1850ba15e1be/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= | ||||||
| golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | ||||||
| golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | ||||||
| golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= | ||||||
|  | @ -345,6 +362,8 @@ golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ | ||||||
| golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= | golang.org/x/oauth2 v0.0.0-20220223155221-ee480838109b/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= | ||||||
| golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM= | golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a h1:qfl7ob3DIEs3Ml9oLuPwY2N04gymzAW04WsUQHIClgM= | ||||||
| golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= | golang.org/x/oauth2 v0.0.0-20220309155454-6242fa91716a/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= | ||||||
|  | golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5 h1:OSnWWcOd/CtWQC2cYSBgbTSJv3ciqd8r54ySIW2y3RE= | ||||||
|  | golang.org/x/oauth2 v0.0.0-20220411215720-9780585627b5/go.mod h1:DAh4E804XQdzx2j+YRIaUnCqCV2RuMz24cGBJ5QYIrc= | ||||||
| golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
| golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||||||
|  | @ -414,9 +433,13 @@ golang.org/x/sys v0.0.0-20220227234510-4e6760a101f9/go.mod h1:oPkhp1MJrh7nUepCBc | ||||||
| golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 h1:QyVthZKMsyaQwBTJE04jdNN0Pp5Fn9Qga0mrgxyERQM= | golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12 h1:QyVthZKMsyaQwBTJE04jdNN0Pp5Fn9Qga0mrgxyERQM= | ||||||
| golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.0.0-20220406163625-3f8b81556e12/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
|  | golang.org/x/sys v0.0.0-20220412211240-33da011f77ad h1:ntjMns5wyP/fN65tdBD4g8J5w8n015+iIIs9rtjXkY0= | ||||||
|  | golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||||
| golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= | ||||||
| golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= | ||||||
| golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||||||
|  | golang.org/x/term v0.0.0-20220411215600-e5f449aeb171 h1:EH1Deb8WZJ0xc0WK//leUHXcX9aLE5SymusoTmMZye8= | ||||||
|  | golang.org/x/term v0.0.0-20220411215600-e5f449aeb171/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= | ||||||
| golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||||
| golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||||
| golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||||||
|  | @ -432,6 +455,8 @@ golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxb | ||||||
| golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||||
| golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs= | golang.org/x/time v0.0.0-20220224211638-0e9765cccd65 h1:M73Iuj3xbbb9Uk1DYhzydthsj6oOd6l9bpuFcNoUvTs= | ||||||
| golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | golang.org/x/time v0.0.0-20220224211638-0e9765cccd65/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||||
|  | golang.org/x/time v0.0.0-20220411224347-583f2d630306 h1:+gHMid33q6pen7kv9xvT+JRinntgeXO2AeZVd0AWD3w= | ||||||
|  | golang.org/x/time v0.0.0-20220411224347-583f2d630306/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | ||||||
| golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||||
| golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||||||
| golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= | golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= | ||||||
|  | @ -488,6 +513,8 @@ golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8T | ||||||
| golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
| golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= | ||||||
| golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
|  | golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f h1:GGU+dLjvlC3qDwqYgL6UgRmHXhOOgns0bZu2Ty5mm6U= | ||||||
|  | golang.org/x/xerrors v0.0.0-20220411194840-2f41105eb62f/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||||||
| google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= | google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= | ||||||
| google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= | google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= | ||||||
| google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= | google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= | ||||||
|  | @ -528,6 +555,8 @@ google.golang.org/api v0.70.0/go.mod h1:Bs4ZM2HGifEvXwd50TtW70ovgJffJYw2oRCOFU/S | ||||||
| google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= | google.golang.org/api v0.71.0/go.mod h1:4PyU6e6JogV1f9eA4voyrTY2batOLdgZ5qZ5HOCc4j8= | ||||||
| google.golang.org/api v0.74.0 h1:ExR2D+5TYIrMphWgs5JCgwRhEDlPDXXrLwHHMgPHTXE= | google.golang.org/api v0.74.0 h1:ExR2D+5TYIrMphWgs5JCgwRhEDlPDXXrLwHHMgPHTXE= | ||||||
| google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= | google.golang.org/api v0.74.0/go.mod h1:ZpfMZOVRMywNyvJFeqL9HRWBgAuRfSjJFpe9QtRRyDs= | ||||||
|  | google.golang.org/api v0.75.0 h1:0AYh/ae6l9TDUvIQrDw5QRpM100P6oHgD+o3dYHMzJg= | ||||||
|  | google.golang.org/api v0.75.0/go.mod h1:pU9QmyHLnzlpar1Mjt4IbapUCy8J+6HD6GeELN69ljA= | ||||||
| google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | ||||||
| google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | ||||||
| google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | ||||||
|  | @ -575,6 +604,7 @@ google.golang.org/genproto v0.0.0-20210222152913-aa3ee6e6a81c/go.mod h1:FWY/as6D | ||||||
| google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= | google.golang.org/genproto v0.0.0-20210303154014-9728d6b83eeb/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= | ||||||
| google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= | google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= | ||||||
| google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= | google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= | ||||||
|  | google.golang.org/genproto v0.0.0-20210329143202-679c6ae281ee/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= | ||||||
| google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= | google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A= | ||||||
| google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= | google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= | ||||||
| google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= | google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= | ||||||
|  | @ -613,6 +643,11 @@ google.golang.org/genproto v0.0.0-20220310185008-1973136f34c6/go.mod h1:kGP+zUP2 | ||||||
| google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= | google.golang.org/genproto v0.0.0-20220324131243-acbaeb5b85eb/go.mod h1:hAL49I2IFola2sVEjAn7MEwsja0xp51I0tlGAf9hz4E= | ||||||
| google.golang.org/genproto v0.0.0-20220405205423-9d709892a2bf h1:JTjwKJX9erVpsw17w+OIPP7iAgEkN/r8urhWSunEDTs= | google.golang.org/genproto v0.0.0-20220405205423-9d709892a2bf h1:JTjwKJX9erVpsw17w+OIPP7iAgEkN/r8urhWSunEDTs= | ||||||
| google.golang.org/genproto v0.0.0-20220405205423-9d709892a2bf/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= | google.golang.org/genproto v0.0.0-20220405205423-9d709892a2bf/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= | ||||||
|  | google.golang.org/genproto v0.0.0-20220407144326-9054f6ed7bac/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= | ||||||
|  | google.golang.org/genproto v0.0.0-20220413183235-5e96e2839df9/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= | ||||||
|  | google.golang.org/genproto v0.0.0-20220414192740-2d67ff6cf2b4/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= | ||||||
|  | google.golang.org/genproto v0.0.0-20220420195807-44278fea765b h1:5zvsLqz9A1TKTeI6AhjJH/Vkaw0GGBs+D3GkvUUqNO0= | ||||||
|  | google.golang.org/genproto v0.0.0-20220420195807-44278fea765b/go.mod h1:8w6bsBMX6yCPbAVTeqQHvzxW0EIFigd5lZyahWgyfDo= | ||||||
| google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= | google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= | ||||||
| google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= | google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= | ||||||
| google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= | google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= | ||||||
|  |  | ||||||
|  | @ -90,7 +90,7 @@ const ( | ||||||
| 
 | 
 | ||||||
| // Schema management queries | // Schema management queries | ||||||
| const ( | const ( | ||||||
| 	currentSchemaVersion          = 5 | 	currentSchemaVersion          = 6 | ||||||
| 	createSchemaVersionTableQuery = ` | 	createSchemaVersionTableQuery = ` | ||||||
| 		CREATE TABLE IF NOT EXISTS schemaVersion ( | 		CREATE TABLE IF NOT EXISTS schemaVersion ( | ||||||
| 			id INT PRIMARY KEY, | 			id INT PRIMARY KEY, | ||||||
|  | @ -168,6 +168,11 @@ const ( | ||||||
| 		ALTER TABLE messages_new RENAME TO messages; | 		ALTER TABLE messages_new RENAME TO messages; | ||||||
| 		COMMIT; | 		COMMIT; | ||||||
| 	` | 	` | ||||||
|  | 
 | ||||||
|  | 	// 5 -> 6 | ||||||
|  | 	migrate5To6AlterMessagesTableQuery = ` | ||||||
|  | 		ALTER TABLE messages ADD COLUMN actions TEXT NOT NULL DEFAULT(''); | ||||||
|  | 	` | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| type messageCache struct { | type messageCache struct { | ||||||
|  | @ -509,6 +514,8 @@ func setupCacheDB(db *sql.DB) error { | ||||||
| 		return migrateFrom3(db) | 		return migrateFrom3(db) | ||||||
| 	} else if schemaVersion == 4 { | 	} else if schemaVersion == 4 { | ||||||
| 		return migrateFrom4(db) | 		return migrateFrom4(db) | ||||||
|  | 	} else if schemaVersion == 5 { | ||||||
|  | 		return migrateFrom5(db) | ||||||
| 	} | 	} | ||||||
| 	return fmt.Errorf("unexpected schema version found: %d", schemaVersion) | 	return fmt.Errorf("unexpected schema version found: %d", schemaVersion) | ||||||
| } | } | ||||||
|  | @ -581,5 +588,16 @@ func migrateFrom4(db *sql.DB) error { | ||||||
| 	if _, err := db.Exec(updateSchemaVersion, 5); err != nil { | 	if _, err := db.Exec(updateSchemaVersion, 5); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
|  | 	return migrateFrom5(db) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | func migrateFrom5(db *sql.DB) error { | ||||||
|  | 	log.Print("Migrating cache database schema: from 5 to 6") | ||||||
|  | 	if _, err := db.Exec(migrate5To6AlterMessagesTableQuery); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	if _, err := db.Exec(updateSchemaVersion, 6); err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
| 	return nil // Update this when a new version is added | 	return nil // Update this when a new version is added | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -3,7 +3,6 @@ package server | ||||||
| import ( | import ( | ||||||
| 	"encoding/json" | 	"encoding/json" | ||||||
| 	"fmt" | 	"fmt" | ||||||
| 	"github.com/pkg/errors" |  | ||||||
| 	"heckel.io/ntfy/util" | 	"heckel.io/ntfy/util" | ||||||
| 	"net/http" | 	"net/http" | ||||||
| 	"strings" | 	"strings" | ||||||
|  | @ -96,7 +95,10 @@ func parseActionsFromSimple(s string) ([]*action, error) { | ||||||
| 	actions := make([]*action, 0) | 	actions := make([]*action, 0) | ||||||
| 	rawActions := util.SplitNoEmpty(s, ";") | 	rawActions := util.SplitNoEmpty(s, ";") | ||||||
| 	for _, rawAction := range rawActions { | 	for _, rawAction := range rawActions { | ||||||
| 		newAction := &action{} | 		newAction := &action{ | ||||||
|  | 			Headers: make(map[string]string), | ||||||
|  | 			Extras:  make(map[string]string), | ||||||
|  | 		} | ||||||
| 		parts := util.SplitNoEmpty(rawAction, ",") | 		parts := util.SplitNoEmpty(rawAction, ",") | ||||||
| 		if len(parts) < 3 { | 		if len(parts) < 3 { | ||||||
| 			return nil, fmt.Errorf("cannot parse action: action requires at least keys 'action', 'label' and one parameter: %s", rawAction) | 			return nil, fmt.Errorf("cannot parse action: action requires at least keys 'action', 'label' and one parameter: %s", rawAction) | ||||||
|  | @ -109,6 +111,10 @@ func parseActionsFromSimple(s string) ([]*action, error) { | ||||||
| 				newAction.Label = value | 				newAction.Label = value | ||||||
| 			} else if key == "" && util.InStringList([]string{"view", "http"}, newAction.Action) && i == 2 { | 			} else if key == "" && util.InStringList([]string{"view", "http"}, newAction.Action) && i == 2 { | ||||||
| 				newAction.URL = value | 				newAction.URL = value | ||||||
|  | 			} else if strings.HasPrefix(key, "headers.") { | ||||||
|  | 				newAction.Headers[strings.TrimPrefix(key, "headers.")] = value | ||||||
|  | 			} else if strings.HasPrefix(key, "extras.") { | ||||||
|  | 				newAction.Extras[strings.TrimPrefix(key, "extras.")] = value | ||||||
| 			} else if key != "" { | 			} else if key != "" { | ||||||
| 				switch strings.ToLower(key) { | 				switch strings.ToLower(key) { | ||||||
| 				case "action": | 				case "action": | ||||||
|  | @ -122,10 +128,10 @@ func parseActionsFromSimple(s string) ([]*action, error) { | ||||||
| 				case "body": | 				case "body": | ||||||
| 					newAction.Body = value | 					newAction.Body = value | ||||||
| 				default: | 				default: | ||||||
| 					return nil, errors.Errorf("cannot parse action: key '%s' not supported, please use JSON format instead", part) | 					return nil, fmt.Errorf("cannot parse action: key '%s' not supported, please use JSON format instead", part) | ||||||
| 				} | 				} | ||||||
| 			} else { | 			} else { | ||||||
| 				return nil, errors.Errorf("cannot parse action: unknown phrase '%s'", part) | 				return nil, fmt.Errorf("cannot parse action: unknown phrase '%s'", part) | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| 		actions = append(actions, newAction) | 		actions = append(actions, newAction) | ||||||
|  |  | ||||||
|  | @ -61,4 +61,22 @@ func TestParseActions(t *testing.T) { | ||||||
| 	require.Equal(t, "https://door.lan/open", actions[0].URL) | 	require.Equal(t, "https://door.lan/open", actions[0].URL) | ||||||
| 	require.Equal(t, "PUT", actions[0].Method) | 	require.Equal(t, "PUT", actions[0].Method) | ||||||
| 	require.Equal(t, "this is a body", actions[0].Body) | 	require.Equal(t, "this is a body", actions[0].Body) | ||||||
|  | 
 | ||||||
|  | 	actions, err = parseActions("action=broadcast, label=Do a thing, extras.command=some command, extras.some_param=a parameter") | ||||||
|  | 	require.Nil(t, err) | ||||||
|  | 	require.Equal(t, 1, len(actions)) | ||||||
|  | 	require.Equal(t, "broadcast", actions[0].Action) | ||||||
|  | 	require.Equal(t, "Do a thing", actions[0].Label) | ||||||
|  | 	require.Equal(t, 2, len(actions[0].Extras)) | ||||||
|  | 	require.Equal(t, "some command", actions[0].Extras["command"]) | ||||||
|  | 	require.Equal(t, "a parameter", actions[0].Extras["some_param"]) | ||||||
|  | 
 | ||||||
|  | 	actions, err = parseActions("action=http, label=Send request, url=http://example.com, method=GET, headers.Content-Type=application/json, headers.Authorization=Basic sdasffsf") | ||||||
|  | 	require.Nil(t, err) | ||||||
|  | 	require.Equal(t, 1, len(actions)) | ||||||
|  | 	require.Equal(t, "http", actions[0].Action) | ||||||
|  | 	require.Equal(t, "Send request", actions[0].Label) | ||||||
|  | 	require.Equal(t, 2, len(actions[0].Headers)) | ||||||
|  | 	require.Equal(t, "application/json", actions[0].Headers["Content-Type"]) | ||||||
|  | 	require.Equal(t, "Basic sdasffsf", actions[0].Headers["Authorization"]) | ||||||
| } | } | ||||||
|  |  | ||||||
							
								
								
									
										1869
									
								
								web/package-lock.json
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										1869
									
								
								web/package-lock.json
									
										
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue