mirror of
https://github.com/caronc/apprise-api.git
synced 2024-12-04 22:10:42 +01:00
Attachment Support Added (#118)
This commit is contained in:
parent
a5f8767094
commit
86c9f16d69
@ -11,6 +11,7 @@ LABEL maintainer="Chris-Caron"
|
||||
ENV PYTHONDONTWRITEBYTECODE 1
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
ENV APPRISE_CONFIG_DIR /config
|
||||
ENV APPRISE_ATTACH_DIR /attach
|
||||
ENV CRYPTOGRAPHY_DONT_BUILD_RUST=1
|
||||
|
||||
# Install nginx and supervisord
|
||||
@ -38,11 +39,12 @@ RUN apt-get remove -y -qq build-essential libffi-dev libssl-dev python-dev && \
|
||||
|
||||
# Configuration Permissions (to run nginx as a non-root user)
|
||||
RUN umask 0002 && \
|
||||
mkdir -p /config /run/apprise && \
|
||||
chown www-data:www-data -R /run/apprise /var/lib/nginx /config
|
||||
mkdir -p /attach /config /run/apprise && \
|
||||
chown www-data:www-data -R /run/apprise /var/lib/nginx /attach /config
|
||||
|
||||
# Handle running as a non-root user (www-data is id/gid 33)
|
||||
USER www-data
|
||||
VOLUME /config
|
||||
VOLUME /attach
|
||||
EXPOSE 8000
|
||||
CMD ["/usr/bin/supervisord", "-c", "/opt/apprise/webapp/etc/supervisord.conf"]
|
||||
|
28
README.md
28
README.md
@ -111,6 +111,25 @@ Here is a *stateless* example of how one might send a notification (using `/noti
|
||||
curl -X POST -d 'urls=mailto://user:pass@gmail.com&body=test message' \
|
||||
http://localhost:8000/notify
|
||||
|
||||
# Send a notification with an attachment
|
||||
curl -X POST \
|
||||
-F 'urls=mailto://user:pass@gmail.com' \
|
||||
-F 'body=test message' \
|
||||
-F attach=@Screenshot-1.png \
|
||||
http://localhost:8000/notify
|
||||
|
||||
# Send multiple attachments; just make sure the attach keyword is unique:
|
||||
curl -X POST \
|
||||
-F 'urls=mailto://user:pass@gmail.com' \
|
||||
-F 'body=test message' \
|
||||
-F attach1=@Screenshot-1.png \
|
||||
-F attach2=@/my/path/to/Apprise.doc \
|
||||
http://localhost:8000/notify
|
||||
|
||||
curl -X POST -d 'urls=mailto://user:pass@gmail.com&body=test message' \
|
||||
-F @/path/to/your/attachment \
|
||||
http://localhost:8000/notify
|
||||
|
||||
# Send your notifications directly using JSON
|
||||
curl -X POST -d '{"urls": "mailto://user:pass@gmail.com", "body":"test message"}' \
|
||||
-H "Content-Type: application/json" \
|
||||
@ -167,6 +186,14 @@ curl -X POST -d "body=test message" \
|
||||
curl -X POST -d '{"body":"test message"}' \
|
||||
-H "Content-Type: application/json" \
|
||||
http://localhost:8000/notify/abc123
|
||||
|
||||
# Send attachments:
|
||||
curl -X POST \
|
||||
-F 'urls=mailto://user:pass@gmail.com' \
|
||||
-F 'body=test message' \
|
||||
-F attach1=@Screenshot-1.png \
|
||||
-F attach2=@/my/path/to/Apprise.doc \
|
||||
http://localhost:8000/notify/abc123
|
||||
```
|
||||
|
||||
🏷️ You can also leverage _tagging_ which allows you to associate one or more tags with your Apprise URLs. By doing this, notifications only need to be referred to by their easy to remember notify tag name such as `devops`, `admin`, `family`, etc. You can very easily group more than one notification service under the same _tag_ allowing you to notify a group of services at once. This is accomplished through configuration files ([documented here](https://github.com/caronc/apprise/wiki/config)) that can be saved to the persistent storage previously associated with a `{KEY}`.
|
||||
@ -239,6 +266,7 @@ The use of environment variables allow you to provide over-rides to default sett
|
||||
| Variable | Description |
|
||||
|--------------------- | ----------- |
|
||||
| `APPRISE_CONFIG_DIR` | Defines an (optional) persistent store location of all configuration files saved. By default:<br/> - Configuration is written to the `apprise_api/var/config` directory when just using the _Django_ `manage runserver` script. However for the path for the container is `/config`.
|
||||
| `APPRISE_ATTACH_DIR` | The directory the uploaded attachments are placed in. By default:<br/> - Attachments are written to the `apprise_api/var/attach` directory when just using the _Django_ `manage runserver` script. However for the path for the container is `/attach`.
|
||||
| `APPRISE_STATELESS_URLS` | For a non-persistent solution, you can take advantage of this global variable. Use this to define a default set of Apprise URLs to notify when using API calls to `/notify`. If no `{KEY}` is defined when calling `/notify` then the URLs defined here are used instead. By default, nothing is defined for this variable.
|
||||
| `APPRISE_STATEFUL_MODE` | This can be set to the following possible modes:<br/>📌 **hash**: This is also the default. It stores the server configuration in a hash formatted that can be easily indexed and compressed.<br/>📌 **simple**: Configuration is written straight to disk using the `{KEY}.cfg` (if `TEXT` based) and `{KEY}.yml` (if `YAML` based).<br/>📌 **disabled**: Straight up deny any read/write queries to the servers stateful store. Effectively turn off the Apprise Stateful feature completely.
|
||||
| `APPRISE_CONFIG_LOCK` | Locks down your API hosting so that you can no longer delete/update/access stateful information. Your configuration is still referenced when stateful calls are made to `/notify`. The idea of this switch is to allow someone to set their (Apprise) configuration up and then as an added security tactic, they may choose to lock their configuration down (in a read-only state). Those who use the Apprise CLI tool may still do it, however the `--config` (`-c`) switch will not successfully reference this access point anymore. You can however use the `apprise://` plugin without any problem ([see here for more details](https://github.com/caronc/apprise/wiki/Notify_apprise_api)). This defaults to `no` and can however be set to `yes` by simply defining the global variable as such.
|
||||
|
@ -138,6 +138,12 @@ class NotifyForm(forms.Form):
|
||||
max_length=apprise.NotifyBase.body_maxlen,
|
||||
)
|
||||
|
||||
# Attachment Support
|
||||
attachment = forms.FileField(
|
||||
label=_('Attachment'),
|
||||
required=False,
|
||||
)
|
||||
|
||||
tag = forms.CharField(
|
||||
label=_('Tags'),
|
||||
widget=forms.TextInput(
|
||||
|
@ -40,7 +40,7 @@
|
||||
<!-- Page Layout here -->
|
||||
<div class="row">
|
||||
|
||||
<div class="col s3">
|
||||
<div class="col s3" style="width:20em">
|
||||
{% if STATEFUL_MODE != 'disabled' %}
|
||||
<ul class="collection z-depth-1">
|
||||
<a class="collection-item" href="{% url 'config' 'apprise' %}"><i class="tiny material-icons">settings</i>
|
||||
|
@ -23,6 +23,7 @@
|
||||
{% blocktrans %}
|
||||
Here is where you can store your Apprise configuration associated with the key <code>{{key}}</code>.
|
||||
{% endblocktrans %}
|
||||
For some examples on how to build a development environment around this, <strong><a href="{% url 'welcome'%}?key={{key}}">click here</a></strong>.
|
||||
</li>
|
||||
<li>
|
||||
{% blocktrans %}
|
||||
@ -78,7 +79,14 @@
|
||||
{% blocktrans %}The following command would cause apprise to directly notify all of your services:{% endblocktrans %}
|
||||
<br />
|
||||
<pre><code class="bash">apprise --body="Test Message" \<br/>
|
||||
apprise{% if request.is_secure %}s{% endif %}://{{request.META.HTTP_HOST}}{{BASE_URL}}/{{key}}?tags=all</code></pre>
|
||||
apprise{% if request.is_secure %}s{% endif %}://{{request.META.HTTP_HOST}}{{BASE_URL}}/<em>{{key}}</em>/?tags=all</code></pre>
|
||||
<br />
|
||||
{% blocktrans %}Send one or more attachments like this:{% endblocktrans %}
|
||||
<pre><code class="bash">apprise --body="Test Message" \<br/>
|
||||
apprise{% if request.is_secure %}s{% endif %}://{{request.META.HTTP_HOST}}{{BASE_URL}}/<em>{{key}}</em>/?tags=all \<br/>
|
||||
--attach=/path/to/an/attachment.jpeg \ <br/>
|
||||
--attach=https://raw.githubusercontent.com/caronc/apprise/master/apprise/assets/themes/default/apprise-logo.png<br/>
|
||||
</code></pre>
|
||||
</p>
|
||||
{% if not CONFIG_LOCK %}
|
||||
<p>
|
||||
@ -86,7 +94,7 @@
|
||||
send a test notification to all of your added services:{% endblocktrans %}
|
||||
<br />
|
||||
<pre><code class="bash">apprise --body="Test Message" --tag=all \<br/>
|
||||
--config={{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/get/{{key}}</code></pre>
|
||||
--config={{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/get/<em>{{key}}</em></code></pre>
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
@ -122,7 +130,7 @@
|
||||
{% blocktrans %}
|
||||
You can send a notification using the loaded configuration:
|
||||
{% endblocktrans %}
|
||||
<form id="donotify" action="{% url "notify" key %}" method="post">
|
||||
<form id="donotify" enctype="multipart/form-data" action="{% url "notify" key %}" method="post">
|
||||
{{ form_notify }}
|
||||
<button class="btn waves-effect waves-light" type="submit" name="action">{% trans "Send Notification" %}
|
||||
<i class="material-icons right">send</i>
|
||||
@ -411,8 +419,8 @@ function notify_init() {
|
||||
return s;
|
||||
}, []).join(",")
|
||||
|
||||
const form = this;
|
||||
const body = new URLSearchParams(new FormData(form));
|
||||
// our Form
|
||||
const form = new FormData(this);
|
||||
|
||||
// perform our notification
|
||||
Swal.fire(
|
||||
@ -422,7 +430,7 @@ function notify_init() {
|
||||
Swal.showLoading()
|
||||
let response = fetch('{% url "notify" key %}', {
|
||||
method: 'POST',
|
||||
body: body,
|
||||
body: form,
|
||||
headers: {
|
||||
'Accept': 'text/html',
|
||||
'X-Apprise-Log-Level': 'info'
|
||||
|
@ -71,7 +71,7 @@
|
||||
<ul class="collapsible">
|
||||
<li>
|
||||
<div class="collapsible-header">
|
||||
<i class="material-icons">code</i>curl example
|
||||
<i class="material-icons">code</i>Curl Example
|
||||
</div>
|
||||
<div class="collapsible-body">
|
||||
<pre><code class="bash">
|
||||
@ -83,7 +83,7 @@
|
||||
</li>
|
||||
<li>
|
||||
<div class="collapsible-header">
|
||||
<i class="material-icons">code</i>python example
|
||||
<i class="material-icons">code</i>Python Example
|
||||
</div>
|
||||
<div class="collapsible-body">
|
||||
<pre><code class="python">
|
||||
@ -101,7 +101,7 @@
|
||||
</li>
|
||||
<li>
|
||||
<div class="collapsible-header">
|
||||
<i class="material-icons">code</i>php example
|
||||
<i class="material-icons">code</i>PHP Example
|
||||
</div>
|
||||
<div class="collapsible-body">
|
||||
<pre><code class="php">
|
||||
|
@ -25,7 +25,7 @@
|
||||
<table class="highlighted">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "URL" %}</th>
|
||||
<th style="min-width: 18%;">{% trans "URL" %}</th>
|
||||
<th>{% trans "Description" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@ -83,17 +83,26 @@
|
||||
</table>
|
||||
<ul class="collapsible">
|
||||
<li>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>curl example</div>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>Curl Example</div>
|
||||
<div class="collapsible-body">
|
||||
<pre><code class="bash">
|
||||
# {% blocktrans %}Notifies an email address{% endblocktrans %}<br/>
|
||||
curl -X POST -d '{"urls":"mailto://user:pass@gmail.com","body":"test body","title":"test title"}' \<br/>
|
||||
-H "Content-Type: application/json" \<br/>
|
||||
{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/notify/</code></pre>
|
||||
"{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/notify/"
|
||||
<br/><br/>
|
||||
# {% blocktrans %}Notifies an email address with attachments{% endblocktrans %}<br/>
|
||||
curl -X POST -F 'urls=mailto://user:pass@gmail.com' \<br/>
|
||||
-F 'title=test title' \<br/>
|
||||
-F 'body=test body' \<br/>
|
||||
-F attach1=@/path/to/attachment.doc \<br/>
|
||||
-F attach2=@Screenshot-2.png \ <br/>
|
||||
"{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/notify/"
|
||||
</code></pre>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>python example</div>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>Python Example</div>
|
||||
<div class="collapsible-body">
|
||||
<pre><code class="python">
|
||||
import json<br/>
|
||||
@ -104,18 +113,33 @@
|
||||
'title': 'test title',<br/>
|
||||
'body': 'test body',<br/>
|
||||
}<br/>
|
||||
<br/># The URL<br/>
|
||||
req = Request(<br/>
|
||||
<br/># The Request<br/>
|
||||
response = Request(<br/>
|
||||
"{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/notify/",<br/>
|
||||
json.dumps(payload).encode('utf-8'),<br/>
|
||||
{"Content-Type": "application/json"},<br/>
|
||||
method='POST',<br/>
|
||||
)
|
||||
<br/>
|
||||
</code></pre>
|
||||
<pre><code class="python">
|
||||
# {% blocktrans %}Notifies an email address with attachments{% endblocktrans %}<br/>
|
||||
import requests<br/><br/>
|
||||
payload = {<br/>
|
||||
'urls': 'mailto://user:pass@gmail.com',<br/>
|
||||
'title': 'test title',<br/>
|
||||
'body': 'test body',<br/>
|
||||
}<br/><br/>
|
||||
with open("my/path/to/attachment.png", 'rb') as fp:<br/>
|
||||
response = request.post("{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/notify/",<br/>
|
||||
data=payload,<br/>
|
||||
files={'attach1':('attachment.png', fp)},<br/>
|
||||
)
|
||||
</code></pre>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>php example</div>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>PHP Example</div>
|
||||
<div class="collapsible-body">
|
||||
<pre><code class="php"><?php<br/>
|
||||
<br/>
|
||||
@ -145,7 +169,49 @@
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));<br/>
|
||||
<br/>
|
||||
//Execute the request<br/>
|
||||
$result = curl_exec($ch);
|
||||
$result = curl_exec($ch);<br/>
|
||||
<br/>
|
||||
// Close our handler<br/>
|
||||
curl_close($ch);<br/>
|
||||
?>
|
||||
</code></pre>
|
||||
<pre><code class="php"><?php<br/>
|
||||
// Sending an Attachment using PHP<br/><br/>
|
||||
// The URL<br/>
|
||||
$url = '{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/notify/';<br/>
|
||||
<br/>
|
||||
//Initiate cURL.<br/>
|
||||
$ch = curl_init($url);<br/>
|
||||
<br/>
|
||||
// Prepare our File attachment<br/>
|
||||
$path = '/path/to/photo.jpg';<br/>
|
||||
<br/>
|
||||
// Acquire our Filename<br/>
|
||||
$fname = basename($path);<br/>
|
||||
<br/>
|
||||
// Get our attachment mime-type (in this case it's 'image/jpg')<br/>
|
||||
$mimeType = mime_content_type($path);<br/>
|
||||
<br/>
|
||||
//The multipart data.<br/>
|
||||
$data = array(<br/>
|
||||
'urls' => 'mailto://user:pass@hotmail.com',<br/>
|
||||
'title' => 'test title',<br/>
|
||||
'body' => 'test body',<br/>
|
||||
'attach1' => new CURLFile($path, $mimeType, $fname)<br/>
|
||||
);<br/>
|
||||
<br/>
|
||||
//Tell cURL that we want to send a POST request.<br/>
|
||||
curl_setopt($ch, CURLOPT_POST, 1);<br/>
|
||||
<br/>
|
||||
//Attach our data to the POST fields.<br/>
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);<br/>
|
||||
<br/>
|
||||
//Execute the request<br/>
|
||||
$result = curl_exec($ch);<br/>
|
||||
<br/>
|
||||
// Close our handler<br/>
|
||||
curl_close($ch);<br/>
|
||||
?>
|
||||
</code></pre>
|
||||
</div>
|
||||
</li>
|
||||
@ -171,17 +237,17 @@
|
||||
<table class="highlighted">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{% trans "URL" %}</th>
|
||||
<th style="min-width: 18%;">{% trans "URL" %}</th>
|
||||
<th>{% trans "Description" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><code>{{BASE_URL}}/add/<em>{% trans "KEY" %}</em></code></td>
|
||||
<td><code>{{BASE_URL}}/add/<em>{{key}}</em></code></td>
|
||||
<td>
|
||||
{% blocktrans %}Used to add a new Apprise configuration or a set of URLs and associates them with the
|
||||
specified <em>KEY</em>. See the <a target="_blank"
|
||||
{% blocktrans %}Used to add a new Apprise configuration or a set of URLs and associates them with configuration
|
||||
identified with the id of <em>{{key}}</em>. See the <a target="_blank"
|
||||
href="https://github.com/caronc/apprise/wiki#notification-services">Apprise Wiki</a> if you need help
|
||||
constructing your URLs.{% endblocktrans %}
|
||||
<div class="section">
|
||||
@ -229,23 +295,23 @@
|
||||
</table>
|
||||
<ul class="collapsible">
|
||||
<li>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>curl example</div>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>Curl Example</div>
|
||||
<div class="collapsible-body">
|
||||
<pre><code class="bash">
|
||||
# {% blocktrans %}Load a single URL and assign it to the <em>KEY</em> of abc123{% endblocktrans %}<br/>
|
||||
# {% blocktrans %}Load a single URL and assign it to: <em>{{key}}</em>{% endblocktrans %}<br/>
|
||||
curl -X POST -d '{"urls":"mailto://user:pass@gmail.com"}' \<br/>
|
||||
-H "Content-Type: application/json" \<br/>
|
||||
{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/add/<em>abc123</em></code></pre>
|
||||
{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/add/<em>{{key}}</em></code></pre>
|
||||
<pre><code class="bash">
|
||||
# {% blocktrans %}Load a simple TEXT config entry <em>KEY</em> abc123{% endblocktrans %}<br/>
|
||||
# {% blocktrans %}Load a simple TEXT config entry sent to: <em>{{key}}</em>{% endblocktrans %}<br/>
|
||||
curl -X POST -d '{"format":"text","config":"devops=mailto://user:pass@gmail.com"}' \<br/>
|
||||
-H "Content-Type: application/json" \<br/>
|
||||
{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/add/abc123/
|
||||
{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/add/{{key}}/
|
||||
</code></pre>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>python example</div>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>Python Example</div>
|
||||
<div class="collapsible-body">
|
||||
<pre><code class="python">
|
||||
import json<br/>
|
||||
@ -254,9 +320,9 @@
|
||||
payload = {<br/>
|
||||
'urls': 'mailto://user:pass@gmail.com',<br/>
|
||||
}<br/>
|
||||
<br/># The URL if the key was <em>abc123</em><br/>
|
||||
<br/># The URL if the key was <em>{{key}}</em><br/>
|
||||
req = Request(<br/>
|
||||
"{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/add/<em>abc123</em>",<br/>
|
||||
"{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/add/<em>{{key}}</em>",<br/>
|
||||
json.dumps(payload).encode('utf-8'),<br/>
|
||||
{"Content-Type": "application/json"},<br/>
|
||||
method='POST',<br/>
|
||||
@ -265,12 +331,12 @@
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>php example</div>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>PHP Example</div>
|
||||
<div class="collapsible-body">
|
||||
<pre><code class="php"><?php<br/>
|
||||
<br/>
|
||||
// The URL if the key was <em>abc123</em><br/>
|
||||
$url = '{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/add/<em>abc123</em>';<br/>
|
||||
// The URL if the key was <em>{{key}}</em><br/>
|
||||
$url = '{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/add/<em>{{key}}</em>';<br/>
|
||||
<br/>
|
||||
//Initiate cURL.<br/>
|
||||
$ch = curl_init($url);<br/>
|
||||
@ -293,7 +359,11 @@
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));<br/>
|
||||
<br/>
|
||||
//Execute the request<br/>
|
||||
$result = curl_exec($ch);
|
||||
$result = curl_exec($ch);<br/>
|
||||
<br/>
|
||||
// Close our handler<br/>
|
||||
curl_close($ch);<br/>
|
||||
?>
|
||||
</code></pre>
|
||||
</div>
|
||||
</li>
|
||||
@ -302,28 +372,27 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>{{BASE_URL}}/del/<em>{% trans "KEY" %}</em></code></td>
|
||||
<td>{% blocktrans %}There are no arguments required. If the <em>KEY</em> exists and has data associated with
|
||||
it,
|
||||
it will be removed.{% endblocktrans %}
|
||||
<td><code>{{BASE_URL}}/del/<em>{{key}}</em></code></td>
|
||||
<td>{% blocktrans %}There are no arguments required. If configuration id of <em>{{key}}</em> exists and has data associated with
|
||||
it, it will be removed.{% endblocktrans %}
|
||||
<ul class="collapsible">
|
||||
<li>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>curl example</div>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>Curl Example</div>
|
||||
<div class="collapsible-body">
|
||||
<pre><code class="bash">
|
||||
# {% blocktrans %}Remove previously loaded configuration associated with the <em>KEY</em> of abc123{% endblocktrans %}<br/>
|
||||
curl -X POST {{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/del/<em>abc123</em></code></pre>
|
||||
# {% blocktrans %}Remove previously loaded configuration associated with the id of <em>{{key}}</em>{% endblocktrans %}<br/>
|
||||
curl -X POST {{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/del/<em>{{key}}</em></code></pre>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>python example</div>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>Python Example</div>
|
||||
<div class="collapsible-body">
|
||||
<pre><code class="python">
|
||||
import json<br/>
|
||||
from urllib.request import Request<br/>
|
||||
<br/># The request if the key was <em>abc123</em><br/>
|
||||
<br/># The request if the key was <em>{{key}}</em><br/>
|
||||
req = Request(<br/>
|
||||
"{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/del/<em>abc123</em>",<br/>
|
||||
"{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/del/<em>{{key}}</em>",<br/>
|
||||
json.dumps(payload).encode('utf-8'),<br/>
|
||||
{"Content-Type": "application/json"},<br/>
|
||||
method='POST',<br/>
|
||||
@ -332,12 +401,12 @@
|
||||
</div>
|
||||
<li>
|
||||
<li>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>php example</div>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>PHP Example</div>
|
||||
<div class="collapsible-body">
|
||||
<pre><code class="php"><?php<br/>
|
||||
<br/>
|
||||
// The URL if the key was <em>abc123</em><br/>
|
||||
$url = '{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/del/<em>abc123</em>';<br/>
|
||||
// The URL if the key was <em>{{key}}</em><br/>
|
||||
$url = '{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/del/<em>{{key}}</em>';<br/>
|
||||
<br/>
|
||||
//Initiate cURL.<br/>
|
||||
$ch = curl_init($url);<br/>
|
||||
@ -346,7 +415,11 @@
|
||||
curl_setopt($ch, CURLOPT_POST, 1);<br/>
|
||||
<br/>
|
||||
//Execute the request<br/>
|
||||
$result = curl_exec($ch);
|
||||
$result = curl_exec($ch);<br/>
|
||||
<br/>
|
||||
// Close our handler<br/>
|
||||
curl_close($ch);<br/>
|
||||
?>
|
||||
</code></pre>
|
||||
</div>
|
||||
</li>
|
||||
@ -354,17 +427,17 @@
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>{{BASE_URL}}/get/<em>{% trans "KEY" %}</em></code></td>
|
||||
<td><code>{{BASE_URL}}/get/<em>{{key}}</em></code></td>
|
||||
<td>{% blocktrans %}This feature can be used by Apprise itself. It provides a means of remotely fetching it's
|
||||
configuration.{% endblocktrans %}<br />
|
||||
the configuration associated with the configuration identified through the id of <em>{{key}}</em>.{% endblocktrans %}<br />
|
||||
<pre><code lang="bash"># Use Apprise to retrieve your configuration:<br/>
|
||||
apprise --body="test message" --config={{ request.scheme }}://{{request.META.HTTP_HOST}}{{BASE_URL}}/get/<em>{% trans "KEY" %}</em></code></pre>
|
||||
apprise --body="test message" --config={{ request.scheme }}://{{request.META.HTTP_HOST}}{{BASE_URL}}/get/<em>{{key}}</em></code></pre>
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><code>{{BASE_URL}}/notify/<em>{% trans "KEY" %}</em></code></td>
|
||||
<td>{% blocktrans %}Notifies the URLs associated with the specified <em>KEY</em>.{% endblocktrans %}
|
||||
<td><code>{{BASE_URL}}/notify/<em>{{key}}</em></code></td>
|
||||
<td>{% blocktrans %}Notifies the URLs associated with configuration identified by the id of <em>{{key}}</em>.{% endblocktrans %}
|
||||
<div class="section">
|
||||
<table>
|
||||
<thead>
|
||||
@ -411,18 +484,42 @@
|
||||
</table>
|
||||
<ul class="collapsible">
|
||||
<li>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>curl example</div>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>Curl Example</div>
|
||||
<div class="collapsible-body">
|
||||
<pre><code class="bash">
|
||||
# {% blocktrans %}Notifies all URLs assigned to the configuration{% endblocktrans %}<br/>
|
||||
curl -X POST \<br/>
|
||||
-F "tag=all" \ <br/>
|
||||
-F "body=test body" \ <br/>
|
||||
-F "title=test title" \ <br/>
|
||||
"{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/notify/<em>{{key}}</em>"</code></pre>
|
||||
<pre><code class="bash">
|
||||
# {% blocktrans %}Notifies all URLs assigned the <em>devops</em> tag{% endblocktrans %}<br/>
|
||||
curl -X POST -d '{"tag":"devops","body":"test body","title":"test title"}' \<br/>
|
||||
-H "Content-Type: application/json" \<br/>
|
||||
{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/notify/<em>KEY</em></code></pre>
|
||||
"{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/notify/<em>{{key}}</em>"</code></pre>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>python example</div>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>Python Example</div>
|
||||
<div class="collapsible-body">
|
||||
Ideally you should leverage the Apprise Library, it will make your life much easier:
|
||||
<pre><code class="python">
|
||||
import apprise<br/>
|
||||
<br/>
|
||||
# Create an Apprise Instance<br/>
|
||||
aobj = apprise.Apprise()<br/>
|
||||
<br/>
|
||||
# Add our URL</br>
|
||||
aobj.add("apprise{% if secure %}s{%else%}{%endif%}://{{request.META.HTTP_HOST}}{{BASE_URL}}/<em>{{key}}</em>")<br/>
|
||||
<br/>
|
||||
# Send our notification:<br/>
|
||||
aobj.notify("test body", "test title")<br/>
|
||||
<br/>
|
||||
# Sending an attachment is just as easy:<br/>
|
||||
aobj.notify("test body", "test title", attach="/path/to/file")<br/>
|
||||
</code></pre>
|
||||
The legacy (but more compatible and light weight) way of doing things:
|
||||
<pre><code class="python">
|
||||
import json<br/>
|
||||
from urllib.request import Request<br/>
|
||||
@ -432,9 +529,9 @@
|
||||
'title': 'test title',<br/>
|
||||
'body': 'test body',<br/>
|
||||
}<br/>
|
||||
<br/># The URL if the key was <em>abc123</em><br/>
|
||||
<br/># The URL if the key was <em>{{key}}</em><br/>
|
||||
req = Request(<br/>
|
||||
"{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/notify/<em>abc123</em>",<br/>
|
||||
"{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/notify/<em>{{key}}</em>",<br/>
|
||||
json.dumps(payload).encode('utf-8'),<br/>
|
||||
{"Content-Type": "application/json"},<br/>
|
||||
method='POST',<br/>
|
||||
@ -443,12 +540,12 @@
|
||||
</div>
|
||||
<li>
|
||||
<li>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>php example</div>
|
||||
<div class="collapsible-header"><i class="material-icons">code</i>PHP Example</div>
|
||||
<div class="collapsible-body">
|
||||
<pre><code class="php"><?php<br/>
|
||||
<br/>
|
||||
// The URL if the key was <em>abc123</em><br/>
|
||||
$url = '{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/notify/<em>abc123</em>';<br/>
|
||||
// The URL if the key was <em>{{key}}</em><br/>
|
||||
$url = '{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/notify/<em>{{key}}</em>';<br/>
|
||||
<br/>
|
||||
//Initiate cURL.<br/>
|
||||
$ch = curl_init($url);<br/>
|
||||
@ -473,7 +570,49 @@
|
||||
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Type: application/json'));<br/>
|
||||
<br/>
|
||||
//Execute the request<br/>
|
||||
$result = curl_exec($ch);
|
||||
$result = curl_exec($ch);<br/>
|
||||
<br/>
|
||||
// Close our handler<br/>
|
||||
curl_close($ch);<br/>
|
||||
?>
|
||||
</code></pre>
|
||||
<pre><code class="php"><?php<br/>
|
||||
// Sending an Attachment using PHP<br/><br/>
|
||||
// The URL<br/>
|
||||
$url = '{{request.scheme}}://{{request.META.HTTP_HOST}}{{BASE_URL}}/notify/<em>{{key}}</em>';<br/>
|
||||
<br/>
|
||||
//Initiate cURL.<br/>
|
||||
$ch = curl_init($url);<br/>
|
||||
<br/>
|
||||
// Prepare our File attachment<br/>
|
||||
$path = '/path/to/photo.jpg';<br/>
|
||||
<br/>
|
||||
// Acquire our Filename<br/>
|
||||
$fname = basename($path);<br/>
|
||||
<br/>
|
||||
// Get our attachment mime-type (in this case it's 'image/jpg')<br/>
|
||||
$mimeType = mime_content_type($path);<br/>
|
||||
<br/>
|
||||
//The multipart data.<br/>
|
||||
$data = array(<br/>
|
||||
'urls' => 'mailto://user:pass@hotmail.com',<br/>
|
||||
'title' => 'test title',<br/>
|
||||
'body' => 'test body',<br/>
|
||||
'attach1' => new CURLFile($path, $mimeType, $fname)<br/>
|
||||
);<br/>
|
||||
<br/>
|
||||
//Tell cURL that we want to send a POST request.<br/>
|
||||
curl_setopt($ch, CURLOPT_POST, 1);<br/>
|
||||
<br/>
|
||||
//Attach our data to the POST fields.<br/>
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);<br/>
|
||||
<br/>
|
||||
//Execute the request<br/>
|
||||
$result = curl_exec($ch);<br/>
|
||||
<br/>
|
||||
// Close our handler<br/>
|
||||
curl_close($ch);<br/>
|
||||
?>
|
||||
</code></pre>
|
||||
</div>
|
||||
</li>
|
||||
@ -487,7 +626,7 @@
|
||||
<div class="section">
|
||||
<h4>{% trans "Endpoint Notes" %}</h4>
|
||||
<p>
|
||||
The <em>KEY</em> you plan to associate your configuration with:
|
||||
The Configuration ID (<em>{{key}}</em>) you plan to associate your configuration with:
|
||||
<ol>
|
||||
<li>Can not have spaces and/or special characters in it. Both a dash (<code>-</code>) and underscore
|
||||
(<code>_</code>) are the only exceptions to this rule.</li>
|
||||
|
@ -23,6 +23,7 @@
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
# THE SOFTWARE.
|
||||
import re
|
||||
import binascii
|
||||
import os
|
||||
import tempfile
|
||||
import shutil
|
||||
@ -30,6 +31,7 @@ import gzip
|
||||
import apprise
|
||||
import hashlib
|
||||
import errno
|
||||
import base64
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
@ -63,6 +65,202 @@ STORE_MODES = (
|
||||
)
|
||||
|
||||
|
||||
class Attachment(apprise.attachment.AttachFile):
|
||||
"""
|
||||
A Light Weight Attachment Object for Auto-cleanup that wraps the Apprise
|
||||
Attachments
|
||||
"""
|
||||
|
||||
def __init__(self, filename, path=None, delete=True):
|
||||
"""
|
||||
Initialize our attachment
|
||||
"""
|
||||
self._filename = filename
|
||||
try:
|
||||
os.makedirs(settings.APPRISE_ATTACH_DIR, exist_ok=True)
|
||||
|
||||
except OSError:
|
||||
# Permission error
|
||||
raise ValueError('Could not create directory {}'.format(
|
||||
settings.APPRISE_ATTACH_DIR))
|
||||
|
||||
if not path:
|
||||
try:
|
||||
d, path = tempfile.mkstemp(dir=settings.APPRISE_ATTACH_DIR)
|
||||
# Close our file descriptor
|
||||
os.close(d)
|
||||
|
||||
except FileNotFoundError:
|
||||
raise ValueError(
|
||||
'Could not prepare {} attachment in {}'.format(
|
||||
filename, settings.APPRISE_ATTACH_DIR))
|
||||
|
||||
self._path = path
|
||||
self.delete = delete
|
||||
|
||||
# Prepare our item
|
||||
super().__init__(path=self._path, name=filename)
|
||||
|
||||
@property
|
||||
def filename(self):
|
||||
return self._filename
|
||||
|
||||
@property
|
||||
def size(self):
|
||||
"""
|
||||
Return filesize
|
||||
"""
|
||||
return os.stat(self._path).st_size
|
||||
|
||||
def __del__(self):
|
||||
"""
|
||||
De-Construtor is used to tidy up files during garbage collection
|
||||
"""
|
||||
if self.delete:
|
||||
try:
|
||||
os.remove(self._path)
|
||||
except FileNotFoundError:
|
||||
# no problem
|
||||
pass
|
||||
|
||||
|
||||
def parse_attachments(attachment_payload, files_request):
|
||||
"""
|
||||
Takes the payload provided in a `/notify` call and extracts the
|
||||
attachments out of it.
|
||||
|
||||
Content is written to a temporary directory until the garbage
|
||||
collection kicks in.
|
||||
"""
|
||||
attachments = []
|
||||
|
||||
# Attachment Count
|
||||
count = sum([
|
||||
0 if not isinstance(attachment_payload, (tuple, list))
|
||||
else len(attachment_payload),
|
||||
0 if not isinstance(files_request, dict) else len(files_request),
|
||||
])
|
||||
|
||||
if settings.APPRISE_MAX_ATTACHMENTS > 0 and \
|
||||
count > settings.APPRISE_MAX_ATTACHMENTS:
|
||||
raise ValueError(
|
||||
"There is a maximum of %d attachments" %
|
||||
settings.APPRISE_MAX_ATTACHMENTS)
|
||||
|
||||
if isinstance(attachment_payload, (tuple, list)):
|
||||
for no, entry in enumerate(attachment_payload, start=1):
|
||||
|
||||
if isinstance(entry, str):
|
||||
filename = "attachment.%.3d" % no
|
||||
|
||||
elif isinstance(entry, dict):
|
||||
try:
|
||||
filename = entry.get("filename", "").strip()
|
||||
|
||||
# Max filename size is 250
|
||||
if len(filename) > 250:
|
||||
raise ValueError(
|
||||
"The filename associated with attachment "
|
||||
"%d is too long" % no)
|
||||
|
||||
elif not filename:
|
||||
filename = "attachment.%.3d" % no
|
||||
|
||||
except TypeError:
|
||||
raise ValueError(
|
||||
"An invalid filename was provided for attachment %d" %
|
||||
no)
|
||||
|
||||
else:
|
||||
# you must pass in a base64 string, or a dict containing our
|
||||
# required parameters
|
||||
raise ValueError(
|
||||
"An invalid filename was provided for attachment %d" % no)
|
||||
|
||||
#
|
||||
# Prepare our Attachment
|
||||
#
|
||||
attachment = Attachment(filename)
|
||||
|
||||
try:
|
||||
with open(attachment.path, 'wb') as f:
|
||||
# Write our content to disk
|
||||
f.write(base64.b64decode(entry["base64"]))
|
||||
|
||||
except binascii.Error:
|
||||
# The file ws not base64 encoded
|
||||
raise ValueError(
|
||||
"Invalid filecontent was provided for attachment %s" %
|
||||
filename)
|
||||
|
||||
except OSError:
|
||||
raise ValueError(
|
||||
"Could not write attachment %s to disk" % filename)
|
||||
|
||||
#
|
||||
# Some Validation
|
||||
#
|
||||
if settings.APPRISE_MAX_ATTACHMENT_SIZE > 0 and \
|
||||
attachment.size > settings.APPRISE_MAX_ATTACHMENT_SIZE:
|
||||
raise ValueError(
|
||||
"attachment %s's filesize is to large" % filename)
|
||||
|
||||
# Add our attachment
|
||||
attachments.append(attachment)
|
||||
|
||||
#
|
||||
# Now handle the request.FILES
|
||||
#
|
||||
if isinstance(files_request, dict):
|
||||
for no, (key, meta) in enumerate(
|
||||
files_request.items(), start=len(attachments) + 1):
|
||||
|
||||
try:
|
||||
# Filetype is presumed to be of base class
|
||||
# django.core.files.UploadedFile
|
||||
filename = meta.name.strip()
|
||||
|
||||
# Max filename size is 250
|
||||
if len(filename) > 250:
|
||||
raise ValueError(
|
||||
"The filename associated with attachment "
|
||||
"%d is too long" % no)
|
||||
|
||||
elif not filename:
|
||||
filename = "attachment.%.3d" % no
|
||||
|
||||
except (AttributeError, TypeError):
|
||||
raise ValueError(
|
||||
"An invalid filename was provided for attachment %d" %
|
||||
no)
|
||||
|
||||
#
|
||||
# Prepare our Attachment
|
||||
#
|
||||
attachment = Attachment(filename)
|
||||
try:
|
||||
with open(attachment.path, 'wb') as f:
|
||||
# Write our content to disk
|
||||
f.write(meta.read())
|
||||
|
||||
except OSError:
|
||||
raise ValueError(
|
||||
"Could not write attachment %s to disk" % filename)
|
||||
|
||||
#
|
||||
# Some Validation
|
||||
#
|
||||
if settings.APPRISE_MAX_ATTACHMENT_SIZE > 0 and \
|
||||
attachment.size > settings.APPRISE_MAX_ATTACHMENT_SIZE:
|
||||
raise ValueError(
|
||||
"attachment %s's filesize is to large" % filename)
|
||||
|
||||
# Add our attachment
|
||||
attachments.append(attachment)
|
||||
|
||||
return attachments
|
||||
|
||||
|
||||
class SimpleFileExtension(object):
|
||||
"""
|
||||
Defines the simple file exension lookups
|
||||
@ -130,10 +328,10 @@ class AppriseConfigCache(object):
|
||||
return False
|
||||
|
||||
# Write our file to a temporary file
|
||||
_, tmp_path = tempfile.mkstemp(suffix='.tmp', dir=path)
|
||||
d, tmp_path = tempfile.mkstemp(suffix='.tmp', dir=path)
|
||||
# Close the file handle provided by mkstemp()
|
||||
# We're reopening it, and it can't be renamed while open on Windows
|
||||
os.close(_)
|
||||
os.close(d)
|
||||
|
||||
if self.mode == AppriseStoreMode.HASH:
|
||||
try:
|
||||
|
@ -34,6 +34,7 @@ from django.views.decorators.gzip import gzip_page
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.core.serializers.json import DjangoJSONEncoder
|
||||
|
||||
from .utils import parse_attachments
|
||||
from .utils import ConfigCache
|
||||
from .utils import apply_global_filters
|
||||
from .forms import AddByUrlForm
|
||||
@ -121,7 +122,12 @@ class WelcomeView(View):
|
||||
template_name = 'welcome.html'
|
||||
|
||||
def get(self, request):
|
||||
return render(request, self.template_name, {})
|
||||
default_key = 'KEY'
|
||||
key = request.GET.get('key', default_key).strip()
|
||||
return render(request, self.template_name, {
|
||||
'secure': request.scheme[-1].lower() == 's',
|
||||
'key': key if key else default_key,
|
||||
})
|
||||
|
||||
|
||||
@method_decorator((gzip_page, never_cache), name='dispatch')
|
||||
@ -571,9 +577,7 @@ class NotifyView(View):
|
||||
# our content
|
||||
content = {}
|
||||
if MIME_IS_FORM.match(request.content_type):
|
||||
content = {}
|
||||
|
||||
form = NotifyForm(request.POST)
|
||||
form = NotifyForm(data=request.POST, files=request.FILES)
|
||||
if form.is_valid():
|
||||
content.update(form.cleaned_data)
|
||||
|
||||
@ -604,6 +608,12 @@ class NotifyView(View):
|
||||
status=status,
|
||||
)
|
||||
|
||||
# Handle Attachments
|
||||
attach = None
|
||||
if 'attachments' in content or request.FILES:
|
||||
attach = parse_attachments(
|
||||
content.get('attachments'), request.FILES)
|
||||
|
||||
#
|
||||
# Allow 'tag' value to be specified as part of the URL parameters
|
||||
# if not found otherwise defined.
|
||||
@ -837,6 +847,7 @@ class NotifyView(View):
|
||||
title=content.get('title', ''),
|
||||
notify_type=content.get('type', apprise.NotifyType.INFO),
|
||||
tag=content.get('tag'),
|
||||
attach=attach,
|
||||
)
|
||||
|
||||
if content_type == 'text/html':
|
||||
@ -863,6 +874,7 @@ class NotifyView(View):
|
||||
title=content.get('title', ''),
|
||||
notify_type=content.get('type', apprise.NotifyType.INFO),
|
||||
tag=content.get('tag'),
|
||||
attach=attach,
|
||||
)
|
||||
|
||||
if not result:
|
||||
@ -901,7 +913,7 @@ class StatelessNotifyView(View):
|
||||
content = {}
|
||||
if MIME_IS_FORM.match(request.content_type):
|
||||
content = {}
|
||||
form = NotifyByUrlForm(request.POST)
|
||||
form = NotifyByUrlForm(request.POST, request.FILES)
|
||||
if form.is_valid():
|
||||
content.update(form.cleaned_data)
|
||||
|
||||
@ -999,12 +1011,19 @@ class StatelessNotifyView(View):
|
||||
status=ResponseCode.no_content,
|
||||
)
|
||||
|
||||
# Handle Attachments
|
||||
attach = None
|
||||
if 'attachments' in content or request.FILES:
|
||||
attach = parse_attachments(
|
||||
content.get('attachments'), request.FILES)
|
||||
|
||||
# Perform our notification at this point
|
||||
result = a_obj.notify(
|
||||
content.get('body'),
|
||||
title=content.get('title', ''),
|
||||
notify_type=content.get('type', apprise.NotifyType.INFO),
|
||||
tag='all',
|
||||
attach=attach,
|
||||
)
|
||||
|
||||
if not result:
|
||||
|
@ -124,6 +124,10 @@ STATIC_URL = BASE_URL + '/s/'
|
||||
APPRISE_CONFIG_DIR = os.environ.get(
|
||||
'APPRISE_CONFIG_DIR', os.path.join(BASE_DIR, 'var', 'config'))
|
||||
|
||||
# The location to place file attachments
|
||||
APPRISE_ATTACH_DIR = os.environ.get(
|
||||
'APPRISE_ATTACH_DIR', os.path.join(BASE_DIR, 'var', 'attach'))
|
||||
|
||||
# When set Apprise API Locks itself down so that future (configuration)
|
||||
# changes can not be made or accessed. It disables access to:
|
||||
# - the configuration screen: /cfg/{token}
|
||||
@ -155,7 +159,7 @@ APPRISE_STATELESS_URLS = os.environ.get('APPRISE_STATELESS_URLS', '')
|
||||
APPRISE_STATEFUL_MODE = os.environ.get('APPRISE_STATEFUL_MODE', 'hash')
|
||||
|
||||
# Our Apprise Deny List
|
||||
# - By default we disable all non-remote calling servicess
|
||||
# - By default we disable all non-remote calling services
|
||||
# - You do not need to identify every schema supported by the service you
|
||||
# wish to disable (only one). For example, if you were to specify
|
||||
# xml, that would include the xmls entry as well (or vs versa)
|
||||
@ -172,3 +176,16 @@ APPRISE_ALLOW_SERVICES = os.environ.get('APPRISE_ALLOW_SERVICES', '')
|
||||
# a call to the same server again, and again and again. By default we allow
|
||||
# 1 level of recursion
|
||||
APPRISE_RECURSION_MAX = int(os.environ.get('APPRISE_RECURSION_MAX', 1))
|
||||
|
||||
# Provided optional plugin paths to scan for custom schema definitions
|
||||
APPRISE_PLUGIN_PATHS = os.environ.get(
|
||||
'APPRISE_PLUGIN_PATHS', os.path.join(BASE_DIR, 'var', 'plugin')).split(',')
|
||||
|
||||
# Define the number of attachments that can exist as part of a payload
|
||||
# Setting this to zero disables the limit
|
||||
APPRISE_MAX_ATTACHMENTS = int(os.environ.get('APPRISE_MAX_ATTACHMENTS', 6))
|
||||
|
||||
# Defines the maximum size each attachment can be
|
||||
# 8388608 == 8MB
|
||||
APPRISE_MAX_ATTACHMENT_SIZE = int(
|
||||
os.environ.get('APPRISE_MAX_ATTACHMENT_SIZE', 8388608))
|
||||
|
@ -17,6 +17,11 @@ http {
|
||||
include /etc/nginx/mime.types;
|
||||
default_type application/octet-stream;
|
||||
|
||||
##
|
||||
# Upload Restriction
|
||||
##
|
||||
client_max_body_size 100M;
|
||||
|
||||
##
|
||||
# Logging Settings
|
||||
##
|
||||
|
@ -13,6 +13,10 @@
|
||||
font-size: 0.7rem;
|
||||
}
|
||||
|
||||
input {
|
||||
display: block;
|
||||
}
|
||||
|
||||
code {
|
||||
background-color: #eee;
|
||||
font-family: monospace;
|
||||
|
@ -16,3 +16,7 @@ services:
|
||||
# $> chown -R 33:33 ./config
|
||||
# $> chmod -R 775 ./config
|
||||
# - ./config:/config:rw
|
||||
# Note: The attachment directory can be exposed outside of the container if required
|
||||
# $> chown -R 33:33 ./attach
|
||||
# $> chmod -R 775 ./attach
|
||||
# - ./attach:/attach:rw
|
||||
|
@ -1,5 +1,5 @@
|
||||
django
|
||||
apprise == 1.3.0
|
||||
apprise == 1.4.0
|
||||
|
||||
# 3rd party service support
|
||||
paho-mqtt
|
||||
|
Loading…
Reference in New Issue
Block a user