"use strict";
Object.defineProperty(exports, "__esModule", {
    value: true
});
Object.defineProperty(exports, "adminRoutes", {
    enumerable: true,
    get: function() {
        return adminRoutes;
    }
});
const _express = /*#__PURE__*/ _interop_require_default(require("express"));
const _expressasynchandler = /*#__PURE__*/ _interop_require_default(require("express-async-handler"));
const _lodash = require("lodash");
const _middleware = require("@tamanu/shared/permissions/middleware");
const _errors = require("@tamanu/errors");
const _crudHelpers = require("@tamanu/shared/utils/crudHelpers");
const _settings = require("@tamanu/settings");
const _crypto = require("@tamanu/shared/utils/crypto");
const _exporter = require("./exporter");
const _importer = require("./importer");
const _asset = require("./asset");
const _designations = require("./designations");
const _fhirJobStats = require("./fhirJobStats");
const _formBuilder = require("./formBuilder");
const _locationAssignments = require("./locationAssignments");
const _patientMerge = require("./patientMerge");
const _permissions = require("./permissions");
const _programs = require("./programs");
const _programRegistries = require("./programRegistries");
const _referenceDataManage = require("./referenceDataManage");
const _reportRoutes = require("./reports/reportRoutes");
const _roles = require("./roles");
const _sync = require("./sync");
const _template = require("./template");
const _translation = require("./translation");
const _userPreferences = require("./userPreferences");
const _users = require("./users");
function _interop_require_default(obj) {
    return obj && obj.__esModule ? obj : {
        default: obj
    };
}
const adminRoutes = _express.default.Router();
adminRoutes.use(_middleware.ensurePermissionCheck);
adminRoutes.use('/reports', _reportRoutes.reportsRouter);
adminRoutes.use('/translation', _translation.translationRouter);
adminRoutes.post('/mergePatient', _patientMerge.mergePatientHandler);
// A temporary lookup-patient-by-displayId endpoint, just to
// support patient merge because the patient search functionality is only
// available on Facility and there was some time pressure to get it out the door.
// This should be replaced by the full-fledged patient search once some
// more consideration has been put into how that functionality should best
// be shared between the server modules.
adminRoutes.get('/lookup/patient/:displayId', (0, _expressasynchandler.default)(async (req, res)=>{
    req.checkPermission('read', 'Patient');
    const { Patient } = req.store.models;
    const { displayId } = req.params;
    const patient = await Patient.findOne({
        where: {
            displayId
        },
        include: [
            'village'
        ]
    });
    if (!patient) throw new _errors.NotFoundError(`Could not find patient with display ID ${displayId}.`);
    await req.audit.access({
        recordId: patient.id,
        frontEndContext: req.params,
        model: Patient
    });
    res.send(patient);
}));
adminRoutes.use('/import', _importer.importerRouter);
adminRoutes.use('/export', _exporter.exporterRouter);
adminRoutes.get('/sync/lastCompleted', _sync.syncLastCompleted);
adminRoutes.get('/fhir/jobStats', _fhirJobStats.fhirJobStats);
adminRoutes.use('/template', _template.templateRoutes);
adminRoutes.use('/form-builder', _formBuilder.formBuilderRouter);
adminRoutes.use('/asset', _asset.assetRoutes);
adminRoutes.use('/designations', _designations.designationsRouter);
adminRoutes.use('/designation', _designations.designationRouter);
adminRoutes.use('/users', _users.usersRouter);
adminRoutes.use('/user', _userPreferences.userPreferencesRouter);
adminRoutes.use('/location-assignments', _locationAssignments.locationAssignmentsRouter);
adminRoutes.use('/permissions', _permissions.permissionsRouter);
adminRoutes.use('/programs', _programs.programsRouter);
adminRoutes.use('/program', _programs.programRouter);
adminRoutes.use('/programRegistries', _programRegistries.programRegistriesRouter);
adminRoutes.use('/programRegistry', _programRegistries.programRegistryRouter);
adminRoutes.patch('/programRegistryClinicalStatus/:id', (0, _crudHelpers.simplePatch)('ProgramRegistryClinicalStatus', {
    allowedFields: [
        'color',
        'name',
        'visibilityStatus'
    ]
}));
adminRoutes.patch('/programRegistryCondition/:id', (0, _crudHelpers.simplePatch)('ProgramRegistryCondition', {
    allowedFields: [
        'name',
        'visibilityStatus'
    ]
}));
adminRoutes.patch('/programRegistryConditionCategory/:id', (0, _crudHelpers.simplePatch)('ProgramRegistryConditionCategory', {
    allowedFields: [
        'name',
        'visibilityStatus'
    ]
}));
adminRoutes.use('/referenceData/manage', _referenceDataManage.referenceDataManageRouter);
adminRoutes.use('/roles', _roles.rolesRouter);
adminRoutes.use('/role', _roles.roleRouter);
adminRoutes.patch('/survey/:id', (0, _crudHelpers.simplePatch)('Survey', {
    allowedFields: [
        'isSensitive',
        'name',
        'notifiable',
        'notifyEmailAddresses',
        'surveyType',
        'visibilityStatus'
    ]
}));
// These settings endpoints are setup for viewing and saving the settings in the JSON editor in the admin panel.
// Both endpoints require an explicit `scope` so that we can resolve the schema
// and mask/encrypt secret fields. Without a scope we have no way to know which
// fields are secret, so allowing the call would silently bypass masking on read
// and encryption on write.
const requireScope = (scope)=>{
    if (!scope) {
        throw new _errors.InvalidParameterError('scope is required');
    }
    const schema = (0, _settings.getScopedSchema)(scope);
    if (!schema) {
        throw new _errors.InvalidParameterError(`unknown scope: ${scope}`);
    }
    return schema;
};
adminRoutes.get('/settings', (0, _expressasynchandler.default)(async (req, res)=>{
    req.checkPermission('read', 'Setting');
    const { Setting } = req.store.models;
    const { facilityId, scope } = req.query;
    const schema = requireScope(scope);
    const data = await Setting.get('', facilityId, scope);
    if (!data || typeof data !== 'object') {
        res.send(data);
        return;
    }
    const secretPaths = (0, _settings.extractSecretPaths)(schema);
    res.send((0, _settings.maskSecrets)(data, secretPaths));
}));
/**
 * Resolves secret fields in `settings` so the object can be safely passed to
 * Setting.set('', ...) as a single bulk write. Setting.set with an empty key
 * soft-deletes any row in scope that isn't in its records, so handling secrets
 * via separate setSecret/unsetSecret calls around the bulk write would lose
 * the freshly-written secret rows. Instead, for each schema-declared secret
 * path we mutate `settings` in place:
 *   - encrypt new plaintext values
 *   - replace SECRET_PLACEHOLDER (unchanged) with the existing encrypted DB
 *     value, so the bulk write's isEqual check leaves the row alone
 *   - remove empty/null entries so the bulk cleanup soft-deletes them
 */ async function resolveSecretsForSave(Setting, settings, schema, scope, facilityId) {
    const secretPaths = (0, _settings.extractSecretPaths)(schema);
    if (secretPaths.length === 0) return;
    let keyBuffer;
    for (const path of secretPaths){
        const value = (0, _lodash.get)(settings, path);
        if (value === undefined) continue;
        if (value === _settings.SECRET_PLACEHOLDER) {
            const existing = await Setting.findOne({
                where: {
                    key: path,
                    scope,
                    facilityId
                }
            });
            if (existing) {
                (0, _lodash.set)(settings, path, existing.value);
            } else {
                (0, _lodash.unset)(settings, path);
            }
            continue;
        }
        if (value === null || value === '') {
            (0, _lodash.unset)(settings, path);
            continue;
        }
        if (!keyBuffer) keyBuffer = await (0, _crypto.getSettingsPskKeyBuffer)();
        (0, _lodash.set)(settings, path, await (0, _crypto.encryptSecret)(keyBuffer, String(value)));
    }
}
adminRoutes.put('/settings', (0, _expressasynchandler.default)(async (req, res)=>{
    req.checkPermission('write', 'Setting');
    const { Setting } = req.store.models;
    const { settings, scope, facilityId = null } = req.body;
    const schema = requireScope(scope);
    if (!settings || typeof settings !== 'object') {
        res.json({
            code: 200
        });
        return;
    }
    await resolveSecretsForSave(Setting, settings, schema, scope, facilityId);
    await Setting.set('', settings, scope, facilityId);
    await req.aiService?.refreshContexts(req.ctx.settings);
    res.json({
        code: 200
    });
}));
adminRoutes.delete('/settings/cache', (0, _expressasynchandler.default)(async (req, res)=>{
    req.checkPermission('manage', 'all');
    _settings.settingsCache.reset();
    await req.aiService?.refreshContexts(req.ctx.settings);
    res.status(204).send();
}));
adminRoutes.get('/facilities', (0, _expressasynchandler.default)(async (req, res)=>{
    req.checkPermission('list', 'Facility');
    const { Facility } = req.store.models;
    const data = await Facility.findAll({
        attributes: [
            'id',
            'name'
        ]
    });
    res.send(data);
}));

//# sourceMappingURL=adminRoutes.js.map