Add channel viewing

This commit is contained in:
Midgard 2020-03-29 00:40:47 +01:00
parent 4ce30be711
commit 49bc51175a
Signed by: midgard
GPG key ID: 511C112F1331BBB4
3 changed files with 105 additions and 7 deletions

16
ajax.js
View file

@ -68,10 +68,26 @@ function xhrParseJsonResponse(xhr) {
return xhr; return xhr;
} }
function withParams(url, queryParams) {
let sep = "?";
for (let paramName of Object.getOwnPropertyNames(queryParams)) {
const paramValue = queryParams[paramName];
if (!paramValue) continue;
url += `${sep}${encodeURIComponent(paramName)}`;
if (paramValue !== true) {
url += `=${encodeURIComponent(paramValue)}`;
}
sep = "&";
}
}
function getJson(url, options={}) { function getJson(url, options={}) {
if (!options.queryParams) options.queryParams = {};
if (!options.headers) options.headers = {}; if (!options.headers) options.headers = {};
options.headers["Accept"] = MIME_JSON; options.headers["Accept"] = MIME_JSON;
const urlWithParams = withParams(url, options.queryParams);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
let xhr = xhrInitForPromise(resolve, reject, url, "GET", options.headers); let xhr = xhrInitForPromise(resolve, reject, url, "GET", options.headers);
xhr.send(); xhr.send();

View file

@ -42,3 +42,29 @@ h1 img {
#login_server_row td, #login_server_row th { #login_server_row td, #login_server_row th {
padding-bottom: 1em; padding-bottom: 1em;
} }
.post {
margin: 1em 0;
display: grid;
grid-template-rows: auto auto;
grid-template-columns: auto auto;
}
.post .author {
grid-row: 1;
grid-column: 1;
color: #888;
}
.post .create_at {
text-align: right;
grid-row: 1;
grid-column: 2;
color: #888;
}
.post .message {
grid-row: 2;
grid-column-start: 1;
grid-column-end: 3;
}

70
main.js
View file

@ -54,16 +54,16 @@ class MattermostApi {
return this._endpoint; return this._endpoint;
} }
async get(path, token) { async get(path, token, queryParams) {
const headers = token ? {"Authorization": `Bearer ${token}`} : {}; const headers = token ? {"Authorization": `Bearer ${token}`} : {};
const response = await ajax.getJson(`${this._endpoint}${path}`, {headers}); const response = await ajax.getJson(`${this._endpoint}${path}`, {headers, queryParams});
if (!response.ok) { if (!response.ok) {
throw response; throw response;
} }
return response; return response;
} }
async post(path, data, token) { async post(path, token, data) {
const headers = token ? {"Authorization": `Bearer ${token}`} : {}; const headers = token ? {"Authorization": `Bearer ${token}`} : {};
const response = await ajax.postJson(`${this._endpoint}${path}`, data, {headers}); const response = await ajax.postJson(`${this._endpoint}${path}`, data, {headers});
if (!response.ok) { if (!response.ok) {
@ -81,7 +81,7 @@ class MattermostClient {
} }
async logIn(login_id, password) { async logIn(login_id, password) {
const response = await this.api.post("/users/login", {login_id, password}); const response = await this.api.post("/users/login", undefined, {login_id, password});
const token = response.getResponseHeader("Token"); const token = response.getResponseHeader("Token");
if (!token) { if (!token) {
throw Error("No Token header in response to log in request"); throw Error("No Token header in response to log in request");
@ -95,7 +95,7 @@ class MattermostClient {
if (!stored || !stored.token) { if (!stored || !stored.token) {
throw Error("No token stored"); throw Error("No token stored");
} }
const response = await this.api.post("/users/logout", undefined, stored.token); const response = await this.api.post("/users/logout", stored.token);
// Verify that the token is now invalidated // Verify that the token is now invalidated
let tokenWorks; let tokenWorks;
@ -137,6 +137,14 @@ class MattermostClient {
const response = await this.api.get(`/users/me/teams/${team_id}/channels`, stored.token); const response = await this.api.get(`/users/me/teams/${team_id}/channels`, stored.token);
return response.responseJson; return response.responseJson;
} }
async channelPosts(channel_id, beforePost=null, afterPost=null, since=null) {
const stored = this.storage.get(this.api.id);
const response = await this.api.get(`/channels/${channel_id}/posts`, stored.token, {
before: beforePost, after: afterPost, since
});
return response.responseJson;
}
} }
@ -231,7 +239,7 @@ function populateChannelList() {
a.innerText = `${channel.type} ${team.name}/${channel.name}`; a.innerText = `${channel.type} ${team.name}/${channel.name}`;
break; break;
} }
a.addEventListener("click", () => switchToChannel(team.id, channel.id)); a.addEventListener("click", () => switchToChannel(client, team.id, channel.id));
li.appendChild(a); li.appendChild(a);
nodes.push(li); nodes.push(li);
} }
@ -248,6 +256,42 @@ function populateChannelList() {
} }
populateChannelList(); populateChannelList();
function populateChannelContents(contents) {
byId("channel_contents").innerHTML = "";
let nodes = [];
for (let id of contents.order) {
const post = contents.posts[id];
const isThreadReply = !!post.parent_id;
const messageDiv = document.createElement("div");
messageDiv.className = "message";
messageDiv.innerText = post.message;
const createAt = new Date(post.create_at);
const createAtDiv = document.createElement("time");
createAtDiv.className = "create_at";
createAtDiv.innerText = createAt.toLocaleString("nl-BE");
createAtDiv.dateTime = createAt.toISOString();
const authorDiv = document.createElement("div");
authorDiv.className = "author";
authorDiv.innerText = `Auteur: ${post.user_id}`;
const postDiv = document.createElement("div");
postDiv.className = "post";
postDiv.dataset["postid"] = id;
postDiv.appendChild(authorDiv);
postDiv.appendChild(createAtDiv);
postDiv.appendChild(messageDiv);
nodes.unshift(postDiv);
}
byId("channel_contents").append(...nodes);
}
function logIn() { function logIn() {
const client = createClient(byId("login_server").value); const client = createClient(byId("login_server").value);
@ -289,8 +333,20 @@ function logOut(endpoint, button) {
}); });
} }
function switchToChannel(team_id, channel_id) { function switchToChannel(client, team_id, channel_id) {
byId("channel_contents").innerText = "Loading…";
window.location = "#channel_contents"; window.location = "#channel_contents";
client.channelPosts(channel_id)
.then(response => {
console.info(`Got channel contents of ${channel_id}`);
populateChannelContents(response);
window.location = "#channel_contents";
//})
//.catch(error => {
//console.error(error);
//byId("channel_contents").innerText = `Failed to get channel contents:\n${error.message}`;
});
} }
byId("login_button").addEventListener("click", logIn); byId("login_button").addEventListener("click", logIn);