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