Source: tree/treeQueue/treeAdd.functionActions.js

// @ts-check
/**
 * @import {treeAction} from './../../types.js'
 */
import { query, transaction, HEX2uuid } from '@commtool/sql-query'
import { personRebuildAccess } from '../rebuildList.js'
import { requalify } from '../../Router/job/utilities.js'
import { errorLoggerUpdate } from '../../utils/requestLogger.js'

/**
 * Handles the `function` add action.
 *
 * Fired when a function template is created or modified with respect to its
 * qualification requirements. Re-qualifies all jobs based on this template.
 *
 * @param {treeAction} action
 * @returns {Promise<void>}
 */
export const addFunctionAction = async (action) => {
    try {
        requalify(HEX2uuid(action.UIDroot), action.UIDObjectID)
    } catch (e) {
        errorLoggerUpdate(e || new Error('treeAdd.functionActions.addFunctionAction: Unknown error occurred'))
    }
}

/**
 * Handles the `functionV` add action.
 *
 * Fired when a function template is modified with respect to its visibility or
 * changeability requirements. Deletes and rebuilds all visibility/changeability
 * filter entries for every job linked to this function template, then refreshes
 * the holding person's access.
 *
 * @param {treeAction} action
 * @returns {Promise<void>}
 */
export const addFunctionVAction = async (action) => {
    try {
    const jobs = await query(
        `SELECT Jobs.UID AS UIDJob, Jobs.UIDBelongsTo AS UIDPerson, GLinks.UIDTarget AS UIDGroup
         FROM ObjectBase AS Jobs
         INNER JOIN Links AS FLinks ON (FLinks.UIDTarget=Jobs.UID AND FLinks.Type='function' AND Jobs.Type='job')
         INNER JOIN Links AS GLinks ON (GLinks.UID=Jobs.UID AND GLinks.Type='memberA')
         AND FLinks.UID=?`,
        [action.UIDObjectID],
    )

    for await (const job of jobs) {
        await transaction(
            async (connection) => {
                // delete all visibility and changeability filters for this job
                await connection.query(
                    `DELETE ObjectBase,Links
                     FROM ObjectBase
                     INNER JOIN Links ON (ObjectBase.UID=Links.UID AND ObjectBase.Type IN ('visible','changeable') AND Links.Type='list')
                     WHERE Links.UIDTarget=?`,
                    [job.UIDJob],
                )

                const functionTemplate = await connection.query(
                    `SELECT ObjectBase.Data FROM ObjectBase WHERE UID=?`,
                    [action.UIDObjectID],
                    { cast: ['json'] },
                )
                const functionData = functionTemplate[0].Data

                if (functionTemplate.length > 0 && Object.keys(functionData.access).length > 0) {
                    // get the groups from the hierarchy of this job given by the access key
                    const hGroups = await connection.query(
                        `SELECT ObjectBase.UID,
                                JSON_VALUE(Member.Data,'$.hierarchie') AS Hierarchie,
                                JSON_VALUE(Member.Data,'$.gender')     AS Gender,
                                ObjectBase.Title
                         FROM ObjectBase
                         INNER JOIN Member ON (Member.UID=ObjectBase.UID)
                         INNER JOIN Links  ON (Links.UIDTarget=ObjectBase.UID)
                         WHERE (Links.UID=? OR ObjectBase.UID=?)
                           AND ObjectBase.Type='group'
                           AND JSON_VALUE(Member.Data,'$.hierarchie') IN (?)
                         GROUP BY ObjectBase.UID`,
                        [job.UIDGroup, job.UIDGroup, Object.keys(functionData.access)],
                    )

                    // add a visibility filter for each matching hierarchie group
                    if (hGroups.length > 0) {
                        for (const hGroup of hGroups) {
                            // add only filters to combined groups; skip if a combined group
                            // for the same hierarchie already exists
                            if (hGroup.Gender === 'C' || !hGroups.find(hg =>
                                hg.Hierarchie === hGroup.Hierarchie && hg.Gender === 'C',
                            )) {
                                const [{ UID: filterUID }] = await query(`SELECT UIDV1() AS UID`, [])
                                await connection.query(
                                    `INSERT INTO ObjectBase
                                         (UID, Type, UIDBelongsTo, Title, Display, SortName, FullTextIndex, dindex, Data)
                                     VALUES (?, 'visible', ?, ?, ?, 'visible', '', 0, ?)`,
                                    [
                                        filterUID,
                                        hGroup.UID,
                                        functionData.name,
                                        hGroup.Title,
                                        JSON.stringify(functionData.access[hGroup.Hierarchie]),
                                    ],
                                )
                                await connection.query(
                                    `INSERT IGNORE INTO Links (UID, Type, UIDTarget) VALUES (?, 'list', ?)`,
                                    [filterUID, job.UIDJob],
                                )
                            }
                        }
                    }

                    // add changeability filter
                    if (functionData.writeAccess) {
                        const [{ UID: filterUID }] = await query(`SELECT UIDV1() AS UID`, [])
                        await connection.query(
                            `INSERT INTO ObjectBase
                                 (UID, Type, UIDBelongsTo, Title, Display, SortName, FullTextIndex, dindex, Data)
                             VALUES (?, 'changeable', ?, ?, ?, 'changeable', '', 0, ?)`,
                            [
                                filterUID,
                                job.UIDGroup,
                                functionData.name,
                                '',
                                JSON.stringify(functionData.writeAccess),
                            ],
                        )
                        await connection.query(
                            `INSERT IGNORE INTO Links (UID, Type, UIDTarget) VALUES (?, 'list', ?)`,
                            [filterUID, job.UIDJob],
                        )
                    }
                }
            },
            {
                beforeTransaction: async (connection) =>
                    await connection.query(`SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;`),
            },
        )
        await personRebuildAccess(job.UIDPerson)
    }
    } catch (e) {
        errorLoggerUpdate(e || new Error('treeAdd.functionActions.addFunctionVAction: Unknown error occurred'))
    }
}