diff --git a/again.go b/again.go index be1186a..e980e9b 100644 --- a/again.go +++ b/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/ diff --git a/cmd/again/again.go b/cmd/again/again.go index afd9cb3..aa56fcd 100644 --- a/cmd/again/again.go +++ b/cmd/again/again.go @@ -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"))) diff --git a/public/.prettierrc b/public/.prettierrc new file mode 100644 index 0000000..20f3bd7 --- /dev/null +++ b/public/.prettierrc @@ -0,0 +1,8 @@ +{ + "bracketSpacing": true, + "printWidth": 120, + "singleQuote": true, + "tabWidth": 2, + "trailingComma": "none", + "useTabs": true +} diff --git a/public/hooks.js b/public/app.js similarity index 58% rename from public/hooks.js rename to public/app.js index d5391e0..f274bd3 100644 --- a/public/hooks.js +++ b/public/app.js @@ -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 = ''; } }); innerHTML += ''; }); - $('.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); })(); diff --git a/public/index.html b/public/index.html index e31ace4..549029e 100644 --- a/public/index.html +++ b/public/index.html @@ -10,26 +10,29 @@
- +
 
-
+