403Webshell
Server IP : 52.25.153.185  /  Your IP : 216.73.217.131
Web Server : Apache
System : Linux ip-172-26-6-158 5.10.0-35-cloud-amd64 #1 SMP Debian 5.10.237-1 (2025-05-19) x86_64
User : daemon ( 1)
PHP Version : 8.1.10
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /bitnami/wordpress/wp-content/plugins/fluent-crm/app/Http/Controllers/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /bitnami/wordpress/wp-content/plugins/fluent-crm/app/Http/Controllers/TemplateController.php
<?php

namespace FluentCrm\App\Http\Controllers;

use FluentCrm\App\Models\Template;
use FluentCrm\App\Services\Helper;
use FluentCrm\App\Services\Sanitize;
use FluentCrm\Framework\Support\Arr;
use FluentCrm\Framework\Http\Request\Request;

/**
 *  TemplateController - REST API Handler Class
 *
 *  REST API Handler
 *
 * @package FluentCrm\App\Http
 *
 * @version 1.0.0
 */
class TemplateController extends Controller
{
    public function templates(Request $request)
    {
        $order = $request->getSafe('order', 'sanitize_sql_orderby', 'desc');
        $orderBy = $request->getSafe('orderBy', 'sanitize_sql_orderby', 'ID');

        $templatesQuery = Template::emailTemplates(
            $request->get('types', ['publish', 'draft'])
        );

        if ($search = $request->getSafe('search')) {
            $templatesQuery->where('post_title', 'LIKE', '%' . $search . '%');
        }

        // Order the query results and paginate
        $templates = $templatesQuery
            ->orderBy($orderBy, $order)
            ->paginate();

        foreach ($templates as $template) {
            $template->design_template = get_post_meta($template->ID, '_design_template', true);
        }

        return $this->sendSuccess([
            'templates' => $templates
        ]);
    }

    public function template(Request $request, $templateId = 0)
    {
        $template = Template::find($templateId);

        if ($template) {
            $editType = get_post_meta($template->ID, '_edit_type', true);
            if (!$editType) {
                $editType = 'html';
            }

            $designTemplate = get_post_meta($template->ID, '_design_template', true);
            $templateConfig = get_post_meta($template->ID, '_template_config', true);

            if(!$templateConfig || !is_array($templateConfig)) {
                $templateConfig = [];
            }

            $footerSettings = get_post_meta($template->ID, '_footer_settings', true);
            $normalizedSettings = $this->normalizeTemplateSettings([
                'template_config' => $templateConfig,
                'footer_settings' => $footerSettings
            ], $designTemplate);

            $templateData = [
                'post_title'      => $template->post_title,
                'post_content'    => $template->post_content,
                'post_excerpt'    => $template->post_excerpt,
                'email_subject'   => get_post_meta($template->ID, '_email_subject', true),
                'edit_type'       => $editType,
                'design_template' => $designTemplate,
                'settings'        => $normalizedSettings
            ];

            /**
             * Filter the template data before editing.
             *
             * @since 2.6.51
             *
             * @param array  $templateData The data of the template being edited.
             * @param object $template     The template object.
             */
            $templateData = apply_filters('fluent_crm/editing_template_data', $templateData, $template);

        } else {
            $defaultTemplate = Helper::getDefaultEmailTemplate();
            $normalizedSettings = $this->normalizeTemplateSettings([
                'template_config' => Helper::getTemplateConfig($defaultTemplate),
                'footer_settings' => []
            ], $defaultTemplate);

            $templateData = [
                'post_title'      => '',
                'post_content'    => '',
                'post_excerpt'    => '',
                'email_subject'   => '',
                'edit_type'       => 'html',
                'design_template' => $defaultTemplate,
                'settings'        => $normalizedSettings
            ];
        }

        return $this->sendSuccess([
            'template' => $templateData
        ]);
    }

