feat: implement check functionality

This commit is contained in:
2025-09-13 07:45:19 +02:00
parent ec1a2ba7f0
commit fab05f32ec
15 changed files with 258 additions and 61 deletions

View File

@@ -0,0 +1,3 @@
-- Add tri-state checked column to messages (NULL | 0 | 1)
ALTER TABLE messages ADD COLUMN checked INTEGER NULL;

View File

@@ -13,19 +13,20 @@ CREATE TABLE IF NOT EXISTS files (
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (channelId) REFERENCES channels (id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
channelId INTEGER,
content TEXT,
fileId INTEGER NULL,
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (channelId) REFERENCES channels (id) ON DELETE CASCADE,
FOREIGN KEY (fileId) REFERENCES files (id) ON DELETE
SET
NULL
);
CREATE TABLE IF NOT EXISTS messages (
id INTEGER PRIMARY KEY AUTOINCREMENT,
channelId INTEGER,
content TEXT,
fileId INTEGER NULL,
checked INTEGER NULL,
createdAt DATETIME DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (channelId) REFERENCES channels (id) ON DELETE CASCADE,
FOREIGN KEY (fileId) REFERENCES files (id) ON DELETE
SET
NULL
);
CREATE VIRTUAL TABLE IF NOT EXISTS messages_fts USING fts5(
content,
content = 'messages',
content_rowid = 'id'
);
);

View File

@@ -53,7 +53,7 @@ export const getMessages = async (req: Request, res: Response) => {
res.json({ messages });
}
export const moveMessage = async (req: Request, res: Response) => {
export const moveMessage = async (req: Request, res: Response) => {
const { messageId } = req.params;
const { targetChannelId } = req.body;
@@ -77,4 +77,19 @@ export const moveMessage = async (req: Request, res: Response) => {
logger.critical(`Failed to move message ${messageId}:`, error);
res.status(500).json({ error: 'Failed to move message' });
}
}
}
export const setChecked = async (req: Request, res: Response) => {
const { messageId } = req.params;
const { checked } = req.body as { checked: boolean | null | undefined };
if (!messageId) {
return res.status(400).json({ error: 'Message ID is required' });
}
const value = (checked === undefined) ? null : checked;
const result = await MessageService.setMessageChecked(messageId, value);
if (result.changes === 0) {
return res.status(404).json({ error: 'Message not found' });
}
logger.info(`Message ${messageId} checked set to ${value}`);
res.json({ id: parseInt(messageId), checked: value });
}

View File

@@ -4,9 +4,10 @@ import { authenticate } from '../middleware/auth';
export const router = Router({mergeParams: true});
router.post('/', authenticate, MessageController.createMessage);
router.put('/:messageId', authenticate, MessageController.updateMessage);
router.put('/:messageId/move', authenticate, MessageController.moveMessage);
router.delete('/:messageId', authenticate, MessageController.deleteMessage);
router.get('/', authenticate, MessageController.getMessages);
router.post('/', authenticate, MessageController.createMessage);
router.put('/:messageId', authenticate, MessageController.updateMessage);
router.put('/:messageId/move', authenticate, MessageController.moveMessage);
router.put('/:messageId/checked', authenticate, MessageController.setChecked);
router.delete('/:messageId', authenticate, MessageController.deleteMessage);
router.get('/', authenticate, MessageController.getMessages);

View File

@@ -1,9 +1,9 @@
import { db, FTS5Enabled } from "../db";
import { events } from "../globals";
export const createMessage = async (channelId: string, content: string) => {
const query = db.prepare(`INSERT INTO messages (channelId, content) VALUES ($channelId, $content)`);
const result = query.run({ channelId: channelId, content: content });
export const createMessage = async (channelId: string, content: string) => {
const query = db.prepare(`INSERT INTO messages (channelId, content, checked) VALUES ($channelId, $content, NULL)`);
const result = query.run({ channelId: channelId, content: content });
const messageId = result.lastInsertRowid;
console.log(`Adding message for search with id ${messageId}`);
@@ -17,9 +17,9 @@ export const createMessage = async (channelId: string, content: string) => {
return messageId;
}
export const updateMessage = async (messageId: string, content: string, append: boolean = false) => {
const query = db.prepare(`UPDATE messages SET content = $content WHERE id = $id`);
const result = query.run({ content: content, id: messageId });
export const updateMessage = async (messageId: string, content: string, append: boolean = false) => {
const query = db.prepare(`UPDATE messages SET content = $content WHERE id = $id`);
const result = query.run({ content: content, id: messageId });
@@ -46,13 +46,13 @@ export const deleteMessage = async (messageId: string) => {
return result;
}
export const getMessages = async (channelId: string) => {
const query = db.prepare(`
SELECT
messages.id, messages.channelId, messages.content, messages.createdAt,
files.id as fileId, files.filePath, files.fileType, files.createdAt as fileCreatedAt, files.originalName, files.fileSize
FROM
messages
export const getMessages = async (channelId: string) => {
const query = db.prepare(`
SELECT
messages.id, messages.channelId, messages.content, messages.createdAt, messages.checked,
files.id as fileId, files.filePath, files.fileType, files.createdAt as fileCreatedAt, files.originalName, files.fileSize
FROM
messages
LEFT JOIN
files
ON
@@ -61,16 +61,16 @@ export const getMessages = async (channelId: string) => {
messages.channelId = $channelId
`);
const rows = query.all({ channelId: channelId });
return rows;
}
return rows;
}
export const getMessage = async (id: string) => {
const query = db.prepare(`
SELECT
messages.id, messages.channelId, messages.content, messages.createdAt,
files.id as fileId, files.filePath, files.fileType, files.createdAt as fileCreatedAt, files.originalName, files.fileSize
FROM
messages
export const getMessage = async (id: string) => {
const query = db.prepare(`
SELECT
messages.id, messages.channelId, messages.content, messages.createdAt, messages.checked,
files.id as fileId, files.filePath, files.fileType, files.createdAt as fileCreatedAt, files.originalName, files.fileSize
FROM
messages
LEFT JOIN
files
ON
@@ -79,8 +79,17 @@ export const getMessage = async (id: string) => {
messages.id = $id
`);
const row = query.get({ id: id });
return row;
}
return row;
}
export const setMessageChecked = async (messageId: string, checked: boolean | null) => {
const query = db.prepare(`UPDATE messages SET checked = $checked WHERE id = $id`);
// SQLite stores booleans as integers; NULL for unknown
const value = checked === null ? null : (checked ? 1 : 0);
const result = query.run({ id: messageId, checked: value });
events.emit('message-updated', messageId, { checked: value });
return result;
}
export const moveMessage = async (messageId: string, targetChannelId: string) => {
// Get current message to emit proper events
@@ -104,4 +113,4 @@ export const moveMessage = async (messageId: string, targetChannelId: string) =>
events.emit('message-moved', messageId, (currentMessage as any).channelId, targetChannelId);
return result;
}
}

View File

@@ -4,12 +4,13 @@ export interface Channel {
created_at: string;
}
export interface Message {
id: number;
channel_id: number;
content: string;
created_at: string;
}
export interface Message {
id: number;
channel_id: number;
content: string;
created_at: string;
checked?: boolean | null;
}
export interface File {
id: number;
@@ -18,4 +19,4 @@ export interface File {
file_path: string;
file_type: string;
created_at: string;
}
}