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 (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
webhooks "git.rootprojects.org/root/go-again/webhooks"
|
||||
)
|
||||
|
||||
type Schedule struct {
|
||||
NextRunAt time.Time
|
||||
Webhooks []webhooks.Webhook
|
||||
}
|
||||
|
||||
// https://yourbasic.org/golang/time-change-convert-location-timezone/
|
||||
|
|
|
@ -75,7 +75,7 @@ func main() {
|
|||
MaxHeaderBytes: 1 << 20,
|
||||
}
|
||||
//mux.Handle("/api/", http.HandlerFunc(handleFunc))
|
||||
mux.HandleFunc("/api/schedules", s.Handle)
|
||||
mux.HandleFunc("/api/v0/schedules", s.Handle)
|
||||
|
||||
// TODO Filebox FS
|
||||
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 state = {};
|
||||
var state = { account: { schedules: [] } };
|
||||
|
||||
var $grantTpl;
|
||||
var $devTpl;
|
||||
|
@ -14,24 +14,13 @@
|
|||
var $webhookTpl;
|
||||
var $webhookHeaderTpl;
|
||||
|
||||
// TODO add offset based on date selected (i.e. MDT -0500)
|
||||
var tzdb = [
|
||||
'America/New_York',
|
||||
'America/Chicago',
|
||||
'America/Denver',
|
||||
'America/Phoenix',
|
||||
'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 pad(i) {
|
||||
i = String(i);
|
||||
while (i.length < 2) {
|
||||
i = '0' + i;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
function run() {
|
||||
$headerTpl = $('.js-new-webhook .js-header').outerHTML;
|
||||
|
@ -44,6 +33,14 @@
|
|||
// after blanking all inner templates
|
||||
$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');
|
||||
|
||||
$('body').addEventListener('click', function(ev) {
|
||||
|
@ -51,15 +48,9 @@
|
|||
newWebhookHeader(ev.target);
|
||||
} else if (ev.target.matches('.js-rm-header')) {
|
||||
rmWebhookHeader(ev.target);
|
||||
} else if (
|
||||
ev.target.matches('.js-delete') &&
|
||||
ev.target.closest('.js-grant')
|
||||
) {
|
||||
} else if (ev.target.matches('.js-delete') && ev.target.closest('.js-grant')) {
|
||||
deleteGrant(ev.target.closest('.js-grant'));
|
||||
} else if (
|
||||
ev.target.matches('.js-delete') &&
|
||||
ev.target.closest('.js-webhook')
|
||||
) {
|
||||
} else if (ev.target.matches('.js-delete') && ev.target.closest('.js-webhook')) {
|
||||
deleteWebhook(ev.target.closest('.js-webhook'));
|
||||
} else {
|
||||
return;
|
||||
|
@ -68,26 +59,44 @@
|
|||
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) {
|
||||
if (ev.target.matches('.js-new-schedule')) {
|
||||
newSchedule(ev.target);
|
||||
} else if (ev.target.matches('.js-schedules-list')) {
|
||||
doLogin();
|
||||
} else if (ev.target.matches('.js-schedules-new')) {
|
||||
scheduleTask();
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
ev.preventDefault();
|
||||
ev.stopPropagation();
|
||||
});
|
||||
}
|
||||
|
||||
function newSchedule() {
|
||||
var $hook = $('.js-new-webhook');
|
||||
var deviceId = $hook.closest('.js-schedule').querySelector('.js-id').value;
|
||||
var $hook = $('.js-schedule');
|
||||
//var deviceId = $hook.closest('.js-schedule').querySelector('.js-id').value;
|
||||
var hook = {
|
||||
date: $('.js-date', $hook).value,
|
||||
time: $('.js-time', $hook).value,
|
||||
tz: $('.js-tz', $hook).value,
|
||||
comment: $('.js-comment', $hook).value,
|
||||
method: $('.js-method', $hook).value,
|
||||
url: $('.js-url', $hook).value,
|
||||
headers: {}
|
||||
};
|
||||
console.log('schedule:', hook);
|
||||
$$('.js-header', $hook).forEach(function($head) {
|
||||
var key = $('.js-key', $head).value;
|
||||
var val = $('.js-value', $head).value;
|
||||
|
@ -102,7 +111,7 @@
|
|||
method: 'POST',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: JSON.parse(localStorage.getItem('session')).access_token,
|
||||
Authorization: getToken(),
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify(hook),
|
||||
|
@ -110,39 +119,32 @@
|
|||
};
|
||||
|
||||
/*
|
||||
state.account.devices
|
||||
.filter(function(d) {
|
||||
return d.accessToken == deviceId;
|
||||
})[0]
|
||||
.webhooks.push(hook);
|
||||
state.account.devices
|
||||
.filter(function(d) {
|
||||
return d.accessToken == deviceId;
|
||||
})[0]
|
||||
.webhooks.push(hook);
|
||||
|
||||
displayAccount(state.account);
|
||||
return;
|
||||
displayAccount(state.account);
|
||||
return;
|
||||
*/
|
||||
|
||||
window
|
||||
.fetch('/api/iot/devices/' + deviceId + '/webhooks', opts)
|
||||
.then(function(resp) {
|
||||
return resp
|
||||
.json()
|
||||
.then(function(data) {
|
||||
if (!data.webhook) {
|
||||
throw new Error('something bad happened');
|
||||
return;
|
||||
}
|
||||
window.fetch('/api/v0/schedules', opts).then(function(resp) {
|
||||
return resp
|
||||
.json()
|
||||
.then(function(data) {
|
||||
if (!data.schedule) {
|
||||
throw new Error('something bad happened');
|
||||
}
|
||||
|
||||
state.account.devices
|
||||
.filter(function(d) {
|
||||
return d.accessToken == deviceId;
|
||||
})[0]
|
||||
.webhooks.push(resp.data.webhook);
|
||||
state.account.schedules.webhooks.push(resp.data.schedule);
|
||||
|
||||
displayAccount(state.account);
|
||||
})
|
||||
.catch(function(e) {
|
||||
window.alert(e.message);
|
||||
});
|
||||
});
|
||||
displayAccount(state.account);
|
||||
})
|
||||
.catch(function(e) {
|
||||
window.alert(e.message);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function newWebhookHeader($newHeader) {
|
||||
|
@ -168,35 +170,33 @@
|
|||
method: 'DELETE',
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
Authorization: JSON.parse(localStorage.getItem('session')).access_token
|
||||
Authorization: getToken()
|
||||
},
|
||||
cors: true
|
||||
};
|
||||
window
|
||||
.fetch('/api/iot/devices/' + deviceId + '/webhooks/' + id, opts)
|
||||
.then(function(resp) {
|
||||
return resp.json().then(function(result) {
|
||||
if (!result.webhook) {
|
||||
console.error(result);
|
||||
window.alert('something went wrong: ' + JSON.stringify(result));
|
||||
return;
|
||||
}
|
||||
var index = -1;
|
||||
var dev = state.account.devices.filter(function(d, i) {
|
||||
return d.accessToken == deviceId;
|
||||
})[0];
|
||||
dev.webhooks.some(function(g, i) {
|
||||
if (g.id === id) {
|
||||
index = i;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (index > -1) {
|
||||
dev.webhooks.splice(index, 1);
|
||||
displayAccount(state.account);
|
||||
window.fetch('/api/iot/devices/' + deviceId + '/webhooks/' + id, opts).then(function(resp) {
|
||||
return resp.json().then(function(result) {
|
||||
if (!result.webhook) {
|
||||
console.error(result);
|
||||
window.alert('something went wrong: ' + JSON.stringify(result));
|
||||
return;
|
||||
}
|
||||
var index = -1;
|
||||
var dev = state.account.devices.filter(function(d, i) {
|
||||
return d.accessToken == deviceId;
|
||||
})[0];
|
||||
dev.webhooks.some(function(g, i) {
|
||||
if (g.id === id) {
|
||||
index = i;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (index > -1) {
|
||||
dev.webhooks.splice(index, 1);
|
||||
displayAccount(state.account);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function displayAccount(data) {
|
||||
|
@ -232,11 +232,7 @@
|
|||
$('.js-comment', $grant).innerText = g.comment;
|
||||
$('.js-token', $grant).innerText = g.token;
|
||||
//TODO Math.floor(Date.now() / 1000);
|
||||
var url =
|
||||
'https://test.therootcompany.com/api/v1/devices/' +
|
||||
d.accessToken +
|
||||
'/updates?since=' +
|
||||
0;
|
||||
var url = '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-token', $grant).innerText = g.token;
|
||||
$('.js-example-js .js-example-url', $grant).innerText = url;
|
||||
|
@ -258,10 +254,11 @@
|
|||
return resp.json().then(function(tzdb) {
|
||||
console.info('[tzdb] received');
|
||||
var tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
var options = $$('.js-schedule-tz option');
|
||||
var options = $$('.js-tz option');
|
||||
var valOpt = options[0].outerHTML; // UTC
|
||||
var spaceOpt = options[1].outerHTML; // ----
|
||||
var innerHTML = $('.js-schedule-tz').innerHTML;
|
||||
var innerHTML = $('.js-tz').innerHTML;
|
||||
/*
|
||||
innerHTML =
|
||||
'<option selected value="' +
|
||||
tz +
|
||||
|
@ -270,8 +267,9 @@
|
|||
'</option>' +
|
||||
spaceOpt +
|
||||
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)
|
||||
.sort()
|
||||
.forEach(function(k) {
|
||||
|
@ -287,15 +285,68 @@
|
|||
areas.forEach(function(_tz) {
|
||||
if (tz !== _tz) {
|
||||
innerHTML += valOpt.replace(/UTC/g, _tz);
|
||||
} else {
|
||||
innerHTML += '<option selected value="' + tz + '">' + tz + '</option>';
|
||||
}
|
||||
});
|
||||
innerHTML += '</optgroup>';
|
||||
});
|
||||
$('.js-schedule-tz').innerHTML = innerHTML;
|
||||
$('.js-tz').innerHTML = innerHTML;
|
||||
|
||||
console.info('[tzdb] loaded');
|
||||
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);
|
||||
})();
|
|
@ -10,26 +10,29 @@
|
|||
<form class="js-schedules-list">
|
||||
<label
|
||||
>Token:
|
||||
<input class="js-auth-token" type="text" />
|
||||
<input class="js-auth-token" type="text" required />
|
||||
</label>
|
||||
<button>See Schedules</button>
|
||||
<button>Login</button>
|
||||
</form>
|
||||
|
||||
<pre><code class="js-schedules-output"> </code></pre>
|
||||
|
||||
<div class="js-schedules">
|
||||
<div class="js-schedules" hidden>
|
||||
<h2>Schedules</h2>
|
||||
<div class="js-schedule">
|
||||
<form class="js-new-schedule">
|
||||
<label>Date: <input type="date" required/></label>
|
||||
<br />
|
||||
<label>Time: <input type="time" step="60" required/></label>
|
||||
<br />
|
||||
<label>Date: <input type="date" class="js-date" required/></label>
|
||||
<label
|
||||
>Time: <input type="time" class="js-time" step="60" required
|
||||
/></label>
|
||||
<!-- TODO combo box -->
|
||||
<select class="js-schedule-tz">
|
||||
<option value="UTC">UTC</option>
|
||||
<option disabled>──────────</option>
|
||||
</select>
|
||||
<label
|
||||
>Location:
|
||||
<select class="js-tz">
|
||||
<option value="UTC">UTC</option>
|
||||
<option disabled>──────────</option>
|
||||
</select>
|
||||
</label>
|
||||
<br />
|
||||
|
||||
<div class="doc-webhooks-container">
|
||||
|
@ -54,11 +57,16 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="js-new-webhook">
|
||||
<!--
|
||||
<select class="js-template">
|
||||
<option value="" selected>Custom</option>
|
||||
<option value="dweet-v2">Dweet v2</option>
|
||||
<option value="webhook" selected>Custom Webhook</option>
|
||||
<option value="requestbin">RequestBin</option>
|
||||
<option value="mailgun">Maligun</option>
|
||||
<option value="twilio">Twilio</option>
|
||||
<option value="pushbullet">Pushbullet</option>
|
||||
</select>
|
||||
<br />
|
||||
-->
|
||||
<input
|
||||
class="js-comment"
|
||||
type="text"
|
||||
|
@ -101,66 +109,6 @@
|
|||
</div>
|
||||
|
||||
<script src="./ajquery.js"></script>
|
||||
<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>
|
||||
<script src="./app.js"></script>
|
||||
</body>
|
||||
</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