    public function create(Request $request)
    {
        if($templateId = $request->get('template_id')) {
            return $this->update($request, $templateId);
        }

        $templateData = Helper::parseArrayOrJson($this->request->get('template'));

        $designTemplate = Arr::get($templateData, 'design_template');
        if (!$designTemplate) {
            $designTemplate = Helper::getDefaultEmailTemplate();
            $templateData['design_template'] = $designTemplate;
        }

        $templateData['settings'] = $this->normalizeTemplateSettings(Arr::get($templateData, 'settings', []), $designTemplate);

        $postData = Arr::only($templateData, [
            'post_title',
            'post_content',
            'post_excerpt'
        ]);

        if(empty($postData['post_title'])) {
            $postData['post_title'] = 'Email Template @ '.current_time('mysql');
        }

        if (empty($templateData['email_subject'])) {
            $templateData['email_subject'] = $postData['post_title'];
        }

        if(empty($postData['post_excerpt'])) {
            $postData['post_excerpt'] =  '';
        }

        $postData['post_modified'] = current_time('mysql');
        $postData['post_modified_gmt'] = gmdate('Y-m-d H:i:s');
        $postData['post_date'] = current_time('mysql');
        $postData['post_date_gmt'] = gmdate('Y-m-d H:i:s');
        $postData['post_type'] = fluentcrmTemplateCPTSlug();

        $templateId = wp_insert_post($postData);

        update_post_meta($templateId, '_email_subject', Arr::get($templateData, 'email_subject'));
        update_post_meta($templateId, '_edit_type', Arr::get($templateData, 'edit_type'));
        update_post_meta($templateId, '_template_config', Arr::get($templateData, 'settings.template_config', []));
        update_post_meta($templateId, '_footer_settings', Arr::get($templateData, 'settings.footer_settings', []));
        update_post_meta($templateId, '_design_template', $designTemplate);

        do_action('fluent_crm/email_template_created', $templateId, $templateData);

        return $this->sendSuccess([
            'message'     => __('Template successfully created', 'fluent-crm'),
            'template_id' => $templateId
        ]);
    }

    public function duplicate($templateId)
    {
        $template = Template::findOrFail($templateId);

        $postData = [
            'post_title'        => __('[Duplicate] ', 'fluent-crm') . $template['post_title'],
            'post_content'      => $template['post_content'],
            'post_excerpt'      => $template['post_excerpt'],
            'post_modified'     => current_time('mysql'),
            'post_modified_gmt' => gmdate('Y-m-d H:i:s'),
            'post_date'         => current_time('mysql'),
            'post_date_gmt'     => gmdate('Y-m-d H:i:s'),
            'post_type'         => fluentcrmTemplateCPTSlug(),
        ];

        $newTemplateId = wp_insert_post($postData);

        // Meta fields to copy over
        $metaKeys = [
            '_email_subject',
            '_edit_type',
            '_template_config',
            '_design_template',
            '_footer_settings'
        ];

        // Update post meta in a loop
        $this->copyMetaFields($templateId, $newTemplateId, $metaKeys);

        do_action('fluent_crm/email_template_duplicated', $newTemplateId, $template);

        return $this->sendSuccess([
            'message'     => __('Template successfully duplicated', 'fluent-crm'),
            'template_id' => $newTemplateId
        ]);
    }

    /**
     * Helper method to copy meta fields from one post to another
     */
    protected function copyMetaFields($oldPostId, $newPostId, $metaKeys)
    {
        foreach ($metaKeys as $metaKey) {
            update_post_meta($newPostId, $metaKey, get_post_meta($oldPostId, $metaKey, true));
        }
    }

