From 86c29a89c287f0438bf1cf4a1e4e7616e809cac7 Mon Sep 17 00:00:00 2001 From: FreeScout Date: Fri, 2 Oct 2020 00:19:15 -0700 Subject: [PATCH 01/13] Added proc_open to the list of required functions in System Status --- app/Http/Controllers/SystemController.php | 1 + 1 file changed, 1 insertion(+) diff --git a/app/Http/Controllers/SystemController.php b/app/Http/Controllers/SystemController.php index 2b6794684..b4dc93fdb 100644 --- a/app/Http/Controllers/SystemController.php +++ b/app/Http/Controllers/SystemController.php @@ -46,6 +46,7 @@ public function status(Request $request) // Functions. $functions = [ 'shell_exec (PHP)' => function_exists('shell_exec'), + 'proc_open (PHP)' => function_exists('proc_open'), 'ps (shell)' => function_exists('shell_exec') ? shell_exec('ps') : false, ]; From b4b440f871698ebb62ea5c3d419345075706de35 Mon Sep 17 00:00:00 2001 From: FreeScout Date: Fri, 2 Oct 2020 00:21:42 -0700 Subject: [PATCH 02/13] Hide New Mailbox button from non-admins --- resources/views/mailboxes/mailboxes.blade.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/resources/views/mailboxes/mailboxes.blade.php b/resources/views/mailboxes/mailboxes.blade.php index 25ce0a663..5e847baa2 100644 --- a/resources/views/mailboxes/mailboxes.blade.php +++ b/resources/views/mailboxes/mailboxes.blade.php @@ -8,9 +8,11 @@
{{ __('Mailboxes') }}
- + @if (Auth::user()->isAdmin()) + + @endif
From 7c248803dd001a58af166894861d4c56410b89d5 Mon Sep 17 00:00:00 2001 From: FreeScout Date: Fri, 2 Oct 2020 00:24:31 -0700 Subject: [PATCH 03/13] Do no show Disable User checkbox to non-admins --- resources/views/users/profile.blade.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/resources/views/users/profile.blade.php b/resources/views/users/profile.blade.php index 8012316a9..5ffeb87d1 100644 --- a/resources/views/users/profile.blade.php +++ b/resources/views/users/profile.blade.php @@ -53,14 +53,14 @@ @endif - @if ($user->invite_state == App\User::INVITE_STATE_ACTIVATED) + @if (auth()->user()->isAdmin() && $user->invite_state == App\User::INVITE_STATE_ACTIVATED)
- +
@include('partials/field_error', ['field'=>'disabled'])
From 13ad09022b2cdae0b8edabc836a6cc30eb128398 Mon Sep 17 00:00:00 2001 From: FreeScout Date: Fri, 2 Oct 2020 01:00:47 -0700 Subject: [PATCH 04/13] Fix in_array() expects parameter 2 to be array in BroadcastNotification - closes #761 --- app/Providers/PolycastServiceProvider.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Providers/PolycastServiceProvider.php b/app/Providers/PolycastServiceProvider.php index 3e4b01dc1..8d45c6074 100644 --- a/app/Providers/PolycastServiceProvider.php +++ b/app/Providers/PolycastServiceProvider.php @@ -78,8 +78,8 @@ public function boot() $payload = $collection->map(function ($item, $key) use ($request) { $created = \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $item->created_at); $requested = \Carbon\Carbon::createFromFormat('Y-m-d H:i:s', $request->get('time')); - $item->channels = json_decode($item->channels); - $item->payload = json_decode($item->payload); + $item->channels = json_decode($item->channels, false); + $item->payload = json_decode($item->payload, false); // Add extra data to the payload // This works only if payload has medius and thread_id $item->data = BroadcastNotification::fetchPayloadData($item->payload); From fde1e9610466cc0a508f0192acad8824718bb17a Mon Sep 17 00:00:00 2001 From: FreeScout Date: Fri, 2 Oct 2020 01:18:13 -0700 Subject: [PATCH 05/13] Do not cut out regular Gmail quotes - closes #778 --- app/Misc/Mail.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Misc/Mail.php b/app/Misc/Mail.php index 3f51c4269..f425500f1 100644 --- a/app/Misc/Mail.php +++ b/app/Misc/Mail.php @@ -66,7 +66,7 @@ class Mail 'regex:/
[^<]*

