Merge branch 'master' of github.com:freescout-helpdesk/freescout into dist

pull/814/head 1.6.2
FreeScout 4 years ago
commit fbf88be324

1
.gitignore vendored

@ -27,6 +27,7 @@ Thumbs.db
/Modules
/Modules/**/.git
/public/modules
/public/docs
/storage/.ignore_locales
/storage/.installed
/tools

@ -56,7 +56,9 @@ Need anything else? Suggest features [here](https://freescout.net/request-featur
## Mobile Apps
<a href="https://freescout.net/android-app/" target="_blank"><img alt="Android App" src="https://freescout-helpdesk.github.io/img/apps/android.png" width="200px" /></a>
<a href="https://freescout.net/android-app/" target="_blank" rel="nofollow"><img alt="Android App" src="https://freescout-helpdesk.github.io/img/apps/android.png" width="200px" /></a>
<a href="https://freescout.net/ios-app/" target="_blank" rel="nofollow"><img alt="iOS App" src="https://freescout-helpdesk.github.io/img/apps/ios.png?v=1" width="200px" /></a>
## Modules

@ -645,6 +645,7 @@ class Customer extends Model
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 @@ class Customer extends Model
*/
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 @@ class Customer extends Model
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 @@ class Customer extends Model
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 @@ class Customer extends Model
$email_obj->save();
}
// Todo: check phone uniqueness.
if ($new) {
\Eventy::action('customer.created', $customer);
}
@ -803,6 +872,11 @@ class Customer extends Model
{
$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 @@ class Customer extends Model
}
// 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 @@ class Customer extends Model
}
/**
* 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 @@ class Customer extends Model
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.
*

@ -69,4 +69,19 @@ class Email extends Model
{
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;
}
}
}

@ -311,7 +311,7 @@ class ModulesController extends Controller
$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 @@ class ModulesController extends Controller
}
}
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' => '<strong>'.$msg.'</strong><pre class="margin-top">'.$output.'</pre>',

@ -46,6 +46,7 @@ class SystemController extends Controller
// 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,
];

@ -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',
// ],
];
/**

@ -1363,4 +1363,9 @@ class Helper
{
return (bool)app('request')->input('print');
}
public static function isDev()
{
return config('app.env') != 'production';
}
}

@ -66,7 +66,7 @@ class Mail
'regex:/<div style="border:none;border\-top:solid \#[A-Z0-9]{6} 1\.0pt;padding:3\.0pt 0in 0in 0in">[^<]*<p class="MsoNormal"><b>/', // MS Outlook
// General separators.
'<blockquote', // General sepator
'regex:/<blockquote((?!quote)[^>])*>/', // General sepator. Should skip Gmail's <blockquote class="gmail_quote">.
'<!-- originalMessage -->',
' Original Message ',
'--------------- Original Message ---------------',

@ -78,8 +78,8 @@ class PolycastServiceProvider extends ServiceProvider
$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);

@ -35,7 +35,7 @@ class RouteServiceProvider extends ServiceProvider
*/
public function map()
{
$this->mapApiRoutes();
//$this->mapApiRoutes();
$this->mapWebRoutes();
@ -71,11 +71,11 @@ class RouteServiceProvider extends ServiceProvider
*
* @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'));
// }
}

