HEX
Server: Apache/2.4.52 (Ubuntu)
System: Linux spn-python 5.15.0-89-generic #99-Ubuntu SMP Mon Oct 30 20:42:41 UTC 2023 x86_64
User: arjun (1000)
PHP: 8.1.2-1ubuntu2.20
Disabled: NONE
Upload Files
File: /var/www/html/appointmentbook.me/wp-content/plugins/booknetic/app/Providers/Core/Backend.php
<?php

namespace BookneticApp\Providers\Core;

use BookneticSaaS\Models\Tenant;
use BookneticApp\Backend\Boostore\Helpers\BoostoreHelper;
use BookneticApp\Backend\Settings\Helpers\LocalizationService;
use BookneticApp\Config;
use BookneticApp\Providers\DB\DB;
use BookneticApp\Providers\Helpers\Date;
use BookneticApp\Providers\Helpers\Helper;
use BookneticSaaS\Providers\Helpers\Helper as SaasHelper;
use Exception;

class Backend
{
	const MENU_SLUG			= 'booknetic';
	const MODULES_DIR		= __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'Backend' . DIRECTORY_SEPARATOR;

	private static $installError = '';

	public static function init()
	{
		Permission::setAsBackEnd();

        Config::registerPaymentShortCode();

		self::initAdditionalData( true );

        $updateResult = self::updatePluginDB();

		if ( $updateResult !== true )
        {
            add_action( 'admin_notices', function () use ( $updateResult ) {
                echo '<div class="notice notice-warning"><p>' . $updateResult[ 1 ] . '</p></div>';
            } );

            return;
        }

        if ( Permission::isSuperAdministrator() && ! Route::isAjax() && Route::getCurrentAction() !== 'my_purchases' && ! empty( Helper::getOption( 'migration_v3', false, false ) ) )
        {
            $currentPage = Helper::_get( 'page', '', 'string' );

            if ( Helper::isSaaSVersion() && $currentPage === 'booknetic-saas' )
            {
                Helper::redirect( admin_url( 'admin.php?page=booknetic-saas&module=boostore&action=my_purchases' ) );
            }
            else if ( ! Helper::isSaaSVersion() && $currentPage == self::MENU_SLUG )
            {
                Helper::redirect( admin_url( 'admin.php?page=' . Helper::getSlugName() . '&module=boostore&action=my_purchases' ) );
            }
        }

		if( ! Permission::canUseBooknetic() )
			return;

		add_action( 'admin_menu', function()
		{
            $menuTitle = Helper::isSaaSVersion() ? SaasHelper::getOption( 'powered_by', 'Booknetic' ) : 'Booknetic';
            $icon = Helper::isSaaSVersion() ? Helper::profileImage( SaasHelper::getOption( 'whitelabel_logo_sm', 'logo-sm' ) ) : Helper::assets( 'images/logo-sm.svg' );

			add_menu_page(
				'Booknetic',
				$menuTitle,
				'read',
				self::getSlugName(),
				[ self::class , 'initMenu' ],
				$icon,
				90
			);
		});

		add_action('admin_init', function ()
		{
			$page = Helper::_get('page' , '', 'string');

			if( $page == self::getSlugName() && is_user_logged_in() )
			{
				do_action( 'bkntc_backend' );

				try
				{
					Route::init();
				}
				catch ( Exception $e )
				{
				    if( $_SERVER['REQUEST_METHOD'] === 'GET')
				    {
                        $childViewFile = Backend::MODULES_DIR . 'Base/view/404.php';
                        $currentModule = 'base';
                        $currentAction = '404';
                        $fullViewPath = Backend::MODULES_DIR . 'Base' . DIRECTORY_SEPARATOR . 'view' . DIRECTORY_SEPARATOR . 'index' . '.php';
                        require_once $fullViewPath;
                    }
				    else
				    {
                        $errorMessage = $e->getMessage();
                        if( empty( $errorMessage ) )
                        {
                            $errorMessage = bkntc__( 'Page not found or access denied!');
                        }

                        echo json_encode( Helper::response( false, $errorMessage, true) );
                    }
				}

				exit();
			}
			else
			{
				self::initGutenbergBlocks();
				self::initPopupBookingGutenbergBlocks();
                self::initChangeStatusGutenbergBlocks();
                self::initSigninGutenbergBlocks();
                self::initSignUpGutenbergBlocks();
                self::initForgotPasswordGutenbergBlocks();
			}
		});
	}