/', // MS Outlook // General separators. - '])*>/', // General sepator. Should skip Gmail's

. '', '‐‐‐‐‐‐‐ Original Message ‐‐‐‐‐‐‐', '--------------- Original Message ---------------', From 8a667cb8a250d28999bf07b9296c62452db60ffd Mon Sep 17 00:00:00 2001 From: FreeScout Date: Fri, 2 Oct 2020 04:53:12 -0700 Subject: [PATCH 06/13] Run second migration after the module has been activated - closes #773 --- app/Http/Controllers/ModulesController.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/ModulesController.php b/app/Http/Controllers/ModulesController.php index e8aa762a9..eac2302d9 100644 --- a/app/Http/Controllers/ModulesController.php +++ b/app/Http/Controllers/ModulesController.php @@ -311,7 +311,7 @@ public function ajax(Request $request) $type = 'success'; $msg = __('":name" module successfully activated!', ['name' => $name]); } else { - // Deactivate module + // Deactivate the module. \App\Module::setActive($alias, false); \Artisan::call('freescout:clear-cache'); } @@ -327,6 +327,11 @@ public function ajax(Request $request) } } + if ($type == 'success') { + // Migrate again, in case migration did not work in the moment the module was activated. + \Artisan::call('migrate'); + } + // \Session::flash does not work after BufferedOutput $flash = [ 'text' => ''.$msg.'
'.$output.'
', From 2befc5c1729543a5b3be6d411e608b833e3ff078 Mon Sep 17 00:00:00 2001 From: FreeScout Date: Sun, 4 Oct 2020 10:33:08 -0700 Subject: [PATCH 07/13] Helper::isDev() function --- app/Misc/Helper.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/Misc/Helper.php b/app/Misc/Helper.php index a38e9d34b..4cddb8d87 100644 --- a/app/Misc/Helper.php +++ b/app/Misc/Helper.php @@ -1363,4 +1363,9 @@ public static function isPrint() { return (bool)app('request')->input('print'); } + + public static function isDev() + { + return config('app.env') != 'production'; + } } From 7dca17f2aa733c84e8b05a9739fcbfeda1ee5524 Mon Sep 17 00:00:00 2001 From: "M@" Date: Mon, 5 Oct 2020 13:43:37 -0700 Subject: [PATCH 08/13] make permissions manager scrollable on mobile screens --- resources/views/mailboxes/permissions.blade.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/views/mailboxes/permissions.blade.php b/resources/views/mailboxes/permissions.blade.php index 35cb419cb..7740f751d 100644 --- a/resources/views/mailboxes/permissions.blade.php +++ b/resources/views/mailboxes/permissions.blade.php @@ -53,7 +53,7 @@

{{ __('Access Settings') }}:

