@natlibfi/melinda-ui-commons
Version:
Common modules for Melinda UI applications
212 lines (160 loc) • 6.46 kB
JavaScript
//****************************************************************************//
// //
// SERVER NOTIFICATIONS FOR MELINDA UI APPLICATIONS //
// - collection 'notes' in Mongo DB //
// //
//****************************************************************************//
import httpStatus from 'http-status';
import {MongoClient, ObjectId} from 'mongodb';
import sanitize from 'mongo-sanitize';
import {createLogger} from '@natlibfi/melinda-backend-commons';
import {Error as ApiError} from '@natlibfi/melinda-commons';
import {construct, hasUndefinedProperty, isObject} from './notificationUtils.js';
export default async function (MONGO_URI, dbName = 'melinda-ui') {
const logger = createLogger();
// Connect to mongo (MONGO)
const client = await MongoClient.connect(MONGO_URI);
const db = client.db(dbName);
const collection = 'notes';
// Default projection for a note item
// The returned note item object:
// - has property '_id' removed
// - has property 'id' added
// - all other properties are returned without modifications
// * url is an optional property and is therefore not always present in returned objects
const noteItemProjection = {
projection: {
_id: 0,
id: {$toString: '$_id'},
blocksInteraction: 1,
componentStyle: 1,
context: 1,
endDate: 1,
isDismissible: 1,
messageStyle: 1,
messageText: 1,
url: 1
}
};
return {addNoteItem, getNoteItem, getNoteItems, getNoteItemsForApp, removeNoteItem, removeNoteItemsByMessageStyle};
//-----------------------------------------------------------------------------
// ADD SERVER NOTIFICATIONS
//-----------------------------------------------------------------------------
/**
* Add note item to collection
* @param {Object} noteItem contains note item data:
* {
* blocksInteraction: false,
* componentStyle: "banner",
* context: ["artikkelit", "muuntaja"],
* endDate: new Date("2024-12-30T12:30:15.002"),
* isDismissible: true,
* messageStyle: "info",
* messageText: "Test server notification message",
* url: "https://www.kansalliskirjasto.fi/" //optional property
* }
* @returns {void}
*/
async function addNoteItem(noteItem) {
logger.info(`MongoNotes: Adding one note item ${JSON.stringify(noteItem)}`);
if (!isObject(noteItem)) {
logger.debug('MongoNotes: NoteItem parameter is not object');
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, 'NoteItem data is not valid');
}
const newNoteItem = construct(noteItem);
if (hasUndefinedProperty(newNoteItem)) {
logger.debug('MongoNotes: NoteItem data did not pass validation');
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, 'NoteItem data is not valid');
}
// '_id' property is automatically generated by mongo node driver
// and added to noteItem before insert to collection.
// type of '_id' is ObjectId.
const result = await db.collection(collection).insertOne(newNoteItem);
if (result.acknowledged) {
logger.info(`New ${noteItem.componentStyle} note item added with ${noteItem.messageStyle} message: ${noteItem.messageText}`);
const {_id: _, ...rest} = newNoteItem;
return {id: result.insertedId.toString(), ...rest};
}
throw new ApiError(httpStatus.INTERNAL_SERVER_ERROR, `MongoNotes could not add note ${noteItem}`);
}
//-----------------------------------------------------------------------------
// GET SERVER NOTIFICATIONS
//-----------------------------------------------------------------------------
/**
* Get note item with id
* @param {String} noteId object's id
* @returns Boolean
*/
async function getNoteItem(noteId) {
logger.info(`MongoNotes: Getting one note item`);
const cleanId = sanitize(noteId);
const query = {_id: new ObjectId(cleanId)};
const result = await db.collection(collection).findOne(query, noteItemProjection);
return result;
}
/**
* Get note items with matching context.app
* @param {String} app apps name
* @returns Array of note objects
*/
async function getNoteItemsForApp(app) {
logger.info(`MongoNotes: Getting all note items for app`);
const cleanAppName = sanitize(app);
const query = {
'context': {
$in: [cleanAppName, 'all']
}
};
const result = await db.collection(collection).find(query, noteItemProjection).toArray();
return result;
}
/**
* Get note items
* @returns Array of note objects
*/
async function getNoteItems() {
logger.info(`MongoNotes: Getting all note items`);
const query = {};
const result = await db.collection(collection).find(query, noteItemProjection).toArray();
return result;
}
//-----------------------------------------------------------------------------
// REMOVE SERVER NOTIFICATIONS
//-----------------------------------------------------------------------------
/**
* Remove note
* @param {String} noteId object's id
* @returns Boolean
*/
async function removeNoteItem(noteId) {
logger.info(`MongoNotes: Removing one note item with id ${noteId}`);
const cleanId = sanitize(noteId);
const filter = {_id: new ObjectId(cleanId)};
const result = await db.collection(collection).deleteOne(filter);
if (result.deletedCount > 0) {
return true;
}
if (result.deletedCount === 0) {
return false;
}
throw new ApiError(httpStatus.NOT_FOUND, `MongoNotes could not remove note with id ${noteId}`);
}
/**
* Remove notes by message style
* @param {String} messageStyle
* @returns Boolean
*/
async function removeNoteItemsByMessageStyle(messageStyle) {
logger.info(`MongoNotes: Removing all notes with message style ${messageStyle}`);
const cleanMessageStyle = sanitize(messageStyle);
const filter = {messageStyle: cleanMessageStyle};
const result = await db.collection(collection).deleteMany(filter);
if (result.deletedCount > 0) {
return true;
}
if (result.deletedCount === 0) {
return false;
}
throw new ApiError(httpStatus.NOT_FOUND, `MongoNotes could not remove notes`);
}
}