Browse Source

wip can send event

wip
AJ ONeal 5 years ago
parent
commit
f135020914
  1. 3
      again.go
  2. 2
      cmd/again/again.go
  3. 8
      public/.prettierrc
  4. 233
      public/app.js
  5. 96
      public/index.html
  6. 12
      webhooks/webhooks.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/

2
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")))

8
public/.prettierrc

@ -0,0 +1,8 @@
{
"bracketSpacing": true,
"printWidth": 120,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "none",
"useTabs": true
}

233
public/hooks.js → 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 =
'<option selected value="' +
tz +
@ -270,8 +267,9 @@
'</option>' +
spaceOpt +
innerHTML.replace(/>UTC/, '>&nbsp;&nbsp;&nbsp;&nbsp;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);
})();

96
public/index.html

@ -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>

12
webhooks/webhooks.go

@ -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…
Cancel
Save