// @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)
}
}