-
+
nouns.headerLonger
diff --git a/server/index.js b/server/index.js
index 52f40d7c..4668e8bb 100644
--- a/server/index.js
+++ b/server/index.js
@@ -44,6 +44,7 @@ app.use(require('./routes/pronouns').default);
app.use(require('./routes/sources').default);
app.use(require('./routes/nouns').default);
app.use(require('./routes/inclusive').default);
+app.use(require('./routes/terms').default);
app.use(require('./routes/pronounce').default);
app.use(require('./routes/census').default);
diff --git a/server/routes/terms.js b/server/routes/terms.js
new file mode 100644
index 00000000..6e3dc1d6
--- /dev/null
+++ b/server/routes/terms.js
@@ -0,0 +1,108 @@
+import { Router } from 'express';
+import SQL from 'sql-template-strings';
+import {ulid} from "ulid";
+import {isTroll} from "../../src/helpers";
+
+const approve = async (db, id) => {
+ const { base_id } = await db.get(SQL`SELECT base_id FROM terms WHERE id=${id}`);
+ if (base_id) {
+ await db.get(SQL`
+ UPDATE terms
+ SET deleted=1
+ WHERE id = ${base_id}
+ `);
+ }
+ await db.get(SQL`
+ UPDATE terms
+ SET approved = 1, base_id = NULL
+ WHERE id = ${id}
+ `);
+}
+
+const router = Router();
+
+router.get('/terms', async (req, res) => {
+ return res.json(await req.db.all(SQL`
+ SELECT i.*, u.username AS author FROM terms i
+ LEFT JOIN users u ON i.author_id = u.id
+ WHERE i.locale = ${req.config.locale}
+ AND i.approved >= ${req.admin ? 0 : 1}
+ AND i.deleted = 0
+ ORDER BY i.term
+ `));
+});
+
+router.get('/terms/search/:term', async (req, res) => {
+ const term = '%' + req.params.term + '%';
+ return res.json(await req.db.all(SQL`
+ SELECT i.*, u.username AS author FROM terms i
+ LEFT JOIN users u ON i.author_id = u.id
+ WHERE i.locale = ${req.config.locale}
+ AND i.approved >= ${req.admin ? 0 : 1}
+ AND i.deleted = 0
+ AND (i.term like ${term} OR i.original like ${term})
+ ORDER BY i.term
+ `));
+});
+
+router.post('/terms/submit', async (req, res) => {
+ if (!(req.user && req.user.admin) && isTroll(JSON.stringify(req.body))) {
+ return res.json('ok');
+ }
+
+ const id = ulid();
+ await req.db.get(SQL`
+ INSERT INTO terms (id, term, original, definition, approved, base_id, locale, author_id)
+ VALUES (
+ ${id},
+ ${req.body.term.join('|')}, ${req.body.original.join('|')}, ${req.body.definition},
+ 0, ${req.body.base}, ${req.config.locale}, ${req.user ? req.user.id : null}
+ )
+ `);
+
+ if (req.admin) {
+ await approve(req.db, id);
+ }
+
+ return res.json('ok');
+});
+
+router.post('/terms/hide/:id', async (req, res) => {
+ if (!req.admin) {
+ res.status(401).json({error: 'Unauthorised'});
+ }
+
+ await req.db.get(SQL`
+ UPDATE terms
+ SET approved = 0
+ WHERE id = ${req.params.id}
+ `);
+
+ return res.json('ok');
+});
+
+router.post('/terms/approve/:id', async (req, res) => {
+ if (!req.admin) {
+ res.status(401).json({error: 'Unauthorised'});
+ }
+
+ await approve(req.db, req.params.id);
+
+ return res.json('ok');
+});
+
+router.post('/terms/remove/:id', async (req, res) => {
+ if (!req.admin) {
+ res.status(401).json({error: 'Unauthorised'});
+ }
+
+ await req.db.get(SQL`
+ UPDATE terms
+ SET deleted=1
+ WHERE id = ${req.params.id}
+ `);
+
+ return res.json('ok');
+});
+
+export default router;
diff --git a/src/classes.js b/src/classes.js
index 648579f0..7ae42e57 100644
--- a/src/classes.js
+++ b/src/classes.js
@@ -675,6 +675,31 @@ export class InclusiveEntry {
}
}
+export class TermsEntry {
+ constructor({id, term, original, definition, approved = true, base_id = null}) {
+ this.id = id;
+ this.term = term.split('|');
+ this.original = original ? original.split('|') : [];
+ this.definition = definition;
+ this.approved = !!approved;
+ this.base = base_id;
+ }
+
+ matches(filter) {
+ if (!filter) {
+ return true;
+ }
+
+ for (let field of ['term', 'original']) {
+ for (let value of this[field]) {
+ if (value.toLowerCase().indexOf(filter.toLowerCase()) > -1) {
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+}
export class Name {
constructor(name, origin, meaning, usage, legally, pros, cons, notablePeople, count, links) {