2019-10-27 04:53:40 +01:00
|
|
|
{% extends 'base.html' %}
|
|
|
|
{% load i18n %}
|
|
|
|
{% block body %}
|
|
|
|
<h3>{% trans "Management for:" %} <em>{{ key }}</em></h3>
|
2019-10-28 00:41:02 +01:00
|
|
|
<div class="row">
|
|
|
|
<div class="col s12">
|
|
|
|
<ul class="tabs config-overview">
|
|
|
|
<li class="tab col s4"><a class="active" href="#overview">{% trans "Overview" %}</a></li>
|
|
|
|
<li class="tab col s4"><a href="#config">{%trans "Configuration" %}</a></li>
|
|
|
|
<li class="tab col s4"><a href="#notify">{%trans "Notifications" %}</a></li>
|
|
|
|
</ul>
|
|
|
|
</div>
|
|
|
|
<div id="overview" class="col s12">
|
|
|
|
<p>
|
|
|
|
{% blocktrans %}
|
|
|
|
Here is where you can store your configuration so that it can be accessed by Apprise. You can always refer to the
|
|
|
|
<a href="https://github.com/caronc/apprise/wiki#notification-services">Apprise Wiki</a> if you're having troubles
|
|
|
|
assembling your URL(s).
|
|
|
|
You have chosen to associate your configuration with the key <code>{{key}}</code>. If anything was previously
|
|
|
|
associated with this key, it will be replaced if you continue.
|
|
|
|
{% endblocktrans %}
|
|
|
|
</p>
|
|
|
|
<p>
|
|
|
|
{% blocktrans %}
|
|
|
|
In the future you can return to this configuration screen at any time by placing the following into your
|
|
|
|
browser:{% endblocktrans %}
|
|
|
|
<br /><code>{{request.scheme}}://{{request.META.HTTP_HOST}}{{request.path}}</code>
|
|
|
|
</p>
|
|
|
|
<div class="section">
|
|
|
|
{% blocktrans %}For example, the following command would cause apprise to retrieve the configuration loaded and
|
|
|
|
send a test notification to all of your added services:{% endblocktrans %}
|
|
|
|
<br /><code>apprise --body="Test Message" --tag=all --config={{request.scheme}}://{{request.META.HTTP_HOST}}{% url "get" key %}</code>
|
2019-10-27 04:53:40 +01:00
|
|
|
</div>
|
2019-10-28 00:41:02 +01:00
|
|
|
</div>
|
|
|
|
<div id="config" class="col s12">
|
2019-10-27 04:53:40 +01:00
|
|
|
|
2019-10-28 00:41:02 +01:00
|
|
|
<div class="section">
|
|
|
|
<h5>{% trans "Option 1: Set By URL(s)" %}</h5>
|
|
|
|
<p>
|
|
|
|
{% blocktrans %}
|
|
|
|
Use a comma and/or space to separate one Apprise URL from another.
|
|
|
|
{% endblocktrans %}
|
|
|
|
<form id="addurl" action="{% url "add" key %}" method="post">
|
|
|
|
{{ form_url }}
|
|
|
|
<button class="btn waves-effect waves-light" type="submit" name="action">{% trans "Submit" %}
|
|
|
|
<i class="material-icons right">send</i>
|
|
|
|
</button>
|
|
|
|
</form>
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
|
|
|
|
<div class="section">
|
|
|
|
<h5>{% trans "Option 2: Set By Config" %}</h5>
|
|
|
|
<p>
|
|
|
|
{% blocktrans %}
|
|
|
|
This option grants you a bit more flexability because you can additionally associate tags with your URLs. Those
|
|
|
|
using YAML configuration can also alter the Apprise Asset object as well for a more customized look and feel.
|
|
|
|
{% endblocktrans %}
|
|
|
|
<form id="addconfig" action="{% url "add" key %}" method="post">
|
|
|
|
{{ form_cfg }}
|
|
|
|
<button class="btn waves-effect waves-light" type="submit" name="action">{% trans "Submit" %}
|
|
|
|
<i class="material-icons right">send</i>
|
|
|
|
</button>
|
|
|
|
</form>
|
|
|
|
</p>
|
|
|
|
</div>
|
2019-10-27 04:53:40 +01:00
|
|
|
</div>
|
2019-10-28 00:41:02 +01:00
|
|
|
<div id="notify" class="col s12">
|
|
|
|
<p>
|
|
|
|
{% blocktrans %}
|
|
|
|
You can send a notification using the loaded configuration:
|
|
|
|
{% endblocktrans %}
|
|
|
|
<form id="donotify" action="{% url "notify" key %}" method="post">
|
|
|
|
{{ form_notify }}
|
|
|
|
<button class="btn waves-effect waves-light" type="submit" name="action">{% trans "Submit" %}
|
|
|
|
<i class="material-icons right">send</i>
|
|
|
|
</button>
|
|
|
|
</form>
|
|
|
|
</p>
|
|
|
|
</div>
|
|
|
|
</div>
|
|
|
|
{% endblock %}
|
|
|
|
{% block jsfooter %}
|
|
|
|
|
|
|
|
async function update() {
|
|
|
|
|
|
|
|
// disable the notification tab until we know for certain
|
|
|
|
// a notification is possible
|
|
|
|
document.querySelector('.config-overview li a[href="#notify"]')
|
|
|
|
.parentNode.classList.add('disabled');
|
|
|
|
|
|
|
|
// perform our status check
|
|
|
|
let response = await fetch('{% url "get" key %}', {
|
|
|
|
method: 'POST',
|
|
|
|
});
|
|
|
|
|
|
|
|
let result = await response;
|
|
|
|
if(response.status == 204)
|
|
|
|
{
|
|
|
|
// no problem; we simply have no content to retrieve
|
|
|
|
return '';
|
|
|
|
}
|
|
|
|
else if(response.status == 200)
|
|
|
|
{
|
|
|
|
// configuration found
|
|
|
|
|
|
|
|
// Remove our restrictions on sending notifications
|
|
|
|
document.querySelector('.config-overview li a[href="#notify"]')
|
|
|
|
.parentNode.classList.remove('disabled');
|
|
|
|
|
|
|
|
// Set our configuration so it's visible
|
|
|
|
response.text().then(function (text) {
|
|
|
|
document.querySelector('#id_config').value = text;
|
|
|
|
});
|
|
|
|
|
2020-01-12 05:36:19 +01:00
|
|
|
// perform a tag retrieval; start with 'all'
|
|
|
|
let tags = ['all'];
|
|
|
|
|
|
|
|
let jsonResponse = fetch('{% url "json_urls" key %}', {
|
|
|
|
method: 'GET',
|
|
|
|
}).then(function(jsonResponse) {
|
|
|
|
return jsonResponse.json();
|
|
|
|
|
|
|
|
}).then(function (data) {
|
|
|
|
// Initialize our tags making it easy for an end user to
|
|
|
|
// choose from. Tags are based off ones found in the saved
|
|
|
|
// configuration.
|
|
|
|
M.Chips.init(document.querySelectorAll('.chips'), {
|
|
|
|
placeholder: 'Optional Tag',
|
|
|
|
secondaryPlaceholder: 'Another Tag',
|
|
|
|
autocompleteOptions: {
|
|
|
|
data: tags.concat(data.tags).reduce(function(result, item) {
|
|
|
|
result[item] = null;
|
|
|
|
return result;
|
|
|
|
}, {}),
|
|
|
|
limit: Infinity,
|
|
|
|
minLength: 1
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
}).catch(function (err) {
|
|
|
|
// There was an error
|
|
|
|
});
|
|
|
|
|
2019-10-28 00:41:02 +01:00
|
|
|
return response;
|
|
|
|
}
|
|
|
|
// if we reach here, we failed
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
update();
|
|
|
|
|
|
|
|
// over-ride manual submit for a nicer user experience
|
|
|
|
document.querySelector('#addurl').onsubmit = function(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
|
|
|
|
const form = this;
|
|
|
|
const body = new URLSearchParams(new FormData(form));
|
|
|
|
|
|
|
|
// perform our status check
|
|
|
|
let response = fetch('{% url "add" key %}', {
|
|
|
|
method: 'POST',
|
|
|
|
body: body,
|
|
|
|
}).then(function(response) {
|
|
|
|
if(response.status == 200)
|
|
|
|
{
|
|
|
|
// update our settings
|
|
|
|
update();
|
|
|
|
|
|
|
|
// reset our form
|
|
|
|
form.reset();
|
2020-01-12 01:15:51 +01:00
|
|
|
|
|
|
|
Swal.fire(
|
|
|
|
'Save',
|
|
|
|
'Successfully saved the specified URL(s).',
|
|
|
|
'success'
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
Swal.fire(
|
|
|
|
'Save',
|
|
|
|
'Failed to save the specified URL(s).',
|
|
|
|
'error'
|
|
|
|
);
|
2019-10-28 00:41:02 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// over-ride manual submit for a nicer user experience
|
|
|
|
document.querySelector('#addconfig').onsubmit = function(event) {
|
|
|
|
event.preventDefault();
|
|
|
|
const form = this;
|
|
|
|
const body = new URLSearchParams(new FormData(form));
|
|
|
|
|
|
|
|
// perform our status check
|
|
|
|
let response = fetch('{% url "add" key %}', {
|
|
|
|
method: 'POST',
|
|
|
|
body: body,
|
|
|
|
}).then(function(response) {
|
|
|
|
if(response.status == 200)
|
|
|
|
{
|
|
|
|
// update our settings
|
|
|
|
update();
|
2020-01-12 01:15:51 +01:00
|
|
|
|
|
|
|
// user notification
|
|
|
|
Swal.fire(
|
|
|
|
'Save',
|
|
|
|
'Successfully saved the specified URL(s).',
|
|
|
|
'success'
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
// user notification
|
|
|
|
Swal.fire(
|
|
|
|
'Save',
|
|
|
|
'Failed to save the specified URL(s).',
|
|
|
|
'error'
|
|
|
|
);
|
2019-10-28 00:41:02 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// over-ride manual submit for a nicer user experience
|
|
|
|
document.querySelector('#donotify').onsubmit = function(event) {
|
|
|
|
event.preventDefault();
|
2020-01-12 05:36:19 +01:00
|
|
|
|
|
|
|
const chipElement = document.querySelector('.chips');
|
|
|
|
|
|
|
|
chipElement.querySelector('.chips');
|
|
|
|
const chipInput = document.querySelector('.chips > input');
|
|
|
|
if(chipInput.value) {
|
|
|
|
// This code just handles text typed in the tag section that was
|
|
|
|
// not submitted. This forces any lingering un-commited text
|
|
|
|
// into a tag just prior to it's submission
|
|
|
|
const ev = new KeyboardEvent('keydown', {
|
|
|
|
altKey:false,
|
|
|
|
bubbles: true,
|
|
|
|
cancelBubble: false,
|
|
|
|
cancelable: true,
|
|
|
|
charCode: 0,
|
|
|
|
code: "Enter",
|
|
|
|
composed: true,
|
|
|
|
ctrlKey: false,
|
|
|
|
currentTarget: null,
|
|
|
|
defaultPrevented: true,
|
|
|
|
detail: 0,
|
|
|
|
eventPhase: 0,
|
|
|
|
isComposing: false,
|
|
|
|
isTrusted: true,
|
|
|
|
key: "Enter",
|
|
|
|
keyCode: 13,
|
|
|
|
location: 0,
|
|
|
|
metaKey: false,
|
|
|
|
repeat: false,
|
|
|
|
returnValue: false,
|
|
|
|
shiftKey: false,
|
|
|
|
type: "keydown",
|
|
|
|
which: 13
|
|
|
|
});
|
|
|
|
chipInput.dispatchEvent(ev);
|
|
|
|
}
|
|
|
|
|
|
|
|
// store tags (as comma separated string) from materialize chip type into form
|
|
|
|
document.querySelector('#id_tag').value = M.Chips.getInstance(chipElement).chipsData.reduce(
|
|
|
|
function(s, a){
|
|
|
|
s.push(a.tag)
|
|
|
|
return s;
|
|
|
|
}, []).join(",")
|
|
|
|
|
2019-10-28 00:41:02 +01:00
|
|
|
const form = this;
|
|
|
|
const body = new URLSearchParams(new FormData(form));
|
|
|
|
|
|
|
|
// perform our status check
|
|
|
|
let response = fetch('{% url "notify" key %}', {
|
|
|
|
method: 'POST',
|
|
|
|
body: body,
|
|
|
|
}).then(function(response) {
|
|
|
|
if(response.status == 200)
|
|
|
|
{
|
2020-01-12 01:15:51 +01:00
|
|
|
// user notification
|
|
|
|
Swal.fire(
|
|
|
|
'Notification',
|
|
|
|
'Successfully sent the notification(s).',
|
|
|
|
'success'
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
// user notification
|
|
|
|
Swal.fire(
|
|
|
|
'Notification',
|
|
|
|
'Failed to send the notification(s).',
|
|
|
|
'error'
|
|
|
|
);
|
2019-10-28 00:41:02 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2019-10-27 04:53:40 +01:00
|
|
|
{% endblock %}
|
2020-01-12 05:36:19 +01:00
|
|
|
|
|
|
|
{% block onload %}
|
|
|
|
{{ block.super }}
|
|
|
|
document.querySelector('label [for="id_tag"]')
|
|
|
|
|
|
|
|
{
|
|
|
|
// create a new div with the class 'chips' assigned to it
|
|
|
|
const element = document.createElement('div')
|
|
|
|
let refNode = document.querySelector('label[for="id_tag"]')
|
|
|
|
element.classList.add("chips")
|
|
|
|
element.style.margin = '0'
|
|
|
|
refNode.parentNode.insertBefore(element, refNode.nextSibling)
|
|
|
|
}
|
|
|
|
|
|
|
|
// Hide tag field since we use the pretty Materialize Chip setup instead
|
|
|
|
document.querySelector('#id_tag').style.display = 'none';
|
|
|
|
{% endblock %}
|