Source: Router/extraApi.js

// @ts-check
/**
 * @import {ExpressRequestAuthorized, ExpressResponse} from '../types.js'
 */
/**
 * @module extraApi
 * @description Main API router for the Commtool Members system
 *
 * This module provides the core REST API endpoints for managing:
 * - Organizations and hierarchical group structures
 * - Members, guests, and external contacts
 * - Offices, functions, and role assignments
 * - Qualifications, achievements, and training records
 * - Lists (static and dynamic) for member management
 * - Email communications and notifications
 * - User authentication and authorization
 * - File management and document storage
 * - System maintenance and analytics
 *
 * The API follows a hierarchical permission system where users can manage
 * entities within their organizational scope and permission level.
 *
 * @requires express - Web framework for routing and middleware
 * @requires @commtool/sql-query - Database query utilities
 * @requires @commtool/shared-auth - Authentication and authorization
 */

import express, { json } from 'express';
import {query,UUID2hex,HEX2uuid} from '@commtool/sql-query'
import { makeAuthCheck } from '@commtool/shared-auth';

import {configs, getConfig} from '../utils/compileTemplates.js'
import {requestUpdateLogger, loginLogger, errorLoggerRead,errorLoggerUpdate} from '../utils/requestLogger.js'
import { getSuperAdmin } from './orga/service.js'; // Add getSuperAdmin import

import { wsFakeUser } from '../server.ws.js';
import {checkAdmin,isAdmin, isAdminOrga, isBaseAdmin} from '../utils/authChecks.js'
import * as extraController from './extraApi/extraController.js';
import linkGraph from'./linkGraph.js';
import admins from './admins.js'
import group from './group.js'
import member from './person.js'
import guest from './guest.js'
import extern from './extern.js'
import functionTemplate from './functionTemplate.js'
import job from './job.js'
import {list,dlist} from './list.js'
import email from './email.js'
import filter from './filter.js';
import achievement from './achievement.js'
import achievementTemplate from './achievementTemplate.js'
import object from './object.js'
import persons from './persons.js'
import collections from './collections.js'
import SearchData from './SearchData.js'
import Value2Title from './Value2Title.js'
import filesApi from './files.js'
import userApi from './user.js'
import action from './action.js'
import orga from './orga.js'
import family from './family.js'
import maintenance from './maintenance.js'
import analisys from './analisys.js'
import actionTemplate from './actionTemplate.js'
import configApi from './apiConfigFile.js'
import languagesApi from './languageFile.js'

import _ from 'lodash'
import session from 'express-session';

// Import refactored utilities
import { checkRoot, setOrgaRoot, alternativeRoot } from '../utils/organizationUtils.js';
import { validateUserForOrganization, getUser } from '../utils/userUtils.js';

// Import controllers
import {
    generateUID,
    generateMultipleUIDs,
    getTimestamp,
    validateUser,
    checkIsAdmin,
    getQueueCount,
    getUsersWithVisibility,
    getUsersWithVisibilityData
} from './extraApi/extraController.js';



const api = express.Router({ caseSensitive: true });

export default api

const authCheckAdmin = (req, res, next) => {
    return checkAdmin(req, res, (err) => {
        if (err) {
            errorLoggerUpdate(new Error(`❌ authCheckAdmin failed: ${err.message}`));
        }
        next(err);
    });
}

// Debug wrapper for authCheckAdmin with bootstrap support
const authCheckAdminDebug = (req, res, next) => {
    console.log('🔍 authCheckAdmin called:', {
        method: req.method,
        url: req.url,
        headers: req.headers,
        user: req.user,
        session: req.session
    });
    
    return authCheckAdmin(req, res, (err) => {
        if (err) {
            console.error('❌ authCheckAdminBootstrap failed:', err);
        } else {
            console.log('✅ authCheckAdminBootstrap passed');
        }
        next(err);
    });
};

/**
 * @route GET /api/kpe20/UID
 * @group Utility API
 * @description Generate a single unique identifier (UID) for the system
 * @param {boolean} [base64] - Return UID in base64 format instead of UUID format
 * @example
 * GET /api/kpe20/UID
 * Response: {"UID": "UUID-12345678-1234-1234-1234-123456789012"}
 *
 * GET /api/kpe20/UID?base64=true
 * Response: {"UID": "base64-encoded-string"}
 * @returns {Object} Response object
 * @property {string} .UID - The generated unique identifier
 */
// @ts-ignore
api.get('/UID', /** @type {any} */ (generateUID))