    public function update(Request $request, $id)
    {
        $oldTemplate = Template::findOrFail($id);

        $templateData = Helper::parseArrayOrJson($this->request->get('template'));
        $designTemplate = Arr::get($templateData, 'design_template');
        if (!$designTemplate) {
            $designTemplate = get_post_meta($id, '_design_template', true) ?: Helper::getDefaultEmailTemplate();
            $templateData['design_template'] = $designTemplate;
        }

        $templateData['settings'] = $this->normalizeTemplateSettings(Arr::get($templateData, 'settings', []), $designTemplate);

        $footerSettings = Arr::get($templateData, 'settings.footer_settings');
        if($footerSettings) {
            if (($footerSettings['custom_footer'] == 'yes') && !Helper::hasComplianceText($footerSettings['footer_content'])) {
                return $this->sendError([
                    'message' => __('##crm.manage_subscription_url## or ##crm.unsubscribe_url## string is required for compliance. Please include unsubscription or manage subscription link', 'fluent-crm')
                ]);
            }
        }

        if(empty($templateData['post_title'])) {
            $templateData['post_title'] = 'Email template created at '.gmdate('Y-m-d H:i');
        }

        if(empty($templateData['email_subject'])) {
            $templateData['email_subject'] = 'Email template created at '.gmdate('Y-m-d H:i');
        }

        $postData = Arr::only($templateData, [
            'post_title',
            'post_content',
            'post_excerpt'
        ]);



        $postData['post_modified'] = current_time('mysql');
        $postData['post_modified_gmt'] = gmdate('Y-m-d H:i:s');
        Template::where('ID', $id)->update($postData);

        update_post_meta($id, '_email_subject', Arr::get($templateData, 'email_subject'));
        update_post_meta($id, '_edit_type', Arr::get($templateData, 'edit_type'));
        update_post_meta($id, '_design_template', Arr::get($templateData, 'design_template'));
        update_post_meta($id, '_template_config', Arr::get($templateData, 'settings.template_config', []));
        update_post_meta($id, '_footer_settings', Arr::get($templateData, 'settings.footer_settings', []));

        $template = Template::findOrFail($id);

        do_action('fluent_crm/email_template_updated', $templateData, $template);

        return $this->sendSuccess([
            'message'     => __('Template successfully updated', 'fluent-crm'),
            'template_id' => $id
        ]);
    }

    public function handleBulkAction(Request $request)
    {
        $actionName = sanitize_text_field($request->get('action_name', ''));

        $templateIds = array_map('intval', (array)$request->get('template_ids', []));

        $templateIds = array_unique(array_filter($templateIds));

        $selectAllTemplates = filter_var($request->get('select_all'), FILTER_VALIDATE_BOOLEAN);

        if ($selectAllTemplates) {
            $templateIds = Template::pluck('id')->toArray();
        }

        $templateIds = array_filter($templateIds);
        if ($actionName == 'change_template_status') {
            $newStatus = sanitize_text_field($request->get('status', ''));
            if (!$newStatus) {
                return $this->sendError([
                    'message' => __('Please select status', 'fluent-crm')
                ]);
            }

            $templates = Template::whereIn('ID', $templateIds)->get();

            foreach ($templates as $template) {
                $oldStatus = $template->post_status;
                if ($oldStatus != $newStatus) {
                    $template->post_status = $newStatus;
                    $template->save();
                }
            }

            return [
                'message' => __('Status has been changed for the selected templates', 'fluent-crm')
            ];
        } else if ($actionName == 'delete_templates') {
            $templates = Template::whereIn('id', $templateIds)->get();

            foreach ($templates as $template) {
                wp_delete_post($template->ID, true);
            }

            return $this->sendSuccess([
                'message' => __('Selected Templates have been deleted permanently', 'fluent-crm'),
            ]);
        }

        return [
            'message' => __('invalid bulk action', 'fluent-crm')
        ];
    }

    public function delete(Request $request, $id)
    {
        $template = Template::findOrFail($id);

        wp_delete_post($template->ID, true);

        return $this->sendSuccess([
            'message' => __('The template has been deleted successfully.', 'fluent-crm')
        ]);
    }

    public function render()
    {
        $rendered = Template::findOrFail(
            $this->request->get('ID')
        )->render();

        return $this->sendSuccess($rendered);
    }