-
+
@@ -73,11 +73,11 @@ @endif - + @foreach (\App\Mailbox::$access_permissions as $perm) - + From cfa228083d58ebbee9bb0dd83fc6e0064b702479 Mon Sep 17 00:00:00 2001 From: FreeScout Date: Tue, 6 Oct 2020 01:45:22 -0700 Subject: [PATCH 13/13] v1.6.2 --- config/app.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/app.php b/config/app.php index b16930bbc..7f90fed55 100644 --- a/config/app.php +++ b/config/app.php @@ -12,7 +12,7 @@ | or any other location as required by the application or its packages. */ - 'version' => '1.6.1', + 'version' => '1.6.2', /* |--------------------------------------------------------------------------
hide)) checked="checked" @endif> @if (!$mailbox_user->isAdmin()) - 10) data-toggle="tooltip" title="{{ \App\Mailbox::getAccessPermissionName($perm) }}" @endif @if (!empty($mailbox_user->access) && in_array($perm, json_decode($mailbox_user->access))) checked="checked" @endif @if (Auth::id() == $mailbox_user->id && !Auth::user()->isAdmin()) disabled @endif/> + 10) data-toggle="tooltip" title="{{ \App\Mailbox::getAccessPermissionName($perm) }}" @endif @if (!empty($mailbox_user->access) && in_array($perm, json_decode($mailbox_user->access))) checked="checked" @endif @if (Auth::id() == $mailbox_user->id && !Auth::user()->isAdmin()) disabled @endif/> @else @endif From a5c9a8cea6dc9e442a9c7ce945cff51d2f15c205 Mon Sep 17 00:00:00 2001 From: FreeScout Date: Tue, 6 Oct 2020 00:26:50 -0700 Subject: [PATCH 09/13] Improve customer creation function --- app/Customer.php | 140 +++++++++++++++++++++++++++++++++++++++++++---- app/Email.php | 15 +++++ 2 files changed, 145 insertions(+), 10 deletions(-) diff --git a/app/Customer.php b/app/Customer.php index 20e375de3..4440a902f 100644 --- a/app/Customer.php +++ b/app/Customer.php @@ -645,6 +645,7 @@ public function setPhones(array $phones_array) public static function formatPhones(array $phones_array) { $phones = []; + foreach ($phones_array as $phone) { if (is_array($phone)) { if (!empty($phone['value']) && !empty($phone['type']) && in_array($phone['type'], array_keys(self::$phone_types))) { @@ -669,10 +670,17 @@ public static function formatPhones(array $phones_array) */ public function addPhone($phone, $type = self::PHONE_TYPE_WORK) { - $this->setPhones(array_merge( - $this->getPhones(), - [['value' => $phone, 'type' => $type]] - )); + if (is_string($phone)) { + $this->setPhones(array_merge( + $this->getPhones(), + [['value' => $phone, 'type' => $type]] + )); + } else { + $this->setPhones(array_merge( + $this->getPhones(), + [$phone] + )); + } } /** @@ -725,6 +733,9 @@ public function setWebsites(array $websites_array) foreach ($websites_array as $key => $value) { // FILTER_SANITIZE_URL cuts some symbols. //$value = filter_var((string) $value, FILTER_SANITIZE_URL); + if (isset($value['value'])) { + $value = $value['value']; + } if (!preg_match("/http(s)?:\/\//i", $value)) { $value = 'http://'.$value; } @@ -739,10 +750,66 @@ public function setWebsites(array $websites_array) public function addWebsite($website) { $websites = $this->getWebsites(); + if (isset($website['value'])) { + $website = $website['value']; + } array_push($websites, $website); $this->setWebsites($websites); } + /** + * Sanitize social profiles. + * + * @param array $list [description] + * + * @return array [description] + */ + public static function formatSocialProfiles(array $list) + { + $social_profiles = []; + foreach ($list as $social_profile) { + if (is_array($social_profile)) { + if (!empty($social_profile['value']) && !empty($social_profile['type']) + && in_array($social_profile['type'], array_keys(self::$social_types)) + ) { + $social_profiles[] = [ + 'value' => (string) $social_profile['value'], + 'type' => (int) $social_profile['type'], + ]; + } + } else { + $social_profiles[] = [ + 'value' => (string) $social_profile, + 'type' => self::SOCIAL_TYPE_OTHER, + ]; + } + } + + return $social_profiles; + } + + /** + * Set social profiles as JSON. + * + * @param array $websites_array + */ + public function setSocialProfiles(array $sp_array) + { + $sp_array = self::formatSocialProfiles($sp_array); + + // Remove dubplicates. + $list = []; + foreach ($sp_array as $i => $data) { + if (in_array($data['value'], $list)) { + unset($sp_array[$i]); + } else { + $list[] = $data['value']; + } + } + + $this->social_profiles = \Helper::jsonEncodeUtf8($sp_array); + } + /** * Create customer or get existing and fill empty fields. * @@ -789,6 +856,8 @@ public static function create($email, $data = []) $email_obj->save(); } + // Todo: check phone uniqueness. + if ($new) { \Eventy::action('customer.created', $customer); } @@ -803,6 +872,11 @@ public function setData($data, $replace_data = true, $save = false) { $result = false; + // todo: photoUrl. + if (isset($data['photo_url'])) { + unset($data['photo_url']); + } + if ($replace_data) { // Replace data. $this->fill($data); @@ -818,23 +892,57 @@ public function setData($data, $replace_data = true, $save = false) } // Set JSON values. + if (!empty($data['phone'])) { + $this->addPhone($data['phone']); + } foreach ($data as $key => $value) { - if (!in_array($key, $this->json_fields)) { + if (!in_array($key, $this->json_fields) && $key != 'emails') { continue; } - // todo: setChats, setSocialProfiles + // todo: setChats + if ($key == 'emails') { + foreach ($value as $email_data) { + if (!empty($email_data['value'])) { + if (!$this->id) { + $this->save(); + } + $email_created = Email::create($email_data['value'], $this->id, $email_data['type']); + + if ($email_created) { + $result = true; + } + } + } + } if ($key == 'phones') { - foreach ($value as $phone_value) { - $this->addPhone($phone_value); + if (isset($value['value'])) { + $this->addPhone($value); + } else { + foreach ($value as $phone_value) { + $this->addPhone($phone_value); + } } $result = true; } if ($key == 'websites') { - $this->addWebsite($value); + if (is_array($value)) { + foreach ($value as $website) { + $this->addWebsite($website); + } + } else { + $this->addWebsite($value); + } + $result = true; + } + if ($key == 'social_profiles') { + $this->setSocialProfiles($value); $result = true; } } + // Maybe Todo: check phone uniqueness. + // Same phone can be written in many ways, so it's almost useless to chek uniqueness. + if ($save) { $this->save(); } @@ -843,12 +951,14 @@ public function setData($data, $replace_data = true, $save = false) } /** + * Create a customer, email is not required. * For phone conversations. */ public static function createWithoutEmail($data = []) { $customer = new self(); - $customer->fill($data); + $customer->setData($data); + $customer->save(); \Eventy::action('customer.created', $customer); @@ -866,6 +976,16 @@ public function url() return route('customers.update', ['id'=>$this->id]); } + /** + * Get view customer URL. + * + * @return string + */ + public function urlView() + { + return route('customers.conversations', ['id'=>$this->id]); + } + /** * Format date according to customer's timezone. * diff --git a/app/Email.php b/app/Email.php index 751df5794..323bf9137 100644 --- a/app/Email.php +++ b/app/Email.php @@ -69,4 +69,19 @@ public function getNameFromEmail() { return explode('@', $this->email)[0]; } + + public static function create($email, $customer_id, $type = self::TYPE_WORK) + { + try { + $email_obj = new Email(); + $email_obj->email = $email; + $email_obj->type = array_key_exists($type, self::$types) ? $type : self::TYPE_WORK; + $email_obj->customer_id = $customer_id; + $email_obj->save(); + + return $email_obj; + } catch (\Exception $e) { + return null; + } + } } From e237f76b0ffe7679dda2ccc82871816ff5e53001 Mon Sep 17 00:00:00 2001 From: FreeScout Date: Tue, 6 Oct 2020 00:27:32 -0700 Subject: [PATCH 10/13] Remove api routes --- .gitignore | 1 + app/Http/Kernel.php | 9 ++++----- app/Providers/RouteServiceProvider.php | 16 ++++++++-------- config/auth.php | 8 ++++---- routes/api.php | 18 ------------------ 5 files changed, 17 insertions(+), 35 deletions(-) delete mode 100644 routes/api.php diff --git a/.gitignore b/.gitignore index 34874f039..9194ee838 100644 --- a/.gitignore +++ b/.gitignore @@ -27,6 +27,7 @@ Thumbs.db /Modules /Modules/**/.git /public/modules +/public/docs /storage/.ignore_locales /storage/.installed /tools diff --git a/app/Http/Kernel.php b/app/Http/Kernel.php index 444b45b09..cda6a72a7 100644 --- a/app/Http/Kernel.php +++ b/app/Http/Kernel.php @@ -19,7 +19,6 @@ class Kernel extends HttpKernel \App\Http\Middleware\TrimStrings::class, \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class, \App\Http\Middleware\TrustProxies::class, - // todo: These two may need to be moved into 'web' not to be called in 'api'. \App\Http\Middleware\ResponseHeaders::class, \App\Http\Middleware\TerminateHandler::class, ]; @@ -45,10 +44,10 @@ class Kernel extends HttpKernel \App\Http\Middleware\CustomHandle::class, ], - 'api' => [ - 'throttle:60,1', - 'bindings', - ], + // 'api' => [ + // 'throttle:60,1', + // 'bindings', + // ], ]; /** diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php index 0c8275b6a..d4c0f6013 100644 --- a/app/Providers/RouteServiceProvider.php +++ b/app/Providers/RouteServiceProvider.php @@ -35,7 +35,7 @@ public function boot() */ public function map() { - $this->mapApiRoutes(); + //$this->mapApiRoutes(); $this->mapWebRoutes(); @@ -71,11 +71,11 @@ protected function mapWebRoutes() * * @return void */ - protected function mapApiRoutes() - { - Route::prefix('api') - ->middleware('api') - ->namespace($this->namespace) - ->group(base_path('routes/api.php')); - } + // protected function mapApiRoutes() + // { + // Route::prefix('api') + // ->middleware('api') + // ->namespace($this->namespace) + // ->group(base_path('routes/api.php')); + // } } diff --git a/config/auth.php b/config/auth.php index a9264b4a2..c2938a2ac 100644 --- a/config/auth.php +++ b/config/auth.php @@ -41,10 +41,10 @@ 'provider' => 'users', ], - 'api' => [ - 'driver' => 'token', - 'provider' => 'users', - ], + // 'api' => [ + // 'driver' => 'token', + // 'provider' => 'users', + // ], ], /* diff --git a/routes/api.php b/routes/api.php deleted file mode 100644 index c641ca5e5..000000000 --- a/routes/api.php +++ /dev/null @@ -1,18 +0,0 @@ -get('/user', function (Request $request) { - return $request->user(); -}); From 7e24125fe3b820bef80d931f18504f4df22f276e Mon Sep 17 00:00:00 2001 From: FreeScout Date: Tue, 6 Oct 2020 01:07:34 -0700 Subject: [PATCH 11/13] iOS to readme --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 3e78290ff..250808290 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,9 @@ Need anything else? Suggest features [here](https://freescout.net/request-featur ## Mobile Apps -Android App +Android App + +iOS App ## Modules From f25259e78b2b4979aa1fe707cb855d3aa5969a3e Mon Sep 17 00:00:00 2001 From: FreeScout Date: Tue, 6 Oct 2020 01:10:25 -0700 Subject: [PATCH 12/13] iOS app link to the Notifications settings --- resources/views/users/notifications.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/users/notifications.blade.php b/resources/views/users/notifications.blade.php index fa73e2099..e5af0e742 100644 --- a/resources/views/users/notifications.blade.php +++ b/resources/views/users/notifications.blade.php @@ -34,7 +34,7 @@ {{ __('Email') }}
{{ __('Browser') }}
{{ __('Mobile') }}
(Android)
{{ __('Mobile') }}
(Android / iOS)
{{ __('There is a new conversation') }}