diff --git a/index.html b/index.html index e83b1f0..70cf1f3 100644 --- a/index.html +++ b/index.html @@ -3,9 +3,18 @@ - Battermost + Bettermost +
+ + + + +
Server
Username
Password
+ +
+ diff --git a/main.js b/main.js index 981fb1f..9533e46 100644 --- a/main.js +++ b/main.js @@ -1,84 +1,57 @@ -//async function postJson(url, data = {}, options = {}) { - //const response = await fetch(url, { - //method: "POST", - //mode: "no-cors", - //credentials: "include", - //headers: { "Content-Type": "application/json" }, - //redirect: "follow", - //referrerPolicy: "no-referrer", - //body: JSON.stringify(data), - //...options - //}); - ////return await response.json(); - //return response; -//} +"use strict"; -//var endpoint = "https://mattermost.zeus.gent/api/v4"; // Must not end with slash -var endpoint = "http://localhost:8080"; // Must not end with slash -var username = "fill me in"; -var password = "fill me in"; +function byId(id, nullOk=false) { + const el = document.getElementById(id); + if (!el && !nullOk) { + console.error(`No element #${id}`); + } + return el; +} +class MattermostApi { + constructor(endpoint) { + this.endpoint = endpoint; + } -function scopeToArg(f) { - return function(...rest) { - return f(this, ...rest); + async validateToken(token) { + const response = await ajax.getJson(`${this.endpoint}/users/me`, { + headers: { + "Token": `Authorization: Bearer ${token}` + } + }); + return response.ok; + } + + logIn(username, password) { + return ajax.postJson(`${this.endpoint}/users/login`, { + "login_id": username, + "password": password + }) + .then(response => { + let token = response.getHeader("Token"); + window.localStorage.setItem("token", token); + return response; + }) + .then(response => { + document.body.innerHTML = ""; + const pre = document.createElement("pre"); + pre.innerText = JSON.stringify(response.json, null, 2); + document.body.appendChild(pre); + + return response; + }) + .catch(error => { + console.error(error); + document.body.innerText = `An error occurred: ${error}`; + }); } } -function postJson(url, data={}, options={}) { - const prom = new Promise((resolve, reject) => { - let oReq = new XMLHttpRequest(); - oReq.addEventListener("load", scopeToArg(resolve)); - oReq.addEventListener("abort", scopeToArg(reject)); - oReq.addEventListener("error", scopeToArg(reject)); - oReq.addEventListener("timeout", scopeToArg(reject)); - oReq.open("POST", url); - oReq.send(JSON.stringify(data)); +function logIn() { + let endpoint = byId("server").value; + if (!endpoint.endsWith("/")) endpoint += "/"; + endpoint += "api/v4"; - }); - return prom; + let api = new MattermostApi(endpoint); + api.logIn(byId("username").value, byId("password").value); } - -var token = null; - -function printIt(response) { - console.log(response); - if (response.status == 0) { - document.body.innerText = "Network error"; - return; - } - - if (200 <= response.status && response.status < 300) { - try { - const json = JSON.parse(response.response); - document.body.innerHTML = ""; - const pre = document.createElement("pre"); - pre.innerText = "Received " + JSON.stringify(json, null, 2); - document.body.appendChild(pre); - - token = response.getResponseHeader("token"); - window.localStorage.setItem("token", token); - - return token; - } catch(e) { - document.body.innerText = "The server did not reply with a valid JSON object. Make sure the server URL points to a Mattermost instance that is working correctly."; - } - - } else { - console.log(response.getAllResponseHeaders()); - try { - const json = JSON.parse(response.response); - document.body.innerText = "Failed to log in: " + json.message; - } catch(e) { - document.body.innerText = "Error: " + response.statusText; - } - } -} - - -postJson(`${endpoint}/api/v4/users/login`, { - "login_id": username, - "password": password -}) - .then(printIt, printIt) - .then(token => console.log(token)); diff --git a/xhr.js b/xhr.js new file mode 100644 index 0000000..a8e36e3 --- /dev/null +++ b/xhr.js @@ -0,0 +1,91 @@ +const ajax = (function() { "use strict"; + +class NetworkError extends Error {} +class UnexpectedMimeError extends Error {} +class InvalidJsonError extends Error {} + +const MIME_JSON = "application/json"; + + +/** + * Wrap a function so that it receives `this` as first argument. + */ +function thisToArg(f) { + return function(...rest) { + return f(this, ...rest); + } +} + +function xhrInitForPromise(resolve, reject, url, method, headers) { + const t_resolve = thisToArg(resolve), + t_reject = thisToArg(reject); + + let xhr = new XMLHttpRequest(); + xhr.addEventListener("load", t_resolve); + xhr.addEventListener("error", t_resolve); + xhr.addEventListener("abort", t_reject); + xhr.addEventListener("timeout", t_reject); + xhr.open(method, url); + for (let header of Object.getOwnPropertyNames(headers)) { + xhr.setRequestHeader(header, headers[header]); + } + return xhr; +} + +function xhrParseJsonResponse(xhr) { + if (xhr.status == 0) { + console.error(xhr); + throw new NetworkError("Failed to connect to server"); + } + + if (!xhr.responseText) { + const json = null; + } else { + const contentType = xhr.getResponseHeader("Content-Type"); + if (contentType != MIME_JSON) { + throw new UnexpectedMimeError(`Server did not reply with JSON but with ${contentType}`); + } + try { + const json = JSON.parse(xhr.responseText); + } catch(e) { + throw new InvalidJsonError(); + } + } + + return { + ok: 200 <= xhr.status && xhr.status < 300, + status: xhr.status, + statusText: xhr.statusText, + getHeader: xhr.getResponseHeader, + json, + xhr, + }; +} + +function getJson(url, options={}) { + if (!options.headers) options.headers = {}; + options.headers["Accept"] = MIME_JSON; + + return new Promise((resolve, reject) => { + let xhr = xhrInitForPromise(resolve, reject, url, "GET", options.headers); + xhr.send(); + }).then(xhrParseJsonResponse); +} + +function postJson(url, data={}, options={}) { + if (!options.headers) options.headers = {}; + options.headers["Content-Type"] = MIME_JSON; + options.headers["Accept"] = MIME_JSON; + + return new Promise((resolve, reject) => { + let xhr = xhrInitForPromise(resolve, reject, url, "POST", options.headers); + xhr.send(JSON.stringify(data)); + }).then(xhrParseJsonResponse); +} + +return { + NetworkError, UnexpectedMimeError, InvalidJsonError, + getJson, postJson +}; + +})();