Source: Router/achievement/delete.js

// @ts-check
/**
 * @import {ExpressRequestAuthorized, ExpressResponse} from '../../types.js'
 */
import {query,transaction,UUID2hex,HEX2uuid,HEX2base64} from '@commtool/sql-query'
import { parseTimestampToSeconds } from '../../utils/parseTimestamp.js'
import { queueAdd} from '../../tree/treeQueue/treeQueue.js';
import {addUpdateList} from '../../server.ws.js'
import { errorLoggerUpdate} from '../../utils/requestLogger.js'
import {authorizeUser} from './utilities.js'
import {isAdmin} from '../../utils/authChecks.js'
import { recreateJobsPerson } from '../job/utilities.js';
import { updateAchievements } from '../achievement/utilities.js';


/**
 * Delete an achievement from the database
 * 
 * @param {Object} req - Express request object
 * @param {Object} req.query - Query parameters
 * @param {string} req.query.timestamp - Optional timestamp for historical data (milliseconds since epoch)
 * @param {Object} req.params - Route parameters
 * @param {string} req.params.UID - UID of the achievement to delete
 * @param {Object} req.session - Session information
 * @param {string} req.session.user - Current user's UID
 * @param {string} req.session.root - Root UID
 * @param {Object} res - Express response object
 * @returns {Promise<Object>} JSON response with success status and optional error message
 * @throws {Error} Logs error to errorLoggerUpdate
 * 
 * @description
 * This function deletes an achievement from the database. It performs the following steps:
 * 1. Retrieves the achievement data using the provided UID
 * 2. Checks if the user is authorized to delete the achievement
 * 3. Deletes the achievement and related links from the database
 * 4. Updates the achievement queue and list membership
 * 5. Updates the client with the changes
 * 
 * Authorization is based on either template-defined filters or admin status.
 */
export const deleteAchievement=async (req,res)=>
{
    try {
        const timestamp = parseTimestampToSeconds(req.query.timestamp ? String(req.query.timestamp) : undefined)
        const asOf=timestamp ? `FOR SYSTEM_TIME AS OF FROM_UNIXTIME(${timestamp})` : ''
        const UID=UUID2hex(req.params.UID)
        // get achievemnt Data
        const [achievement]=await query(`SELECT ObjectBase.UID, ObjectBase.UIDBelongsTo AS user, Links.UIDTarget
            FROM ObjectBase ${asOf} INNER JOIN Links ${asOf} ON
            (Links.UID=ObjectBase.UID AND Links.Type ='achievement')
            WHERE ObjectBase.UID =? AND ObjectBase.Type='achievement'`,[UID])
        if(achievement)
        {
            // get the template data for this achievement
            const templates = await query (`SELECT ObjectBase.Data FROM ObjectBase ${asOf}
                            INNER JOIN Links ${asOf} ON (Links.UIDTarget=ObjectBase.UID AND Links.Type='achievement')
                            WHERE Links.UID=?`,[UID])
            let filter=null
            if(templates.length)
            {
                filter= JSON.parse(templates[0].Data).authorized
            }
            // check if user is authorized to delete this achievement
            const authorized = await authorizeUser(req.session.user,filter)
            if(!authorized && !await isAdmin(req.session))
            {
                res.status(300).json({success:false,message:'user not authorized to remove this achievement'})
                return
            }
            // delete achievement And Link maybe backdated by timestamp
            await transaction(async (connection)=>
            {
                // delete achievement And Link
                await connection.query(`DELETE ObjectBase,Links FROM ObjectBase INNER JOIN Links ON (Links.UID=ObjectBase.UID AND Links.Type='achievement') 
                        WHERE ObjectBase.UID =? AND ObjectBase.Type='achievement'`,
                        [UID])

                // update lists
                queueAdd(UUID2hex(req.session.root),UUID2hex(req.session.user),'listMember',achievement.user,achievement.user,null,achievement.user,timestamp)
                // client update
            

            },{
                backDate:timestamp,
                beforeTransaction:async (connection)=> await connection.query(`SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;`)
            })
            // recreate jobs for this person
            recreateJobsPerson(req,achievement.user)
            // update achievements in the person objects for right filtering
            updateAchievements(achievement.user)
            res.json({success:true})
            addUpdateList(achievement.user)
        }
        else
        {
            res.json({success:false, message:'achievement not found for this person'})
        }
    }
    catch(e)
    {
        errorLoggerUpdate(e)
    }
}