Source: Router/job/insert.js

// @ts-check
/**
 * @import {ExpressRequestAuthorized, ExpressResponse} from '../../types.js'
 */
import {query, transaction, UUID2hex, HEX2uuid} from '@commtool/sql-query'
import { parseTimestampToSeconds } from '../../utils/parseTimestamp.js'
import { queueAdd } from '../../tree/treeQueue/treeQueue.js'
import { isObjectAdmin, isObjectVisible } from '../../utils/authChecks.js'
import { errorLoggerUpdate } from '../../utils/requestLogger.js'
import { Templates } from '../../utils/compileTemplates.js'
import { renderObject } from '../../utils/renderTemplates.js'
import { getUID, isValidUID } from '../../utils/UUIDs.js'
import { addUpdateList } from '../../server.ws.js'  
import { jobQualified } from './utilities.js'
import { publishEvent } from '../../utils/events.js'
import { publishGroupEvent } from '../person/personHelpers.js'

/**
 * Inserts or updates a job in the system.
 * 
 * This function handles the creation of a job for a member in a specific group with a specified function.
 * It performs several authorization checks and validations before proceeding with the insertion.
 * 
 * @async
 * @function insertOrUpdateJob
 * @param {Object} req - The HTTP request object
 * @param {Object} req.query - Query parameters
 * @param {number} [req.query.timestamp] - Optional timestamp for the job
 * @param {Object} req.params - URL parameters
 * @param {string} req.params.group - UUID of the group
 * @param {string} req.params.member - UUID of the member
 * @param {string} req.params.function - UUID of the function
 * @param {Object} req.body - Request body
 * @param {string} req.body.UID - UUID of the job to be created
 * @param {Object} req.session - Session information
 * @param {string} req.session.user - Current user's UUID
 * @param {string} req.session.root - Root UUID
 * @param {Object} res - The HTTP response object
 * 
 * @returns {Promise<void>} - Sends a JSON response with success status and result or error message
 * 
 * @throws {Error} - Logs errors through errorLoggerUpdate
 */
export const insertJob= async (req,res)=>
    {   
        try {
            const timestamp = parseTimestampToSeconds(req.query.timestamp ? String(req.query.timestamp) : undefined);
            if(!await isObjectAdmin(req,req.params.group))
            {
                res.status(300).json({success:false,message: 'user not authorized for this group'})
                return
            }
            if(!await isObjectVisible(req,req.params.member))
            {
                res.status(300).json({success:false,message: 'user not authorized for this person'})
                return
            }
            const groupUID=UUID2hex(req.params.group)
            const memberUID=UUID2hex(req.params.member)
            const functionUID=UUID2hex(req.params.function)
            const jobUID=await getUID(req)
            // avoid duplications
            const exists=await query(`SELECT ObjectBase.UID FROM 
                ObjectBase INNER JOIN Links AS GLink ON (GLink.UID=ObjectBase.UID AND GLink.Type='memberA' )
                INNER JOIN Links AS FLink ON (FLink.UIDTarget=ObjectBase.UID AND FLink.Type='function')
                WHERE GLink.UIDTarget=? AND FLink.UID=? AND ObjectBase.UIDBelongsTo=? AND ObjectBase.Type='job'
            `,[groupUID,functionUID,memberUID])
            if(exists.length)
            {
                res.json({success:false,message:'this job exists already for this person in this group'})
                return
            }       
            const jobs = await query(`SELECT Data FROM ObjectBase WHERE UID=? AND Type='job'`,[jobUID],{cast:['json']})
            if(jobs.length)
            {
                res.json({success:false,message:'a job with this UID already exists'})
                return
            }      
            const functionTemplates=await query(`SELECT Data FROM ObjectBase WHERE UID=?`,[functionUID],{cast:['json']})
            if(!functionTemplates.length)
            {
                res.status(300).json({success:false,message:'missing or unkown UIDfunction'})
            }
            else
            {
                const functionTemplate=functionTemplates[0]
                const functionData=functionTemplate.Data
                const members=await query(`SELECT Data FROM Member WHERE UID=? `,[memberUID],{cast:['json']})
                if(!members.length)
                {
                    res.status(300).json({success:false,message:'invalid member UID'})
                }
                else
                {
                    const member=members[0]
                    const [group]=await query(`SELECT Member.Data 
                        FROM ObjectBase
                        INNER JOIN Member ON (Member.UID=ObjectBase.UID) 
                        WHERE ObjectBase.UID=? AND ObjectBase.Type='group'`,[groupUID],{cast:['json']})
                    if(!group)
                    {
                        res.status(300).json({success:false,message:'invalid group UID'})
                    }
                    else
                    {
    
                        const qualified=await jobQualified(memberUID,functionData.qualification,timestamp)
                        const template= Templates[req.session.root].job
                        const objectData= {
                            group:{...group.Data,UID:req.params.group},
                            function:{...functionData,functionUID:req.params.function},
                            member:member.Data,
                            UID:req.body.UID,
                            qualified:qualified
                        }
                        const object=await renderObject(template,objectData,req)
                        // delete memberData
                        objectData.member=undefined                
                        
                        if(!isValidUID(req.body.UID))
                        {
                            res.res.status(300).json({success:false,message:'invalid UID format in body.UID'})
                        }
                        await transaction(async (connection)=>
                        {
                            await query(`
                                INSERT INTO ObjectBase (UID,UIDuser,Type,UIDBelongsTo,Title,SortName,dindex,hierarchie,stage,gender,Data)
                                VALUES (?,?,'job',?,?,?,?,?,?,?,?)
                                `,
                                [object.UID,UUID2hex(req.session.user),memberUID,object.Title,object.SortBase,qualified,object.hierarchie,object.stage,object.gender,JSON.stringify(objectData)
    
                                ])
                    
                            // Link the job as memberA to the group 
                            await connection.query(
                                `INSERT IGNORE INTO Links(UID, Type, UIDTarget, UIDuser) VALUES (?,'memberA',?,?)`,
                                [object.UID,groupUID, UUID2hex(req.session.user)])
    
                            // Link the job to his function template
                            await connection.query(`
                                INSERT IGNORE INTO Links(UID, Type, UIDTarget,UIDuser) VALUES (?,'function',?,?)`,
                                [functionUID,object.UID,UUID2hex(req.session.user)]
                            )
                                    // make sure the job is vsible to the curent user
                            await connection.query(`INSERT INTO Visible (UID,Type,UIDUser) VALUES(?,'changeable',?)`,
                                [object.UID,UUID2hex(req.session.user)]
                            )
                        
                        },{backDate:timestamp})
                        // now get the other stuff performed inside the update loop
                        queueAdd(UUID2hex(req.session.root),UUID2hex(req.session.user),'job',object.UID,jobUID,null,groupUID,timestamp)
                        addUpdateList(memberUID)
                        res.json({success:true,result:{...object,UID: HEX2uuid(object.UID)}})
                        
                    }
                }
            }
        }
        catch(e)
        {
            errorLoggerUpdate(e)
        }
    }