/**
 * @route GET /api/kpe20/UID/:count
 * @group Utility API
 * @description Generate multiple unique identifiers (UIDs) for the system
 * @param {number} count - Number of UIDs to generate (1-100)
 * @returns {string[]} Array of generated UUIDs
 * @example
 * GET /api/kpe20/UID/5
 * Response: ["UUID-12345678-1234-1234-1234-123456789012", "UUID-87654321-4321-4321-4321-210987654321", ...]
 */
// @ts-ignore
api.get('/UID/:count', /** @type {any} */ (generateMultipleUIDs))

/**
 * @route GET /api/kpe20/timestamp
 * @group Utility API
 * @description Get current server timestamp
 * @example
 * GET /api/kpe20/timestamp
 * Response: {"timestamp": 1703123456789}
 * @returns {Object} Response object
 * @property {number} .timestamp - Unix timestamp in milliseconds
 */
// @ts-ignore
api.get('/timestamp', /** @type {any} */ (getTimestamp))

/**
 * @route POST /api/kpe20/validate-user
 * @group Authentication API
 * @description Validate user access for an organization and populate cache
 * Used by other APIs to verify user permissions and cache user data
 * @param {string} userUID - UUID of the user to validate
 * @param {string} orgaUID - UUID of the organization
 * @example
 * POST /api/kpe20/validate-user
 * Body: {"userUID": "UUID-12345678-1234-1234-1234-123456789012", "orgaUID": "UUID-87654321-4321-4321-4321-210987654321"}
 * @returns {Object} Response object
 * @property {boolean} .success - Whether the request was successful
 * @property {boolean} .valid - Whether the user is valid for the organization
 * @property {boolean} .isAdmin - Whether the user has admin privileges
 * @property {object} .userData - Cached user information
 * @property {string} .userUID - Confirmed user UUID
 * @property {boolean} .cached - Whether data was cached
 */
// @ts-ignore
api.post('/validate-user', /** @type {any} */ (validateUser));

// change the root organisation for the next api calls
/**
 * @route GET /api/kpe20/:app/:UIDroot
 * @group Organization API
 * @description Set the root organization context for subsequent API calls
 * This establishes the organizational scope for all following operations
 * @param {string} app - Application identifier (must match configured apps)
 * @param {string} UIDroot - UUID of the root organization



 * @example
 * GET /api/kpe20/members/UUID-12345678-1234-1234-1234-123456789012
 * Response: {"success": true, "result": {...organization config...}}
  * @returns {Object} Response object
 * @property {boolean} .success - Whether the root was successfully set
 * @property {object} .result - Organization configuration data
 */