	public static function initInstallation()
	{
		self::initAdditionalData( false );

		self::checkInstallationRequest();

		add_action( 'admin_menu', function()
		{
			add_menu_page(
				'Booknetic',
				'Booknetic',
				'read',
				self::getSlugName(),
				array( self::class , 'installationMenu' ),
				Helper::assets('images/logo-sm.svg'),
				90
			);
		});

		if( Helper::_get('page', '', 'string') == self::getSlugName() )
		{
			wp_enqueue_script( 'booknetic-install', Helper::assets('js/install.js'), ['jquery'] );
			wp_enqueue_style('booknetic-install', Helper::assets('css/install.css') );
		}
	}

	private static function checkInstallationRequest()
	{
		add_action( 'wp_ajax_booknetic_install_plugin', function ()
		{
			$purchaseCode = Helper::_post( 'purchase_code', null, 'string' );
			$foundFrom = Helper::_post( 'found_from', null, 'string' );
			$email = Helper::_post( 'email', null, 'string' );
            $subscribedToNewsletter = Helper::_post( 'subscribed_to_newsletter', 0, 'int', [ 0, 1 ] ) === 1;
            $staging = Helper::_post( 'staging', 0, 'int', [ 0, 1 ] ) === 1;

            if ( empty( $purchaseCode ) ) {
                Helper::response( false, 'Please enter the purchase code' );
            } else if ( empty( $foundFrom ) ) {
                Helper::response( false, 'Please select where did you find Booknetic from' );
            } else if ( empty( $email ) ) {
                Helper::response( false,'Please enter the email' );
            }

            set_time_limit( 0 );

            Helper::setOption( 'bkntc_staging', $staging );

            try {
                $result = DotComApi::get( 'install', [
                    'purchase_code' => $purchaseCode,
                    'found_from' => $foundFrom,
                    'email' => $email,
                    'subscribed_to_newsletter' => $subscribedToNewsletter,
                    'staging' => $staging
                ] );

                if( $result[ 'status' ] !== 'ok' || ! isset( $result[ 'migrations' ] ) ) {
                    Helper::response(false, $result[ 'error_msg' ] ?? bkntc__( 'Error! Migration files not found.' ) );
                }

                self::runMigrations( $result[ 'migrations' ] );

                register_uninstall_hook( dirname( __DIR__, 3 ) . '/init.php', [ Helper::class, 'uninstallPlugin' ]);

                Helper::setOption( 'plugin_version', Helper::getVersion(), false );
                Helper::setOption( 'purchase_code', $purchaseCode, false );

                if ( ! empty( $result[ 'access_token' ] ) ) {
                    Helper::setOption( 'access_token', $result[ 'access_token' ], false );
                }

                if( ! empty( $result['saas_url'] ) ) {
                    $saasInstaller = new PluginInstaller( $result['saas_url'] , '/booknetic-saas/init.php' );

                    if( $saasInstaller->install() === false )
                    {
                        Helper::response(false, bkntc__('An error occurred, please try again later'));
                    }

                    Helper::setOption('saas_plugin_version', '0.0.0', false);
                } else {
                    //not a SaaS version, applying default templates.
                    Helper::applyDefaultTemplates();
                }

                return Helper::response( true );
            } catch ( Exception $e ) {
                return Helper::response(false, $e->getMessage() );
            }
		});
	}

	public static function installationMenu()
	{
        $options = DotComApi::safeGet( 'statistic_option' );

		$hasError = self::$installError;
		require_once self::MODULES_DIR . 'Base/view/install.php';
	}

	public static function initDisabledPage()
	{
		self::initAdditionalData( false );

		self::checkReActivateAction();

		add_action( 'admin_menu', function()
		{
			add_menu_page(
				'Booknetic (!)',
				'Booknetic (!)',
				'read',
				self::getSlugName(),
				[ self::class , 'disabledMenu' ],
				Helper::assets('images/logo-sm.svg'),
				90
			);
		});

		if( Helper::_get('page', '', 'string') == self::getSlugName() )
		{
			wp_enqueue_script( 'booknetic-disabled', Helper::assets('js/disabled.js'), ['jquery'] );
			wp_enqueue_style('booknetic-disabled', Helper::assets('css/disabled.css') );
		}
	}

