Your IP : 216.73.216.224


Current Path : /var/www/html/libraries/noboss/src/Util/
Upload File :
Current File : /var/www/html/libraries/noboss/src/Util/NbModuleParamsUtil.php

<?php
/**
 * @package         No Boss Extensions
 * @subpackage      No Boss Library
 * @author          No Boss Technology <contact@nobosstechnology.com>
 * @copyright       Copyright (C) 2026 No Boss Technology. All rights reserved.
 * @license         GNU Lesser General Public License version 3 or later; see <https://www.gnu.org/licenses/lgpl-3.0.en.html>
 */

namespace Noboss\Library\Util;

use Joomla\CMS\Factory;
use Joomla\Database\DatabaseInterface;

// phpcs:disable PSR1.Files.SideEffects
\defined('_JEXEC') or die;
// phpcs:enable PSR1.Files.SideEffects

/**
 * Utilitário para exportar e importar os parâmetros (coluna `params`) de instâncias de módulo.
 *
 * Permite copiar configurações de um módulo para outro — inclusive entre sites diferentes.
 *
 * Endpoints via com_nobossajax:
 *   GET  index.php?option=com_nobossajax&library=noboss.src.Util.NbModuleParamsUtil&method=exportModuleParams&id_module=X&format=raw
 *   POST index.php?option=com_nobossajax&library=noboss.src.Util.NbModuleParamsUtil&method=importModuleParams&format=raw
 */
class NbModuleParamsUtil
{
    /**
     * Verifica se o usuário está autenticado e tem permissão administrativa.
     * Em caso negativo, emite JSON de erro e encerra a execução.
     */
    private static function requireAdminUser(): void
    {
        header('Content-Type: application/json; charset=utf-8');
        $user = Factory::getApplication()->getIdentity();

        if ($user->guest) {
            http_response_code(401);
            echo json_encode(['success' => false, 'message' => 'Authentication required.']);
            exit;
        }

        if (!$user->authorise('core.admin') && !in_array(8, $user->groups, true)) {
            http_response_code(403);
            echo json_encode(['success' => false, 'message' => 'Access denied: administrator permission required.']);
            exit;
        }
    }

