Remove CommentService and related tests (#2160)

Deleted the CommentService implementation and its test file, and unregistered the service from CoreModule. This removes all comment-related backend functionality.
This commit is contained in:
Nariman Jelveh
2025-12-12 21:49:54 -08:00
committed by GitHub
parent 6bb4e9dfae
commit b8ed8caa3a
3 changed files with 0 additions and 415 deletions

View File

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

View File

@@ -1,219 +0,0 @@
/*
* Copyright (C) 2024-present Puter Technologies Inc.
*
* This file is part of Puter.
*
* Puter is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published
* by the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
// METADATA // {"ai-commented":{"service":"claude"}}
const APIError = require('../api/APIError');
const FSNodeParam = require('../api/filesystem/FSNodeParam');
const { get_user } = require('../helpers');
const configurable_auth = require('../middleware/configurable_auth');
const { Endpoint } = require('../util/expressutil');
const BaseService = require('./BaseService');
const { DB_WRITE } = require('./database/consts');
/**
* CommentService class handles all comment-related functionality in the system.
* Extends BaseService to provide comment creation, retrieval, and attachment capabilities
* for filesystem entries. Manages database operations for user comments and their
* associations with filesystem nodes. Provides REST API endpoints for comment
* operations including posting new comments and listing existing comments.
* @extends BaseService
*/
class CommentService extends BaseService {
/**
* Static module dependencies used by the CommentService class
* @property {Function} uuidv4 - UUID v4 generator function from the uuid package
*/
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 }) {
/**
* Installs route handlers for comment-related endpoints
* Sets up POST routes for creating and listing comments on filesystem entries
*
* @param {*} _ Unused parameter
* @param {Object} options Installation options
* @param {Express} options.app Express application instance
* @private
*/
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 ) {
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 ) {
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,
user: {
username: comment.user?.username,
},
});
}
res.json({
comments: client_safe_comments,
});
},
}).attach(app);
}
/**
* Creates a new comment with the given text
*
* @param {Object} params - The parameters object
* @param {Object} params.req - Express request object containing user and body data
* @param {Object} params.res - Express response object
* @returns {Promise<Object>} The created comment object with id and uid
* @throws {APIError} If text field is missing from request body
*/
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,
};
}
/**
* Attaches a comment to a filesystem entry
*
* @param {Object} params - The parameters object
* @param {Object} params.node - The filesystem node to attach the comment to
* @param {Object} params.comment - The comment object containing id and other details
* @returns {Promise<void>} Resolves when comment is successfully attached
*/
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')]);
}
/**
* Retrieves all comments associated with a filesystem entry
*
* @param {Object} params - The parameters object
* @param {Object} params.node - The filesystem node to get comments for
* @returns {Promise<Array>} Array of comment objects with user info attached
*/
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')]);
for ( const comment of comments ) {
const user_id = comment.user_id;
const user = await get_user({ id: user_id });
comment.user = user;
}
return comments;
}
}
module.exports = { CommentService };

View File