	private static function checkReActivateAction()
	{
		add_action( 'wp_ajax_booknetic_reactivate_plugin', function ()
		{
			$code = Helper::_post( 'code', '', 'string' );

			if ( empty( $code ) ) {
				Helper::response( false, bkntc__( 'Please enter the purchase code!' ) );
			}

			set_time_limit( 0 );

            try {
                $result = DotComApi::get( 'reactivate', [ 'purchase_code' => $code ] );
            } catch ( Exception $e ) {
                return Helper::response( false, $e->getMessage() );
            }

			if ( $result[ 'status' ] !== 'ok' ) {
				return Helper::response( false, $result[ 'error_msg' ] ?? bkntc__( 'Server returned with an unknown error.' ) );
			}

			Helper::setOption( 'plugin_disabled', '0', false );
			Helper::setOption( 'plugin_alert', '', false );
            Helper::setOption('purchase_code', $code, false);

			return Helper::response( true, [ 'msg' => bkntc__( 'Plugin reactivated!' ) ] );
		} );
	}

	public static function disabledMenu()
	{
		$select_options = [];

		require_once self::MODULES_DIR . 'Base/view/disabled.php';
	}

	public static function initMenu()
	{
		return;
	}

	private static function initAdditionalData( $initUpdater )
	{
		if( $initUpdater )
		{
			$updater = new PluginUpdater( 'booknetic' );

            $updater->check_if_forced_for_update();
            $updater->set_filters();
            $updater->plugin_update_message();
		}

		add_filter('plugin_action_links_booknetic/init.php' , function ($links)
		{
			$newLinks = [
				'<a href="https://support.fs-code.com" target="_blank">' . __('Support', 'booknetic') . '</a>',
				'<a href="https://www.booknetic.com/documentation/" target="_blank">' . __('Doc', 'booknetic') . '</a>'
			];

			return array_merge($newLinks, $links);
		});
	}

	private static function updatePluginDB()
	{
		$installedVersion = Helper::getInstalledVersion();
		$currentVersion   = Helper::getVersion();

		if ( $installedVersion == $currentVersion ) {
            return true;
        }

        ignore_user_abort( true );
        set_time_limit( 0 );

        try {
            $result = DotComApi::get( 'update', [
                'version1' => $installedVersion,
                'version2' => $currentVersion,
            ] );
        } catch ( Exception $e ) {
            return [ false, $e->getMessage() ];
        }

		if( $result[ 'status' ] !== 'ok' || ! isset( $result[ 'migrations' ] ) ) {
            return [ false, ( $result[ 'error_msg' ] ?? bkntc__( 'Error! Migration files not found.' ) ) ];
		}

        if ( Helper::getOption( 'is_updating', '0', false ) == '1' )
        {
            return [ false, bkntc__("Booknetic Database update is running, please wait. If this notice doesn't gone in few minutes contact support.")];
        }

        Helper::setOption( 'is_updating', '1', false );

        self::runMigrations( $result[ 'migrations' ] );

		self::restoreLocalizations();

		Helper::setOption( 'plugin_version', Helper::getVersion(), false );

        Helper::deleteOption('addons_updates_cache', false);

        if ( ! empty( $result[ 'access_token' ] ) )
        {
            Helper::setOption( 'access_token', $result[ 'access_token' ], false );
        }

        if ( ! empty( $result[ 'changelogs_url' ] ) )
        {
            $changeLogQuery =  http_build_query( [
                'purchase_code' => Helper::getOption( 'purchase_code', null, false ),
                'domain' => site_url()
            ] );

            Helper::setOption( 'changelogs_url', $result[ 'changelogs_url' ] . '&' . $changeLogQuery, false );
        }

        Helper::setOption( 'is_updating', '0', false );

		return true;
	}

    public static function updateAddonsDB()
    {
        foreach (Bootstrap::$addons as $addon)
        {
            $slug = $addon->getAddonSlug();
            $currentVersion = $addon->getVersion();
            $versionOnDb = Helper::getOption("addon_{$slug}_version", '0.0.0', false);

            if (version_compare($currentVersion, $versionOnDb, '>'))
            {
                set_time_limit( 0 );

                $migrations = BoostoreHelper::get( 'get_migrations/' . $slug, [
                    'domain' => site_url(),
                    'from' => $versionOnDb,
                    'to' => $currentVersion
                ] );

                self::runMigrations( $migrations );

                Helper::setOption( "addon_{$slug}_version", $currentVersion, false );
            }
        }
    }