    /**
     * Exporta a coluna `params` de um módulo como arquivo JSON para download.
     *
     * Parâmetros GET:
     *   - id_module (int, obrigatório): ID da linha em #__modules
     *
     * O arquivo gerado pode ser reimportado diretamente por importModuleParams().
     */
    public static function exportModuleParams(): void
    {
        self::requireAdminUser();

        $input    = Factory::getApplication()->input;
        $idModule = $input->getInt('id_module', 0);

        if ($idModule <= 0) {
            http_response_code(400);
            echo json_encode(['success' => false, 'message' => 'Missing required parameter: id_module.']);
            exit;
        }

        $db = Factory::getContainer()->get(DatabaseInterface::class);
        $query = $db->getQuery(true)
            ->select($db->quoteName(['id', 'title', 'module', 'params']))
            ->from($db->quoteName('#__modules'))
            ->where($db->quoteName('id') . ' = ' . $idModule);
        $db->setQuery($query);
        $row = $db->loadObject();

        if (empty($row)) {
            http_response_code(404);
            echo json_encode(['success' => false, 'message' => 'Module not found (id=' . $idModule . ').']);
            exit;
        }

        $params = json_decode($row->params);

        if ($params === null && $row->params !== '' && $row->params !== 'null') {
            http_response_code(500);
            echo json_encode(['success' => false, 'message' => 'The module params column does not contain valid JSON.']);
            exit;
        }

        // Envelope com metadados para facilitar identificação no momento da importação
        $export = [
            '_nb_layout_export' => true,
            '_module'           => $row->module,
            '_module_id'        => (int) $row->id,
            '_module_title'     => $row->title,
            '_exported_at'      => date('Y-m-d H:i:s'),
            'params'            => $params ?? new \stdClass(),
        ];

        $filename = $row->module . '_id' . $row->id . '_layout_' . date('Ymd_His') . '.json';

        header('Content-Type: application/json; charset=utf-8');
        header('Content-Disposition: attachment; filename="' . $filename . '"');
        header('Cache-Control: no-cache, no-store, must-revalidate');
        header('Pragma: no-cache');
        header('Expires: 0');

        echo json_encode($export, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
        exit;
    }

    /**
     * Importa um arquivo de layout JSON e salva na coluna `params` do módulo indicado.
     *
     * Parâmetros POST:
     *   - id_module   (int,    obrigatório): ID da linha em #__modules que receberá os dados
     *   - json_content (string, obrigatório): conteúdo JSON bruto do arquivo exportado
     *
     * Validações:
     *   1. JSON válido
     *   2. Raiz deve ser um objeto (não primitivo, não array simples sem chaves de string)
     *   3. Pelo menos uma chave presente
     *
     * Retorna JSON: { success: bool, message: string }
     */
    public static function importModuleParams(): void
    {
        self::requireAdminUser();

        $input       = Factory::getApplication()->input;
        $idModule    = $input->getInt('id_module', 0);
        $jsonContent = $input->post->getRaw('json_content', '');

        if ($idModule <= 0) {
            echo json_encode(['success' => false, 'message' => 'Missing required parameter: id_module.']);
            exit;
        }

        if (empty(trim($jsonContent))) {
            echo json_encode(['success' => false, 'message' => 'No JSON content received.']);
            exit;
        }

        // Valida o JSON recebido
        $decoded = json_decode($jsonContent, true);

        if (json_last_error() !== JSON_ERROR_NONE) {
            echo json_encode([
                'success' => false,
                'message' => 'Invalid file: not valid JSON. Error: ' . json_last_error_msg(),
            ]);
            exit;
        }

        // A raiz deve ser um objeto associativo (array com chaves string no PHP)
        if (!is_array($decoded)) {
            echo json_encode([
                'success' => false,
                'message' => 'Invalid structure: the JSON root must be an object, not a primitive value.',
            ]);
            exit;
        }

        // Detecta envelope gerado por exportModuleParams() e extrai apenas a chave params
        if (isset($decoded['_nb_layout_export'], $decoded['params']) && $decoded['_nb_layout_export'] === true) {
            $paramsToSave = $decoded['params'];

            if (!is_array($paramsToSave) && !is_object($paramsToSave)) {
                echo json_encode([
                    'success' => false,
                    'message' => 'Invalid file: the "params" key inside the exported file is not an object.',
                ]);
                exit;
            }
        } else {
            // Aceita também um objeto de params puro (sem envelope)
            $paramsToSave = $decoded;
        }

        if (empty($paramsToSave)) {
            echo json_encode([
                'success' => false,
                'message' => 'The JSON contains no parameters to import (empty object).',
            ]);
            exit;
        }

        // Confirma que o módulo existe no banco
        $db    = Factory::getContainer()->get(DatabaseInterface::class);
        $query = $db->getQuery(true)
            ->select($db->quoteName('id'))
            ->from($db->quoteName('#__modules'))
            ->where($db->quoteName('id') . ' = ' . $idModule);
        $db->setQuery($query);
        $existingId = $db->loadResult();

        if (empty($existingId)) {
            echo json_encode([
                'success' => false,
                'message' => 'Module with id=' . $idModule . ' was not found in the database.',
            ]);
            exit;
        }

        // Serializa de volta para string JSON, como o Joomla espera na coluna params
        $paramsJson = json_encode($paramsToSave, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);

        $query = $db->getQuery(true)
            ->update($db->quoteName('#__modules'))
            ->set($db->quoteName('params') . ' = ' . $db->quote($paramsJson))
            ->where($db->quoteName('id') . ' = ' . $idModule);
        $db->setQuery($query);

        if (!$db->execute()) {
            echo json_encode([
                'success' => false,
                'message' => 'Database error: could not save the layout.',
            ]);
            exit;
        }

        echo json_encode([
            'success' => true,
            'message' => 'Layout imported successfully! Reload the page to see the changes.',
        ]);
        exit;
    }
}