    public function allTemplates()
    {
        return $this->sendSuccess([
            'templates'  => Template::emailTemplates(['publish'])->orderBy('ID', 'desc')->get(),
            'smartcodes' => $this->smartCodes()
        ]);
    }

    public function getSmartCodes()
    {
        return $this->sendSuccess([
            'smartcodes' => $this->smartCodes()
        ]);
    }

    protected function smartCodes()
    {
        return Helper::getGlobalSmartCodes();
    }

    public function setGlobalStyle(Request $request)
    {
        $settings = $request->get('config', []);

        foreach ($settings as $settingKey => $setting) {
            $settings[$settingKey] = sanitize_text_field($setting);
        }

        fluentcrm_update_option('global_email_style_config', $settings);

        return [
            'message' => __('Global style settings have been updated', 'fluent-crm')
        ];
    }

    /**
     * Fetches built-in templates from cached locally
     * cached for 24 hours, then refreshed
     * @return 
     */
    public function getBuiltInTemplates()
    {
        $templates = fluentCrmPersistentCache('email_remote_templates', function () {
                return $this->loadRemoteTemplates();
            }, 60 * 60 * 24); // 24 hours

        // Return a success response with the formatted templates
        return $this->sendSuccess([
            'templates' => $templates
        ]);
    }

    /**
     * Downloads a single built-in template file and returns it without saving
     * it as a local email template.
     *
     * @param \FluentCrm\Framework\Http\Request\Request $request
     * @return \FluentCrm\Framework\Http\Response\Response
     */
    public function getBuiltInTemplate(Request $request)
    {
        $fileUrl = esc_url_raw($request->get('file', ''));

        if (!$fileUrl || !$this->isAllowedRemoteTemplateUrl($fileUrl)) {
            return $this->sendError([
                'message' => __('Invalid template source URL', 'fluent-crm')
            ]);
        }

        $response = wp_remote_get($fileUrl, [
            'sslverify'           => true,
            'timeout'             => 20,
            'redirection'         => 0,
            'limit_response_size' => 1024 * 1024
        ]);

        if (is_wp_error($response)) {
            return $this->sendError([
                'message' => __('Unable to download the selected template. Please try again.', 'fluent-crm')
            ]);
        }

        $responseCode = wp_remote_retrieve_response_code($response);
        if ($responseCode < 200 || $responseCode >= 300) {
            return $this->sendError([
                'message' => __('Unable to download the selected template. Please try again.', 'fluent-crm')
            ]);
        }

        $templateData = Helper::parseArrayOrJson(wp_remote_retrieve_body($response));

        if (Arr::get($templateData, 'is_fc_template') !== 'yes') {
            return $this->sendError([
                'message' => __('The selected file is not a valid FluentCRM template.', 'fluent-crm')
            ]);
        }

        $template = $this->formatRemoteTemplateData($templateData);

        $hasVisualBuilderDesign = $template['design_template'] === 'visual_builder' && !empty($template['_visual_builder_design']);

        if (!$template['post_content'] && !$hasVisualBuilderDesign) {
            return $this->sendError([
                'message' => __('The selected template does not have any email content.', 'fluent-crm')
            ]);
        }

        return $this->sendSuccess([
            'message'  => __('Template has been inserted', 'fluent-crm'),
            'template' => $template
        ]);
    }

    /**
     * Restricts direct template downloads to trusted FluentCRM template hosts.
     *
     * @param string $url
     * @return bool
     */
    protected function isAllowedRemoteTemplateUrl($url)
    {
        $parsedUrl = wp_parse_url($url);

        if (empty($parsedUrl['scheme']) || empty($parsedUrl['host']) || $parsedUrl['scheme'] !== 'https') {
            return false;
        }

        $allowedHosts = [
            'fluentcrm.com',
            'www.fluentcrm.com',
            'wpmanageninja.com',
            'www.wpmanageninja.com'
        ];

        if (defined('FC_TEMPLATE_API_DOMAIN')) {
            $configuredHost = wp_parse_url(FC_TEMPLATE_API_DOMAIN, PHP_URL_HOST);
            if ($configuredHost) {
                $allowedHosts[] = strtolower($configuredHost);
            }
        }

        return in_array(strtolower($parsedUrl['host']), array_unique($allowedHosts), true);
    }

