1
0
mirror of https://github.com/freescout-helpdesk/freescout.git synced 2025-01-31 20:11:38 +01:00

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

This commit is contained in:
FreeScout 2023-02-01 00:23:40 -08:00
commit f5f88f01a7
18 changed files with 287 additions and 22 deletions

View File

@ -56,7 +56,7 @@ class ClearCache extends Command
}
// This should not be done during installation.
if (\Helper::isInstalled()) {
\App\Jobs\RestartQueueWorker::dispatch()->onQueue('default');
\Helper::queueWorkerRestart();
}
}
}

View File

@ -284,6 +284,26 @@ class FetchEmails extends Command
$this->line('['.date('Y-m-d H:i:s').'] Message-ID is empty, generated artificial Message-ID: '.$message_id);
}
$duplicate_message_id = Thread::where('message_id', $message_id)->first();
// Mailbox has been mentioned in Bcc.
if ($duplicate_message_id) {
$recipients = array_merge(
$this->formatEmailList($message->getTo()),
$this->formatEmailList($message->getCc())
);
if (!in_array(Email::sanitizeEmail($mailbox->email), $recipients)
// Make sure that previous email has been imported into other mailbox.
&& $duplicate_message_id->conversation
&& $duplicate_message_id->conversation->mailbox_id != $mailbox->id
) {
$extra = true;
$duplicate_message_id = null;
}
}
// Gnerate artificial Message-ID if importing same email into several mailboxes.
if ($extra) {
// Generate artificial Message-ID.
@ -292,7 +312,7 @@ class FetchEmails extends Command
}
// Check if message already fetched.
if (Thread::where('message_id', $message_id)->first()) {
if ($duplicate_message_id) {
$this->line('['.date('Y-m-d H:i:s').'] Message with such Message-ID has been fetched before: '.$message_id);
$this->setSeen($message, $mailbox);
return;
@ -561,13 +581,11 @@ class FetchEmails extends Command
}
$to = $this->formatEmailList($message->getTo());
//$to = $mailbox->removeMailboxEmailsFromList($to);
$cc = $this->formatEmailList($message->getCc());
//$cc = $mailbox->removeMailboxEmailsFromList($cc);
// It will always return an empty value as it's Bcc.
$bcc = $this->formatEmailList($message->getBcc());
//$bcc = $mailbox->removeMailboxEmailsFromList($bcc);
// Create customers
$emails = array_merge(
@ -575,6 +593,7 @@ class FetchEmails extends Command
$this->attrToArray($message->getReplyTo()),
$this->attrToArray($message->getTo()),
$this->attrToArray($message->getCc()),
// It will always return an empty value as it's Bcc.
$this->attrToArray($message->getBcc())
);
$this->createCustomers($emails, $mailbox->getEmails());
@ -605,6 +624,7 @@ class FetchEmails extends Command
$recipient_emails = array_unique($this->formatEmailList(array_merge(
$this->attrToArray($message->getTo()),
$this->attrToArray($message->getCc()),
// It will always return an empty value as it's Bcc.
$this->attrToArray($message->getBcc())
)));

View File

@ -150,7 +150,7 @@ class Kernel extends ConsoleKernel
if (count($running_commands) > 1) {
// Stop all queue:work processes.
// queue:work command is stopped by settings a cache key
\Helper::queueWorkRestart();
\Helper::queueWorkerRestart();
// Sometimes processes stuck and just continue running, so we need to kill them.
// Sleep to let processes stop.
sleep(1);

View File

@ -1565,6 +1565,14 @@ class Conversation extends Model
return array_merge($mailbox->getEmails(), $customer_emails);
}
/**
* Is it an email conversation.
*/
public function isEmail()
{
return ($this->type == self::TYPE_EMAIL);
}
/**
* Is it as phone conversation.
*/

View File

@ -786,6 +786,7 @@ class ConversationsController extends Controller
if (!empty($to_array)) {
$customer_email = $to_array[0];
} elseif (!$conversation->customer_email
&& ($conversation->isEmail() || $conversation->isPhone())
&& $conversation->customer_id
&& $conversation->customer
) {

View File

@ -354,7 +354,7 @@ class MailboxesController extends Controller
}
// Sometimes background job continues to use old connection settings.
\Helper::queueWorkRestart();
\Helper::queueWorkerRestart();
\Session::flash('flash_success_floating', __('Connection settings saved!'));

View File

@ -117,7 +117,7 @@ class SystemController extends Controller
} elseif ($running_commands > 1) {
// queue:work command is stopped by settings a cache key
if ($command_name == 'queue:work') {
\Helper::queueWorkRestart();
\Helper::queueWorkerRestart();
$commands[] = [
'name' => $command_name,
'status' => 'error',

View File

@ -20,8 +20,17 @@ class SendAlert implements ShouldQueue
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public $text;
public $title;
/**
* The number of seconds the job can run before timing out.
* fwrite() function in /vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php
* in some cases may stuck and continue infinitely. This blocks queue:work and no other jobs are processed.
* So we need to set the timeout. On timeout the whole queue:work process is being killed by Laravel.
*/
public $timeout = 120;
/**
* Create a new job instance.
*

View File

@ -23,6 +23,14 @@ class SendAutoReply implements ShouldQueue
public $customer;
/**
* The number of seconds the job can run before timing out.
* fwrite() function in /vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php
* in some cases may stuck and continue infinitely. This blocks queue:work and no other jobs are processed.
* So we need to set the timeout. On timeout the whole queue:work process is being killed by Laravel.
*/
public $timeout = 120;
/**
* Create a new job instance.
*

View File

@ -24,6 +24,14 @@ class SendEmailReplyError implements ShouldQueue
public $mailbox;
/**
* The number of seconds the job can run before timing out.
* fwrite() function in /vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php
* in some cases may stuck and continue infinitely. This blocks queue:work and no other jobs are processed.
* So we need to set the timeout. On timeout the whole queue:work process is being killed by Laravel.
*/
public $timeout = 120;
/**
* Create a new job instance.
*

View File

@ -16,15 +16,23 @@ class SendNotificationToUsers implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
// Max retries + 1
public $tries = 168; // One per hour
public $users;
public $conversation;
public $threads;
// Max retries + 1
public $tries = 168; // One per hour
/**
* The number of seconds the job can run before timing out.
* fwrite() function in /vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php
* in some cases may stuck and continue infinitely. This blocks queue:work and no other jobs are processed.
* So we need to set the timeout. On timeout the whole queue:work process is being killed by Laravel.
*/
public $timeout = 120;
/**
* Create a new job instance.
*
@ -32,7 +40,7 @@ class SendNotificationToUsers implements ShouldQueue
*/
public function __construct($users, $conversation, $threads)
{
$this->users = $users;
$this->users = \Eventy::filter('jobs.send_notification_to_users.users', $users);
$this->conversation = $conversation;
$this->threads = $threads;
}

View File

@ -17,9 +17,6 @@ class SendReplyToCustomer implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
// Number of retries + 1
public $tries = 168; // one per hour
public $conversation;
public $threads;
@ -32,6 +29,17 @@ class SendReplyToCustomer implements ShouldQueue
private $message_id = '';
private $customer_email = '';
// Number of retries + 1
public $tries = 168; // one per hour
/**
* The number of seconds the job can run before timing out.
* fwrite() function in /vendor/swiftmailer/swiftmailer/lib/classes/Swift/Transport/StreamBuffer.php
* in some cases may stuck and continue infinitely. This blocks queue:work and no other jobs are processed.
* So we need to set the timeout. On timeout the whole queue:work process is being killed by Laravel.
*/
public $timeout = 120;
/**
* Create a new job instance.
*

View File

@ -1144,9 +1144,17 @@ class Helper
/**
* Stop all queue:work processes.
*/
public static function queueWorkRestart()
public static function queueWorkerRestart()
{
\Cache::forever('illuminate:queue:restart', Carbon::now()->getTimestamp());
// In some systems queue:work runs on a separate file system,
// so those queue:work processes may not get illuminate:queue:restart.
$job_exists = \App\Job::where('queue', 'default')
->where('payload', 'like', '{"displayName":"App\\\\\\\\Jobs\\\\\\\\RestartQueueWorker"%')
->exists();
if (!$job_exists) {
\App\Jobs\RestartQueueWorker::dispatch()->onQueue('default');
}
}
/**

View File

@ -39,6 +39,8 @@ class Mail
const MAIL_ENCRYPTION_TLS = 'tls';
const FETCH_SCHEDULE_EVERY_MINUTE = 1;
const FETCH_SCHEDULE_EVERY_TWO_MINUTES = 2;
const FETCH_SCHEDULE_EVERY_THREE_MINUTES = 3;
const FETCH_SCHEDULE_EVERY_FIVE_MINUTES = 5;
const FETCH_SCHEDULE_EVERY_TEN_MINUTES = 10;
const FETCH_SCHEDULE_EVERY_FIFTEEN_MINUTES = 15;

View File

@ -121,6 +121,7 @@
"Illuminate\\Session\\": "overrides/laravel/framework/src/Illuminate/Session/",
"Carbon\\": "overrides/nesbot/carbon/src/Carbon/",
"Illuminate\\Cache\\": "overrides/laravel/framework/src/Illuminate/Cache/",
"Illuminate\\Config\\": "overrides/laravel/framework/src/Illuminate/Config/",
"Doctrine\\DBAL\\Driver\\": "overrides/doctrine/dbal/lib/Doctrine/DBAL/Driver/",
"Doctrine\\DBAL\\Schema\\": "overrides/doctrine/dbal/lib/Doctrine/DBAL/Schema/",
"Symfony\\Component\\Finder\\Iterator\\": "overrides/symfony/finder/Iterator/",
@ -208,6 +209,7 @@
"vendor/laravel/framework/src/Illuminate/Session/FileSessionHandler.php",
"vendor/nesbot/carbon/src/Carbon/Carbon.php",
"vendor/laravel/framework/src/Illuminate/Cache/Repository.php",
"vendor/laravel/framework/src/Illuminate/Config/Repository.php",
"vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOConnection.php",
"vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOQueryImplementation.php",
"vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php",

View File

@ -18,7 +18,7 @@ return [
| or any other location as required by the application or its packages.
*/
'version' => '1.8.55',
'version' => '1.8.56',
/*
|--------------------------------------------------------------------------
@ -188,12 +188,13 @@ return [
| Checks for new jobs every --sleep seconds.
| If --tries is set and job fails it is being processed right away without any delay.
| --delay parameter does not work to set delays between retry attempts.
| --timeout parameter sets job timeout and is used to avoid queue:work stucking.
|
| Jobs sending emails are retried manually in handle().
| Number of retries is set in each job class.
|-------------------------------------------------------------------------
*/
'queue_work_params' => ['--queue' => 'emails,default', '--sleep' => '5', '--tries' => '1'],
'queue_work_params' => ['--queue' => 'emails,default', '--sleep' => '5', '--tries' => '1', '--timeout' => '1800'],
/*
|--------------------------------------------------------------------------

View File

@ -0,0 +1,180 @@
<?php
namespace Illuminate\Config;
use ArrayAccess;
use Illuminate\Support\Arr;
use Illuminate\Contracts\Config\Repository as ConfigContract;
class Repository implements ArrayAccess, ConfigContract
{
/**
* All of the configuration items.
*
* @var array
*/
protected $items = [];
/**
* Create a new configuration repository.
*
* @param array $items
* @return void
*/
public function __construct(array $items = [])
{
$this->items = $items;
}
/**
* Determine if the given configuration value exists.
*
* @param string $key
* @return bool
*/
public function has($key)
{
return Arr::has($this->items, $key);
}
/**
* Get the specified configuration value.
*
* @param array|string $key
* @param mixed $default
* @return mixed
*/
public function get($key, $default = null)
{
if (is_array($key)) {
return $this->getMany($key);
}
return Arr::get($this->items, $key, $default);
}
/**
* Get many configuration values.
*
* @param array $keys
* @return array
*/
public function getMany($keys)
{
$config = [];
foreach ($keys as $key => $default) {
if (is_numeric($key)) {
list($key, $default) = [$default, null];
}
$config[$key] = Arr::get($this->items, $key, $default);
}
return $config;
}
/**
* Set a given configuration value.
*
* @param array|string $key
* @param mixed $value
* @return void
*/
public function set($key, $value = null)
{
$keys = is_array($key) ? $key : [$key => $value];
foreach ($keys as $key => $value) {
Arr::set($this->items, $key, $value);
}
}
/**
* Prepend a value onto an array configuration value.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function prepend($key, $value)
{
$array = $this->get($key);
array_unshift($array, $value);
$this->set($key, $array);
}
/**
* Push a value onto an array configuration value.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function push($key, $value)
{
$array = $this->get($key);
$array[] = $value;
$this->set($key, $array);
}
/**
* Get all of the configuration items for the application.
*
* @return array
*/
public function all()
{
return $this->items;
}
/**
* Determine if the given configuration option exists.
*
* @param string $key
* @return bool
*/
public function offsetExists($key): bool
{
return $this->has($key);
}
/**
* Get a configuration option.
*
* @param string $key
* @return mixed
*/
#[\ReturnTypeWillChange]
public function offsetGet($key)
{
return $this->get($key);
}
/**
* Set a configuration option.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function offsetSet($key, $value): void
{
$this->set($key, $value);
}
/**
* Unset a configuration option.
*
* @param string $key
* @return void
*/
public function offsetUnset($key): void
{
$this->set($key, null);
}
}

View File

@ -114,10 +114,12 @@
<div class="col-sm-6">
<select id="fetch_schedule" class="form-control input-sized" name="settings[fetch_schedule]">
<option value="{{ \MailHelper::FETCH_SCHEDULE_EVERY_MINUTE }}" @if (old('settings.fetch_schedule', $settings['fetch_schedule']) == \MailHelper::FETCH_SCHEDULE_EVERY_MINUTE)selected="selected"@endif>{{ __('Every minute') }}</option>
<option value="{{ \MailHelper::FETCH_SCHEDULE_EVERY_FIVE_MINUTES }}" @if (old('settings.fetch_schedule', $settings['fetch_schedule']) == \MailHelper::FETCH_SCHEDULE_EVERY_FIVE_MINUTES)selected="selected"@endif>{{ __('Every 5 minutes') }}</option>
<option value="{{ \MailHelper::FETCH_SCHEDULE_EVERY_TEN_MINUTES }}" @if (old('settings.fetch_schedule', $settings['fetch_schedule']) == \MailHelper::FETCH_SCHEDULE_EVERY_TEN_MINUTES)selected="selected"@endif>{{ __('Every 10 minutes') }}</option>
<option value="{{ \MailHelper::FETCH_SCHEDULE_EVERY_FIFTEEN_MINUTES }}" @if (old('settings.fetch_schedule', $settings['fetch_schedule']) == \MailHelper::FETCH_SCHEDULE_EVERY_FIFTEEN_MINUTES)selected="selected"@endif>{{ __('Every 15 minutes') }}</option>
<option value="{{ \MailHelper::FETCH_SCHEDULE_EVERY_THIRTY_MINUTES }}" @if (old('settings.fetch_schedule', $settings['fetch_schedule']) == \MailHelper::FETCH_SCHEDULE_EVERY_THIRTY_MINUTES)selected="selected"@endif>{{ __('Every 30 minutes') }}</option>
<option value="{{ \MailHelper::FETCH_SCHEDULE_EVERY_TWO_MINUTES }}" @if (old('settings.fetch_schedule', $settings['fetch_schedule']) == \MailHelper::FETCH_SCHEDULE_EVERY_TWO_MINUTES)selected="selected"@endif>{{ __('Every :number minutes', ['number' => \MailHelper::FETCH_SCHEDULE_EVERY_TWO_MINUTES]) }}</option>
<option value="{{ \MailHelper::FETCH_SCHEDULE_EVERY_THREE_MINUTES }}" @if (old('settings.fetch_schedule', $settings['fetch_schedule']) == \MailHelper::FETCH_SCHEDULE_EVERY_THREE_MINUTES)selected="selected"@endif>{{ __('Every :number minutes', ['number' => \MailHelper::FETCH_SCHEDULE_EVERY_THREE_MINUTES]) }}</option>
<option value="{{ \MailHelper::FETCH_SCHEDULE_EVERY_FIVE_MINUTES }}" @if (old('settings.fetch_schedule', $settings['fetch_schedule']) == \MailHelper::FETCH_SCHEDULE_EVERY_FIVE_MINUTES)selected="selected"@endif>{{ __('Every :number minutes', ['number' => \MailHelper::FETCH_SCHEDULE_EVERY_FIVE_MINUTES]) }}</option>
<option value="{{ \MailHelper::FETCH_SCHEDULE_EVERY_TEN_MINUTES }}" @if (old('settings.fetch_schedule', $settings['fetch_schedule']) == \MailHelper::FETCH_SCHEDULE_EVERY_TEN_MINUTES)selected="selected"@endif>{{ __('Every :number minutes', ['number' => \MailHelper::FETCH_SCHEDULE_EVERY_TEN_MINUTES]) }}</option>
<option value="{{ \MailHelper::FETCH_SCHEDULE_EVERY_FIFTEEN_MINUTES }}" @if (old('settings.fetch_schedule', $settings['fetch_schedule']) == \MailHelper::FETCH_SCHEDULE_EVERY_FIFTEEN_MINUTES)selected="selected"@endif>{{ __('Every :number minutes', ['number' => \MailHelper::FETCH_SCHEDULE_EVERY_FIFTEEN_MINUTES]) }}</option>
<option value="{{ \MailHelper::FETCH_SCHEDULE_EVERY_THIRTY_MINUTES }}" @if (old('settings.fetch_schedule', $settings['fetch_schedule']) == \MailHelper::FETCH_SCHEDULE_EVERY_THIRTY_MINUTES)selected="selected"@endif>{{ __('Every :number minutes', ['number' => \MailHelper::FETCH_SCHEDULE_EVERY_THIRTY_MINUTES]) }}</option>
<option value="{{ \MailHelper::FETCH_SCHEDULE_HOURLY }}" @if (old('settings.fetch_schedule', $settings['fetch_schedule']) == \MailHelper::FETCH_SCHEDULE_HOURLY)selected="selected"@endif>{{ __('Hourly') }}</option>
</select>
</div>