155 changes: 94 additions & 61 deletions app/Module.php
Original file line number Diff line number Diff line change
Expand Up @@ -401,76 +401,45 @@ public static function updateModule($alias)

// Download new version.
if (!$result['msg']) {
$params = [
'license' => self::getLicense($alias),
'module_alias' => $alias,
'url' => self::getAppUrl(),
];
$license_details = WpApi::getVersion($params);

if (WpApi::$lastError) {
$result['msg'] = WpApi::$lastError['message'];
} elseif (!empty($license_details['code']) && !empty($license_details['message'])) {
$result['msg'] = $license_details['message'];
} elseif (!empty($license_details['required_app_version']) && !\Helper::checkAppVersion($license_details['required_app_version'])) {
$result['msg'] = 'Module requires app version:'.' '.$license_details['required_app_version'];
} elseif (!empty($license_details['download_link'])) {
// Download module.
$module_archive = \Module::getPath().DIRECTORY_SEPARATOR.$alias.'.zip';

try {
\Helper::downloadRemoteFile($license_details['download_link'], $module_archive);
} catch (\Exception $e) {
$result['msg'] = $e->getMessage();
}

if (!file_exists($module_archive)) {
$result['download_error'] = true;
// Check if the module's author is officially recognized
if (self::isOfficial($module->author_url)) {
$params = [
'license' => self::getLicense($alias),
'module_alias' => $alias,
'url' => self::getAppUrl(),
];
$license_details = WpApi::getVersion($params);

if (WpApi::$lastError) {
$result['msg'] = WpApi::$lastError['message'];
} elseif (!empty($license_details['code']) && !empty($license_details['message'])) {
$result['msg'] = $license_details['message'];
} elseif (!empty($license_details['required_app_version']) && !\Helper::checkAppVersion($license_details['required_app_version'])) {
$result['msg'] = 'Module requires app version:'.' '.$license_details['required_app_version'];
} elseif (!empty($license_details['download_link'])) {
// If a download link is available, proceed to update the module from the URL
self::updateFromUrl($module, $license_details['download_link'], $result);
} elseif ($license_details['status'] && $result['msg'] = self::getErrorMessage($license_details['status'])) {
//$result['msg'] = ;
} else {
// Extract.
try {
// Sometimes by some reason Public folder becomes a symlink leading to itself.
// It causes an error during updating process.
// https://github.com/freescout-helpdesk/freescout/issues/2709
$public_folder = $module->getPath().DIRECTORY_SEPARATOR.'Public';
try {
if (is_link($public_folder)) {
unlink($public_folder);
}
} catch (\Exception $e) {
// Do nothing.
}

\Helper::unzip($module_archive, \Module::getPath());
} catch (\Exception $e) {
$result['msg'] = $e->getMessage();
}
// Check if extracted module exists.
\Module::clearCache();
$module = \Module::findByAlias($alias);
if (!$module) {
$result['download_error'] = true;
}
}

// Remove archive.
if (file_exists($module_archive)) {
\File::delete($module_archive);
$result['msg'] = __('Error occurred').': '.json_encode($license_details);
}
} else {
// If the module's author is not officially recognized, check for a direct download link
$latest_version_zip_url = $module->latestVersionZipUrl ?? null;

if ($result['download_error']) {
$result['download_msg'] = __('Error occurred downloading the module. Please :%a_being%download:%a_end% module manually and extract into :folder', ['%a_being%' => '<a href="'.$license_details['download_link'].'" target="_blank">', '%a_end%' => '</a>', 'folder' => '<strong>'.\Module::getPath().'</strong>']);
if (!empty($latest_version_zip_url)) {
// Update the module from the provided ZIP URL
self::updateFromUrl($module, $module->latestVersionZipUrl, $result);
} else {
// If no download link is available, set an error message indicating the module cannot be downloaded
$result['msg'] = __('Error occurred') . ': module not available for download';
}
} elseif ($license_details['status'] && $result['msg'] = self::getErrorMessage($license_details['status'])) {
//$result['msg'] = ;
} else {
$result['msg'] = __('Error occurred').': '.json_encode($license_details);
}
}

// Run post-update instructions.
if (!$result['msg'] && !$result['download_error']) {

$output_log = new BufferedOutput();
\Artisan::call('freescout:module-install', ['module_alias' => $alias], $output_log);
$result['output'] = $output_log->fetch() ?: ' ';
Expand Down Expand Up @@ -500,6 +469,70 @@ public static function updateModule($alias)
return $result;
}

/**
* Updates a module from a given URL.
*
* @param Module $module The module to be updated.
* @param string $url The URL where the new version of the module can be downloaded.
* @param array $result An associative array to store the result of the update operation.
*
* @return void
*/
private static function updateFromUrl($module, $url, &$result)
{
$alias = $module->alias;
// Download module.
$module_archive = \Module::getPath() . DIRECTORY_SEPARATOR . $alias . '.zip';

try {
\Helper::downloadRemoteFile($url, $module_archive);
} catch (\Exception $e) {
$result['msg'] = $e->getMessage();
}

if (! file_exists($module_archive)) {
$result['download_error'] = true;
} else {
// Extract.
try {
// Sometimes by some reason Public folder becomes a symlink leading to itself.
// It causes an error during updating process.
// https://github.com/freescout-helpdesk/freescout/issues/2709
$public_folder = $module->getPath() . DIRECTORY_SEPARATOR . 'Public';
try {
if (is_link($public_folder)) {
unlink($public_folder);
}
} catch (\Exception $e) {
// Do nothing.
}

\Helper::unzip($module_archive, \Module::getPath());
} catch (\Exception $e) {
$result['msg'] = $e->getMessage();
}
// Check if extracted module exists.
\Module::clearCache();
$module = \Module::findByAlias($alias);
if (! $module) {
$result['download_error'] = true;
}
}

// Remove archive.
if (file_exists($module_archive)) {
\File::delete($module_archive);
}

if ($result['download_error']) {
$result['download_msg'] = __('Error occurred downloading the module. Please :%a_being%download:%a_end% module manually and extract into :folder', [
'%a_being%' => '<a href="' . $url . '" target="_blank">',
'%a_end%' => '</a>',
'folder' => '<strong>' . \Module::getPath() . '</strong>',
]);
}
}

public static function getErrorMessage($code, $result = null)
{
$msg = '';
Expand Down
6 changes: 4 additions & 2 deletions app/Policies/ConversationPolicy.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public function view(User $user, Conversation $conversation)
if ($conversation->mailbox->users->contains($user)) {
// Maybe user can see only assigned conversations.
if (!\Eventy::filter('conversation.is_user_assignee', $conversation->user_id == $user->id, $conversation, $user->id)
&& $user->hasManageMailboxPermission($conversation->mailbox_id, Mailbox::ACCESS_PERM_ASSIGNED)
&& $conversation->created_by_user_id != $user->id
&& $user->canSeeOnlyAssignedConversations()
) {
return false;
} else {
Expand All @@ -54,7 +55,8 @@ public function viewCached(User $user, Conversation $conversation)
if ($conversation->mailbox->users_cached->contains($user)) {
// Maybe user can see only assigned conversations.
if (!\Eventy::filter('conversation.is_user_assignee', $conversation->user_id == $user->id, $conversation, $user->id)
&& $user->hasManageMailboxPermission($conversation->mailbox_id, Mailbox::ACCESS_PERM_ASSIGNED)
&& $conversation->created_by_user_id != $user->id
&& $user->canSeeOnlyAssignedConversations()
) {
return false;
} else {
Expand Down
3 changes: 3 additions & 0 deletions app/SendLog.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,9 @@ public function thread()
*/
public static function log($thread_id, $message_id, $email, $mail_type, $status, $customer_id = null, $user_id = null, $status_message = null, $smtp_queue_id = null)
{
// Sanitize status message - remove SMTP username and password.
$status_message = \MailHelper::sanitizeSmtpStatusMessage($status_message);

$send_log = new self();
$send_log->thread_id = $thread_id;
$send_log->message_id = $message_id;
Expand Down
8 changes: 8 additions & 0 deletions app/Subscription.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

namespace App;

use App\Mailbox;
use App\Notifications\BroadcastNotification;
use App\Notifications\WebsiteNotification;
use Illuminate\Database\Eloquent\Model;
Expand Down Expand Up @@ -282,6 +283,13 @@ public static function usersToNotify($event_type, $conversation, $threads, $mail
}
}
//}

// https://github.com/freescout-helpdesk/freescout/issues/3843#issuecomment-1974811457
if ($conversation->user_id != $subscription->user_id
&& $subscription->user->canSeeOnlyAssignedConversations()
) {
continue;
}

if (\Eventy::filter('subscription.filter_out', false, $subscription, $thread)) {
continue;
Expand Down
3 changes: 3 additions & 0 deletions app/Thread.php
Original file line number Diff line number Diff line change
Expand Up @@ -873,6 +873,9 @@ public function updateSendStatusData($new_data)
} else {
$send_status_data = $new_data;
}
if (!empty($send_status_data['msg'])) {
$send_status_data['msg'] = \MailHelper::sanitizeSmtpStatusMessage($send_status_data['msg']);
}
$this->send_status_data = \Helper::jsonEncodeUtf8($send_status_data);
} else {
$this->send_status_data = null;
Expand Down
5 changes: 5 additions & 0 deletions app/User.php
Original file line number Diff line number Diff line change
Expand Up @@ -1227,4 +1227,9 @@ public function setJobTitleAttribute($job_title)
{
$this->attributes['job_title'] = mb_substr($job_title ?? '', 0, 100);
}

public function canSeeOnlyAssignedConversations()
{
return $this->hasManageMailboxPermission(0, Mailbox::ACCESS_PERM_ASSIGNED);
}
}
2 changes: 1 addition & 1 deletion config/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
| or any other location as required by the application or its packages.
*/

'version' => '1.8.122',
'version' => '1.8.123',

/*
|--------------------------------------------------------------------------
Expand Down
2 changes: 1 addition & 1 deletion public/js/summernote/summernote.js
7 changes: 5 additions & 2 deletions resources/lang/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -351,6 +351,7 @@
"Installed Modules": "Nainstalované moduly",
"Installing": "Instaluji",
"Invalid license key": "Neplatný licenční klíč",
"Invalid or missing modules symlinks": "Chybějící nebo neplatné symlinky modulů",
"Invite email has been resent": "E-mail s pozvánkou byl znovu odeslán",
"Invite email has been sent": "E-mail s pozvánkou byl odeslán",
"Invited": "Pozván",
Expand All @@ -373,6 +374,7 @@
"License key has been revoked": "Licenční klíč byl zrušen",
"License key has expired": "Platnost licenčního klíče vypršela",
"License key has not been activated yet": "Licenční klíč ještě nebyl aktivován",
"License key is activated on another domain.": "Licenční klíč je aktivován na jiné doméně.",
"License successfully Deactivated!": "Licence byla úspěšně deaktivována!",
"License successfully activated!": "Licence byla úspěšně aktivována!",
"List": "Seznam",
Expand All @@ -391,6 +393,7 @@
"Logs Monitoring": "Sledování protokolů",
"Logs to monitor": "Protokoly ke sledování",
"Lost internet connection": "Internetové připojení ztraceno",
"Mail Date & Time": "Datum a čas e-mailu",
"Mail From": "Od",
"Mail Settings": "Nastavení e-mailu",
"Mailbox": "Schránka",
Expand Down Expand Up @@ -570,7 +573,6 @@
"Role": "Role",
"Role of the only one administrator can not be changed.": "Roli jediného správce nelze změnit.",
"Roles": "Role",
"Run Workflow": "Spustit pracovní postup",
"Run the following command": "Spusťte následující příkaz",
"Running": "Běží",
"SMTP": "SMTP",
Expand Down Expand Up @@ -714,6 +716,8 @@
"Updating": "Aktualizuji",
"Upload Attachments": "Nahrávání příloh",
"Use 'Deactivate License' link above to transfer license key from another domain": "Pro přenos licenčního klíče z jiné domény použijte tlačítko Deaktivovat licenci.",
"Use actual fetching date and time": "Použít skutečné datum a čas načtení",
"Use date and time from mail headers": "Použít datum a čas načtení z hlavičky e-mailu",
"User": "Uživatel",
"User Permissions": "Uživatelská oprávnění",
"User Setup Problem": "Problém s nastavením uživatele",
Expand Down Expand Up @@ -783,7 +787,6 @@
"auto reply": "automatická odpověď",
"close": "zavřít",
"me": "",
"more": "více",
"none": "žádné",
"on :date": "dne :date",
"or Enter Mailbox Email": "nebo zadejte e-mailovou adresu schránky",
Expand Down
410 changes: 228 additions & 182 deletions resources/lang/es.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions resources/views/conversations/conversations_table.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@
<th class="conv-date">
<span>
<span class="conv-col-sort" data-sort-by="date" data-order="@if ($sorting['sort_by'] == 'date'){{ $sorting['order'] }}@else{{ 'asc' }}@endif">
@if ($folder->type == App\Folder::TYPE_CLOSED){{ __("Closed") }}@elseif ($folder->type == App\Folder::TYPE_DRAFTS){{ __("Last Updated") }}@elseif ($folder->type == App\Folder::TYPE_DELETED){{ __("Deleted") }}@else{{ \Eventy::filter('conversations_table.column_title_date', __("Waiting Since"), $folder) }}@endif @if ($sorting['sort_by'] == 'date' && $sorting['order'] == 'desc')↑@elseif ($sorting['sort_by'] == 'date' && $sorting['order'] == 'asc')↓@elseif ($sorting['sort_by'] == '' && $sorting['order'] =='')↓@endif
@if ($folder->type == App\Folder::TYPE_CLOSED)@php $column_title_date = __("Closed"); @endphp@elseif ($folder->type == App\Folder::TYPE_DRAFTS)@php $column_title_date = __("Last Updated"); @endphp@elseif ($folder->type == App\Folder::TYPE_DELETED)@php $column_title_date = __("Deleted"); @endphp@else@php $column_title_date = \Eventy::filter('conversations_table.column_title_date', __("Waiting Since"), $folder) @endphp@endif{{ $column_title_date }} @if ($sorting['sort_by'] == 'date' && $sorting['order'] == 'desc')↑@elseif ($sorting['sort_by'] == 'date' && $sorting['order'] == 'asc')↓@elseif ($sorting['sort_by'] == '' && $sorting['order'] =='')↓@endif
</a>
</span>
</th>
Expand Down Expand Up @@ -204,7 +204,7 @@
<a href="{{ $conversation->url() }}" title="{{ __('View conversation') }}" @if (!empty($params['target_blank'])) target="_blank" @endif><i>#</i>{{ $conversation->number }}</a>
</td>
<td class="conv-date">
<a href="{{ $conversation->url() }}" @if (!in_array($folder->type, [App\Folder::TYPE_CLOSED, App\Folder::TYPE_DRAFTS, App\Folder::TYPE_DELETED])) data-toggle="tooltip" data-html="true" data-placement="left" title="{{ $conversation->getDateTitle() }}"@else title="{{ __('View conversation') }}" @endif @if (!empty($params['target_blank'])) target="_blank" @endif>{{ $conversation->getWaitingSince($folder) }}</a>
<a href="{{ $conversation->url() }}" @if (!in_array($folder->type, [App\Folder::TYPE_CLOSED, App\Folder::TYPE_DRAFTS, App\Folder::TYPE_DELETED]))@php $conv_date_title = $conversation->getDateTitle(); $conv_waiting_since = $conversation->getWaitingSince($folder); @endphp aria-label="{{ $conv_waiting_since }}" aria-description="{{ $conv_date_title }}" data-toggle="tooltip" data-html="true" data-placement="left" title="{{ $conv_date_title }}"@else title="{{ __('View conversation') }}" @endif @if (!empty($params['target_blank'])) target="_blank" @endif>{{ $conv_waiting_since }}</a>
</td>
</tr>
@action('conversations_table.after_row', $conversation, $columns, $col_counter)
Expand Down
7 changes: 7 additions & 0 deletions resources/views/modules/partials/module_card.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,13 @@
</p>
<div class="module-details">
<span>{{ __('Version') }}: {{ $module['version'] }}</span>
@if (!empty($module['author']))
@if(!empty($module['authorUrl']))
| <a href="{{ $module['authorUrl'] }}" target="_blank">{{$module['author']}}</a>
@else
| {{$module['author']}}
@endif
@endif
@if (!empty($module['detailsUrl']))
| <a href="{{ $module['detailsUrl'] }}" target="_blank">{{ __('View details') }}</a>
@endif
Expand Down