#101 stats - server

This commit is contained in:
Andrea Vos 2020-11-25 00:54:02 +01:00
parent 2ee74b0a1d
commit 073612a10f
6 changed files with 90 additions and 10 deletions

View File

@ -1,17 +1,12 @@
import { loadSuml } from './server/loader';
import fs from 'fs';
import {buildDict} from "./src/helpers";
import {buildDict, buildLocaleList} from "./src/helpers";
const config = loadSuml('config');
const translations = loadSuml('translations');
const locale = config.locale;
const locales = buildDict(function* () {
for (let locale of process.env.LOCALES.split('|')) {
const [code, name, url] = locale.split(',');
yield [code, {name, url}];
}
});
const locales = buildLocaleList();
const title = translations.title;
const description = translations.description;
const banner = process.env.BASE_URL + '/api/banner/zaimki.png';

View File

@ -145,7 +145,12 @@
for (let pronoun in this.profile.pronouns) {
if (!this.profile.pronouns.hasOwnProperty(pronoun)) { continue; }
const link = decodeURIComponent(pronoun.replace(new RegExp('^' + this.$base), '').replace(new RegExp('^/'), ''));
const link = decodeURIComponent(
pronoun
.replace(new RegExp('^' + this.$base), '')
.replace(new RegExp('^' + this.$base.replace(/^https?:\/\//, '')), '')
.replace(new RegExp('^/'), '')
);
const pronounEntity = buildPronoun(pronouns, link);
if (pronounEntity) {

View File

@ -189,7 +189,12 @@
this.$router.push(`/@${this.$user().username}`)
},
validatePronoun(pronoun) {
const link = decodeURIComponent(pronoun.replace(new RegExp('^' + this.$base), '').replace(new RegExp('^/'), ''));
const link = decodeURIComponent(
pronoun
.replace(new RegExp('^' + this.$base), '')
.replace(new RegExp('^' + this.$base.replace(/^https?:\/\//, '')), '')
.replace(new RegExp('^/'), '')
);
return buildPronoun(pronouns, link) ? null : 'profile.pronounsNotFound'
},

View File

@ -6,6 +6,7 @@ import cookieParser from 'cookie-parser';
import grant from "grant";
import router from "./routes/user";
import { loadSuml } from './loader';
import {buildLocaleList} from "../src/helpers";
const app = express()
@ -21,6 +22,7 @@ app.use(session({
app.use(async function (req, res, next) {
req.config = loadSuml('config');
req.locales = buildLocaleList();
req.rawUser = authenticate(req);
req.user = req.rawUser && req.rawUser.authenticated ? req.rawUser : null;
req.admin = req.user && req.user.roles === 'admin';

View File

@ -2,7 +2,7 @@ import { Router } from 'express';
import SQL from 'sql-template-strings';
import avatar from '../avatar';
import {config as socialLoginConfig} from "../social";
import {now} from "../../src/helpers";
import {now, sortByValue} from "../../src/helpers";
const router = Router();
@ -46,4 +46,50 @@ router.get('/admin/users', async (req, res) => {
return res.json(groupedUsers);
});
router.get('/admin/stats', async (req, res) => {
if (!req.admin) {
return res.status(401).json({error: 'Unauthorised'});
}
const users = {
overall: (await req.db.get(SQL`SELECT count(*) AS c FROM users`)).c,
admins: (await req.db.get(SQL`SELECT count(*) AS c FROM users WHERE roles=${'admin'}`)).c,
};
const locales = {};
for (let locale in req.locales) {
if (!req.locales.hasOwnProperty(locale)) { continue; }
const profiles = await req.db.all(SQL`SELECT pronouns FROM profiles WHERE locale=${locale}`);
const pronouns = {}
for (let profile of profiles) {
const pr = JSON.parse(profile.pronouns);
for (let pronoun in pr) {
if (!pr.hasOwnProperty(pronoun)) { continue; }
if (pronoun.includes(',') || pr[pronoun] < 0) {
continue;
}
const p = pronoun.replace(/^.*:\/\//, '').replace(/^\//, '').toLowerCase().replace(/^[a-z]+\.[^/]+\//, '');
if (pronouns[p] === undefined) {
pronouns[p] = 0;
}
pronouns[p]++;
}
}
locales[locale] = {
name: req.locales[locale].name,
url: req.locales[locale].url,
profiles: profiles.length,
pronouns: sortByValue(pronouns, true),
nouns: {
approved: (await req.db.get(SQL`SELECT count(*) AS c FROM nouns WHERE locale=${locale} AND approved=1`)).c,
awaiting: (await req.db.get(SQL`SELECT count(*) AS c FROM nouns WHERE locale=${locale} AND approved=0`)).c,
}
};
}
return res.json({ users, locales });
});
export default router;

View File

@ -131,3 +131,30 @@ export const now = function () {
export const isEmoji = char => {
return !!char.match(/^(?:[\u2700-\u27bf]|(?:\ud83c[\udde6-\uddff]){2}|[\ud800-\udbff][\udc00-\udfff]|[\u0023-\u0039]\ufe0f?\u20e3|\u3299|\u3297|\u303d|\u3030|\u24c2|\ud83c[\udd70-\udd71]|\ud83c[\udd7e-\udd7f]|\ud83c\udd8e|\ud83c[\udd91-\udd9a]|\ud83c[\udde6-\uddff]|\ud83c[\ude01-\ude02]|\ud83c\ude1a|\ud83c\ude2f|\ud83c[\ude32-\ude3a]|\ud83c[\ude50-\ude51]|\u203c|\u2049|[\u25aa-\u25ab]|\u25b6|\u25c0|[\u25fb-\u25fe]|\u00a9|\u00ae|\u2122|\u2139|\ud83c\udc04|[\u2600-\u26FF]|\u2b05|\u2b06|\u2b07|\u2b1b|\u2b1c|\u2b50|\u2b55|\u231a|\u231b|\u2328|\u23cf|[\u23e9-\u23f3]|[\u23f8-\u23fa]|\ud83c\udccf|\u2934|\u2935|[\u2190-\u21ff])$/)
}
export const buildLocaleList = () => {
return buildDict(function* () {
for (let locale of process.env.LOCALES.split('|')) {
const [code, name, url] = locale.split(',');
yield [code, {name, url}];
}
})
}
export const zip = (list, reverse) => {
return buildDict(function* () {
for (let [k, v] of list) {
yield reverse ? [v, k] : [k, v];
}
});
}
export const sortByValue = (obj, reverse = false) => {
const sortedArray = [];
for (let i in obj) {
if (obj.hasOwnProperty(i)) {
sortedArray.push([parseInt(obj[i]), i]);
}
}
return zip(sortedArray.sort((a, b) => reverse ? b[0] - a[0] : a[0] - b[0]), true);
}