// @ts-check
/**
* @import {ExpressRequestAuthorized} from '../../types.js'
*/
import {query,pool,UUID2hex,HEX2uuid} from '@commtool/sql-query'
import {renderObject} from '../../utils/renderTemplates.js'
import { Templates } from '../../utils/compileTemplates.js';
import {getUID} from '../../utils/UUIDs.js'
import {addUpdateEntry, addUpdateList} from '../../server.ws.js'
import { addVisibility, deleteVisibility, rebuildListVisibility } from '../../utils/listVisibilty.js';
import { isObjectAdmin, isListAdmin } from '../../utils/authChecks.js';
import {requestUpdateLogger, readLogger, errorLoggerRead, errorLoggerUpdate} from '../../utils/requestLogger.js'
import { publishEvent } from '../../utils/events.js';
/**
* Insert a new list or dlist
* @param {ExpressRequestAuthorized} req
* @param {string} ownerUID
* @param {'list'|'dlist'} type
* @returns {Promise<{success:boolean,result?:any,message?:string}>}
*/
export const insertList=async (req,ownerUID,type)=>
{
try {
const UID=await getUID(req)
let memberUID=UUID2hex(req.session.user)
if(req.query.user )
{
memberUID=UUID2hex(req.query.user)
}
const template= Templates[req.session.root][type]
const object=await renderObject(template,req.body,req)
let resOwner=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 IN ('group','event')`,[ownerUID],{cast:['UUID','json']})
if(resOwner.length===0)
{
resOwner=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'`,
[UUID2hex(req.session.root)],
{cast:['UUID','json']})
}
const owner=resOwner[0]
const [list] = await query(`SELECT Data,dindex FROM ObjectBase WHERE UID=? `,[UID])
if(!list)
{
await query(`
INSERT INTO ObjectBase (UID,Type,UIDBelongsTo,Title, dindex)
VALUES (?,?,?,?,?)
`,
[object.UID,type,object.UID,object.Title,object.dindex])
await query(`
INSERT INTO Member (UID,Display,SortName, FullTextIndex, Data)
VALUES (?,?,?,?,?)
`,
[object.UID,object.Display,object.SortIndex,object.FullTextIndex,JSON.stringify({...req.body,visibility:undefined})])
await query(`INSERT IGNORE INTO Links (UID,Type,UIDTarget) VALUES (?,?,?)`,
[
[object.UID,'memberA',ownerUID],
[object.UID,'member',memberUID]
],
{batch:true}
)
await query(`INSERT INTO Visible (UID,UIDUser,Type) VALUES(?,?,'admin')`,[UID,memberUID])
if(!req.query.private)
addVisibility(req,UID,owner)
}
else
{
if(!await isListAdmin(req,UID))
{
return {message: 'user not authorized', success: false}
}
await query( `UPDATE ObjectBase,Member SET
ObjectBase.Title=?,Member.Display=?,Member.SortName=?,Member.FullTextIndex=?,ObjectBase.dindex=?,Member.Data=?
WHERE ObjectBase.UID=? AND Member.UID=ObjectBase.UID`,
[object.Title,object.Display,object.SortIndex,object.FullTextIndex,object.dindex,JSON.stringify(req.body),UID])
const oldOwner= await query(`SELECT ObjectBase.UID, ObjectBase.Type FROM
ObjectBase INNER JOIN Links ON (ObjectBase.UID = Links.UIDTarget AND Links.Type='memberA')
WHERE ObjectBase.Type IN ('person','group') AND Links.UID=? `,[UID],{cast:['json','UUID']})
if(oldOwner.length===1 && oldOwner[0].UID!==owner.UID)
{
if(!await isListAdmin(req,UID))
{
return {message: 'user not authorized for ownership update', success: false}
}
await query(`UPDATE Links SET UIDTarget=? WHERE UID=? AND Type='memberA'`,[ownerUID,UID])
await deleteVisibility(UID)
addVisibility(req,UID,owner)
}
const oldMember= await query(`SELECT ObjectBase.UID, ObjectBase.Type FROM
ObjectBase INNER JOIN Links ON (ObjectBase.UID = Links.UIDTarget AND Links.Type='member')
WHERE ObjectBase.Type IN ('person','group') AND Links.UID=? `,[UID],{cast:['json','UUID']})
const resMember=await query (`SELECT Member.UID, Member.Display, Member.Data, ObjectBase.Title
FROM ObjectBase
INNER JOIN Member ON (ObjectBase.UIDBelongsTo = Member.UID)
WHERE ObjectBase.UID=?`,[memberUID],{cast:['json','UUID']})
const member=resMember[0]
if(oldMember.length===1 && oldMember[0].UID!==member.UID)
{
if(!await isListAdmin(req,UID))
{
return {message: 'user not authorized for ownership update', success: false}
}
await query(`UPDATE Links SET UIDTarget=? WHERE UID=? AND Type='member'`,[memberUID,UID])
rebuildListVisibility(req,UID)
}
object.admin=await isListAdmin(req,UID)
object.writeable=await isObjectAdmin(req,UID)
addUpdateEntry(UID,{Data:{...object,Data:req.body,UID: HEX2uuid(object.UID),owner, member}})
}
return {success: true,result:{...object,Data: {...req.body,visibility:undefined},UID: HEX2uuid(object.UID)}}
}
catch(e)
{
errorLoggerUpdate(e)
}
}
/**
* Update existing list/dlist
* @param {ExpressRequestAuthorized} req
* @param {string} UID
* @param {'list'|'dlist'} type
* @param {boolean} [admin=false]
* @returns {Promise<{success:boolean,message?:string}>}
*/
export const updateList=async (req,UID,type,admin=false)=>
{
try {
let sqlType= `AND ObjectBase.Type='${type}'`
if(req.query.type==='list_dlist')
{
sqlType= `AND ObjectBase.Type IN('list','dlist')`
}
const [list] = await query(`SELECT Member.Data,ObjectBase.dindex FROM ObjectBase
INNER JOIN Member ON (Member.UID=ObjectBase.UID)
WHERE ObjectBase.UID=? ${sqlType} `,[UID],{cast:['json']})
if(!list)
{
return {success: false, message:'List not found'}
}
const Data={...list.Data,...req.body}
const template= Templates[req.session.root][type]
const object=await renderObject(template,Data,req)
await query( `UPDATE ObjectBase,Member SET
ObjectBase.Title=?,Member.Display=?,Member.SortName=?,Member.FullTextIndex=?,ObjectBase.dindex=?,Member.Data=?
WHERE ObjectBase.UID=? AND Member.UID=ObjectBase.UID`,
[object.Title,object.Display,object.SortIndex,object.FullTextIndex,object.dindex,JSON.stringify(Data),UID])
const resMember=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 member= resMember[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='memberA')
WHERE Links.UID=? AND ObjectBase.Type IN('group','event')`,[UID],{cast:['UUID','json']})
const owner=resOwner[0]
object.admin=await isListAdmin(req,UID)
object.writeable=await isObjectAdmin(req,UID)
addUpdateEntry(UID,{Data:{...object,Data:Data,UID: HEX2uuid(object.UID),owner, member}})
// addUpdateList(UID)
return {success: true }
}
catch(e)
{
errorLoggerUpdate(e)
}
}
/**
* Get list/dlist details
* @param {ExpressRequestAuthorized} req
* @param {string} UID
* @param {'list'|'dlist'} type
* @returns {Promise<{success:boolean,result?:any,message?:string}>}
*/
export const getList=async(req,UID,type)=>
{
let sqlType= `AND ObjectBase.Type='${type}'`
if(req.query.type==='list_dlist')
{
sqlType= `AND ObjectBase.Type IN('list','dlist')`
}
const resList=await query(`SELECT ObjectBase.UID,Member.Data,Member.Display,ObjectBase.dindex
FROM ObjectBase
INNER JOIN Member ON (Member.UID=ObjectBase.UID)
WHERE ObjectBase.UID=? ${sqlType}`,[UID,UUID2hex(req.session.user)],{cast:['UUID','json']})
if(resList && resList.length===1)
{
const list=resList[0]
const resMember=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 member= resMember[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='memberA')
WHERE Links.UID=? AND ObjectBase.Type IN ('group','event')`,[UID],{cast:['UUID','json']})
const owner= resOwner[0]
list.admin=await isListAdmin(req,UID)
list.writeable=await isObjectAdmin(req,UID)
return{success:true,result:{...list,owner:owner, member:member}}
}
else
{
return {success:false,message: type+' not found or user not authorized'}
}
}
/**
* Delete a list/dlist
* @param {ExpressRequestAuthorized} req
* @param {'list'|'dlist'} type
* @returns {Promise<{success:boolean,message?:string}>}
*/
export const deleteList=async(req,type)=>
{
try {
const UID=UUID2hex(req.params.UID)
let sqlType= `AND ObjectBase.Type='${type}'`
if(req.query.type==='list_dlist')
{
sqlType= `AND ObjectBase.Type IN('list','dlist')`
}
const lres=await query(`SELECT ObjectBase.UIDBelongsTo,ObjectBase.UID FROM ObjectBase
WHERE ObjectBase.UID =? ${sqlType}`,[UID])
if(lres.length===0)
{
return({success:false,message:type+' not found'})
}
const list=lres[0]
const hasLinks = await query(`SELECT Links.UID,ObjectBase.Display FROM Links
INNER JOIN ObjectBase ON (Links.UID=ObjectBase.UID)
WHERE Links.Type IN ('filter','member','memberA') AND Links.UIDTarget=? `,[UID])
if(hasLinks.length && !req.query.force)
{
return({success:false,message:'has still members or active filters'})
}
else
{
if(list)
{
query(`DELETE ObjectBase,Member FROM ObjectBase LEFT JOIN Member ON (Member.UID=ObjectBase.UID) WHERE ObjectBase.UID=? ${sqlType}`,[list.UID])
query(`DELETE Links FROM Links WHERE UID=? AND Type IN ('memberA','member')`,[UID])
if(req.query.force)
{
query(`DELETE ObjectBase,Links FROM ObjectBase,Links
WHERE ObjectBase.Type IN ('entry','guest','filter')
AND Links.UID=ObjectBase.UID AND Links.Type IN ('member','memberA','filter')
AND Links.UIDTarget=?`,[UID] )
}
deleteVisibility(UID)
const actions= await query(`SELECT ObjectBase.UID,ObjectBase.Data, ObjectBase.Display, Links.UID AS UIDtemplate
FROM ObjectBase
INNER JOIN Links ON (Links.UIDTarget=ObjectBase.UID AND Links.Type='action')
WHERE ObjectBase.UIDBelongsTo=? AND ObjectBase.Type='action'`, [list.UID], { cast: ['json', 'UUID'] });
if(actions.length>0)
{
await query(`DELETE ObjectBase,Links
FROM ObjectBase
LEFT JOIN Links
ON (Links.UID=ObjectBase.UID AND Links.Type='action')
WHERE ObjectBase.UID IN (?) AND ObjectBase.Type='action'`, [actions.map(a => a.UID)]);
for(const action of actions)
{
publishEvent(`/remove/actionT/action/${HEX2uuid(action.UIDtemplate)}`, {
organization: req.session.root,
data: HEX2uuid(UID)
});
}
}
return {success:true}
}
else
{
return {success:false, message:'list not found'}
}
}
}
catch(e)
{
errorLoggerUpdate(e)
}
}