    private static function runMigrations ( $migrations )
    {
        if (!empty($migrations))
        {
            try {
                $timezone = Date::format( 'P' );
                DB::DB()->query("set time_zone = '$timezone';");
            } catch ( Exception $e) {}
        }

        $migrationFiles = [];

        foreach ( $migrations as $migrationStep )
        {
            if ( $migrationStep[ 'type' ] === 'sql' )
            {
                $sql = str_replace( [ '{tableprefix}', '{tableprefixbase}' ] , [ DB::DB()->base_prefix . DB::PLUGIN_DB_PREFIX, DB::DB()->base_prefix ] , base64_decode( $migrationStep[ 'data' ] ) );

                foreach( preg_split( '/;\n|;\r/', $sql, -1, PREG_SPLIT_NO_EMPTY ) AS $sqlQueryOne )
                {
                    $sqlQueryOne = trim( $sqlQueryOne );

                    if ( empty( $sqlQueryOne ) ) continue;

                    try {
                        DB::DB()->query( $sqlQueryOne );
                    } catch ( Exception $e) {}
                }
            }
            else if  ( $migrationStep[ 'type' ] === 'script' )
            {
                $migrationFile  = base64_decode( $migrationStep[ 'data' ] );
                $fileName       = __DIR__ . DIRECTORY_SEPARATOR . 'bkntc_migration_' . time() . '_' . count( $migrationFiles ) . '.php';

                $migrationFiles[] = $fileName;

                file_put_contents( $fileName, $migrationFile );

                include $fileName;
            }
        }

        foreach ( $migrationFiles as $migrationFile )
        {
            @unlink( $migrationFile );
        }
    }

