feat: implement check functionality
This commit is contained in:
3
backend/migrations/3_checked.sql
Normal file
3
backend/migrations/3_checked.sql
Normal file
@@ -0,0 +1,3 @@
|
||||
-- Add tri-state checked column to messages (NULL | 0 | 1)
|
||||
ALTER TABLE messages ADD COLUMN checked INTEGER NULL;
|
||||
|
||||
@@ -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'
|
||||
);
|
||||
);
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user