wip can send event
This commit is contained in:
parent
0c6003a894
commit
f135020914
3
again.go
3
again.go
|
@ -3,10 +3,13 @@ package again
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
webhooks "git.rootprojects.org/root/go-again/webhooks"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Schedule struct {
|
type Schedule struct {
|
||||||
NextRunAt time.Time
|
NextRunAt time.Time
|
||||||
|
Webhooks []webhooks.Webhook
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://yourbasic.org/golang/time-change-convert-location-timezone/
|
// https://yourbasic.org/golang/time-change-convert-location-timezone/
|
||||||
|
|
|
@ -75,7 +75,7 @@ func main() {
|
||||||
MaxHeaderBytes: 1 << 20,
|
MaxHeaderBytes: 1 << 20,
|
||||||
}
|
}
|
||||||
//mux.Handle("/api/", http.HandlerFunc(handleFunc))
|
//mux.Handle("/api/", http.HandlerFunc(handleFunc))
|
||||||
mux.HandleFunc("/api/schedules", s.Handle)
|
mux.HandleFunc("/api/v0/schedules", s.Handle)
|
||||||
|
|
||||||
// TODO Filebox FS
|
// TODO Filebox FS
|
||||||
mux.Handle("/", http.FileServer(http.Dir("./public")))
|
mux.Handle("/", http.FileServer(http.Dir("./public")))
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
{
|
||||||
|
"bracketSpacing": true,
|
||||||
|
"printWidth": 120,
|
||||||
|
"singleQuote": true,
|
||||||
|
"tabWidth": 2,
|
||||||
|
"trailingComma": "none",
|
||||||
|
"useTabs": true
|
||||||
|
}
|
|
@ -5,7 +5,7 @@
|
||||||
var $ = window.$;
|
var $ = window.$;
|
||||||
var $$ = window.$$;
|
var $$ = window.$$;
|
||||||
|
|
||||||
var state = {};
|
var state = { account: { schedules: [] } };
|
||||||
|
|
||||||
var $grantTpl;
|
var $grantTpl;
|
||||||
var $devTpl;
|
var $devTpl;
|
||||||
|
@ -14,24 +14,13 @@
|
||||||
var $webhookTpl;
|
var $webhookTpl;
|
||||||
var $webhookHeaderTpl;
|
var $webhookHeaderTpl;
|
||||||
|
|
||||||
// TODO add offset based on date selected (i.e. MDT -0500)
|
function pad(i) {
|
||||||
var tzdb = [
|
i = String(i);
|
||||||
'America/New_York',
|
while (i.length < 2) {
|
||||||
'America/Chicago',
|
i = '0' + i;
|
||||||
'America/Denver',
|
}
|
||||||
'America/Phoenix',
|
return i;
|
||||||
'America/Los_Angeles',
|
}
|
||||||
'America/Sao_Paulo',
|
|
||||||
'Europe/London',
|
|
||||||
'Europe/Berlin',
|
|
||||||
'Europe/Moscow',
|
|
||||||
'Asia/Dubai',
|
|
||||||
'Asia/Kolkata',
|
|
||||||
'Asia/Hong_Kong',
|
|
||||||
'Asia/Tokyo',
|
|
||||||
'Pacific/Auckland',
|
|
||||||
'Australia/Sydney'
|
|
||||||
];
|
|
||||||
|
|
||||||
function run() {
|
function run() {
|
||||||
$headerTpl = $('.js-new-webhook .js-header').outerHTML;
|
$headerTpl = $('.js-new-webhook .js-header').outerHTML;
|
||||||
|
@ -44,6 +33,14 @@
|
||||||
// after blanking all inner templates
|
// after blanking all inner templates
|
||||||
$devTpl = $('.js-schedule').outerHTML;
|
$devTpl = $('.js-schedule').outerHTML;
|
||||||
|
|
||||||
|
// Pick a date and time on an even number
|
||||||
|
// between 10 and 15 minutes in the future
|
||||||
|
var d = new Date(Date.now() + 10 * 60 * 1000);
|
||||||
|
var minutes = d.getMinutes() + (5 - (d.getMinutes() % 5)) - d.getMinutes();
|
||||||
|
d = new Date(d.valueOf() + minutes * 60 * 1000);
|
||||||
|
$('.js-date').value = d.getFullYear() + '-' + pad(d.getMonth() + 1) + '-' + pad(d.getDate());
|
||||||
|
$('.js-time').value = pad(d.getHours()) + ':' + pad(d.getMinutes());
|
||||||
|
|
||||||
console.log('hello');
|
console.log('hello');
|
||||||
|
|
||||||
$('body').addEventListener('click', function(ev) {
|
$('body').addEventListener('click', function(ev) {
|
||||||
|
@ -51,15 +48,9 @@
|
||||||
newWebhookHeader(ev.target);
|
newWebhookHeader(ev.target);
|
||||||
} else if (ev.target.matches('.js-rm-header')) {
|
} else if (ev.target.matches('.js-rm-header')) {
|
||||||
rmWebhookHeader(ev.target);
|
rmWebhookHeader(ev.target);
|
||||||
} else if (
|
} else if (ev.target.matches('.js-delete') && ev.target.closest('.js-grant')) {
|
||||||
ev.target.matches('.js-delete') &&
|
|
||||||
ev.target.closest('.js-grant')
|
|
||||||
) {
|
|
||||||
deleteGrant(ev.target.closest('.js-grant'));
|
deleteGrant(ev.target.closest('.js-grant'));
|
||||||
} else if (
|
} else if (ev.target.matches('.js-delete') && ev.target.closest('.js-webhook')) {
|
||||||
ev.target.matches('.js-delete') &&
|
|
||||||
ev.target.closest('.js-webhook')
|
|
||||||
) {
|
|
||||||
deleteWebhook(ev.target.closest('.js-webhook'));
|
deleteWebhook(ev.target.closest('.js-webhook'));
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
|
@ -68,26 +59,44 @@
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$('body').addEventListener('change', function(ev) {
|
||||||
|
var $hook = ev.target.closest('.js-new-webhook');
|
||||||
|
if (ev.target.matches('.js-url') && $hook) {
|
||||||
|
if (!$('.js-comment', $hook).value) {
|
||||||
|
$('.js-comment', $hook).value = ev.target.value.replace(/https:\/\//, '').replace(/\/.*/, '');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
$('body').addEventListener('submit', function(ev) {
|
$('body').addEventListener('submit', function(ev) {
|
||||||
if (ev.target.matches('.js-new-schedule')) {
|
if (ev.target.matches('.js-new-schedule')) {
|
||||||
newSchedule(ev.target);
|
newSchedule(ev.target);
|
||||||
|
} else if (ev.target.matches('.js-schedules-list')) {
|
||||||
|
doLogin();
|
||||||
|
} else if (ev.target.matches('.js-schedules-new')) {
|
||||||
|
scheduleTask();
|
||||||
} else {
|
} else {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
ev.stopPropagation();
|
ev.stopPropagation();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function newSchedule() {
|
function newSchedule() {
|
||||||
var $hook = $('.js-new-webhook');
|
var $hook = $('.js-schedule');
|
||||||
var deviceId = $hook.closest('.js-schedule').querySelector('.js-id').value;
|
//var deviceId = $hook.closest('.js-schedule').querySelector('.js-id').value;
|
||||||
var hook = {
|
var hook = {
|
||||||
|
date: $('.js-date', $hook).value,
|
||||||
|
time: $('.js-time', $hook).value,
|
||||||
|
tz: $('.js-tz', $hook).value,
|
||||||
comment: $('.js-comment', $hook).value,
|
comment: $('.js-comment', $hook).value,
|
||||||
method: $('.js-method', $hook).value,
|
method: $('.js-method', $hook).value,
|
||||||
url: $('.js-url', $hook).value,
|
url: $('.js-url', $hook).value,
|
||||||
headers: {}
|
headers: {}
|
||||||
};
|
};
|
||||||
|
console.log('schedule:', hook);
|
||||||
$$('.js-header', $hook).forEach(function($head) {
|
$$('.js-header', $hook).forEach(function($head) {
|
||||||
var key = $('.js-key', $head).value;
|
var key = $('.js-key', $head).value;
|
||||||
var val = $('.js-value', $head).value;
|
var val = $('.js-value', $head).value;
|
||||||
|
@ -102,7 +111,7 @@
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
Authorization: JSON.parse(localStorage.getItem('session')).access_token,
|
Authorization: getToken(),
|
||||||
'Content-Type': 'application/json'
|
'Content-Type': 'application/json'
|
||||||
},
|
},
|
||||||
body: JSON.stringify(hook),
|
body: JSON.stringify(hook),
|
||||||
|
@ -120,22 +129,15 @@
|
||||||
return;
|
return;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
window
|
window.fetch('/api/v0/schedules', opts).then(function(resp) {
|
||||||
.fetch('/api/iot/devices/' + deviceId + '/webhooks', opts)
|
|
||||||
.then(function(resp) {
|
|
||||||
return resp
|
return resp
|
||||||
.json()
|
.json()
|
||||||
.then(function(data) {
|
.then(function(data) {
|
||||||
if (!data.webhook) {
|
if (!data.schedule) {
|
||||||
throw new Error('something bad happened');
|
throw new Error('something bad happened');
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
state.account.devices
|
state.account.schedules.webhooks.push(resp.data.schedule);
|
||||||
.filter(function(d) {
|
|
||||||
return d.accessToken == deviceId;
|
|
||||||
})[0]
|
|
||||||
.webhooks.push(resp.data.webhook);
|
|
||||||
|
|
||||||
displayAccount(state.account);
|
displayAccount(state.account);
|
||||||
})
|
})
|
||||||
|
@ -168,13 +170,11 @@
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
headers: {
|
headers: {
|
||||||
Accept: 'application/json',
|
Accept: 'application/json',
|
||||||
Authorization: JSON.parse(localStorage.getItem('session')).access_token
|
Authorization: getToken()
|
||||||
},
|
},
|
||||||
cors: true
|
cors: true
|
||||||
};
|
};
|
||||||
window
|
window.fetch('/api/iot/devices/' + deviceId + '/webhooks/' + id, opts).then(function(resp) {
|
||||||
.fetch('/api/iot/devices/' + deviceId + '/webhooks/' + id, opts)
|
|
||||||
.then(function(resp) {
|
|
||||||
return resp.json().then(function(result) {
|
return resp.json().then(function(result) {
|
||||||
if (!result.webhook) {
|
if (!result.webhook) {
|
||||||
console.error(result);
|
console.error(result);
|
||||||
|
@ -232,11 +232,7 @@
|
||||||
$('.js-comment', $grant).innerText = g.comment;
|
$('.js-comment', $grant).innerText = g.comment;
|
||||||
$('.js-token', $grant).innerText = g.token;
|
$('.js-token', $grant).innerText = g.token;
|
||||||
//TODO Math.floor(Date.now() / 1000);
|
//TODO Math.floor(Date.now() / 1000);
|
||||||
var url =
|
var url = 'https://test.therootcompany.com/api/v1/devices/' + d.accessToken + '/updates?since=' + 0;
|
||||||
'https://test.therootcompany.com/api/v1/devices/' +
|
|
||||||
d.accessToken +
|
|
||||||
'/updates?since=' +
|
|
||||||
0;
|
|
||||||
$('.js-example-curl .js-example-url', $grant).innerText = url;
|
$('.js-example-curl .js-example-url', $grant).innerText = url;
|
||||||
$('.js-example-curl .js-example-token', $grant).innerText = g.token;
|
$('.js-example-curl .js-example-token', $grant).innerText = g.token;
|
||||||
$('.js-example-js .js-example-url', $grant).innerText = url;
|
$('.js-example-js .js-example-url', $grant).innerText = url;
|
||||||
|
@ -258,10 +254,11 @@
|
||||||
return resp.json().then(function(tzdb) {
|
return resp.json().then(function(tzdb) {
|
||||||
console.info('[tzdb] received');
|
console.info('[tzdb] received');
|
||||||
var tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
var tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||||
var options = $$('.js-schedule-tz option');
|
var options = $$('.js-tz option');
|
||||||
var valOpt = options[0].outerHTML; // UTC
|
var valOpt = options[0].outerHTML; // UTC
|
||||||
var spaceOpt = options[1].outerHTML; // ----
|
var spaceOpt = options[1].outerHTML; // ----
|
||||||
var innerHTML = $('.js-schedule-tz').innerHTML;
|
var innerHTML = $('.js-tz').innerHTML;
|
||||||
|
/*
|
||||||
innerHTML =
|
innerHTML =
|
||||||
'<option selected value="' +
|
'<option selected value="' +
|
||||||
tz +
|
tz +
|
||||||
|
@ -270,8 +267,9 @@
|
||||||
'</option>' +
|
'</option>' +
|
||||||
spaceOpt +
|
spaceOpt +
|
||||||
innerHTML.replace(/>UTC/, '> UTC');
|
innerHTML.replace(/>UTC/, '> UTC');
|
||||||
//$('.js-schedule-tz').innerHTML += spaceOpt;
|
*/
|
||||||
//$('.js-schedule-tz').innerHTML += valOpt.replace(/UTC/g, 'custom');
|
//$('.js-tz').innerHTML += spaceOpt;
|
||||||
|
//$('.js-tz').innerHTML += valOpt.replace(/UTC/g, 'custom');
|
||||||
Object.keys(tzdb)
|
Object.keys(tzdb)
|
||||||
.sort()
|
.sort()
|
||||||
.forEach(function(k) {
|
.forEach(function(k) {
|
||||||
|
@ -287,15 +285,68 @@
|
||||||
areas.forEach(function(_tz) {
|
areas.forEach(function(_tz) {
|
||||||
if (tz !== _tz) {
|
if (tz !== _tz) {
|
||||||
innerHTML += valOpt.replace(/UTC/g, _tz);
|
innerHTML += valOpt.replace(/UTC/g, _tz);
|
||||||
|
} else {
|
||||||
|
innerHTML += '<option selected value="' + tz + '">' + tz + '</option>';
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
innerHTML += '</optgroup>';
|
innerHTML += '</optgroup>';
|
||||||
});
|
});
|
||||||
$('.js-schedule-tz').innerHTML = innerHTML;
|
$('.js-tz').innerHTML = innerHTML;
|
||||||
|
|
||||||
console.info('[tzdb] loaded');
|
console.info('[tzdb] loaded');
|
||||||
run();
|
run();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var allSchedules = [];
|
||||||
|
|
||||||
|
function getToken() {
|
||||||
|
return JSON.parse(localStorage.getItem('session')).access_token;
|
||||||
|
}
|
||||||
|
|
||||||
|
function doLogin() {
|
||||||
|
localStorage.setItem(
|
||||||
|
'session',
|
||||||
|
JSON.stringify({
|
||||||
|
access_token: $('.js-auth-token').value
|
||||||
|
})
|
||||||
|
);
|
||||||
|
$('.js-schedules-list').hidden = true;
|
||||||
|
$('.js-schedules').hidden = false;
|
||||||
|
return window
|
||||||
|
.fetch('/api/v0/schedules', {
|
||||||
|
headers: { Authorization: getToken() }
|
||||||
|
})
|
||||||
|
.then(function(resp) {
|
||||||
|
return resp.json().then(function(schedules) {
|
||||||
|
allSchedules = schedules;
|
||||||
|
renderSchedules(schedules);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderSchedules(schedules) {
|
||||||
|
document.querySelector('.js-schedules-output').innerText = JSON.stringify(schedules, null, 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
function scheduleTask() {
|
||||||
|
return window
|
||||||
|
.fetch('/api/v0/schedules/new', {
|
||||||
|
method: 'POST',
|
||||||
|
headers: {
|
||||||
|
Authorization: getToken(),
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
},
|
||||||
|
body: JSON.stringify(task)
|
||||||
|
})
|
||||||
|
.then(function(resp) {
|
||||||
|
return resp.json().then(function(schedule) {
|
||||||
|
console.log('New Schedule:', schedule);
|
||||||
|
allSchedules.push(schedule);
|
||||||
|
renderSchedules(allSchedules);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
//window.addEventListener('load', run);
|
//window.addEventListener('load', run);
|
||||||
})();
|
})();
|
|
@ -10,26 +10,29 @@
|
||||||
<form class="js-schedules-list">
|
<form class="js-schedules-list">
|
||||||
<label
|
<label
|
||||||
>Token:
|
>Token:
|
||||||
<input class="js-auth-token" type="text" />
|
<input class="js-auth-token" type="text" required />
|
||||||
</label>
|
</label>
|
||||||
<button>See Schedules</button>
|
<button>Login</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
<pre><code class="js-schedules-output"> </code></pre>
|
<pre><code class="js-schedules-output"> </code></pre>
|
||||||
|
|
||||||
<div class="js-schedules">
|
<div class="js-schedules" hidden>
|
||||||
<h2>Schedules</h2>
|
<h2>Schedules</h2>
|
||||||
<div class="js-schedule">
|
<div class="js-schedule">
|
||||||
<form class="js-new-schedule">
|
<form class="js-new-schedule">
|
||||||
<label>Date: <input type="date" required/></label>
|
<label>Date: <input type="date" class="js-date" required/></label>
|
||||||
<br />
|
<label
|
||||||
<label>Time: <input type="time" step="60" required/></label>
|
>Time: <input type="time" class="js-time" step="60" required
|
||||||
<br />
|
/></label>
|
||||||
<!-- TODO combo box -->
|
<!-- TODO combo box -->
|
||||||
<select class="js-schedule-tz">
|
<label
|
||||||
|
>Location:
|
||||||
|
<select class="js-tz">
|
||||||
<option value="UTC">UTC</option>
|
<option value="UTC">UTC</option>
|
||||||
<option disabled>──────────</option>
|
<option disabled>──────────</option>
|
||||||
</select>
|
</select>
|
||||||
|
</label>
|
||||||
<br />
|
<br />
|
||||||
|
|
||||||
<div class="doc-webhooks-container">
|
<div class="doc-webhooks-container">
|
||||||
|
@ -54,11 +57,16 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="js-new-webhook">
|
<div class="js-new-webhook">
|
||||||
|
<!--
|
||||||
<select class="js-template">
|
<select class="js-template">
|
||||||
<option value="" selected>Custom</option>
|
<option value="webhook" selected>Custom Webhook</option>
|
||||||
<option value="dweet-v2">Dweet v2</option>
|
<option value="requestbin">RequestBin</option>
|
||||||
|
<option value="mailgun">Maligun</option>
|
||||||
|
<option value="twilio">Twilio</option>
|
||||||
|
<option value="pushbullet">Pushbullet</option>
|
||||||
</select>
|
</select>
|
||||||
<br />
|
<br />
|
||||||
|
-->
|
||||||
<input
|
<input
|
||||||
class="js-comment"
|
class="js-comment"
|
||||||
type="text"
|
type="text"
|
||||||
|
@ -101,66 +109,6 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script src="./ajquery.js"></script>
|
<script src="./ajquery.js"></script>
|
||||||
<script>
|
<script src="./app.js"></script>
|
||||||
'use strict';
|
|
||||||
|
|
||||||
var allSchedules = [];
|
|
||||||
document.body.addEventListener('submit', function(ev) {
|
|
||||||
if (ev.target.matches('.js-schedules-list')) {
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
getSchedules();
|
|
||||||
return;
|
|
||||||
} else if (ev.target.matches('.js-schedules-new')) {
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
scheduleTask();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
function getToken() {
|
|
||||||
return document.querySelector('.js-auth-token').value;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getSchedules() {
|
|
||||||
return window
|
|
||||||
.fetch('/api/schedules', {
|
|
||||||
headers: { Authorization: getToken() }
|
|
||||||
})
|
|
||||||
.then(function(resp) {
|
|
||||||
return resp.json().then(function(schedules) {
|
|
||||||
allSchedules = schedules;
|
|
||||||
renderSchedules(schedules);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function renderSchedules(schedules) {
|
|
||||||
document.querySelector(
|
|
||||||
'.js-schedules-output'
|
|
||||||
).innerText = JSON.stringify(schedules, null, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
function scheduleTask() {
|
|
||||||
return window
|
|
||||||
.fetch('/api/schedules/new', {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
Authorization: getToken(),
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
body: JSON.stringify(task)
|
|
||||||
})
|
|
||||||
.then(function(resp) {
|
|
||||||
return resp.json().then(function(schedule) {
|
|
||||||
console.log('New Schedule:', schedule);
|
|
||||||
allSchedules.push(schedule);
|
|
||||||
renderSchedules(allSchedules);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
<script src="./hooks.js"></script>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
package webooks
|
||||||
|
|
||||||
|
type Webhook struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
URL string `json:"url"`
|
||||||
|
Auth map[string]string `json:"auth"`
|
||||||
|
Headers map[string]string `json:"headers"`
|
||||||
|
Form map[string]string `json:"form"`
|
||||||
|
JSON map[string]string `json:"json"`
|
||||||
|
Config map[string]string `json:"config"`
|
||||||
|
}
|
Loading…
Reference in New Issue