// @ts-check
import './../../types.js';
/**
* Email Controller
*
* Contains all the business logic for email operations:
* - Creating and updating emails
* - Managing email recipients (persons/entries)
* - Handling email status changes and filtering
* - Managing email sharing and admin permissions
* - Retrieving email lists and statistics
*
* Emails are complex objects that can have multiple recipients, different statuses,
* and support filtering, sharing, and administrative features.
*/
import { query, UUID2hex, HEX2uuid } from '@commtool/sql-query';
import { renderObject } from '../../utils/renderTemplates.js';
import { Templates } from '../../utils/compileTemplates.js';
import { getUID, isValidUID } from '../../utils/UUIDs.js';
import { addUpdateEntry, addUpdateList } from '../../server.ws.js';
import { publishEvent } from '../../utils/events.js';
import { isObjectAdmin, isAdmin, isListAdmin, checkVisible, checkObjectAdmin } from '../../utils/authChecks.js';
import { deleteVisibility } from '../../utils/listVisibilty.js';
import { putShare, deleteShare, getSharesAll, getShares, getShared, getShare } from '../list.js';
import { paginateList } from '../../utils/paginateList.js';
import { matchObject } from '../../utils/objectfilter/filters/index.js';
import mysqlTime from '../../utils/mysqlTime.js';
import { errorLoggerRead, errorLoggerUpdate } from '../../utils/requestLogger.js';
import _ from 'lodash';
/**
* Create or update an email
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const createOrUpdateEmail = async (req, res) => {
try {
let ownerUID = UUID2hex(req.session.user);
if (req.query.user && isObjectAdmin(req, req.query.user)) {
ownerUID = UUID2hex(req.query.user);
}
const senderUID = UUID2hex(req.params.sender);
const UID = await getUID(req);
req.body.status = !req.body.status ? 'prepare' : req.body.status;
const template = Templates[req.session.root].email;
const object = await renderObject(template, req.body, req);
object.Data = req.body;
const resSender = await query(`SELECT ObjectBase.UID, Member.Display, Member.Data, ObjectBase.Title
FROM ObjectBase
INNER JOIN Member ON (Member.UID=ObjectBase.UID)
WHERE ObjectBase.UID=? AND ObjectBase.Type='group'`, [senderUID], { cast: ['UUID', 'json'] });
if (resSender.length === 0) {
res.json({ success: false, message: 'invalid sender group UID' });
return;
}
const sender = resSender[0];
const [email] = await query(`SELECT Member.Data,ObjectBase.dindex FROM ObjectBase
INNER JOIN Member ON (Member.UID=ObjectBase.UID)
WHERE ObjectBase.UID=? AND ObjectBase.Type='email'`, [UID], { cast: ['json'] });
if (!email) {
// Create new email
await query(`INSERT INTO ObjectBase(UID,UIDuser,Type,UIDBelongsTo,Title,dindex,Data)
VALUES (?,'email',?,?,?,?,?)`,
[UID, ownerUID, object.Title, object.dindex, JSON.stringify(object.Data)]);
await query(`INSERT INTO Member(UID,Display,SortName,FullTextIndex,Data)
VALUES (?,?,?,?,?)`,
[UID, object.Display, object.SortIndex, object.FullTextIndex, JSON.stringify(object.Data)]);
await query(`INSERT INTO Links(UID, Type, UIDTarget) VALUES (?,'memberA',?)`, [UID, senderUID]);
await query(`INSERT INTO Links(UID, Type, UIDTarget) VALUES (?,'member',?)`, [UID, ownerUID]);
} else {
// Update existing email
await query(`UPDATE ObjectBase,Member SET
ObjectBase.Title=?,Member.Display=?,Member.SortName=?,Member.FullTextIndex=?,ObjectBase.dindex=?,Member.Data=?
WHERE ObjectBase.UID=? AND ObjectBase.UID=Member.UID`,
[object.Title, object.Display, object.SortIndex, object.FullTextIndex, object.dindex, JSON.stringify(object.Data), UID]);
const oldData = _.cloneDeep(email.Data);
// Check if sender update required
const oldSender = await query(`SELECT ObjectBase.UID, Member.Display,Member.Data, ObjectBase.Title
FROM ObjectBase
INNER JOIN Member ON (Member.UID=ObjectBase.UID)
INNER JOIN Links ON (Links.UIDTarget=ObjectBase.UID AND Links.Type='memberA')
WHERE Links.UID=?`, [UID], { cast: ['UUID', 'json'] });
if (oldSender.length === 0 || oldSender[0].UID !== sender.UID) {
await query(`DELETE FROM Links WHERE UID=? AND Type='memberA'`, [UID]);
await query(`INSERT INTO Links(UID, Type, UIDTarget) VALUES (?,'memberA',?)`, [UID, senderUID]);
}
// Update email owner if changed
const oldOwner = await query(`SELECT ObjectBase.UID,Member.Display, Member.Data, ObjectBase.Title
FROM ObjectBase
INNER JOIN Member ON (Member.UID=ObjectBase.UID)
INNER JOIN Links ON (Links.UIDTarget=ObjectBase.UID AND Links.Type='member')
WHERE Links.UID=?`, [UID], { cast: ['UUID', 'json'] });
if (oldOwner.length === 0 || oldOwner[0].UID !== ownerUID) {
await query(`DELETE FROM Links WHERE UID=? AND Type='member'`, [UID]);
await query(`INSERT INTO Links(UID, Type, UIDTarget) VALUES (?,'member',?)`, [UID, ownerUID]);
}
const resOwner = await query(`SELECT Member.UID, Member.Display, Member.Data, ObjectBase.Title
FROM ObjectBase
INNER JOIN Member ON (ObjectBase.UIDBelongsTo = Member.UID)
INNER JOIN Links ON (Links.UIDTarget=ObjectBase.UID AND Links.Type='member')
WHERE Links.UID=?`, [UID]);
const owner = resOwner[0];
object.admin = await isListAdmin(req, UID);
object.writeable = await isObjectAdmin(req, UID);
addUpdateEntry(UID, { Data: { ...object, UID: HEX2uuid(object.UID), owner: sender, member: owner }, committed: true });
if (req.body.status && oldData.status !== req.body.status) {
publishEvent(`/state/email/${req.body.status}`, {
organization: req.session.root,
data: HEX2uuid(UID)
});
}
}
res.json({ success: true, result: { ...object, UID: HEX2uuid(object.UID) } });
} catch (e) {
errorLoggerUpdate(e);
res.status(500).json({ success: false, message: 'Internal server error' });
}
};
/**
* Update email data
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const updateEmail = async (req, res) => {
try {
const updateMessage = { committed: true };
const emailUID = UUID2hex(req.params.UID);
const result = await query(`SELECT Member.Data FROM ObjectBase INNER Join Member ON (Member.UID=ObjectBase.UID)
WHERE ObjectBase.Type='email' AND ObjectBase.UID=?`, [emailUID]);
if (result.length !== 1) {
res.json({ success: false, message: 'email with this UID does not exist' });
return;
}
const oldData = JSON.parse(result[0].Data);
let reset = req.body.reset;
if (req.body.reset) {
req.body.status = 'prepare';
delete req.body.reset;
}
const data = { ...oldData, ...req.body };
const template = Templates[req.session.root].email;
const object = await renderObject(template, data, req);
await query(`UPDATE ObjectBase,Member
SET ObjectBase.Title=?,Member.Display=?,ObjectBase.dindex=?, Member.Data=?
WHERE ObjectBase.UID=? AND ObjectBase.UID=Member.UID`,
[object.Title, object.Display, object.dindex, JSON.stringify(data), emailUID]);
if (!req.query.autoSave || req.query.autoSave === 'false') {
updateMessage.Data = { Data: data };
}
object.admin = await isListAdmin(req, req.params.UID);
object.writeable = await isObjectAdmin(req, req.params.UID);
if (data.status === 'sending' && oldData.status !== 'prepare') {
res.json({ success: true, message: 'you can only change from status prepare into status sending' });
return;
}
if (reset && data.status === 'prepare') {
await query(`UPDATE ObjectBase AS entry INNER JOIN Links ON (entry.UID=Links.UID AND Links.Type IN('member','memberA'))
SET entry.Data=?,entry.dindex=0
WHERE Links.UIDTarget=? AND entry.Type='entry'`, [JSON.stringify({ status: 'added' }), emailUID]);
updateMessage.reset = true;
}
if (!_.isEqual(oldData, data)) {
publishEvent(`/change/email/${HEX2uuid(emailUID)}`, {
organization: req.session.root,
data: {}
});
}
if (oldData.status !== data.status) {
publishEvent('/state/email/' + data.status, {
organization: req.session.root,
data: HEX2uuid(emailUID)
});
}
addUpdateEntry(emailUID, updateMessage);
res.json({ success: true, result: { ...object, UID: HEX2uuid(object.UID) } });
} catch (e) {
errorLoggerUpdate(e);
res.status(500).json({ success: false, message: 'Internal server error' });
}
};
/**
* Delete an email
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const deleteEmail = async (req, res) => {
try {
const UID = UUID2hex(req.params.UID);
const [email] = await query(`SELECT ObjectBase.UIDBelongsTo FROM ObjectBase
WHERE ObjectBase.UID =? AND ObjectBase.Type='email'`, [UID]);
if (email) {
await query(`DELETE FROM ObjectBase WHERE UID =? AND Type='email'`, [UID]);
await query(`DELETE FROM Member WHERE UID =?`, [UID]);
await query(`DELETE Links FROM Links WHERE UID=? AND Type IN ('memberA','member')`, [UID]);
await query(`DELETE Links,Entry
FROM Links
INNER JOIN ObjectBase AS Entry ON (Entry.UID=Links.UID AND Links.Type='memberA' AND Entry.Type='entry')
WHERE Links.UIDTarget=?`, [UID]);
deleteVisibility(UID);
res.json({ success: true });
} else {
res.json({ success: false, message: 'email not found' });
}
} catch (e) {
errorLoggerUpdate(e);
res.status(500).json({ success: false, message: 'Internal server error' });
}
};
/**
* Get pending emails (admin only)
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const getPendingEmails = async (req, res) => {
try {
const orga = UUID2hex(req.session.root);
const result = await query(`SELECT emember.Data AS Data, email.UID, emember.Display, email.dindex,
Member.Data AS MemberData, Member.UID AS UIDowner, Member.Display AS DisplayMember
FROM ObjectBase AS email
INNER JOIN Member AS emember ON (emember.UID=email.UID)
INNER JOIN Links AS gLink ON (gLink.UID=email.UID AND gLink.Type='memberA')
INNER JOIN Links AS rLink ON (rLink.UID=email.UID AND rLink.Type='member')
INNER JOIN Member ON (Member.UID=rLink.UIDTarget)
LEFT JOIN Links AS oLink ON (oLink.UID=gLink.UIDTarget AND oLink.Type IN ('member','memberA'))
WHERE (oLink.UIDTarget=? OR gLink.UIDTarget=? )
AND email.Type='email' AND email.dindex=1 ORDER BY email.validFrom`,
[orga, orga], { cast: ['UUID', 'json'] });
const newResult = result.map(r => ({
UID: r.UID,
Data: { ...r.Data, UID: r.UID },
Display: r.Display,
dindex: r.dindex,
owner: {
UID: r.UIDowner,
Data: r.MemberData,
Display: r.DisplayMember
}
}));
res.json({ success: true, result: newResult });
} catch (e) {
errorLoggerRead(e);
res.status(500).json({ success: false, message: 'Internal server error' });
}
};
/**
* Get a specific email
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const getEmail = async (req, res) => {
try {
const UID = UUID2hex(req.params.UID);
let visible = ` AND Visible.UIDUser=U_UUID2BIN('${req.session.user}')`;
if (await isAdmin(req.session)) {
visible = '';
}
const resEmail = await query(`SELECT ObjectBase.UID,Member.Data,Member.Display,ObjectBase.dindex
FROM ObjectBase
INNER JOIN Member ON (Member.UID=ObjectBase.UID)
INNER JOIN Visible ON (Visible.UID=ObjectBase.UID ${visible} )
WHERE ObjectBase.UID=? AND ObjectBase.Type='email'
GROUP BY ObjectBase.UID`, [UID], { cast: ['UUID', 'json'] });
if (resEmail && resEmail.length > 0) {
const email = resEmail[0];
const resOwner = await query(`SELECT Member.UID, Member.Display, Member.Data, ObjectBase.Title
FROM ObjectBase
INNER JOIN Member ON (ObjectBase.UIDBelongsTo = Member.UID)
INNER JOIN Links ON (Links.UIDTarget=ObjectBase.UID AND Links.Type='member')
WHERE Links.UID=?`, [UID], { cast: ['UUID', 'json'] });
const owner = resOwner[0];
const resSender = await query(`SELECT ObjectBase.UID, Member.Display, Member.Data, ObjectBase.Title
FROM ObjectBase
INNER JOIN Member ON (Member.UID=ObjectBase.UID)
INNER JOIN Links ON (Links.UIDTarget=ObjectBase.UID AND Links.Type='memberA')
WHERE Links.UID=?`, [UID], { cast: ['UUID', 'json'] });
const sender = resSender[0];
email.admin = await isListAdmin(req, UID);
email.writeable = await isObjectAdmin(req, UID);
res.json({ success: true, result: { ...email, owner: sender, member: owner } });
} else {
res.json({ success: false, message: 'E-Mail not found or user not authorized to view this E-Mail' });
}
} catch (e) {
errorLoggerRead(e);
res.status(500).json({ success: false, message: 'Internal server error' });
}
};
/**
* Helper function to add persons to an email
* @param {Array|string} adding - UIDs to add
* @param {string} UIDemail - Email UID
* @param {Object} emailData - Email data
* @param {boolean} noUpdate - Skip update notifications
* @param {string} addStatus - Status for added entries
* @param {Buffer} UIDuser - User UID
* @param {string} organization - Organization UID for multi-tenant context
* @returns {Promise<Object>} Result object
*/
export const addPersons = async (
/** @type {Array|string|Object} */ adding,
/** @type {Buffer} */ UIDemail,
/** @type {Object} */ emailData,
/** @type {boolean} */ noUpdate,
/** @type {string} */ addStatus = 'added',
/** @type {Buffer} */ UIDuser,
/** @type {string} */ organization
) => {
let adds;
let bodyErrors = [];
if (Array.isArray(adding)) {
adds = adding.map(el => {
try {
if (typeof (el) === 'string')
return UUID2hex(el);
else if (el.UID)
return UUID2hex(el.UID);
else
return null;
} catch (e) { bodyErrors.push(e); }
});
} else {
try {
if (typeof (adding) === 'string')
adds = [UUID2hex(adding)];
else if (adding && typeof adding === 'object' && adding.UID)
adds = [UUID2hex(adding.UID)];
} catch (e) { bodyErrors.push(e); }
}
if (bodyErrors.length > 0) {
return { success: false, message: 'invalid body supplied', errors: bodyErrors };
}
const persons = await query(`SELECT Main.UID AS UID, Member.Data AS MemberData,
UIDV1() AS UIDNewEntry,ObjectBase.UID AS ObjectUID,Main.Title
FROM ObjectBase AS Main
INNER JOIN ObjectBase ON (ObjectBase.UIDBelongsTo= Main.UID)
INNER JOIN Member ON (Member.UID=Main.UIDBelongsTo)
LEFT JOIN (ObjectBase AS Entry INNER JOIN Links ON (Entry.UID=Links.UID AND Links.Type='memberA' AND Links.UIDTarget=?))
ON (Entry.UIDBelongsTo= Main.UID)
WHERE ObjectBase.UID IN (?) AND Main.Type IN ('person','extern') AND Entry.UID IS NULL`,
[UIDemail, adds], { log: true, cast: ['json'] });
const toBeAdded = persons.map(p => ({ ...p, Data: { status: addStatus, address: null } }));
if (toBeAdded.length) {
const insertParas = toBeAdded.map(a => ([a.UIDNewEntry, UIDuser, 'entry', a.UID, a.Title, 0, a.Data]));
await query(`INSERT INTO ObjectBase(UID,UIDuser,Type,UIDBelongsTo,Title,dindex,Data)
VALUES (?,?,?,?,?,?,?) ON DUPLICATE KEY UPDATE Data=VALUE(Data), Title=VALUE(Title)`,
insertParas, { batch: true });
await query(`INSERT IGNORE INTO Links(UID, Type, UIDTarget, UIDuser) VALUES (?,'memberA',?,?)`,
toBeAdded.map(a => ([a.UIDNewEntry, UIDemail, UIDuser])), { batch: true });
if (!noUpdate) {
addUpdateList(HEX2uuid(UIDemail));
}
publishEvent(`/add/email/entry/${HEX2uuid(UIDemail)}`, {
organization: organization,
data: toBeAdded.map(a => HEX2uuid(a.UIDNewEntry))
});
}
return { success: true, result: { added: toBeAdded.map(p => ({ ...p, UID: HEX2uuid(p.UID), UIDNewEntry: HEX2uuid(p.UIDNewEntry), ObjectUID: HEX2uuid(p.ObjectUID) })) } };
};
/**
* Add persons to email
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const addPersonsToEmail = async (req, res) => {
try {
const addStatus = req.query.status ? (['added', 'sent', 'error'].includes(req.query.status) ? req.query.status : 'added') : 'added';
const UIDemail = UUID2hex(req.params.UIDemail);
const result = await query(`SELECT Data,UID,Type FROM ObjectBase WHERE ObjectBase.UID=? AND Type ='email'`, [UIDemail]);
if (result.length === 0) {
res.json({ success: false, message: `invalid email UID supplied` });
return;
}
res.json(await addPersons(req.body, UIDemail, JSON.parse(result[0].Data), req.query.noUpdate, addStatus, UUID2hex(req.session.user), req.session.root));
} catch (e) {
errorLoggerRead(e);
res.status(500).json({ success: false, message: 'Internal server error' });
}
};
/**
* Update person status in email
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const updatePersonStatus = async (req, res) => {
try {
const UIDemail = UUID2hex(req.params.UIDemail);
const entryStates = ['added', 'sent', 'error'];
if (!entryStates.includes(req.body.status)) {
res.status(400).json({ success: false, message: 'illegal status' });
return;
}
await query(`UPDATE ObjectBase AS email
INNER JOIN Links ON (Links.UIDTarget=email.UID)
INNER JOIN ObjectBase AS entry ON (Links.UID=entry.UID AND Links.Type IN ('member' ,'memberA') AND entry.Type='entry')
SET entry.Data=?,entry.dindex=?
WHERE email.UID=? AND email.Type ='email' AND entry.UIDBelongsTo=?`,
[JSON.stringify(req.body), entryStates.indexOf(req.body.status), UIDemail, UUID2hex(req.params.UIDperson)]);
addUpdateEntry(req.params.UIDemail, { personStatus: { Data: req.body, UIDperson: req.params.UIDperson } });
res.json({ success: true });
} catch (e) {
errorLoggerUpdate(e);
res.status(500).json({ success: false, message: 'Internal server error' });
}
};
/**
* Remove persons from email
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const removePersonsFromEmail = async (req, res) => {
try {
const UIDemail = UUID2hex(req.params.UIDemail);
const result = await query(`SELECT Data,UID,Type FROM ObjectBase WHERE ObjectBase.UID=? AND Type ='email'`, [UIDemail]);
if (result.length === 0) {
res.json({ success: false, message: `invalid email UID supplied` });
return;
}
let deletes;
let bodyErrors = [];
const deleting = req.body;
if (Array.isArray(deleting)) {
deletes = deleting.map(el => {
try {
if (typeof (el) === 'string')
return UUID2hex(el);
else if (el.UID)
return UUID2hex(el.UID);
else
return null;
} catch (e) { bodyErrors.push(e); }
});
} else {
try {
if (typeof (deleting) === 'string')
deletes = [UUID2hex(deleting)];
else if (deleting.UID)
deletes = [UUID2hex(deleting.UID)];
} catch (e) { bodyErrors.push(e); }
}
if (bodyErrors.length > 0) {
res.json({ success: false, message: 'invalid body supplied', errors: bodyErrors });
return;
}
const persons = await query(`SELECT Entry.UIDBelongsTo AS UID, Entry.UID AS UIDentry
FROM ObjectBase AS Entry INNER JOIN Links ON (Entry.UID=Links.UID AND Links.Type IN ('member','memberA','member0') )
WHERE Links.UIDTarget=? AND (Entry.UIDBelongsTo IN (?) OR Entry.UID IN (?)) AND Entry.Type ='entry'`,
[UIDemail, deletes, deletes], { log: false, cast: ['json', 'UUID'] });
await query(`DELETE Entry,Links
FROM ObjectBase AS Entry INNER JOIN Links ON (Entry.UID=Links.UID AND Links.Type IN ('member','memberA','member0') )
WHERE Links.UIDTarget=? AND (Entry.UIDBelongsTo IN (?) OR Entry.UID IN (?)) AND Entry.Type ='entry'`, [UIDemail, deletes, deletes]);
addUpdateList(HEX2uuid(UIDemail));
publishEvent(`/remove/email/entry${HEX2uuid(UIDemail)}`, {
organization: req.session.root,
data: persons.map(p => p.UIDentry)
});
res.json({ success: true, result: { deleted: persons } });
} catch (e) {
errorLoggerRead(e);
res.status(500).json({ success: false, message: 'Internal server error' });
}
};
/**
* Get email listing (persons in email)
* @param {Object} req - Express request object
* @returns {Promise<Array>} List of persons
*/
export const getListing = async (req) => {
if (!isValidUID(req.params.UID)) {
throw new Error('you have to supply an UID');
}
const UID = UUID2hex(req.params.UID);
const time = req.query.Timestamp ? `FOR SYSTEM_TIME AS OF TIMESTAMP'${mysqlTime(req.query.Timestamp)}'` : '';
const result = await query(`
SELECT Entry.UIDBelongsTo AS UID, ObjectBase.Title, Entry.Data, Entry.UID AS UIDEntry,Member.Data AS MemberData,Member.Display
FROM ObjectBase AS Entry
INNER JOIN ObjectBase ON (ObjectBase.UIDBelongsTo=Entry.UIDBelongsTo AND ObjectBase.Type IN ('person','extern'))
INNER JOIN ObjectBase AS OVisible ON(OVisible.UIDBelongsTo=Entry.UIDBelongsTo AND OVisible.Type IN ('person','job','guest','extern') )
INNER JOIN Visible ON (Visible.UID=OVisible.UID)
INNER JOIN Member ON (Member.UID=ObjectBase.UID)
INNER JOIN Links ON (Links.UID=Entry.UID AND Links.Type='memberA')
WHERE Links.UIDTarget=?
AND Visible.UIDUser=?
AND Entry.Type='entry'
GROUP BY Entry.UID
ORDER BY JSON_VALUE(Member.Data,'$.lastName'),JSON_VALUE(Member.Data,'$.firstName')
`, [UID, UUID2hex(req.session.user)], { log: false, cast: ['json', 'UUID'] });
return result;
};
/**
* Get persons in email (with pagination support)
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const getEmailPersons = async (req, res) => {
try {
// if we want the data paginated- the user has supplied the __page parameter
if (!req.query.__page) {
// normal api request
const result = await getListing(req);
res.json({ success: true, result: result });
return;
}
// paginated api request
res.json(await paginateList(req, getListing));
} catch (e) {
errorLoggerRead(e);
res.status(500).json({ success: false, message: 'Internal server error' });
}
};
/**
* Get emails for a person
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const getEmailsForPerson = async (req, res) => {
try {
const UIDperson = UUID2hex(req.params.UID);
const user = UUID2hex(req.session.user);
const result = await query(`SELECT ObjectBase.UID, ObjectBase.Title, ObjectBase.Display, ObjectBase.Type FROM ObjectBase
INNER JOIN Links ON (Links.UIDTarget=ObjectBase.UID AND Links.Type IN ('member','memberA'))
INNER JOIN ObjectBase AS Entry ON (Entry.UID=Links.UID)
INNER JOIN Visible ON (Visible.UID=ObjectBase.UID)
WHERE ObjectBase.Type ='email' AND Entry.UIDBelongsTo=? AND Visible.UIDUser=?
GROUP BY ObjectBase.UID`, [UIDperson, user], { cast: ['UUID', 'json'] });
res.json({ success: true, result });
} catch (e) {
errorLoggerRead(e);
res.status(500).json({ success: false, message: 'Internal server error' });
}
};
/**
* Apply filter to email
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const applyFilterToEmail = async (req, res) => {
try {
const emailUID = UUID2hex(req.params.email);
const sourceUID = UUID2hex(req.params.source);
if (!isObjectAdmin(req, emailUID)) {
res.json({ success: false, message: 'user not authorized for this E-Mail' });
return;
}
const sources = await query(`SELECT Data,Type FROM ObjectBase WHERE UID=?`, [sourceUID]);
const addStatus = req.query.status ? (['added', 'sent', 'error'].includes(req.query.status) ? req.query.status : 'added') : 'added';
if (sources.length === 0) {
res.json({ success: false, message: 'filter source not found' });
return;
}
const emails = await query(`SELECT Member.Data,ObjectBase.Type
FROM ObjectBase
INNER JOIN Member ON (Member.UID=ObjectBase.UID)
WHERE ObjectBase.UID=? AND ObjectBase.Type='email'`, [emailUID]);
if (emails.length === 0) {
res.json({ success: false, message: 'email not found' });
return;
}
const filter = req.body;
const types = [...Object.keys(filter), 'entry'];
const all = await query(`SELECT ObjectBase.Type, ObjectBase.UIDBelongsTo AS UID,ObjectBase.Data AS ExtraData,Member.Data, MainBase.Data AS MainBaseData,
ObjectBase.Title,ObjectBase.UIDBelongsTo,Member.Display,Member.SortName,Entry.UID AS UIDEntry, UIDV1() AS UIDnew
FROM ObjectBase
INNER JOIN ObjectBase AS MainBase ON (MainBase.UID=ObjectBase.UIDBelongsTo AND MainBase.Type IN('person','extern'))
INNER JOIN Member AS Member ON (Member.UID=MainBase.UID)
INNER JOIN Links
ON (ObjectBase.UID = Links.UID AND Links.Type IN ('member','memberA') AND ObjectBase.Type NOT IN ('filter','list'))
LEFT JOIN (
SELECT Entry.UID, Entry.UIDBelongsTo FROM ObjectBase AS Entry INNER JOIN Links AS ELink
ON (Entry.UID=ELink.UID)
AND ELink.UIDTarget=? AND Entry.Type='entry'
) AS Entry ON (Entry.UIDBelongsTo=ObjectBase.UIDBelongsTo)
INNER JOIN Visible ON (Visible.UID=MainBase.UID)
WHERE Links.UIDTarget=? AND ObjectBase.Type IN (?) AND Visible.UIDUser=?`,
[emailUID, sourceUID, types, UUID2hex(req.session.user)], {
cast: ['json'],
log: false,
filter: Object.keys(filter).length ?
(row) => (matchObject({ ...row, Type: row.Type === 'entry' ? 'person' : row.Type }, filter)) : null,
group: (result, current) => {
const index = result.findIndex(el => el.UIDBelongsTo.equals(current.UIDBelongsTo));
if (index >= 0) {
return result;
}
return [...result, current];
}
});
let toBeAdded = all.filter(o => o.UIDEntry === null);
if (toBeAdded.length) {
await query(`INSERT INTO ObjectBase (UID,Type,UIDBelongsTo,Title,Data) VALUES (?,'entry',?,?,?)`,
toBeAdded.map(o => ([o.UIDnew, o.UID, o.Title, JSON.stringify({ status: addStatus, address: null })])), { batch: true });
await query(`INSERT IGNORE INTO Links (UID,Type,UIDTarget) VALUES (?,'memberA',?)`,
toBeAdded.map(o => [o.UIDnew, emailUID]), { batch: true });
addUpdateEntry(emailUID, { reloadList: true });
}
res.json({ success: true });
} catch (e) {
errorLoggerUpdate(e);
res.status(500).json({ success: false, message: 'Internal server error' });
}
};
/**
* Check if user is email admin
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const checkEmailAdmin = async (req, res) => {
try {
const admin = await isListAdmin(req, req.params.UID);
res.json({ success: true, result: admin });
} catch (e) {
errorLoggerRead(e);
res.status(500).json({ success: false, message: 'Internal server error' });
}
};
/**
* Share email (delegate to list share function)
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const shareEmail = (req, res) => putShare(req, res, 'email');
/**
* Delete email share (delegate to list share function)
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const deleteEmailShare = (req, res) => deleteShare(req, res, 'email');
/**
* Get all email shares (delegate to list share function)
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const getAllEmailShares = (req, res) => getSharesAll(req, res, 'email');
/**
* Get email shares for specific list (delegate to list share function)
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const getEmailShares = (req, res) => getShares(req, res, 'email');
/**
* Get shared email data (delegate to list shared function)
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const getSharedEmailData = async (req, res) => {
try {
// if we want the data paginated- the user has supplied the __page parameter
if (!req.query.__page) {
// normal api request
const result = await getListing(req);
res.json({ success: true, result: result });
return;
}
// paginated api request
res.json(await paginateList(req, getShared));
} catch (e) {
errorLoggerRead(e);
res.status(500).json({ success: false, message: 'Internal server error' });
}
};
/**
* Get email share details (delegate to list share function)
* @param {Object} req - Express request object
* @param {Object} res - Express response object
*/
export const getEmailShare = getShare;