mirror of
https://github.com/HeyPuter/puter.git
synced 2025-12-19 03:30:47 -06:00
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:
@@ -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);
|
||||
|
||||
|
||||
@@ -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 };
|
||||
@@ -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;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user