    /**
     * Normalizes remote JSON to the local template shape without creating a WP post.
     *
     * @param array $templateData
     * @return array
     */
    protected function formatRemoteTemplateData($templateData)
    {
        $designTemplate = sanitize_text_field(Arr::get($templateData, 'design_template'));
        if (!$designTemplate) {
            $designTemplate = Helper::getDefaultEmailTemplate();
        }

        $normalizedSettings = $this->normalizeTemplateSettings(Arr::get($templateData, 'settings', []), $designTemplate);

        return [
            'post_title'      => sanitize_text_field(Arr::get($templateData, 'post_title', '')),
            'post_content'    => Arr::get($templateData, 'post_content', ''),
            'post_excerpt'    => sanitize_textarea_field(Arr::get($templateData, 'post_excerpt', '')),
            'email_subject'   => sanitize_text_field(Arr::get($templateData, 'email_subject', '')),
            'edit_type'       => sanitize_text_field(Arr::get($templateData, 'edit_type', 'html')),
            'design_template' => $designTemplate,
            'settings'        => $normalizedSettings,
            '_visual_builder_design' => Arr::get($templateData, '_visual_builder_design')
        ];
    }

    /**
     * Normalize template settings with legacy footer disable compatibility.
     *
     * @param array $settings
     * @return array
     */
    protected function normalizeTemplateSettings($settings, $designTemplate = '')
    {
        $templateConfig = Arr::get($settings, 'template_config', []);
        if (!is_array($templateConfig)) {
            $templateConfig = [];
        }

        if (!$this->templateSupportsContentPadding($designTemplate)) {
            unset($templateConfig['content_padding']);
        } elseif (!isset($templateConfig['content_padding'])) {
            $templateConfig['content_padding'] = 20;
        }

        $footerSettings = Arr::get($settings, 'footer_settings', []);
        if (!is_array($footerSettings)) {
            $footerSettings = [];
        }

        $hasExplicitDisableFooter = array_key_exists('disable_footer', $footerSettings);
        $hasExplicitCustomFooter = array_key_exists('custom_footer', $footerSettings);

        $disableFooter = Arr::get($footerSettings, 'disable_footer');
        if ($disableFooter !== 'yes' && $disableFooter !== 'no') {
            $legacyDisable = Arr::get($templateConfig, 'disable_footer');
            $disableFooter = ($legacyDisable === 'yes' || $legacyDisable === 'no') ? $legacyDisable : 'no';
        }

        $customFooter = Arr::get($footerSettings, 'custom_footer');
        if ($customFooter !== 'yes' && $customFooter !== 'no') {
            $legacyFooterContent = Arr::get($footerSettings, 'footer_content', '');
            $customFooter = (is_string($legacyFooterContent) && trim(wp_strip_all_tags($legacyFooterContent)))
                ? 'yes'
                : 'no';
        }

        $footerSettings = wp_parse_args($footerSettings, [
            'custom_footer'    => 'no',
            'footer_content'   => '',
            'disable_footer'   => 'no',
            'font_size'        => 13,
            'font_color'       => '#202020',
            'background_color' => 'transparent',
            'footer_padding'   => 20
        ]);

        // Footer content is user-editable from a raw text mode; sanitize before persistence.
        $footerSettings['footer_content'] = Sanitize::sanitizeFooterHtml(Arr::get($footerSettings, 'footer_content', ''));

        $footerSettings['disable_footer'] = $disableFooter;
        $footerSettings['custom_footer'] = $customFooter;

        // Legacy imported templates may carry disable_footer in template_config without
        // explicit footer settings. Treat those as Global Footer instead of hidden footer.
        $isLegacyImportedDisabled = (
            !$hasExplicitDisableFooter &&
            !$hasExplicitCustomFooter &&
            $footerSettings['disable_footer'] === 'yes' &&
            Arr::get($templateConfig, 'disable_footer') === 'yes' &&
            $footerSettings['custom_footer'] !== 'yes' &&
            !trim(wp_strip_all_tags(Arr::get($footerSettings, 'footer_content', '')))
        );

        if ($isLegacyImportedDisabled) {
            $footerSettings['disable_footer'] = 'no';
            $footerSettings['custom_footer'] = 'no';
        }

        // Keep legacy key in sync during transition to avoid regressions in old readers.
        $templateConfig['disable_footer'] = $footerSettings['disable_footer'];

        return [
            'template_config' => $templateConfig,
            'footer_settings' => $footerSettings
        ];
    }

