Added Frontend
This commit is contained in:
198
frontend/js/api.js
Normal file
198
frontend/js/api.js
Normal file
@@ -0,0 +1,198 @@
|
||||
const prefix = document.getElementsByTagName("base")[0].href.replace(/(?=.*)\/$/gm, "");
|
||||
async function unknownResponse(resp) {
|
||||
let text = await resp.text();
|
||||
try {
|
||||
let json = JSON.parse(text);
|
||||
return new Error(`${json["message"]} (${resp.status})`);
|
||||
}
|
||||
catch (error) {
|
||||
return new Error(`Server sent unknown error: ${text} (${resp.status})`);
|
||||
}
|
||||
}
|
||||
function buildQuery(options) {
|
||||
let query = [];
|
||||
options.forEach(element => {
|
||||
if (element[1] !== undefined) {
|
||||
if (element[1] instanceof Date) {
|
||||
element[1] = element[1].getSeconds();
|
||||
}
|
||||
else if (element[1] instanceof Array) {
|
||||
element[1] = JSON.stringify(element[1]);
|
||||
}
|
||||
query.push(`${element[0]}=${element[1]}`);
|
||||
}
|
||||
});
|
||||
return query.join("&");
|
||||
}
|
||||
async function login(username, password) {
|
||||
let result = await fetch(`${prefix}/api/login`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({ "username": username, "password": password }),
|
||||
credentials: "same-origin"
|
||||
});
|
||||
switch (result.status) {
|
||||
case 200:
|
||||
return;
|
||||
case 401:
|
||||
throw new Error("Wrong username and/or password");
|
||||
default:
|
||||
throw await unknownResponse(result);
|
||||
}
|
||||
}
|
||||
async function authors(name, limit) {
|
||||
let query = [["name", name], ["limit", limit]];
|
||||
let result = await fetch(`${prefix}/api/authors?${buildQuery(query)}`);
|
||||
if (result.status == 200) {
|
||||
return await result.json();
|
||||
}
|
||||
else {
|
||||
throw await unknownResponse(result);
|
||||
}
|
||||
}
|
||||
async function tags(name, limit) {
|
||||
let query = [["name", name], ["limit", limit]];
|
||||
let result = await fetch(`${prefix}/api/tags?${buildQuery(query)}`);
|
||||
if (result.status == 200) {
|
||||
return await result.json();
|
||||
}
|
||||
else {
|
||||
throw await unknownResponse(result);
|
||||
}
|
||||
}
|
||||
async function recent(limit = 20) {
|
||||
let query = [["limit", limit]];
|
||||
let result = await fetch(`${prefix}/api/recent?${buildQuery(query)}`);
|
||||
if (result.status == 200) {
|
||||
return await result.json();
|
||||
}
|
||||
else {
|
||||
throw await unknownResponse(result);
|
||||
}
|
||||
}
|
||||
async function search(q) {
|
||||
let query = [["q", q.query], ["from", q.from], ["to", q.to], ["authors", q.authors], ["tags", q.tags], ["limit", q.limit]];
|
||||
let result = await fetch(`${prefix}/api/search?${buildQuery(query)}`);
|
||||
if (result.status == 200) {
|
||||
return await result.json();
|
||||
}
|
||||
else {
|
||||
throw unknownResponse(result);
|
||||
}
|
||||
}
|
||||
async function getArticle(id) {
|
||||
let query = [["id", id]];
|
||||
let result = await fetch(`${prefix}/api/article?${buildQuery(query)}`, {
|
||||
method: "GET"
|
||||
});
|
||||
switch (result.status) {
|
||||
case 200:
|
||||
return await result.json();
|
||||
case 401:
|
||||
throw new Error("Not authorized");
|
||||
case 404:
|
||||
throw new Error("Article not found");
|
||||
default:
|
||||
throw await unknownResponse(result);
|
||||
}
|
||||
}
|
||||
async function uploadArticle(payload) {
|
||||
let result = await fetch(`${prefix}/api/article`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
switch (result.status) {
|
||||
case 201:
|
||||
return await result.json();
|
||||
case 401:
|
||||
throw new Error("Not authorized");
|
||||
case 409:
|
||||
throw new Error("An article with the same title already exists");
|
||||
default:
|
||||
throw await unknownResponse(result);
|
||||
}
|
||||
}
|
||||
async function editArticle(payload) {
|
||||
let result = await fetch(`${prefix}/api/article`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(payload)
|
||||
});
|
||||
let json = await result.json();
|
||||
switch (result.status) {
|
||||
case 201:
|
||||
return json;
|
||||
case 401:
|
||||
throw new Error("Not authorized");
|
||||
case 404:
|
||||
throw new Error("Could not find article");
|
||||
case 409:
|
||||
throw new Error("An article with the same title already exists");
|
||||
default:
|
||||
throw await unknownResponse(result);
|
||||
}
|
||||
}
|
||||
async function deleteArticle(id) {
|
||||
let result = await fetch(`${prefix}/api/article`, {
|
||||
method: "DELETE",
|
||||
body: JSON.stringify({ "id": id })
|
||||
});
|
||||
switch (result.status) {
|
||||
case 200:
|
||||
return;
|
||||
case 401:
|
||||
throw new Error("Not authorized");
|
||||
case 404:
|
||||
throw new Error("Could not find article");
|
||||
default:
|
||||
throw await unknownResponse(result);
|
||||
}
|
||||
}
|
||||
async function getAssets(name, limit = 20) {
|
||||
let query = [["q", name], ["limit", limit]];
|
||||
let result = await fetch(`${prefix}/api/assets?${buildQuery(query)}`, {
|
||||
method: "GET",
|
||||
});
|
||||
switch (result.status) {
|
||||
case 200:
|
||||
return await result.json();
|
||||
case 401:
|
||||
throw new Error("Not authorized");
|
||||
default:
|
||||
throw await unknownResponse(result);
|
||||
}
|
||||
}
|
||||
async function addAsset(name, content) {
|
||||
let result = await fetch(`${prefix}/api/assets`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
"name": name,
|
||||
"content": content,
|
||||
})
|
||||
});
|
||||
switch (result.status) {
|
||||
case 201:
|
||||
return await result.json();
|
||||
case 401:
|
||||
throw new Error("Not authorized");
|
||||
case 409:
|
||||
throw new Error("An asset with the same name already exists");
|
||||
default:
|
||||
throw await unknownResponse(result);
|
||||
}
|
||||
}
|
||||
async function deleteAsset(id) {
|
||||
let result = await fetch(`${prefix}/api/assets`, {
|
||||
method: "DELETE",
|
||||
body: JSON.stringify({ "id": id })
|
||||
});
|
||||
switch (result.status) {
|
||||
case 200:
|
||||
return;
|
||||
case 401:
|
||||
throw new Error("Not authorized");
|
||||
case 404:
|
||||
throw new Error("An asset with this id does not exist");
|
||||
default:
|
||||
throw await unknownResponse(result);
|
||||
}
|
||||
}
|
||||
//# sourceMappingURL=api.js.map
|
||||
1
frontend/js/api.js.map
Normal file
1
frontend/js/api.js.map
Normal file
File diff suppressed because one or more lines are too long
277
frontend/js/api.ts
Normal file
277
frontend/js/api.ts
Normal file
@@ -0,0 +1,277 @@
|
||||
const prefix = document.getElementsByTagName("base")[0].href.replace(/(?=.*)\/$/gm, "");
|
||||
|
||||
|
||||
async function unknownResponse(resp: Response): Promise<Error> {
|
||||
let text = await resp.text()
|
||||
try {
|
||||
let json = JSON.parse(text)
|
||||
return new Error(`${json["message"]} (${resp.status})`)
|
||||
} catch (error) {
|
||||
return new Error(`Server sent unknown error: ${text} (${resp.status})`)
|
||||
}
|
||||
}
|
||||
|
||||
function buildQuery(options: any[][]): string {
|
||||
let query: string[] = []
|
||||
options.forEach(element => {
|
||||
if (element[1] !== undefined) {
|
||||
if (element[1] instanceof Date) {
|
||||
element[1] = element[1].getSeconds()
|
||||
} else if (element[1] instanceof Array) {
|
||||
element[1] = JSON.stringify(element[1])
|
||||
}
|
||||
query.push(`${element[0]}=${element[1]}`)
|
||||
}
|
||||
});
|
||||
return query.join("&")
|
||||
}
|
||||
|
||||
interface Author {
|
||||
id: number,
|
||||
name: string,
|
||||
information: string
|
||||
}
|
||||
|
||||
interface ArticleSummary {
|
||||
id: number,
|
||||
title: string,
|
||||
summary: string
|
||||
authors: Author[],
|
||||
image?: string,
|
||||
tags: string[],
|
||||
created: Date,
|
||||
modified?: Date,
|
||||
link: string
|
||||
}
|
||||
|
||||
interface Asset {
|
||||
id: number,
|
||||
name: string,
|
||||
link: string
|
||||
}
|
||||
|
||||
async function login(username: string, password: string): Promise<void> {
|
||||
let result = await fetch(`${prefix}/api/login`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({"username": username, "password": password}),
|
||||
credentials: "same-origin"
|
||||
})
|
||||
switch (result.status) {
|
||||
case 200:
|
||||
return
|
||||
case 401:
|
||||
throw new Error("Wrong username and/or password")
|
||||
default:
|
||||
throw await unknownResponse(result)
|
||||
}
|
||||
}
|
||||
|
||||
async function authors(name?: string, limit?: number): Promise<Author[]> {
|
||||
let query = [["name", name], ["limit", limit]]
|
||||
|
||||
let result = await fetch(`${prefix}/api/authors?${buildQuery(query)}`)
|
||||
if (result.status == 200) {
|
||||
return await result.json()
|
||||
} else {
|
||||
throw await unknownResponse(result)
|
||||
}
|
||||
}
|
||||
|
||||
async function tags(name?: string, limit?: number): Promise<string[]> {
|
||||
let query = [["name", name], ["limit", limit]]
|
||||
|
||||
let result = await fetch(`${prefix}/api/tags?${buildQuery(query)}`)
|
||||
if (result.status == 200) {
|
||||
return await result.json()
|
||||
} else {
|
||||
throw await unknownResponse(result)
|
||||
}
|
||||
}
|
||||
|
||||
async function recent(limit: number = 20): Promise<ArticleSummary[]> {
|
||||
let query = [["limit", limit]]
|
||||
|
||||
let result = await fetch(`${prefix}/api/recent?${buildQuery(query)}`)
|
||||
if (result.status == 200) {
|
||||
return await result.json()
|
||||
} else {
|
||||
throw await unknownResponse(result)
|
||||
}
|
||||
}
|
||||
|
||||
interface SearchQuery {
|
||||
query?: string,
|
||||
from?: Date,
|
||||
to?: Date,
|
||||
authors?: number[],
|
||||
tags?: string[],
|
||||
limit?: number
|
||||
}
|
||||
|
||||
async function search(q: SearchQuery): Promise<ArticleSummary[]> {
|
||||
let query = [["q", q.query], ["from", q.from], ["to", q.to], ["authors", q.authors], ["tags", q.tags], ["limit", q.limit]]
|
||||
|
||||
let result = await fetch(`${prefix}/api/search?${buildQuery(query)}`)
|
||||
if (result.status == 200) {
|
||||
return await result.json()
|
||||
} else {
|
||||
throw unknownResponse(result)
|
||||
}
|
||||
}
|
||||
|
||||
interface ArticleGetPayload {
|
||||
title: string,
|
||||
summary: string,
|
||||
authors: number[],
|
||||
image: string,
|
||||
tags: string[],
|
||||
link: string
|
||||
content: string
|
||||
}
|
||||
|
||||
async function getArticle(id: number): Promise<ArticleGetPayload> {
|
||||
let query = [["id", id]]
|
||||
|
||||
let result = await fetch(`${prefix}/api/article?${buildQuery(query)}`, {
|
||||
method: "GET"
|
||||
})
|
||||
switch (result.status) {
|
||||
case 200:
|
||||
return await result.json()
|
||||
case 401:
|
||||
throw new Error("Not authorized")
|
||||
case 404:
|
||||
throw new Error("Article not found")
|
||||
default:
|
||||
throw await unknownResponse(result)
|
||||
}
|
||||
}
|
||||
|
||||
interface ArticleUploadPayload {
|
||||
title: string,
|
||||
summary: string,
|
||||
authors: number[],
|
||||
image?: string,
|
||||
tags: string[],
|
||||
link?: string
|
||||
content: string
|
||||
}
|
||||
|
||||
async function uploadArticle(payload: ArticleUploadPayload): Promise<ArticleSummary> {
|
||||
let result = await fetch(`${prefix}/api/article`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
switch (result.status) {
|
||||
case 201:
|
||||
return await result.json()
|
||||
case 401:
|
||||
throw new Error("Not authorized")
|
||||
case 409:
|
||||
throw new Error("An article with the same title already exists")
|
||||
default:
|
||||
throw await unknownResponse(result)
|
||||
}
|
||||
}
|
||||
|
||||
interface ArticleEditPayload {
|
||||
id: number,
|
||||
title?: string,
|
||||
summary?: string,
|
||||
authors?: number[],
|
||||
image?: string,
|
||||
tags?: string[],
|
||||
link?: string
|
||||
content?: string
|
||||
}
|
||||
|
||||
async function editArticle(payload: ArticleEditPayload): Promise<ArticleSummary> {
|
||||
let result = await fetch(`${prefix}/api/article`, {
|
||||
method: "PATCH",
|
||||
body: JSON.stringify(payload)
|
||||
})
|
||||
let json = await result.json()
|
||||
|
||||
switch (result.status) {
|
||||
case 201:
|
||||
return json
|
||||
case 401:
|
||||
throw new Error("Not authorized")
|
||||
case 404:
|
||||
throw new Error("Could not find article")
|
||||
case 409:
|
||||
throw new Error("An article with the same title already exists")
|
||||
default:
|
||||
throw await unknownResponse(result)
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteArticle(id: number): Promise<void> {
|
||||
let result = await fetch(`${prefix}/api/article`, {
|
||||
method: "DELETE",
|
||||
body: JSON.stringify({"id": id})
|
||||
})
|
||||
switch (result.status) {
|
||||
case 200:
|
||||
return
|
||||
case 401:
|
||||
throw new Error("Not authorized")
|
||||
case 404:
|
||||
throw new Error("Could not find article")
|
||||
default:
|
||||
throw await unknownResponse(result)
|
||||
}
|
||||
}
|
||||
|
||||
async function getAssets(name?: string, limit: number = 20): Promise<Asset[]> {
|
||||
let query = [["q", name], ["limit", limit]]
|
||||
|
||||
let result = await fetch(`${prefix}/api/assets?${buildQuery(query)}`, {
|
||||
method: "GET",
|
||||
})
|
||||
switch (result.status) {
|
||||
case 200:
|
||||
return await result.json()
|
||||
case 401:
|
||||
throw new Error("Not authorized")
|
||||
default:
|
||||
throw await unknownResponse(result)
|
||||
}
|
||||
}
|
||||
|
||||
async function addAsset(name: string, content: string): Promise<Asset> {
|
||||
let result = await fetch(`${prefix}/api/assets`, {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
"name": name,
|
||||
"content": content,
|
||||
})
|
||||
})
|
||||
switch (result.status) {
|
||||
case 201:
|
||||
return await result.json()
|
||||
case 401:
|
||||
throw new Error("Not authorized")
|
||||
case 409:
|
||||
throw new Error("An asset with the same name already exists")
|
||||
default:
|
||||
throw await unknownResponse(result)
|
||||
}
|
||||
}
|
||||
|
||||
async function deleteAsset(id: number): Promise<void> {
|
||||
let result = await fetch(`${prefix}/api/assets`, {
|
||||
method: "DELETE",
|
||||
body: JSON.stringify({"id": id})
|
||||
})
|
||||
switch (result.status) {
|
||||
case 200:
|
||||
return
|
||||
case 401:
|
||||
throw new Error("Not authorized")
|
||||
case 404:
|
||||
throw new Error("An asset with this id does not exist")
|
||||
default:
|
||||
throw await unknownResponse(result)
|
||||
}
|
||||
}
|
||||
69
frontend/js/main.js
Normal file
69
frontend/js/main.js
Normal file
@@ -0,0 +1,69 @@
|
||||
let articleParent = document.getElementById("articles");
|
||||
function updateSeach(value) {
|
||||
if (value == "") {
|
||||
addRecent();
|
||||
return;
|
||||
}
|
||||
let query = {
|
||||
query: value,
|
||||
limit: 5
|
||||
};
|
||||
clearArticles();
|
||||
search(query).then(function (data) {
|
||||
data.forEach(function (article) {
|
||||
addArticle(article);
|
||||
});
|
||||
});
|
||||
}
|
||||
function clearArticles() {
|
||||
articleParent.innerHTML = "";
|
||||
}
|
||||
window.onload = function () {
|
||||
addRecent();
|
||||
};
|
||||
function addRecent() {
|
||||
clearArticles();
|
||||
recent(5).then(function (data) {
|
||||
data.forEach(function (article) {
|
||||
addArticle(article);
|
||||
});
|
||||
});
|
||||
}
|
||||
function addArticle(article) {
|
||||
let articleA = document.createElement("a");
|
||||
articleA.setAttribute("href", article.link);
|
||||
let articleDiv = document.createElement("div");
|
||||
articleDiv.setAttribute("class", "article");
|
||||
let articleHeader = document.createElement("div");
|
||||
articleHeader.setAttribute("class", "article-header");
|
||||
let articleHeaderTitle = document.createElement("h3");
|
||||
articleHeaderTitle.innerHTML = article.title;
|
||||
articleHeader.appendChild(articleHeaderTitle);
|
||||
articleDiv.appendChild(articleHeader);
|
||||
let articleDescription = document.createElement("div");
|
||||
articleDescription.setAttribute("class", "article-description");
|
||||
let articleDescriptionP = document.createElement("p");
|
||||
let articleDescriptionTopics = document.createElement("i");
|
||||
articleDescriptionTopics.innerHTML = article.tags.join(", ");
|
||||
let articleDescriptionAuthors = document.createElement("i");
|
||||
articleDescriptionAuthors.innerHTML = article.authors[0].name;
|
||||
let articleDescriptionDate = document.createElement("i");
|
||||
articleDescriptionDate.innerHTML = article.modified.toString();
|
||||
articleDescriptionP.appendChild(articleDescriptionTopics);
|
||||
articleDescriptionP.appendChild(articleDescriptionAuthors);
|
||||
articleDescriptionP.appendChild(articleDescriptionDate);
|
||||
articleDescription.appendChild(articleDescriptionP);
|
||||
articleDiv.appendChild(articleDescription);
|
||||
let articleBody = document.createElement("div");
|
||||
articleBody.setAttribute("class", "article-body");
|
||||
let articleBodyP = document.createElement("p");
|
||||
articleBodyP.innerHTML = article.summary;
|
||||
articleBody.appendChild(articleBodyP);
|
||||
articleDiv.appendChild(articleBody);
|
||||
articleA.appendChild(articleDiv);
|
||||
articleParent.appendChild(articleA);
|
||||
let divider = document.createElement("div");
|
||||
divider.setAttribute("class", "divider");
|
||||
articleParent.appendChild(divider);
|
||||
}
|
||||
//# sourceMappingURL=main.js.map
|
||||
1
frontend/js/main.js.map
Normal file
1
frontend/js/main.js.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"main.js","sourceRoot":"","sources":["main.ts"],"names":[],"mappings":"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"}
|
||||
93
frontend/js/main.ts
Normal file
93
frontend/js/main.ts
Normal file
@@ -0,0 +1,93 @@
|
||||
let articleParent = document.getElementById("articles");
|
||||
|
||||
function updateSeach(value: string) {
|
||||
if(value == "") {
|
||||
addRecent()
|
||||
return
|
||||
}
|
||||
|
||||
let query: SearchQuery = {
|
||||
query: value,
|
||||
limit: 5
|
||||
}
|
||||
|
||||
|
||||
clearArticles()
|
||||
search(query).then(function(data) {
|
||||
data.forEach(function(article) {
|
||||
addArticle(article)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function clearArticles() {
|
||||
articleParent.innerHTML = ""
|
||||
}
|
||||
|
||||
window.onload = function() {
|
||||
addRecent()
|
||||
}
|
||||
|
||||
function addRecent () {
|
||||
clearArticles()
|
||||
recent(5).then(function(data) {
|
||||
data.forEach(function(article) {
|
||||
addArticle(article)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function addArticle(article: ArticleSummary) {
|
||||
let articleA = document.createElement("a")
|
||||
articleA.setAttribute("href", article.link)
|
||||
|
||||
let articleDiv = document.createElement("div")
|
||||
articleDiv.setAttribute("class", "article")
|
||||
|
||||
let articleHeader = document.createElement("div")
|
||||
articleHeader.setAttribute("class", "article-header")
|
||||
|
||||
let articleHeaderTitle = document.createElement("h3")
|
||||
articleHeaderTitle.innerHTML = article.title
|
||||
|
||||
articleHeader.appendChild(articleHeaderTitle)
|
||||
articleDiv.appendChild(articleHeader)
|
||||
|
||||
let articleDescription = document.createElement("div")
|
||||
articleDescription.setAttribute("class", "article-description")
|
||||
|
||||
let articleDescriptionP = document.createElement("p")
|
||||
|
||||
let articleDescriptionTopics = document.createElement("i")
|
||||
articleDescriptionTopics.innerHTML = article.tags.join(", ")
|
||||
|
||||
let articleDescriptionAuthors = document.createElement("i")
|
||||
articleDescriptionAuthors.innerHTML = article.authors[0].name //TODO join ALL Auhtors
|
||||
|
||||
let articleDescriptionDate = document.createElement("i")
|
||||
articleDescriptionDate.innerHTML = article.modified.toString()
|
||||
|
||||
articleDescriptionP.appendChild(articleDescriptionTopics)
|
||||
articleDescriptionP.appendChild(articleDescriptionAuthors)
|
||||
articleDescriptionP.appendChild(articleDescriptionDate)
|
||||
|
||||
articleDescription.appendChild(articleDescriptionP)
|
||||
articleDiv.appendChild(articleDescription)
|
||||
|
||||
let articleBody = document.createElement("div")
|
||||
articleBody.setAttribute("class", "article-body")
|
||||
|
||||
let articleBodyP = document.createElement("p")
|
||||
articleBodyP.innerHTML = article.summary
|
||||
|
||||
articleBody.appendChild(articleBodyP)
|
||||
articleDiv.appendChild(articleBody)
|
||||
|
||||
articleA.appendChild(articleDiv)
|
||||
articleParent.appendChild(articleA)
|
||||
|
||||
let divider = document.createElement("div")
|
||||
divider.setAttribute("class", "divider")
|
||||
|
||||
articleParent.appendChild(divider)
|
||||
}
|
||||
10
frontend/js/tsconfig.json
Normal file
10
frontend/js/tsconfig.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compileOnSave": true,
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es2018",
|
||||
"removeComments": true,
|
||||
"sourceMap": true,
|
||||
"lib": ["es2018", "dom"]
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user