mirror of
https://gh.wpcy.net/https://github.com/LumeWeb/freescout-enduserportal.git
synced 2026-04-18 07:32:23 +08:00
535 lines
16 KiB
PHP
535 lines
16 KiB
PHP
<?php
|
|
|
|
namespace Modules\EndUserPortal\Providers;
|
|
|
|
// Module alias.
|
|
define('EUP_MODULE', 'enduserportal');
|
|
|
|
use App\Conversation;
|
|
use App\Customer;
|
|
use App\Mailbox;
|
|
use Illuminate\Support\ServiceProvider;
|
|
use Illuminate\Database\Eloquent\Factory;
|
|
|
|
class EndUserPortalServiceProvider extends ServiceProvider
|
|
{
|
|
// Subfolder in URL.
|
|
const URL_SUBFOLDER = 'help';
|
|
const WIDGET_SALT = '0624d105de20';
|
|
const AUTH_PERIOD = 43800; // month
|
|
const AUTH_LINK_LIFETIME = 3600; // seconds
|
|
|
|
public static $mailboxes_ids = [];
|
|
|
|
// Authenticated customer.
|
|
public static $auth_customer = null;
|
|
|
|
/**
|
|
* Indicates if loading of the provider is deferred.
|
|
*
|
|
* @var bool
|
|
*/
|
|
protected $defer = false;
|
|
|
|
/**
|
|
* Boot the application events.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function boot()
|
|
{
|
|
$this->registerConfig();
|
|
$this->registerViews();
|
|
$this->registerFactories();
|
|
$this->loadMigrationsFrom(__DIR__ . '/../Database/Migrations');
|
|
$this->hooks();
|
|
}
|
|
|
|
/**
|
|
* Module hooks.
|
|
*/
|
|
public function hooks()
|
|
{
|
|
// Add module's CSS file to the application layout.
|
|
\Eventy::addFilter('stylesheets', function($styles) {
|
|
$styles[] = \Module::getPublicPath(EUP_MODULE).'/css/module.css';
|
|
$styles[] = \Module::getPublicPath(EUP_MODULE).'/css/bootstrap-colorpicker.css';
|
|
return $styles;
|
|
});
|
|
|
|
// Add module's JS file to the application layout.
|
|
\Eventy::addFilter('javascripts', function($javascripts) {
|
|
//$javascripts[] = \Module::getPublicPath(TIMETR_MODULE).'/js/laroute.js';
|
|
$javascripts[] = \Module::getPublicPath(EUP_MODULE).'/js/bootstrap-colorpicker.js';
|
|
$javascripts[] = \Module::getPublicPath(EUP_MODULE).'/js/module.js';
|
|
return $javascripts;
|
|
});
|
|
|
|
// Add item to the mailbox menu
|
|
\Eventy::addAction('mailboxes.settings.menu', function($mailbox) {
|
|
if (auth()->user()->isAdmin()) {
|
|
echo \View::make('enduserportal::partials/settings_menu', ['mailbox' => $mailbox])->render();
|
|
}
|
|
}, 40);
|
|
|
|
\Eventy::addFilter('menu.selected', function($menu) {
|
|
if (self::isEup()) {
|
|
$menu['enduserportal.submit'] = 'enduserportal.submit';
|
|
$menu['enduserportal.tickets'] = 'enduserportal.tickets';
|
|
}
|
|
|
|
return $menu;
|
|
});
|
|
|
|
// Define OAuth settings
|
|
// Add Portal OAuth section to settings
|
|
\Eventy::addFilter( 'settings.sections', function ( $sections ) {
|
|
$sections['portal_oauth'] = [
|
|
'title' => __( 'Portal OAuth' ),
|
|
'icon' => 'lock',
|
|
'order' => 400,
|
|
];
|
|
|
|
return $sections;
|
|
} );
|
|
|
|
// Define Portal OAuth settings
|
|
\Eventy::addFilter( 'settings.section_settings', function ( $settings, $section ) {
|
|
if ( $section === 'portal_oauth' ) {
|
|
$settings = [
|
|
self::getPluginOptionName( 'portal_oauth_enabled' ) => self::getPluginOption( 'portal_oauth_enabled' ),
|
|
self::getPluginOptionName( 'portal_server_url' ) => self::getPluginOption( 'portal_server_url' ),
|
|
self::getPluginOptionName( 'portal_client_id' ) => self::getPluginOption( 'portal_client_id' ),
|
|
self::getPluginOptionName( 'portal_client_secret' ) => self::getPluginOption( 'portal_client_secret' ),
|
|
];
|
|
}
|
|
|
|
return $settings;
|
|
}, 20, 2 );
|
|
// Add Portal OAuth parameters
|
|
\Eventy::addFilter( 'settings.section_params', function ( $params, $section ) {
|
|
if ( $section === 'portal_oauth' ) {
|
|
$params = [
|
|
'settings' => [
|
|
'portal_oauth_enabled' => [
|
|
|
|
],
|
|
'portal_server_url' => [
|
|
|
|
],
|
|
'portal_client_id' => [
|
|
|
|
],
|
|
'portal_client_secret' => [
|
|
|
|
],
|
|
],
|
|
'validator_rules' => [
|
|
'settings.portal_server_url' => 'required_if:settings.portal_oauth_enabled,1|url',
|
|
'settings.portal_client_id' => 'required_if:settings.portal_oauth_enabled,1',
|
|
'settings.portal_client_secret' => 'required_if:settings.portal_oauth_enabled,1',
|
|
],
|
|
];
|
|
}
|
|
|
|
return $params;
|
|
}, 20, 2 );
|
|
}
|
|
|
|
/**
|
|
* Returns a shorter value than encrypt().
|
|
*/
|
|
public static function encodeMailboxId($id, $extra_salt = '')
|
|
{
|
|
return crc32(config('app.key').EUP_MODULE.$extra_salt.$id);
|
|
|
|
//return encrypt($data);
|
|
// $hashids = new Hashids();
|
|
// return $hashids->encode($data);
|
|
}
|
|
|
|
public static function decodeMailboxId($encoded_id, $extra_salt = '')
|
|
{
|
|
if (!empty(self::$mailboxes_ids[$encoded_id])) {
|
|
return self::$mailboxes_ids[$encoded_id];
|
|
}
|
|
$result = '';
|
|
|
|
$mailboxes = Mailbox::get();
|
|
|
|
foreach ($mailboxes as $mailbox) {
|
|
$cur_encoded_id = self::encodeMailboxId($mailbox->id, $extra_salt);
|
|
self::$mailboxes_ids[$cur_encoded_id] = $mailbox->id;
|
|
|
|
if ($cur_encoded_id == $encoded_id) {
|
|
$result = $mailbox->id;
|
|
}
|
|
}
|
|
|
|
return $result;
|
|
|
|
//return decrypt($data);
|
|
|
|
// $hashids = new Hashids();
|
|
// return $hashids->decode($data);
|
|
}
|
|
|
|
public static function getMailboxParam($mailbox, $param)
|
|
{
|
|
return $mailbox->meta['eup'][$param] ?? \EndUserPortal::getDefaultPortalSettings()[$param] ?? '';
|
|
}
|
|
|
|
public static function isEup()
|
|
{
|
|
return preg_match('/.*\/'.self::URL_SUBFOLDER.'\/.*/', \Request::url());
|
|
}
|
|
|
|
public static function urlHome()
|
|
{
|
|
return route('enduserportal.submit', ['mailbox_id' => \Request::route()->parameter('mailbox_id')]);
|
|
}
|
|
|
|
public static function saveWidgetSettings($mailbox_id, $settings)
|
|
{
|
|
return \Option::set(EUP_MODULE.'.widget_settings_'.$mailbox_id, $settings);
|
|
}
|
|
|
|
// public static function saveWidgetScript($mailbox_id, $settings)
|
|
// {
|
|
// $file_name = self::getWidgetScriptFileName($mailbox_id);
|
|
// $file_path = storage_path('app/public/js/'.$file_name);
|
|
|
|
// $content = view('enduserportal::js/widget', ['settings' => $settings])->render();
|
|
|
|
// try {
|
|
// \Storage::put('js/'.$file_name, $content);
|
|
// } catch (\Exception $e) {
|
|
// throw new Exception(__("Could not save widget file, please check folders permissions:").' '.$file_path.' ('.$e->getMessage().')', 1);
|
|
// }
|
|
|
|
// $check = \Storage::get('js/'.$file_name);
|
|
|
|
// if (!$check) {
|
|
// throw new Exception(__("Could not save widget file, please check folders permissions:").' '.$file_path, 1);
|
|
// }
|
|
// }
|
|
|
|
// public static function getWidgetScriptFileName($mailbox_id)
|
|
// {
|
|
// return 'eup_widget_'.self::encodeMailboxId($mailbox_id, self::WIDGET_SALT).'.js';
|
|
// }
|
|
|
|
public static function getWidgetScriptUrl($mailbox_id, $include_version = false)
|
|
{
|
|
$url = config('app.url').\Module::getPublicPath(EUP_MODULE).'/js/widget.js';
|
|
|
|
if ($include_version) {
|
|
$module = \Module::findByAlias(EUP_MODULE);
|
|
if ($module) {
|
|
$url .= '?v='.substr(crc32($module->get('version').config('app.key')), 0, 4);
|
|
}
|
|
}
|
|
|
|
return $url;
|
|
// $file_name = self::getWidgetScriptFileName($mailbox_id);
|
|
// return \Storage::url('js/'.$file_name);
|
|
}
|
|
|
|
public static function getWidgetSettings($mailbox_id)
|
|
{
|
|
return \Option::get(EUP_MODULE.'.widget_settings_'.$mailbox_id, []);
|
|
|
|
// $settings = [];
|
|
|
|
// $file_name = self::getWidgetScriptFileName($mailbox_id);
|
|
// $file_path = storage_path('app/public/js/'.$file_name);
|
|
|
|
// try {
|
|
// $script = \Storage::get('js/'.$file_name);
|
|
// } catch (\Exception $e) {
|
|
// return $settings;
|
|
// }
|
|
|
|
// preg_match("#/\* SETTINGS_START \*/(.*)/\* SETTINGS_END \*/#", $script, $m);
|
|
|
|
// if (!empty($m[1])) {
|
|
// $settings = json_encode($m[1], true);
|
|
// }
|
|
|
|
// return $settings;
|
|
}
|
|
|
|
public static function getDefaultPortalSettings($param = '')
|
|
{
|
|
$settings = [
|
|
//'locales' => [],
|
|
'numbers' => 0,
|
|
'existing' => 0,
|
|
'text_submit' => __('Submit a Ticket'),
|
|
'footer' => '© {%year%} {%mailbox.name%}',
|
|
'subject' => 0,
|
|
'consent' => 0,
|
|
'privacy' => '',
|
|
];
|
|
if ($param) {
|
|
return $settings[$param] ?? '';
|
|
} else {
|
|
return $settings;
|
|
}
|
|
}
|
|
|
|
public static function getDefaultWidgetSettings()
|
|
{
|
|
return [
|
|
'id' => '',
|
|
'color' => '#0068bd',
|
|
//'title' => __('Contact us'),
|
|
'position' => 'br',
|
|
'locale' => '',
|
|
];
|
|
}
|
|
|
|
public static function getPortalName($mailbox)
|
|
{
|
|
return __(':mailbox.name Support Portal', ['mailbox.name' => $mailbox->name]);
|
|
}
|
|
|
|
public static function authenticate($customer_id, $mailbox_id, $hash, $timestamp)
|
|
{
|
|
if (!is_numeric($timestamp) || time() - $timestamp > self::AUTH_LINK_LIFETIME) {
|
|
throw new \Exception(__('Authentication link has expired'), 300);
|
|
}
|
|
|
|
$customer = Customer::find($customer_id);
|
|
|
|
if ($customer && $hash == self::customerHash($customer->created_at)) {
|
|
$cookie = cookie('enduserportal_auth', encrypt($customer_id.'|'.$hash), self::AUTH_PERIOD);
|
|
return redirect()->route('enduserportal.tickets', ['mailbox_id' => \EndUserPortal::encodeMailboxId($mailbox_id)])
|
|
->withCookie($cookie);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
public static function customerHash($str)
|
|
{
|
|
return substr(md5($str), 0, 8);
|
|
}
|
|
|
|
/**
|
|
* Get authenticated customer.
|
|
*/
|
|
public static function authCustomer()
|
|
{
|
|
if (self::$auth_customer) {
|
|
return self::$auth_customer;
|
|
}
|
|
|
|
$customer_id = null;
|
|
$hash = null;
|
|
$auth_data = request()->cookie('enduserportal_auth');
|
|
|
|
if ($auth_data) {
|
|
try {
|
|
$auth_data_decrypted = decrypt($auth_data);
|
|
list($customer_id, $hash) = explode('|', $auth_data_decrypted ?? '');
|
|
} catch (\Exception $e) {
|
|
return null;
|
|
}
|
|
if ($customer_id && $hash) {
|
|
$customer = Customer::find($customer_id);
|
|
if ($customer && self::customerHash($customer->created_at) == $hash) {
|
|
self::$auth_customer = $customer;
|
|
}
|
|
}
|
|
}
|
|
|
|
return self::$auth_customer;
|
|
}
|
|
|
|
public static function dateFormat($date, $format = 'M j, Y H:i')
|
|
{
|
|
if (is_string($date)) {
|
|
// Convert string in to Carbon
|
|
try {
|
|
$date = Carbon::parse($date);
|
|
} catch (\Exception $e) {
|
|
$date = null;
|
|
}
|
|
}
|
|
|
|
if (!$date) {
|
|
return '';
|
|
}
|
|
|
|
|
|
// return $date->setTimezone($user->timezone)->format($format);
|
|
return $date->format($format);
|
|
}
|
|
|
|
public static function hasNewReplies($conversation)
|
|
{
|
|
return !empty($conversation->has_new_replies);
|
|
}
|
|
|
|
public static function ticketUrl($conversation)
|
|
{
|
|
return route('enduserportal.ticket', [
|
|
'mailbox_id' => \EndUserPortal::encodeMailboxId($conversation->mailbox_id),
|
|
'conversation_id' => $conversation->id,
|
|
]);
|
|
}
|
|
|
|
public static function getStatusName($conversation)
|
|
{
|
|
if (in_array($conversation->status, [Conversation::STATUS_ACTIVE, Conversation::STATUS_PENDING]) &&
|
|
$conversation->state != Conversation::STATE_DELETED
|
|
) {
|
|
return __('Open');
|
|
} else {
|
|
return __('Closed');
|
|
}
|
|
}
|
|
|
|
public static function getLocales($mailbox)
|
|
{
|
|
$meta_settings = $mailbox->meta['eup'] ?? [];
|
|
return $meta_settings['locales'] ?? [];
|
|
}
|
|
|
|
public static function getLocale()
|
|
{
|
|
return session()->get('enduserportal.locale') ?: config('app.locale');
|
|
}
|
|
|
|
public static function urlToSwitchLocale($locale)
|
|
{
|
|
$url = \Request::getRequestUri();
|
|
|
|
$url = $url.'?eup_locale='.$locale;
|
|
|
|
return $url;
|
|
}
|
|
|
|
/**
|
|
* Register the service provider.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function register()
|
|
{
|
|
$this->registerTranslations();
|
|
}
|
|
|
|
/**
|
|
* Register config.
|
|
*
|
|
* @return void
|
|
*/
|
|
protected function registerConfig()
|
|
{
|
|
$this->publishes([
|
|
__DIR__.'/../Config/config.php' => config_path('enduserportal.php'),
|
|
], 'config');
|
|
$this->mergeConfigFrom(
|
|
__DIR__.'/../Config/config.php', 'enduserportal'
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Register views.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function registerViews()
|
|
{
|
|
$viewPath = resource_path('views/modules/enduserportal');
|
|
|
|
$sourcePath = __DIR__.'/../Resources/views';
|
|
|
|
$this->publishes([
|
|
$sourcePath => $viewPath
|
|
],'views');
|
|
|
|
$this->loadViewsFrom(array_merge(array_map(function ($path) {
|
|
return $path . '/modules/enduserportal';
|
|
}, \Config::get('view.paths')), [$sourcePath]), 'enduserportal');
|
|
|
|
view()->addLocation( __DIR__ . '/../resources/views');
|
|
}
|
|
|
|
/**
|
|
* Register translations.
|
|
*
|
|
* @return void
|
|
*/
|
|
public function registerTranslations()
|
|
{
|
|
$this->loadJsonTranslationsFrom(__DIR__ .'/../Resources/lang');
|
|
}
|
|
|
|
/**
|
|
* Register an additional directory of factories.
|
|
* @source https://github.com/sebastiaanluca/laravel-resource-flow/blob/develop/src/Modules/ModuleServiceProvider.php#L66
|
|
*/
|
|
public function registerFactories()
|
|
{
|
|
if (! app()->environment('production')) {
|
|
app(Factory::class)->load(__DIR__ . '/../Database/factories');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Get the services provided by the provider.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function provides()
|
|
{
|
|
return [];
|
|
}
|
|
|
|
public static function getPluginOption( $key ) {
|
|
return \Option::get( EUP_MODULE . '.' . $key );
|
|
}
|
|
|
|
public static function getPluginOptionName( $key ) {
|
|
return EUP_MODULE . '.' . $key;
|
|
}
|
|
|
|
public static function getOauthEndpoints() {
|
|
$serverUrl = self::getPluginOption( 'portal_server_url' );
|
|
if ( ! $serverUrl ) {
|
|
return null;
|
|
}
|
|
|
|
// Fetch custom API info from the server
|
|
$client = new \GuzzleHttp\Client();
|
|
try {
|
|
$response = $client->get( $serverUrl . '/api/meta' );
|
|
$data = json_decode( $response->getBody(), true );
|
|
} catch ( Exception $e ) {
|
|
Log::error( 'Failed to fetch custom API info: ' . $e->getMessage() );
|
|
|
|
return null;
|
|
}
|
|
|
|
// Parse the data
|
|
if (!isset($data['plugins']['dashboard']['meta']['subdomain']) || !is_string($data['plugins']['dashboard']['meta']['subdomain'])) {
|
|
Log::error('Invalid or missing subdomain in API response');
|
|
return null;
|
|
}
|
|
|
|
$subdomain = $data['plugins']['dashboard']['meta']['subdomain'];
|
|
$domain = parse_url($serverUrl, PHP_URL_HOST);
|
|
|
|
// Construct the OAuth endpoints
|
|
$endpoints = [
|
|
'authorize_url' => "https://{$subdomain}.{$domain}/api/account/support/oauth/authorize",
|
|
'token_url' => "https://{$subdomain}.{$domain}/api/account/support/oauth/token",
|
|
'userinfo_url' => "https://{$subdomain}.{$domain}/api/account/support/oauth/userinfo",
|
|
];
|
|
|
|
return $endpoints;
|
|
}
|
|
}
|