    /**
     * Raw classic editor templates only support font family and footer flags.
     *
     * @param string $designTemplate
     * @return bool
     */
    protected function templateSupportsContentPadding($designTemplate)
    {
        if ($designTemplate === 'raw_classic') {
            return false;
        }

        $templates = Helper::getEmailDesignTemplates();
        $template = Arr::get($templates, $designTemplate, []);

        return Arr::get($template, 'template_type') !== 'classic_editor';
    }

    /**
     * Fetches and formats email templates from a remote FluentCRM API endpoint.
     * This method makes an HTTP request to retrieve email templates from FluentCRM's public API.
     * It processes the response and formats the templates into a standardized structure.
     * @throws \WP_Error Logs error message if the API request fails
     * @return array
     * @access public
     */

    public function loadRemoteTemplates()
    {
        $restBase =  defined('FC_TEMPLATE_API_DOMAIN') ? FC_TEMPLATE_API_DOMAIN : 'https://fluentcrm.com';
        $restApi = $restBase.'/wp-json/wp/v2/email-templates?per_page=50';

        // Make a GET request to retrieve CRM templates
        $response = wp_remote_get($restApi, [
            'sslverify' => false,
        ]);

        // Check if the request resulted in an error
        if (is_wp_error($response)) {
            // Handle error
            error_log($response->get_error_message());
            return [];
        }

        // Decode the JSON response from the request
        $templateLists = json_decode(wp_remote_retrieve_body($response), true);

        if (!is_array($templateLists)) {
            return [];
        }

        $formattedTemplates = [];

        foreach ($templateLists as $template) {
            if (!$template['template_json']) {
                // Skip if no template json
                continue;
            }
            $mediaURL = '';
            if ($template['featured_media'] != 0) {
                $mediaURL = $this->getMediaURL($template['featured_media'], $restApi);
            }
            $formattedTemplates[] = [
                'id'                => $template['id'],
                'title'             => $template['title']['rendered'],
                'content'           => $template['template_json'],
                'short_description' => $template['short_description'],
                'link'              => $template['link'],
                'media_url'         => $mediaURL,
                'status'            => $template['status'],
                'cover_image'       => $template['cover_image'],
            ];
        }

        return $formattedTemplates;
    }


    /**
     * Retrieves the full source URL of a media item.
     *
     * @param int    $mediaID Media item ID.
     * @param string $restAPI The base URL of the REST API.
     *
     * @return string Full source URL of the media item.
     */
    public function getMediaURL($mediaID, $restAPI) {
        $request = wp_remote_get($restAPI.'media/'.$mediaID, [
            'sslverify' => false,
        ]);

        // Check for request errors
        if (is_wp_error($request)) {
            return '';
        }

        $image = json_decode($request['body'], true);
        $img   = Arr::get($image, 'source_url');

        return $img;
    }
}

Youez - 2016 - github.com/yon3zu
LinuXploit