Compare commits

...

2 Commits

Author SHA1 Message Date
b1ek dd0957f700
add bolerplate resume page 2023-03-09 23:40:29 +10:00
b1ek cb15352e81
add services page 2023-03-09 23:26:00 +10:00
9 changed files with 122 additions and 73 deletions

View File

@ -7,8 +7,12 @@ module.exports = (req, res, next) => {
res.template = async (file, data) => { res.template = async (file, data) => {
let t_data = {};
if (data) t_data = {...data};
res.send(await Helpers.ViewLoader.load(file, { res.send(await Helpers.ViewLoader.load(file, {
...data, ...t_data,
current_route: req.originalUrl, current_route: req.originalUrl,
req, req,
res, res,

View File

@ -1,72 +1,9 @@
const { Model, DataTypes } = require('sequelize'); const { Model, DataTypes } = require('sequelize');
const { sequelize } = require('.'); const { sequelize } = require('.');
/** @type {{data: Permission[], updated: number, expired: function}} */
let cached = {
data: undefined,
updated: 0,
expired: () => {
return (Date.now() - updated) >= 1000
}
}
class Permission extends Model { class Permission extends Model {
static async cache() { static async getAllForUser(user) {
if (!cached.expired()) return; return await this.findAll({where: {user}});
cached.data = await Permission.findAll();
cached.updated = Date.now();
}
/**
* Get value from cache
* @param {number} user
* @param {string} permission
* @returns {Permission?}
*/
static async findFromCache(user, permission) {
await this.cache();
for (const perm of cached.data) {
if (perm.user == userid && perm.permission == permission)
return perm;
}
return null;
}
/**
* Get a permission for user
* @param {number} user
* @param {string} permission
* @returns {boolean}
*/
static async forUser(user, permission) {
await this.cache();
const data = await this.findFromCache(user, permission);
if (!data) return false;
return data.value != 0;
}
/**
* Set a permission for user
* @param {number} user
* @param {string} permission
* @param {number} value
* @returns {Permission}
*/
static async set(user, permission, value) {
const existing = await Permission.findOne({where: {user, permission}});
let perm;
if (!existing) perm = await Permission.create({user, permission, value});
else perm = await Permission.update({user, permission, value}, {where: {user, permission}});
await this.cache();
return perm;
}
static async userAllowed(user, permission) {
return this.forUser(user, permission);
} }
} }
@ -81,12 +18,8 @@ Permission.structure = {
type: DataTypes.BIGINT, type: DataTypes.BIGINT,
allowNull: false allowNull: false
}, },
permission: { perms: {
type: DataTypes.TEXT, type: DataTypes.JSONB,
allowNull: false
},
value: {
type: DataTypes.BIGINT,
allowNull: false allowNull: false
} }
}; };

View File

@ -109,3 +109,18 @@ span.flag_btn {
span.au_flag { span.au_flag {
background: url(/content/au_flag.jpg); background: url(/content/au_flag.jpg);
} }
table.border_table, table.border_table tr td {
border: 1px solid #c2c4c2;
border-collapse: collapse;
}
table.border_table tr td, table.border_table tr th {
padding: 4px 10px;
border: 1px solid #c2c4c2;
}
table.border_table tr th {
border-bottom: 3px double #caccca;
padding: 2px 10px;
font-size: 90%;
text-align: center;
}

BIN
public/static/ui/load.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -0,0 +1,24 @@
div#resume_js_app {
background: #303030;
width:640px;
height:480px;
border: 1px solid #e1e1e1;
font-family: monospace;
box-shadow: 0 2px 4px #30303060;
padding: 10px 8px;
color: #e1e1e1;
position: fixed;
top:50%;left:50%;
transform: translate(-50%, -50%);
}
div#resume_js_app * {
padding: 0; margin: 0;
}
div#resume_js_app p.js_loading_indicator {
position: relative;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
width: fit-content;
text-align: center;
}

14
routes/pages.js Normal file
View File

@ -0,0 +1,14 @@
const handler = require('express-async-handler');
async function services(req, res) {
res.template('page/services.pug');
}
async function resume(req, res) {
res.template('page/resume.pug');
}
module.exports = (router) => {
router.get('/services', handler(services))
router.get('/resume', handler(resume))
}

View File

@ -9,7 +9,9 @@ block root
"Guestbook": "/guestbook", "Guestbook": "/guestbook",
"Articles": "/articles", "Articles": "/articles",
"hr_2": "hr", "hr_2": "hr",
"Sources": "/sources" "Sources": "/sources",
"Services": "/services",
"Resume": "/resume"
} }
doctype html doctype html

13
view/page/resume.pug Normal file
View File

@ -0,0 +1,13 @@
extends ../layout/main.pug
block root
- var title = 'Resume'
link(rel='stylesheet' href='/static/ui/resume.css')
block content
h2 My online resume
hr
div(id='resume_js_app')
p(class='js_loading_indicator')
| JS is loading. Please hold on...
br
img(src='/static/ui/load.gif' style='border-radius:6px;margin-top:6px')

44
view/page/services.pug Normal file
View File

@ -0,0 +1,44 @@
extends ../layout/main.pug
block root
- var title = 'Services'
include ../ui/label.pug
block content
h2 My self-hosted services
hr
table(class='border_table' style='font-size:11pt')
tr
th Name
th Link
th Description
tr
td Excalidraw
td
a(href='https://draw.blek.codes' class='web_link') draw.blek.codes
td
| A draw board. Has real-time collaborative features.
a(href='https://excalidraw.com') Official site
tr
td Gitea
td
a(href='https://git.blek.codes' class='web_link') git.blek.codes
td
| My gitea instance. I store all my new work here, although it is mirrored to github.
tr
td blek! Bin
td
a(href='https://bin.blek.codes' class='web_link') bin.blek.codes
td
| A privacy-respecting, js-free pastebin alternative (inspired by
a(href='https://github.com/hnhx/librebin') Librebin
| )
a(href='/project/blek_bin' class='web_link') Project page
tr
td Mailcow
td No public web gui
td
| A set of programs to run a mail service.
a(href='https://mailcow.email' class='web_link') Official site
p
a(href='http://kuma.blek.codes/status/all')
+label('Status page', '#58ac58')