@@ -1,193 +0,0 @@
import { describe, expect, it, vi } from 'vitest';
import { createTestKernel } from '../../tools/test.mjs';
import * as config from '../config';
import { CommentService } from './CommentService';
describe('CommentService', async () => {
config.load_config({
'services': {
'database': {
path: ':memory:',
},
},
});
const testKernel = await createTestKernel({
serviceMap: {
'comment': CommentService,
},
initLevelString: 'init',
testCore: true,
});
const commentService = testKernel.services!.get('comment') as any;
it('should be instantiated', () => {
expect(commentService).toBeInstanceOf(CommentService);
});
it('should have db connection after init', () => {
expect(commentService.db).toBeDefined();
});
it('should have uuidv4 module', () => {
expect(commentService.modules).toBeDefined();
expect(commentService.modules.uuidv4).toBeDefined();
expect(typeof commentService.modules.uuidv4).toBe('function');
});
it('should have create_comment_ method', () => {
expect(commentService.create_comment_).toBeDefined();
expect(typeof commentService.create_comment_).toBe('function');
});
it('should have attach_comment_to_fsentry method', () => {
expect(commentService.attach_comment_to_fsentry).toBeDefined();
expect(typeof commentService.attach_comment_to_fsentry).toBe('function');
});
it('should have get_comments_for_fsentry method', () => {
expect(commentService.get_comments_for_fsentry).toBeDefined();
expect(typeof commentService.get_comments_for_fsentry).toBe('function');
});
it('should generate UUID for comments', () => {
const uuid1 = commentService.modules.uuidv4();
const uuid2 = commentService.modules.uuidv4();
expect(uuid1).toBeDefined();
expect(uuid2).toBeDefined();
expect(typeof uuid1).toBe('string');
expect(typeof uuid2).toBe('string');
expect(uuid1).not.toBe(uuid2);
});
it('should validate UUID format', () => {
const uuid = commentService.modules.uuidv4();
// UUID v4 format: xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
expect(uuid).toMatch(uuidRegex);
});
it('should create comment with text', async () => {
const mockReq = {
body: { text: 'Test comment text' },
user: { id: 1 },
};
const mockRes = {};
// Mock database write
const originalWrite = commentService.db.write.bind(commentService.db);
commentService.db.write = vi.fn().mockResolvedValue({ insertId: 123 });
try {
const result = await commentService.create_comment_({
req: mockReq,
res: mockRes
});
expect(result).toBeDefined();
expect(result.id).toBe(123);
expect(result.uid).toBeDefined();
expect(typeof result.uid).toBe('string');
// Verify database write was called with correct parameters
expect(commentService.db.write).toHaveBeenCalledWith(
expect.stringContaining('INSERT INTO `user_comments`'),
expect.arrayContaining([
expect.any(String), // UUID
1, // user_id
'{}', // metadata
'Test comment text',
])
);
} finally {
commentService.db.write = originalWrite;
}
});
it('should attach comment to fsentry', async () => {
const mockNode = {
get: vi.fn().mockResolvedValue(456), // mysql-id
};
const comment = {
id: 123,
uid: 'comment-uuid',
};
const originalWrite = commentService.db.write.bind(commentService.db);
commentService.db.write = vi.fn().mockResolvedValue({});
try {
await commentService.attach_comment_to_fsentry({
node: mockNode,
comment: comment,
});
expect(commentService.db.write).toHaveBeenCalledWith(
expect.stringContaining('INSERT INTO `user_fsentry_comments`'),
expect.arrayContaining([123, 456])
);
expect(mockNode.get).toHaveBeenCalledWith('mysql-id');
} finally {
commentService.db.write = originalWrite;
}
});
it('should call database to get comments for fsentry', async () => {
const mockNode = {
get: vi.fn().mockResolvedValue(789),
};
const originalRead = commentService.db.read.bind(commentService.db);
commentService.db.read = vi.fn().mockResolvedValue([]);
try {
// Note: This test only verifies the database call structure
// Full integration tests would require proper user service setup
await commentService.get_comments_for_fsentry({
node: mockNode,
});
expect(commentService.db.read).toHaveBeenCalledWith(
expect.stringContaining('SELECT * FROM `user_comments`'),
expect.arrayContaining([789])
);
expect(mockNode.get).toHaveBeenCalledWith('mysql-id');
} finally {
commentService.db.read = originalRead;
}
});
it('should handle multiple comment attachments', async () => {
const mockNode = {
get: vi.fn().mockResolvedValue(999),
};
const comments = [
{ id: 1, uid: 'uuid-1' },
{ id: 2, uid: 'uuid-2' },
{ id: 3, uid: 'uuid-3' },
];
const originalWrite = commentService.db.write.bind(commentService.db);
commentService.db.write = vi.fn().mockResolvedValue({});
try {
for (const comment of comments) {
await commentService.attach_comment_to_fsentry({
node: mockNode,
comment,
});
}
expect(commentService.db.write).toHaveBeenCalledTimes(3);
} finally {
commentService.db.write = originalWrite;
}
});
});