154 lines
4 KiB
JavaScript
154 lines
4 KiB
JavaScript
'use strict';
|
|
|
|
const _ = require('lodash');
|
|
const inboxRepository = require('./repository');
|
|
const { PUBLIC_ATTRIBUTES } = require('./repository');
|
|
const {
|
|
validateContent,
|
|
validateUid,
|
|
validateSource,
|
|
buildTitleFromContent,
|
|
} = require('./validation');
|
|
const { NotFoundError } = require('../../shared/errors');
|
|
const { processInboxItem } = require('./inboxProcessingService');
|
|
|
|
class InboxService {
|
|
/**
|
|
* Get all active inbox items for a user.
|
|
* Supports pagination if limit/offset provided.
|
|
*/
|
|
async getAll(userId, { limit, offset } = {}) {
|
|
const hasPagination = limit !== undefined || offset !== undefined;
|
|
|
|
if (hasPagination) {
|
|
const parsedLimit = parseInt(limit, 10) || 20;
|
|
const parsedOffset = parseInt(offset, 10) || 0;
|
|
|
|
const [items, totalCount] = await Promise.all([
|
|
inboxRepository.findAllActive(userId, {
|
|
limit: parsedLimit,
|
|
offset: parsedOffset,
|
|
}),
|
|
inboxRepository.countActive(userId),
|
|
]);
|
|
|
|
return {
|
|
items,
|
|
pagination: {
|
|
total: totalCount,
|
|
limit: parsedLimit,
|
|
offset: parsedOffset,
|
|
hasMore: parsedOffset + items.length < totalCount,
|
|
},
|
|
};
|
|
}
|
|
|
|
// Return simple array for backward compatibility
|
|
return inboxRepository.findAllActive(userId);
|
|
}
|
|
|
|
/**
|
|
* Get a single inbox item by UID.
|
|
*/
|
|
async getByUid(userId, uid) {
|
|
validateUid(uid);
|
|
|
|
const item = await inboxRepository.findByUidPublic(userId, uid);
|
|
|
|
if (!item) {
|
|
throw new NotFoundError('Inbox item not found.');
|
|
}
|
|
|
|
return item;
|
|
}
|
|
|
|
/**
|
|
* Create a new inbox item.
|
|
*/
|
|
async create(userId, { content, source }) {
|
|
const validatedContent = validateContent(content);
|
|
const validatedSource = validateSource(source);
|
|
const title = buildTitleFromContent(validatedContent);
|
|
|
|
const item = await inboxRepository.createForUser(userId, {
|
|
content: validatedContent,
|
|
title,
|
|
source: validatedSource,
|
|
});
|
|
|
|
return _.pick(item, PUBLIC_ATTRIBUTES);
|
|
}
|
|
|
|
/**
|
|
* Update an inbox item.
|
|
*/
|
|
async update(userId, uid, { content, status }) {
|
|
validateUid(uid);
|
|
|
|
const item = await inboxRepository.findByUid(userId, uid);
|
|
|
|
if (!item) {
|
|
throw new NotFoundError('Inbox item not found.');
|
|
}
|
|
|
|
const updateData = {};
|
|
|
|
if (content !== undefined && content !== null) {
|
|
const validatedContent = validateContent(content);
|
|
updateData.content = validatedContent;
|
|
updateData.title = buildTitleFromContent(validatedContent);
|
|
}
|
|
|
|
if (status !== undefined && status !== null) {
|
|
updateData.status = status;
|
|
}
|
|
|
|
await inboxRepository.updateItem(item, updateData);
|
|
|
|
return _.pick(item, PUBLIC_ATTRIBUTES);
|
|
}
|
|
|
|
/**
|
|
* Soft delete an inbox item.
|
|
*/
|
|
async delete(userId, uid) {
|
|
validateUid(uid);
|
|
|
|
const item = await inboxRepository.findByUid(userId, uid);
|
|
|
|
if (!item) {
|
|
throw new NotFoundError('Inbox item not found.');
|
|
}
|
|
|
|
await inboxRepository.softDelete(item);
|
|
|
|
return { message: 'Inbox item successfully deleted' };
|
|
}
|
|
|
|
/**
|
|
* Mark an inbox item as processed.
|
|
*/
|
|
async process(userId, uid) {
|
|
validateUid(uid);
|
|
|
|
const item = await inboxRepository.findByUid(userId, uid);
|
|
|
|
if (!item) {
|
|
throw new NotFoundError('Inbox item not found.');
|
|
}
|
|
|
|
await inboxRepository.markProcessed(item);
|
|
|
|
return _.pick(item, PUBLIC_ATTRIBUTES);
|
|
}
|
|
|
|
/**
|
|
* Analyze text content without creating an inbox item.
|
|
*/
|
|
analyzeText(content) {
|
|
validateContent(content);
|
|
return processInboxItem(content);
|
|
}
|
|
}
|
|
|
|
module.exports = new InboxService();
|