// @ts-check
/**
* @import {ExpressRequestAuthorized, ExpressResponse} from '../../types.js'
*/
import {query,UUID2hex,HEX2uuid} from '@commtool/sql-query'
import { parseTimestampToSeconds, parseTimestampToSecondsOrDefault } from '../../utils/parseTimestamp.js'
import { errorLoggerRead } from '../../utils/requestLogger.js';
import { authorizeUser } from './utilities.js';
/**
* Handles GET request for a specific achievement.
*
* @async
* @function getAchievement
* @param {Object} req - Express request object
* @param {Object} req.params - Request parameters
* @param {string} req.params.UID - UID of the achievement to retrieve
* @param {Object} req.query - Query parameters
* @param {string} [req.query.timestamp] - Optional timestamp for point-in-time queries
* @param {Object} req.session - Session information
* @param {string} req.session.user - Current user's UID
* @param {Object} res - Express response object
* @returns {Promise<void>} - Sends JSON response with achievement data or error message
* @description Retrieves an achievement by UID, checking user permissions.
* If timestamp is provided, retrieves the achievement as it was at that time.
* Returns achievement details including template data and authorization status.
*/
export const getAchievement=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)
const result=await query(`SELECT ObjectBase.UID,ObjectBase.UIDBelongsTo,ObjectBase.Title,ObjectBase.Display,Member.Display AS DisplayMember,
Template.Display AS DisplayTemplate,
Member.Data AS MemberData,ObjectBase.Data AS BaseData , ALink.UIDTarget AS UIDTemplate, Template.Data AS TemplateData,
ObjectBase.validFrom
FROM ObjectBase ${asOf}
INNER JOIN Member ON (Member.UID=ObjectBase.UIDBelongsTo)
INNER JOIN Visible ON(Visible.UID=ObjectBase.UIDBelongsTo)
INNER JOIN Links AS ALink ON (ALink.UID=ObjectBase.UID AND ALink.Type='achievement')
INNER JOIN ObjectBase AS Template ON (Template.UID=ALink.UIDTarget AND Template.Type='achievementT')
WHERE ObjectBase.UID=? AND Visible.UIDUser=?`,
[UID,UUID2hex(req.session.user)],
{cast:['UUID','json'],log:false}
)
//console.log(sql)
if(result.length===0)
{
res.json({success:false,message: `achievement does not exist or is not accessible for this user`})
return
}
const achievement=result[0]
const filter= achievement.TemplateData.authorized
achievement.editAuthorized = await authorizeUser(req.session.user,filter)
res.json({success:true, result:achievement})
}
catch(e)
{
errorLoggerRead(e)
}
}
/**
* Retrieves a list of achievements for a person.
*
* @async
* @function listAchievementsPerson
* @param {Object} req - Express request object.
* @param {Object} req.query - Request query parameters.
* @param {number} [req.query.timestamp] - Optional timestamp for point-in-time query.
* @param {boolean} [req.query.unique] - If true, returns only the latest version of each achievement.
* @param {Object} req.params - Request path parameters.
* @param {string} req.params.UID - UID of the person whose achievements to list.
* @param {Object} req.session - User session object.
* @param {string} req.session.user - UID of the current user.
* @param {Object} res - Express response object.
* @returns {Promise<void>} - Returns a JSON response with success status and result array.
* @description Fetches achievements associated with a person, joining with template data.
* Can return achievements as of a specific point in time.
* Can filter to return only unique (latest) achievements.
* @throws {Error} - Logs any errors encountered during database operations.
*/
export const listAchievementsPerson =async (req,res)=>
{
try {
const timestamp = parseTimestampToSecondsOrDefault(req.query.timestamp, Date.now()/1000)
const asOf=timestamp ? `FOR SYSTEM_TIME AS OF FROM_UNIXTIME(${timestamp})` : ''
const result= await query(`SELECT
ObjectBase.UID ,template.UID AS UIDTemplate, ObjectBase.Title ,
UNIX_TIMESTAMP(ObjectBase.ValidFrom) *1000 AS date, UNIX_TIMESTAMP(ObjectBase.ValidUntil)*1000 AS ValidUntil,
IF(ObjectBase.dindex,(${timestamp}-UNIX_TIMESTAMP(ObjectBase.ValidFrom))/24/3600-JSON_VALUE(template.Data,'$.renewal'),NULL) AS expired,
ObjectBase.SortName, template.Display AS template ,ObjectBase.Data
FROM
ObjectBase ${asOf} AS ObjectBase
INNER JOIN Visible AS Visible ON (ObjectBase.UIDBelongsTo = Visible.UID )
INNER JOIN Links ${asOf} ON (Links.UID=ObjectBase.UID AND Links.Type='achievement')
INNER JOIN ObjectBase ${asOf} AS template ON (template.UID=Links.UIDTarget AND template.Type='achievementT')
WHERE
ObjectBase.UIDBelongsTo = ? AND ObjectBase.Type ='achievement' AND Visible.UIDUser = ?
ORDER BY
ObjectBase.SortName,JSON_VALUE(ObjectBase.Data,'$.date')`,
[UUID2hex(req.params.UID),UUID2hex(req.session.user)],
{cast:['UUID','json'], log:true})
const rresult= req.query.unique ? result.reduce((myResult,current)=>
{
const r=myResult.find(el=>(el.UID===current.UID && current.ValidUntil>el.ValidUntil))
if(r)
{
r.expired=current.expired
r.date=current.date
r.ValidUntil=current.ValidUntil
r.Data=current.Data
return myResult
}
else
{
return [...myResult,current]
}
},[])
: result
res.json({success:true,result:rresult})
}
catch(e)
{
errorLoggerRead(e)
}
}