feat(backend): add comments for fsentries

This commit is contained in:
KernelDeimos 2024-11-14 17:31:42 -05:00
parent 0cbe0139d7
commit db79a72daa
4 changed files with 205 additions and 0 deletions

View File

@ -344,6 +344,9 @@ const install = async ({ services, app, useapi, modapi }) => {
const { DriverUsagePolicyService } = require('./services/drivers/DriverUsagePolicyService'); const { DriverUsagePolicyService } = require('./services/drivers/DriverUsagePolicyService');
services.registerService('driver-usage-policy', DriverUsagePolicyService); services.registerService('driver-usage-policy', DriverUsagePolicyService);
const { CommentService } = require('./services/CommentService');
services.registerService('comment', CommentService);
} }
const install_legacy = async ({ services }) => { const install_legacy = async ({ services }) => {

View File

@ -0,0 +1,156 @@
const APIError = require("../api/APIError");
const FSNodeParam = require("../api/filesystem/FSNodeParam");
const configurable_auth = require("../middleware/configurable_auth");
const { Endpoint } = require("../util/expressutil");
const BaseService = require("./BaseService");
const { DB_WRITE } = require("./database/consts");
class CommentService extends BaseService {
static MODULES = {
uuidv4: require('uuid').v4,
}
_init () {
const svc_database = this.services.get('database');
this.db = svc_database.get(DB_WRITE, 'notification');
}
['__on_install.routes'] (_, { app }) {
const r_comment = (() => {
const require = this.require;
const express = require('express');
return express.Router()
})();
app.use('/comment', r_comment);
Endpoint({
route: '/comment',
methods: ['POST'],
mw: [configurable_auth()],
handler: async (req, res) => {
const comment = await this.create_comment_({ req, res });
if ( ! req.body.on ) {
throw APIError.create('field_missing', null, { key: 'on' });
}
const on_ = req.body.on;
if ( on_.startsWith('fs:') ) {
const node = await (new FSNodeParam('path')).consolidate({
req,
getParam: () => on_.slice(3),
});
if ( req.body.version ) {
// this.attach_comment_to_fsentry_version({
// node, comment, version,
// });
res.status(400).send('not implemented yet');
return;
} else {
this.attach_comment_to_fsentry({
node, comment,
});
}
}
res.json({
uid: comment.uid,
});
}
}).attach(app);
Endpoint({
route: '/comment/list',
methods: ['POST'],
mw: [configurable_auth()],
handler: async (req, res) => {
if ( ! req.body.on ) {
throw APIError.create('field_missing', null, { key: 'on' });
}
const on_ = req.body.on;
let comments;
if ( on_.startsWith('fs:') ) {
const node = await (new FSNodeParam('path')).consolidate({
req,
getParam: () => on_.slice(3),
});
if ( req.body.version ) {
// this.attach_comment_to_fsentry_version({
// node, comment, version,
// });
res.status(400).send('not implemented yet');
return;
} else {
comments = await this.get_comments_for_fsentry({
node,
});
}
}
const client_safe_comments = [];
for ( const comment of comments ) {
client_safe_comments.push({
uid: comment.uid,
text: comment.text,
created: comment.created_at,
});
}
res.json({
comments: client_safe_comments,
});
}
}).attach(app);
}
async create_comment_ ({ req, res }) {
if ( ! req.body.text ) {
throw APIError.create('field_missing', null, { key: 'text' });
}
const text = req.body.text;
const uuid = this.modules.uuidv4();
const result = await this.db.write(
'INSERT INTO `user_comments` ' +
'(`uid`, `user_id`, `metadata`, `text`) ' +
'VALUES (?, ?, ?, ?)',
[uuid, req.user.id, '{}', text],
);
return {
id: result.insertId,
uid: uuid,
};
}
async attach_comment_to_fsentry ({ node, comment }) {
await this.db.write(
'INSERT INTO `user_fsentry_comments` ' +
'(`user_comment_id`, `fsentry_id`) ' +
'VALUES (?, ?)',
[comment.id, await node.get('mysql-id')],
);
}
async get_comments_for_fsentry ({ node }) {
const comments = await this.db.read(
'SELECT * FROM `user_comments` ' +
'JOIN `user_fsentry_comments` ' +
'ON `user_comments`.`id` = `user_fsentry_comments`.`user_comment_id` ' +
'WHERE `fsentry_id` = ?',
[await node.get('mysql-id')],
);
return comments;
}
}
module.exports = { CommentService };

View File

@ -132,6 +132,9 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService {
[26, [ [26, [
'0029_emulator_priv.sql', '0029_emulator_priv.sql',
]], ]],
[27, [
'0030_comments.sql',
]],
]; ];
// Database upgrade logic // Database upgrade logic

View File

@ -0,0 +1,43 @@
CREATE TABLE `user_comments` (
`id` INTEGER PRIMARY KEY,
`uid` TEXT NOT NULL UNIQUE,
`user_id` INTEGER NOT NULL,
`metadata` JSON DEFAULT NULL,
`text` TEXT NOT NULL,
`created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY("user_id") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE INDEX `idx_user_comments_uid` ON `user_comments` (`uid`);
CREATE TABLE `user_fsentry_comments` (
`id` INTEGER PRIMARY KEY,
`user_comment_id` INTEGER NOT NULL,
`fsentry_id` INTEGER NOT NULL,
FOREIGN KEY("user_comment_id") REFERENCES "user_comments" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY("fsentry_id") REFERENCES "fsentries" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE `user_fsentry_version_comments` (
`id` INTEGER PRIMARY KEY,
`user_comment_id` INTEGER NOT NULL,
`fsentry_version_id` INTEGER NOT NULL,
FOREIGN KEY("user_comment_id") REFERENCES "user_comments" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY("fsentry_version_id") REFERENCES "fsentry_versions" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE `user_group_comments` (
`id` INTEGER PRIMARY KEY,
`user_comment_id` INTEGER NOT NULL,
`group_id` INTEGER NOT NULL,
FOREIGN KEY("user_comment_id") REFERENCES "user_comments" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY("group_id") REFERENCES "group" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);
CREATE TABLE `user_user_comments` (
`id` INTEGER PRIMARY KEY,
`user_comment_id` INTEGER NOT NULL,
`user_id` INTEGER NOT NULL,
FOREIGN KEY("user_comment_id") REFERENCES "user_comments" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY("user_id") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE
);