// @ts-ignore
api.get(`/:app(${process.env.apps})/:UIDroot`,loginLogger,async (req,res,next)=>
{
    try
    {   
        if(!req.params.UIDroot?.match(/^UUID-[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/))
        {
            
            const {user,config}=await alternativeRoot(req,res)
             // Always wait for session to save before responding
            await new Promise(resolve => /** @type {any} */ (req.session).save(resolve));
  
            if(config)
                return  res.json({success:true,result:config})
            else
                return res.status(400).json({success:false,message:'no valid orga root found'})     
        }
        const {user,config}=await setOrgaRoot(req.params.UIDroot,req)
        if(user !== false)
            res.status(200).json({success:true,result:config})
        else
            res.status(400).json({success:false,message:'user not authorized'})
    }
    catch(e)
    {
        errorLoggerRead(e)
    }

})

// @ts-ignore
api.get('/isAdmin', checkRoot, checkIsAdmin)

/**
 * @route GET /api/kpe20/queue
 * @group System API
 * @description Get the count of pending items in the processing queue
 * Requires organization root to be set first
 * @example
 * GET /api/kpe20/queue
 * Response: {"result": 5, "success": true}
 * @returns {Object} Response object
 * @property {number} .result - Number of items in the queue
 * @property {boolean} .success - Whether the request was successful
 */
// @ts-ignore
api.get('/queue', checkRoot, getQueueCount)

/**
 * get all users with a given visibility for a given object
 * @route GET /api/kpe20/:vtype/:UID
 * @group Permissions API
 * @description Get users who have specific visibility permissions for an entity
 * @param {string} vtype - Visibility type: 'visible', 'changeable', or 'admin'
 * @param {string} UID - UUID of the entity to check permissions for
 * @example
 * GET /api/kpe20/visible/UUID-12345678-1234-1234-1234-123456789012
 * Response: {"success": true, "result": ["UUID-user1", "UUID-user2"]}
 * @returns {Object} Response object
 * @property {boolean} .success - Whether the request was successful
 * @property {string[]} .result - Array of user UUIDs with the specified permission level
 */
// @ts-ignore
api.get('/:vtype(visible|changeable|admin)/:UID', extraController.getUsersWithVisibility)

/**
 *  get all users with a given visibility for a given object with their user Data
 * @route GET /api/kpe20/:vtype/:UID/Data
 * @group Permissions API
 * @description Get users and their data who have specific visibility permissions for an entity
 * @param {string} vtype - Visibility type: 'visible', 'changeable', or 'admin'
 * @param {string} UID - UUID of the entity to check permissions for
 * @example
 * GET /api/kpe20/admin/UUID-12345678-1234-1234-1234-123456789012/Data
 * Response: {"success": true, "result": [{"UIDuser": "UUID-user1", "Data": {...}}]}
 * @returns {Object} Response object
 * @property {boolean} .success - Whether the request was successful
 * @property {object[]} .result - Array of objects with user UUIDs and their data
 */
// @ts-ignore
api.get('/:vtype(visible|changeable|admin)/:UID/Data',  extraController.getUsersWithVisibilityData)


/**
 * @route /api/kpe20/admins/*
 * @group Admin API
 * @description Administrative functions and system management
 * Requires organization root context and admin privileges
 */
// @ts-ignore
api.use('/admins',checkRoot,checkAdmin,admins)


/**
 * @route /api/kpe20/graph/*
 * @group Graph API
 * @description Graph and relationship visualization endpoints
 */
// @ts-ignore
api.use('/graph',linkGraph)

// routers for members api
/**
 * @route /api/kpe20/job/*
 * @group Job API
 * @description Job and task management endpoints
 * Requires organization root context to be set
 */
// @ts-ignore
api.use('/job',checkRoot,job)

/**
 * @route /api/kpe20/group/*
 * @group Group API
 * @description Group management endpoints for hierarchical organization structure
 * Requires organization root context to be set
 * Supports creating, reading, updating groups with gender/age restrictions
 */
// @ts-ignore
api.use('/group',checkRoot,group)

/**
 * @route /api/kpe20/list/*
 * @group List API
 * @description Static list management endpoints
 * Requires organization root context to be set
 */
// @ts-ignore
api.use('/list',checkRoot,list)

/**
 * @route /api/kpe20/orga/*
 * @group Organization API
 * @description Organization management and configuration endpoints
 */
// @ts-ignore
api.use('/orga',orga)

/**
 * @route /api/kpe20/dlist/*
 * @group Dynamic List API
 * @description Dynamic list management with automated filtering
 * Requires organization root context to be set
 */
// @ts-ignore
api.use('/dlist',checkRoot,dlist)

/**
 * @route /api/kpe20/member/*
 * @group Member API
 * @description Member management endpoints (alias for person API)
 * Requires organization root context to be set
 * Supports CRUD operations for members with family relationships
 */
// @ts-ignore
api.use('/member',checkRoot,member)  // is an alias to person

/**
 * @route /api/kpe20/email/*
 * @group Email API
 * @description Email communication and bulk mailing endpoints
 * Requires organization root context to be set
 */
// @ts-ignore
api.use('/email',checkRoot,email)

/**
 * @route /api/kpe20/person/*
 * @group Person API
 * @description Person/member management endpoints
 * Requires organization root context to be set
 * Core API for managing people, their contact info, and memberships
 */
// @ts-ignore
api.use('/person',checkRoot,member)
//api.use('/memberList',checkRoot,memberList)
/**
 * @route /api/kpe20/guest/*
 * @group Guest API
 * @description Guest member management endpoints
 * Requires organization root context to be set
 * For temporary or external members with limited access
 */
// @ts-ignore
api.use('/guest',checkRoot,guest)

/**
 * @route /api/kpe20/filter/*
 * @group Filter API
 * @description Data filtering and search endpoints
 * Requires organization root context to be set
 */
// @ts-ignore
api.use('/filter',checkRoot,filter)

/**
 * @route /api/kpe20/extern/*
 * @group External API
 * @description External contact management endpoints
 * Requires organization root context to be set
 * For managing contacts outside the main membership structure
 */
// @ts-ignore
api.use('/extern',checkRoot,extern)

/**
 * @route /api/kpe20/achievement/*
 * @group Achievement API
 * @description Qualification and achievement tracking endpoints
 * Requires organization root context to be set
 * Manages certifications, training records, and qualifications
 */
// @ts-ignore
api.use('/achievement',checkRoot,achievement)

/**
 * @route /api/kpe20/function/*
 * @group Function API
 * @description Office and function management endpoints
 * Requires organization root context to be set
 * Manages roles, positions, and responsibilities within groups
 */
// @ts-ignore
api.use('/function',checkRoot,functionTemplate)

/**
 * @route /api/kpe20/achievementTemplate/*
 * @group Achievement Template API
 * @description Achievement template management endpoints
 * Requires organization root context to be set
 * Defines standard qualifications and training requirements
 */
// @ts-ignore
api.use('/achievementTemplate',checkRoot,achievementTemplate)
// ...existing code after the achievementTemplate route...

/**
 * @route /api/kpe20/actionTemplate/*
 * @group Action Template API
 * @description Action template management endpoints
 * Requires organization root context to be set
 * Defines standard actions and workflow templates
 */
// @ts-ignore
api.use('/actionTemplate',  actionTemplate)

/**
 * @route /api/kpe20/persons/*
 * @group Persons API
 * @description Multiple person management and bulk operations endpoints
 * Requires organization root context to be set
 * For operations on multiple people simultaneously
 */
// @ts-ignore
api.use('/persons', checkRoot, persons)

/**
 * @route /api/kpe20/object/*
 * @group Object API
 * @description Generic object management endpoints
 * Requires organization root context to be set
 * For managing various system objects and entities
 */
// @ts-ignore
api.use('/object', checkRoot, object)

/**
 * @route /api/kpe20/collections/*
 * @group Collections API
 * @description Data collections and aggregation endpoints
 * Requires organization root context to be set
 * For managing grouped data and collections
 */
// @ts-ignore
api.use('/collections', checkRoot, collections)

/**
 * @route /api/kpe20/search/*
 * @group Search API
 * @description Data search and discovery endpoints
 * Requires organization root context to be set
 * For searching across multiple data types
 */
// @ts-ignore
api.use('/SearchData', checkRoot, SearchData)

/**
 * @route /api/kpe20/value2title/*
 * @group Value Conversion API
 * @description Value to title conversion endpoints
 * Requires organization root context to be set
 * For converting internal values to human-readable titles
 */
// @ts-ignore
api.use('/Value2Title', checkRoot, Value2Title)

/**
 * @route /api/kpe20/files/*
 * @group Files API
 * @description File management and storage endpoints
 * Requires organization root context to be set
 * For uploading, downloading, and managing files
 */
// @ts-ignore
api.use('/files', checkRoot, filesApi)

/**
 * @route /api/kpe20/user/*
 * @group User API
 * @description User account management endpoints
 * Requires organization root context to be set
 * For managing user accounts and preferences
 */
// @ts-ignore
api.use('/user', checkRoot, userApi)

/**
 * @route /api/kpe20/action/*
 * @group Action API
 * @description Action and workflow management endpoints
 * Requires organization root context to be set
 * For managing actions and workflow instances
 */
// @ts-ignore
api.use('/action', checkRoot, action)

/**
 * @route /api/kpe20/family/*
 * @group Family API
 * @description Family relationship management endpoints
 * Requires organization root context to be set
 * For managing family relationships between members
 */
// @ts-ignore
api.use('/family', checkRoot, family)

/**
 * @route /api/kpe20/maintenance/*
 * @group Maintenance API
 * @description System maintenance and administration endpoints
 * Requires admin privileges for system maintenance tasks
 */
// @ts-ignore
api.use('/maintenance', checkRoot, authCheckAdminDebug, maintenance)

/**
 * @route /api/kpe20/analysis/*
 * @group Analysis API
 * @description Data analysis and reporting endpoints
 * Requires organization root context to be set
 * For generating reports and analytics
 */
// @ts-ignore
api.use('/analysis', checkRoot, analisys)

/**
 * @route /api/kpe20/config/*
 * @group Configuration API
 * @description System configuration management endpoints
 * Requires admin privileges for configuration changes
 */
// @ts-ignore
api.use('/config', checkRoot, authCheckAdminDebug, configApi)

/**
 * @route /api/kpe20/languages/*
 * @group Languages API
 * @description Language and localization management endpoints
 * Requires admin privileges for language configuration
 */
// @ts-ignore
api.use('/languages', checkRoot, authCheckAdminDebug, languagesApi)