	private static function initGutenbergBlocks()
	{
		if( !function_exists('register_block_type') )
			return;

		wp_register_script(
			'booknetic-blocks',
			plugins_url( 'assets/gutenberg-block.js', dirname(dirname(dirname(__DIR__))) . '/init.php' ),
			[ 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components' ]
		);
		wp_localize_script( 'booknetic-blocks', 'BookneticData', [
			'appearances'	    =>	DB::fetchAll('appearance', null, null, ['`id` AS `value`', '`name` AS `label`']),
			'staff'			    =>	DB::fetchAll('staff', null, null, ['`id` AS `value`', '`name` AS `label`']),
			'services'		    =>	DB::fetchAll('services', null, null, ['`id` AS `value`', '`name` AS `label`']),
			'service_categs'	=>	DB::fetchAll('service_categories', null, null, ['`id` AS `value`', '`name` AS `label`']),
			'locations'		    =>	DB::fetchAll('locations', null, null, ['`id` AS `value`', '`name` AS `label`'])
		] );

		register_block_type( 'booknetic/booking' , ['editor_script' => 'booknetic-blocks'] );

        /**
         * Since WordPress 5.8 block_categories filter renamed to block_categories_all
         */
        $filterName = class_exists( 'WP_Block_Editor_Context' ) ? 'block_categories_all' : 'block_categories';

        if ( Route::isAjax() )
        {
            add_filter( $filterName, function( $categories )
            {
                return array_merge(
                    $categories,
                    [
                        [
                            'slug' => 'booknetic',
                            'title' => 'Booknetic',
                        ],
                    ]
                );
            }, 10, 2);
        }
	}

	private static function initPopupBookingGutenbergBlocks()
	{
		if( !function_exists('register_block_type') )
			return;

		wp_register_script(
			'booknetic-popup-blocks',
			plugins_url( 'assets/popup-booking-gutenberg-block.js', dirname(dirname(dirname(__DIR__))) . '/init.php' ),
			[ 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components' ]
		);
		wp_localize_script( 'booknetic-popup-blocks', 'BookneticData', [
			'appearances'	    =>	DB::fetchAll('appearance', null, null, ['`id` AS `value`', '`name` AS `label`']),
			'staff'			    =>	DB::fetchAll('staff', null, null, ['`id` AS `value`', '`name` AS `label`']),
			'services'		    =>	DB::fetchAll('services', null, null, ['`id` AS `value`', '`name` AS `label`']),
			'service_categs'	=>	DB::fetchAll('service_categories', null, null, ['`id` AS `value`', '`name` AS `label`']),
			'locations'		    =>	DB::fetchAll('locations', null, null, ['`id` AS `value`', '`name` AS `label`'])
		] );

		register_block_type( 'booknetic/popup-booking' , ['editor_script' => 'booknetic-popup-blocks'] );

        /**
         * Since WordPress 5.8 block_categories filter renamed to block_categories_all
         */
        $filterName = class_exists( 'WP_Block_Editor_Context' ) ? 'block_categories_all' : 'block_categories';

		add_filter( $filterName, function( $categories )
		{
			return array_merge(
				$categories,
				[
					[
						'slug' => 'booknetic',
						'title' => 'Booknetic',
					],
				]
			);
		}, 10, 2);
	}

    private static function initChangeStatusGutenbergBlocks()
    {
        if( !function_exists('register_block_type') )
            return;

        wp_register_script(
            'booknetic-change-status-blocks',
            plugins_url( 'assets/change-status-gutenberg-block.js', dirname(dirname(dirname(__DIR__))) . '/init.php' ),
            [ 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components' ]
        );

        register_block_type( 'booknetic/changestatus' , ['editor_script' => 'booknetic-change-status-blocks'] );

    }

    private static function initSigninGutenbergBlocks()
    {
        if( !function_exists('register_block_type') )
            return;

        wp_register_script(
            'booknetic-signin-blocks',
            plugins_url( 'assets/signin-gutenberg-block.js', dirname(dirname(dirname(__DIR__))) . '/init.php' ),
            [ 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components' ]
        );

        register_block_type( 'booknetic/signin' , ['editor_script' => 'booknetic-signin-blocks'] );
    }

    private static function initSignUpGutenbergBlocks()
    {
        if( !function_exists('register_block_type') )
            return;

        wp_register_script(
            'booknetic-signup-blocks',
            plugins_url( 'assets/signup-gutenberg-block.js', dirname(dirname(dirname(__DIR__))) . '/init.php' ),
            [ 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components' ]
        );

        register_block_type( 'booknetic/signup' , ['editor_script' => 'booknetic-signup-blocks'] );
    }

    private static function initForgotPasswordGutenbergBlocks()
    {
        if( !function_exists('register_block_type') )
            return;

        wp_register_script(
            'booknetic-forgot-password-blocks',
            plugins_url( 'assets/forgot-password-gutenberg-block.js', dirname(dirname(dirname(__DIR__))) . '/init.php' ),
            [ 'wp-blocks', 'wp-element', 'wp-editor', 'wp-components' ]
        );

        register_block_type( 'booknetic/forgot-password' , ['editor_script' => 'booknetic-forgot-password-blocks'] );
    }

	private static function restoreLocalizations()
	{
		$restoreLocalizations = function ( $tenant = '' ){
			$tenantPath = empty( $tenant ) ? $tenant : ( DIRECTORY_SEPARATOR . $tenant );
			$languages = glob( Helper::uploadedFile( 'booknetic_*.lng', 'languages' . $tenantPath ) );
			foreach( $languages AS $language )
			{
				if( !preg_match( '/booknetic_([a-zA-Z0-9\-_]+)\.lng$/', $language, $lang_name ) )
					continue;

				$lang_name = $lang_name[1];

				if( !LocalizationService::isLngCorrect( $lang_name ) )
					continue;

				$translations = file_get_contents( $language );
				$translations = json_decode( base64_decode( $translations ), true );

				if( is_array( $translations ) && !empty( $translations ) )
				{
					LocalizationService::saveFiles( $lang_name, $translations );
				}
			}
		};

		if( Helper::isSaaSVersion() )
		{
			$tenants = Tenant::select( 'id' )->fetchAll();
			$currentTenant = Permission::tenantId();

			foreach ( $tenants as $tenant )
			{
				$tenantID = $tenant->toArray()['id'];
				Permission::setTenantId( $tenantID );
				$restoreLocalizations( $tenantID );
			}

			Permission::setTenantId( $currentTenant );
		}
		else
		{
			$restoreLocalizations();
		}
	}

	public static function getSlugName()
	{
		return Helper::isSaaSVersion() ? SaasHelper::getOption( 'backend_slug', 'booknetic' ) : self::MENU_SLUG;
	}

}