@ -12,7 +12,7 @@ return [
| or any other location as required by the application or its packages.
*/
'version' => '1.6.1',
'version' => '1.6.2',
/*
|--------------------------------------------------------------------------

@ -41,10 +41,10 @@ return [
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
// 'api' => [
// 'driver' => 'token',
// 'provider' => 'users',
// ],
],
/*

@ -8,9 +8,11 @@
<div class="flexy-item">
<span class="heading">{{ __('Mailboxes') }}</span>
</div>
<div class="flexy-item margin-left">
<a href="{{ route('mailboxes.create') }}" class="btn btn-bordered">{{ __('New Mailbox') }}</a>
</div>
@if (Auth::user()->isAdmin())
<div class="flexy-item margin-left">
<a href="{{ route('mailboxes.create') }}" class="btn btn-bordered">{{ __('New Mailbox') }}</a>
</div>
@endif
<div class="flexy-block"></div>
</div>

@ -53,7 +53,7 @@
<div class="col-xs-12 margin-top">
<h3> {{ __('Access Settings') }}:</h3>
</div>
<div class="col-md-11 col-lg-9">
<div class="col-md-11 col-lg-9" style="overflow-x: auto;">
<table class="table">
<tr class="table-header-nb">
@ -73,11 +73,11 @@
@endif
</td>
<td class="text-center"><input type="checkbox" name="managers[{{ $mailbox_user->id }}][hide]" value="1" @if (!empty($mailbox_user->hide)) checked="checked" @endif></td>
@foreach (\App\Mailbox::$access_permissions as $perm)
<td class="text-center">
@if (!$mailbox_user->isAdmin())
<input type="checkbox" name="managers[{{ $mailbox_user->id }}][access][{{ $perm }}]" value="{{ $perm }}" @if (count($managers) > 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/>
<input type="checkbox" name="managers[{{ $mailbox_user->id }}][access][{{ $perm }}]" value="{{ $perm }}" @if (count($managers) > 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
<input type="checkbox" name="" value="" checked="checked" disabled />
@endif

@ -34,7 +34,7 @@
</th>
<td class="text-center">{{ __('Email') }}<br/><input type="checkbox" class="sel-all" value="email"></td>
<td class="text-center">{{ __('Browser') }}<br/><input type="checkbox" class="sel-all" value="browser"></td>
<td class="text-center">{{ __('Mobile') }}<br/><small>(<a href="https://freescout.net/module/mobile-notifications/" target="_blank">Android</a>)</small><br/><input type="checkbox" class="sel-all" @if (!$mobile_available) disabled="disabled" @endif value="mobile"></td>
<td class="text-center">{{ __('Mobile') }}<br/><small>(<a href="https://freescout.net/module/mobile-notifications/" target="_blank">Android</a> / <a href="https://freescout.net/ios-app/" target="_blank">iOS</a>)</small><br/><input type="checkbox" class="sel-all" @if (!$mobile_available) disabled="disabled" @endif value="mobile"></td>
</tr>
<tr>
<td>{{ __('There is a new conversation') }}</td>

@ -53,14 +53,14 @@
</div>
@endif
@if ($user->invite_state == App\User::INVITE_STATE_ACTIVATED)
@if (auth()->user()->isAdmin() && $user->invite_state == App\User::INVITE_STATE_ACTIVATED)
<div class="form-group{{ $errors->has('disabled') ? ' has-error' : '' }}">
<label for="disabled" class="col-sm-2 control-label">{{ __('Disabled') }}</label>
<div class="col-sm-6">
<div class="controls">
<label for="user_disabled" class="checkbox inline plain"><input type="checkbox" name="disabled" value="{{ App\User::STATUS_DISABLED }}" id="user_disabled" @if (old('disabled', $user->status) == App\User::STATUS_DISABLED)checked="checked"@endif> {{ __('Prevent user from logging in') }}</label>
<label for="user_disabled" class="checkbox inline plain"><input type="checkbox" name="disabled" value="{{ App\User::STATUS_DISABLED }}" id="user_disabled" @if (old('disabled', $user->status) == App\User::STATUS_DISABLED)checked="checked"@endif> <span class="text-help">{{ __('Prevent user from logging in') }}</span></label>
</div>
@include('partials/field_error', ['field'=>'disabled'])
</div>

@ -1,18 +0,0 @@
<?php
use Illuminate\Http\Request;
/*
|--------------------------------------------------------------------------
| API Routes
|--------------------------------------------------------------------------
|
| Here is where you can register API routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| is assigned the "api" middleware group. Enjoy building your API!
|
*/
Route::middleware('auth:api')->get('/user', function (Request $request) {
return $request->user();
});
Loading…
Cancel
Save