First version of OpenAuth remake
This commit is contained in:
244
views/src/admin/admin.hbs
Normal file
244
views/src/admin/admin.hbs
Normal file
@ -0,0 +1,244 @@
|
||||
<html>
|
||||
|
||||
|
||||
<head>
|
||||
<title>{{i18n "Administration"}}</title>
|
||||
<meta charset="utf8" />
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js" type="text/javascript"></script>
|
||||
<script src="https://unpkg.com/popper.js@1.12.6/dist/umd/popper.js" type="text/javascript"></script>
|
||||
<script src="https://unpkg.com/bootstrap-material-design@4.1.1/dist/js/bootstrap-material-design.js" type="text/javascript"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.0.11/handlebars.min.js" type="text/javascript"></script>
|
||||
<script>
|
||||
$(document).ready(() => $('body').bootstrapMaterialDesign())
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<header class=bg-primary style="display: flex; justify-content: space-between;">
|
||||
<h3 style="display: inline">{{appname}} {{i18n "Administration"}}
|
||||
<span id="sitename">LOADING</span>
|
||||
</h3>
|
||||
|
||||
<ul class="nav nav-tabs" style="display: inline-block; margin-left: auto; margin-top: -8px;">
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" data-toggle="dropdown" href="#" role="button" aria-haspopup="true"
|
||||
aria-expanded="false">Model</a>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" href="?type=user">User</a>
|
||||
<a class="dropdown-item" href="?type=regcode">RegCode</a>
|
||||
<a class="dropdown-item" href="?type=client">Client</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</header>
|
||||
<div id=content>
|
||||
<div class=container>
|
||||
<div id=error_cont class=row style="margin-bottom: 24px;display: none;">
|
||||
<div class=col-sm>
|
||||
<div class="card error_card">
|
||||
<div id="error_msg" class="card-body"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id=custom_data_cont class=row style="margin-bottom: 24px; display: none">
|
||||
<div class=col-sm>
|
||||
<div class=card>
|
||||
<div id=custom_data class="card-body"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class=row>
|
||||
<div class=col-sm>
|
||||
<div class=card>
|
||||
<div class=card-body>
|
||||
<div id=table-body>
|
||||
<div style="width: 65px; height: 65px; margin: 0 auto;">
|
||||
<svg class="spinner" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle class="circle" fill="none" stroke-width="6" stroke-linecap="round" cx="33" cy="33"
|
||||
r="30"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script id="template-spinner" type="text/x-handlebars-template">
|
||||
<div style="width: 65px; height: 65px; margin: 0 auto;">
|
||||
<svg class="spinner" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle class="circle" fill="none" stroke-width="6" stroke-linecap="round" cx="33" cy="33" r="30"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<script id="template-user-list" type="text/x-handlebars-template">
|
||||
<table class="table table-bordered" style="margin-bottom: 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Username</th>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col">Gender</th>
|
||||
<th scope="col">Role</th>
|
||||
<th scope="col" style="width: 2.5rem"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
\{{#users}}
|
||||
<tr>
|
||||
<td>\{{ username }}</td>
|
||||
<td>\{{ name }}</td>
|
||||
|
||||
<!-- ToDo: Make helper to resolve number to human readaby text-->
|
||||
<td>\{{humangender gender}}</td>
|
||||
|
||||
<td onclick="userOnChangeType('\{{_id}}')">
|
||||
\{{#if admin}}
|
||||
<span class="badge badge-danger">Admin</span>
|
||||
\{{else}}
|
||||
<span class="badge badge-success">User</span>
|
||||
\{{/if}}
|
||||
</td>
|
||||
<td style="padding: 0.25em">
|
||||
<button style="border: 0; background-color: rgba(0, 0, 0, 0); padding: 0; text-align: center;" onclick="deleteUser('\{{_id}}')">
|
||||
<i class="material-icons" style="font-size: 2rem; display: inline">
|
||||
delete
|
||||
</i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
\{{/users}}
|
||||
</tbody>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<script id="template-regcode-list" type="text/x-handlebars-template">
|
||||
<button class="btn btn-raised btn-primary" onclick="createRegcode()">Create</button>
|
||||
<table class="table table-bordered" style="margin-bottom: 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">Code</th>
|
||||
<th scope="col">Valid</th>
|
||||
<th scope="col">Till</th>
|
||||
<th scope="col" style="width: 2.5rem"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
\{{#regcodes}}
|
||||
<tr>
|
||||
<td>\{{ token }}</td>
|
||||
<td>\{{ valid }}</td>
|
||||
|
||||
<!-- ToDo: Make helper to resolve number to human readaby text-->
|
||||
<td>\{{formatDate validTill }}</td>
|
||||
<td style="padding: 0.25em">
|
||||
<button style="border: 0; background-color: rgba(0, 0, 0, 0); padding: 0; text-align: center;" onclick="deleteRegcode('\{{_id}}')">
|
||||
<i class="material-icons" style="font-size: 2rem; display: inline">
|
||||
delete
|
||||
</i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
\{{/regcodes}}
|
||||
</tbody>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<script id="template-client-list" type="text/x-handlebars-template">
|
||||
<button class="btn btn-raised btn-primary" onclick="createClient()">Create</button>
|
||||
<table class="table table-bordered" style="margin-bottom: 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">ID</th>
|
||||
<th scope="col">Secret</th>
|
||||
<th scope="col">Maintainer</th>
|
||||
<th scope="col">Name</th>
|
||||
<th scope="col" style="width: 80px">Type</th>
|
||||
<th scope="col">Website</th>
|
||||
<th scope="col" style="width: 2.5rem">
|
||||
<div></div>
|
||||
</th>
|
||||
<th scope="col" style="width: 2.5rem"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
\{{#clients}}
|
||||
<tr>
|
||||
<td>\{{ client_id }}</td>
|
||||
<td>\{{ client_secret }}</td>
|
||||
<td>\{{ maintainer.username }}</td>
|
||||
<td>\{{ name }}</td>
|
||||
<td>
|
||||
\{{#if internal}}
|
||||
<span class="badge badge-success">Internal</span>
|
||||
\{{else}}
|
||||
<span class="badge badge-danger">External</span>
|
||||
\{{/if}}
|
||||
</td>
|
||||
<td>
|
||||
<a href="\{{ website }}">\{{ website }}</a>
|
||||
</td>
|
||||
|
||||
<!-- ToDo: Make helper to resolve number to human readaby text-->
|
||||
<td style="padding: 0.25em">
|
||||
<button style="border: 0; background-color: rgba(0, 0, 0, 0); padding: 0; text-align: center;" onclick="editClient('\{{_id}}')">
|
||||
<i class="material-icons" style="font-size: 2rem; display: inline">
|
||||
edit
|
||||
</i>
|
||||
</button>
|
||||
</td>
|
||||
<td style="padding: 0.25em">
|
||||
<button style="border: 0; background-color: rgba(0, 0, 0, 0); padding: 0; text-align: center;" onclick="deleteClient('\{{_id}}')">
|
||||
<i class="material-icons" style="font-size: 2rem; display: inline">
|
||||
delete
|
||||
</i>
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
\{{/clients}}
|
||||
</tbody>
|
||||
</table>
|
||||
</script>
|
||||
|
||||
<script id="template-client-form" type="text/x-handlebars-template">
|
||||
<form class="form" action="JavaScript:void(null)" onsubmit="createClientSubmit(this)" style="margin-bottom: 0">
|
||||
<input type=hidden value="\{{_id}}" name=id />
|
||||
<div class="form-group">
|
||||
<label for="name_input" class="bmd-label-floating">Name</label>
|
||||
<input type="text" class="form-control" id="name_input" name=name value="\{{name}}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="redirect_input" class="bmd-label-floating">Redirect Url</label>
|
||||
<input type="text" class="form-control" id="redirect_input" name=redirect_url value="\{{redirect_url}}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="website_input" class="bmd-label-floating">Website</label>
|
||||
<input type="text" class="form-control" id="website_input" name=website value="\{{website}}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="logo_input" class="bmd-label-floating">Logo</label>
|
||||
<input type="text" class="form-control" id="logo_input" name=logo value="\{{logo}}">
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="internal_check" \{{#if internal}} checked="checked" \{{/if}} name=internal>
|
||||
<label class="form-check-label" for="internal_check">Internal</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<span class="form-group bmd-form-group">
|
||||
<!-- needed to match padding for floating labels -->
|
||||
<button type="submit" class="btn btn-raised btn-primary">Save</button>
|
||||
</span>
|
||||
</form>
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
158
views/src/admin/admin.js
Normal file
158
views/src/admin/admin.js
Normal file
@ -0,0 +1,158 @@
|
||||
import request from "../../shared/request";
|
||||
import getFormData from "../../shared/formdata";
|
||||
Handlebars.registerHelper("humangender", function (value, options) {
|
||||
switch (value) {
|
||||
case 1:
|
||||
return "male";
|
||||
case 2:
|
||||
return "female";
|
||||
case 3:
|
||||
return "other";
|
||||
default:
|
||||
case 0:
|
||||
return "none";
|
||||
}
|
||||
});
|
||||
|
||||
// Deprecated since version 0.8.0
|
||||
Handlebars.registerHelper("formatDate", function (datetime, format) {
|
||||
return new Date(datetime).toLocaleString();
|
||||
});
|
||||
|
||||
(() => {
|
||||
const tableb = document.getElementById("table-body");
|
||||
|
||||
function setTitle(title) {
|
||||
document.getElementById("sitename").innerText = title;
|
||||
}
|
||||
|
||||
|
||||
const cc = document.getElementById("custom_data")
|
||||
const ccc = document.getElementById("custom_data_cont")
|
||||
|
||||
function setCustomCard(content) {
|
||||
if (!content) {
|
||||
cc.innerHTML = "";
|
||||
ccc.style.display = "none";
|
||||
} else {
|
||||
cc.innerHTML = content;
|
||||
ccc.style.display = "";
|
||||
}
|
||||
}
|
||||
|
||||
const error_cont = document.getElementById("error_cont")
|
||||
const error_msg = document.getElementById("error_msg")
|
||||
|
||||
function catchError(error) {
|
||||
error_cont.style.display = "";
|
||||
error_msg.innerText = error.message;
|
||||
console.log(error);
|
||||
}
|
||||
|
||||
async function renderUser() {
|
||||
console.log("Rendering User")
|
||||
setTitle("User")
|
||||
const listt = Handlebars.compile(document.getElementById("template-user-list").innerText)
|
||||
|
||||
async function loadList() {
|
||||
let data = await request("/api/admin/user", "GET");
|
||||
tableb.innerHTML = listt({
|
||||
users: data
|
||||
})
|
||||
}
|
||||
|
||||
window.userOnChangeType = (id) => {
|
||||
request("/api/admin/user?id=" + id, "PUT").then(() => loadList()).catch(catchError)
|
||||
}
|
||||
|
||||
window.deleteUser = (id) => {
|
||||
request("/api/admin/user?id=" + id, "DELETE").then(() => loadList()).catch(catchError)
|
||||
}
|
||||
|
||||
await loadList();
|
||||
}
|
||||
|
||||
async function renderClient() {
|
||||
console.log("Rendering Client")
|
||||
setTitle("Client")
|
||||
|
||||
const listt = Handlebars.compile(document.getElementById("template-client-list").innerText)
|
||||
const formt = Handlebars.compile(document.getElementById("template-client-form").innerText)
|
||||
|
||||
let clients = [];
|
||||
async function loadList() {
|
||||
let data = await request("/api/admin/client", "GET");
|
||||
clients = data;
|
||||
tableb.innerHTML = listt({
|
||||
clients: data
|
||||
})
|
||||
}
|
||||
|
||||
window.deleteClient = (id) => {
|
||||
request("/api/admin/client?id=" + id, "DELETE").then(() => loadList()).catch(catchError)
|
||||
}
|
||||
|
||||
window.createClientSubmit = (elm) => {
|
||||
console.log(elm);
|
||||
let data = getFormData(elm);
|
||||
console.log(data);
|
||||
let id = data.id;
|
||||
delete data.id;
|
||||
if (id !== "") {
|
||||
request("/api/admin/client?id=" + id, "PUT", data).then(() => setCustomCard()).then(() => loadList()).catch(catchError)
|
||||
} else {
|
||||
request("/api/admin/client", "POST", data).then(() => setCustomCard()).then(() => loadList()).catch(catchError)
|
||||
}
|
||||
}
|
||||
|
||||
window.createClient = () => {
|
||||
setCustomCard(formt());
|
||||
}
|
||||
|
||||
window.editClient = (id) => {
|
||||
let client = clients.find(e => e._id === id);
|
||||
if (!client) return catchError(new Error("Client does not exist!!"))
|
||||
setCustomCard(formt(client));
|
||||
}
|
||||
|
||||
await loadList();
|
||||
}
|
||||
|
||||
async function renderRegCode() {
|
||||
console.log("Rendering RegCode")
|
||||
setTitle("RegCode")
|
||||
|
||||
const listt = Handlebars.compile(document.getElementById("template-regcode-list").innerText)
|
||||
|
||||
async function loadList() {
|
||||
let data = await request("/api/admin/regcode", "GET");
|
||||
tableb.innerHTML = listt({
|
||||
regcodes: data
|
||||
})
|
||||
}
|
||||
|
||||
window.deleteRegcode = (id) => {
|
||||
request("/api/admin/regcode?id=" + id, "DELETE").then(() => loadList()).catch(catchError)
|
||||
}
|
||||
|
||||
window.createRegcode = () => {
|
||||
request("/api/admin/regcode", "POST").then(() => loadList()).catch(catchError);
|
||||
}
|
||||
|
||||
await loadList();
|
||||
}
|
||||
|
||||
const type = new URL(window.location.href).searchParams.get("type");
|
||||
switch (type) {
|
||||
case "client":
|
||||
renderClient().catch(catchError)
|
||||
break
|
||||
case "regcode":
|
||||
renderRegCode().catch(catchError)
|
||||
break;
|
||||
case "user":
|
||||
default:
|
||||
renderUser().catch(catchError);
|
||||
break;
|
||||
}
|
||||
})()
|
103
views/src/admin/admin.scss
Normal file
103
views/src/admin/admin.scss
Normal file
@ -0,0 +1,103 @@
|
||||
@import "mat_bs";
|
||||
@import "style";
|
||||
.error_card {
|
||||
color: $error;
|
||||
padding: 1rem;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.bg-primary {
|
||||
background-color: $primary !important;
|
||||
}
|
||||
|
||||
.spinner {
|
||||
-webkit-animation: rotation 1.35s linear infinite;
|
||||
animation: rotation 1.35s linear infinite;
|
||||
stroke: $primary;
|
||||
}
|
||||
|
||||
@-webkit-keyframes rotation {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(270deg);
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes rotation {
|
||||
0% {
|
||||
-webkit-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
100% {
|
||||
-webkit-transform: rotate(270deg);
|
||||
transform: rotate(270deg);
|
||||
}
|
||||
}
|
||||
|
||||
.circle {
|
||||
stroke-dasharray: 180;
|
||||
stroke-dashoffset: 0;
|
||||
-webkit-transform-origin: center;
|
||||
-ms-transform-origin: center;
|
||||
transform-origin: center;
|
||||
-webkit-animation: turn 1.35s ease-in-out infinite;
|
||||
animation: turn 1.35s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@-webkit-keyframes turn {
|
||||
0% {
|
||||
stroke-dashoffset: 180;
|
||||
}
|
||||
50% {
|
||||
stroke-dashoffset: 45;
|
||||
-webkit-transform: rotate(135deg);
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
100% {
|
||||
stroke-dashoffset: 180;
|
||||
-webkit-transform: rotate(450deg);
|
||||
transform: rotate(450deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes turn {
|
||||
0% {
|
||||
stroke-dashoffset: 180;
|
||||
}
|
||||
50% {
|
||||
stroke-dashoffset: 45;
|
||||
-webkit-transform: rotate(135deg);
|
||||
transform: rotate(135deg);
|
||||
}
|
||||
100% {
|
||||
stroke-dashoffset: 180;
|
||||
-webkit-transform: rotate(450deg);
|
||||
transform: rotate(450deg);
|
||||
}
|
||||
}
|
||||
|
||||
header {
|
||||
/* height: 60px; */
|
||||
margin-bottom: 8px;
|
||||
padding: 8px 16px;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
word-wrap: break-word;
|
||||
table-layout: fixed;
|
||||
}
|
||||
|
||||
table td {
|
||||
vertical-align: inherit !important;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.col.form-group {
|
||||
padding-left: 0 !important;
|
||||
margin-left: 5px !important;
|
||||
}
|
Reference in New Issue
Block a user