From b0b6ab2c512de1e108f7484a37a9c6fc67302e56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Jaussoin?= Date: Tue, 13 May 2025 08:46:46 +0000 Subject: [PATCH] Fix FLEXIAPI-224 Add a console script to send Space Expiration emails --- CHANGELOG.md | 1 + RELEASE.md | 4 +- cron/flexiapi.debian | 3 +- cron/flexiapi.redhat | 3 +- .../Commands/Accounts/CreateAdminAccount.php | 1 - .../Commands/Spaces/ExpirationEmails.php | 57 +++++++++++++++++++ flexiapi/app/Mail/ExpiringSpace.php | 36 ++++++++++++ flexiapi/app/Space.php | 4 +- flexiapi/lang/fr.json | 1 + .../admin/account/activity/index.blade.php | 2 +- .../views/admin/space/index.blade.php | 5 ++ .../views/mails/expiring_space.blade.php | 14 +++++ flexiapi/routes/web.php | 12 ++-- 13 files changed, 129 insertions(+), 14 deletions(-) create mode 100644 flexiapi/app/Console/Commands/Spaces/ExpirationEmails.php create mode 100644 flexiapi/app/Mail/ExpiringSpace.php create mode 100644 flexiapi/resources/views/mails/expiring_space.blade.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 48de210..ebfad49 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -35,6 +35,7 @@ v1.7 - Fix FLEXIAPI-287 Refactor the emails templates - Fix FLEXIAPI-286 Send an account_recovery_token using a push notification and protect the account recovery using phone page with the account_recovery_token - Fix FLEXIAPI-293 Remove the (long) outdated general documentation +- Fix FLEXIAPI-224 Add a console script to send Space Expiration emails v1.6 ---- diff --git a/RELEASE.md b/RELEASE.md index 631facf..cf88373 100644 --- a/RELEASE.md +++ b/RELEASE.md @@ -61,9 +61,9 @@ php artisan spaces:create-update beta.sip beta.myhost.com "Beta Space" 5. Configure your Spaces. -6. Remove the instance based environnement variables (see **Changed** above) and configure them directly in the spaces using the API or Web Panel. +6. (Optional) Import the old instance DotEnv environnement variables into a space. -7. (Optional) Import the old instance DotEnv environnement variables into a space. +7. Remove the instance based environnement variables (see **Changed** above) and configure them directly in the spaces using the API or Web Panel. ⚠️ Be careful, during this import only the project DotEnv file variables will be imported, other environnement (eg. set in Apache, nginx or Docker) will be ignored. diff --git a/cron/flexiapi.debian b/cron/flexiapi.debian index 465e607..73a4447 100644 --- a/cron/flexiapi.debian +++ b/cron/flexiapi.debian @@ -4,4 +4,5 @@ cd /opt/belledonne-communications/share/flexisip-account-manager/flexiapi/ sudo -su www-data && php artisan digest:clear-nonces 60 sudo -su www-data && php artisan accounts:clear-api-keys 60 sudo -su www-data && php artisan accounts:clear-accounts-tombstones 7 --apply -sudo -su www-data && php artisan accounts:clear-unconfirmed 30 --apply \ No newline at end of file +sudo -su www-data && php artisan accounts:clear-unconfirmed 30 --apply +sudo -su www-data && php artisan spaces:expiration-emails diff --git a/cron/flexiapi.redhat b/cron/flexiapi.redhat index 87d9785..af3c529 100644 --- a/cron/flexiapi.redhat +++ b/cron/flexiapi.redhat @@ -4,4 +4,5 @@ cd /opt/belledonne-communications/share/flexisip-account-manager/flexiapi/ php artisan digest:clear-nonces 60 php artisan accounts:clear-api-keys 60 php artisan accounts:clear-accounts-tombstones 7 --apply -php artisan accounts:clear-unconfirmed 30 --apply \ No newline at end of file +php artisan accounts:clear-unconfirmed 30 --apply +php artisan spaces:expiration-emails \ No newline at end of file diff --git a/flexiapi/app/Console/Commands/Accounts/CreateAdminAccount.php b/flexiapi/app/Console/Commands/Accounts/CreateAdminAccount.php index fc74c29..7f18f58 100644 --- a/flexiapi/app/Console/Commands/Accounts/CreateAdminAccount.php +++ b/flexiapi/app/Console/Commands/Accounts/CreateAdminAccount.php @@ -80,7 +80,6 @@ class CreateAdminAccount extends Command $account = new Account; $account->username = $username; $account->domain = $domain; - $account->email = 'admin_test@sip.example.org'; $account->activated = true; $account->user_agent = 'Test'; $account->ip_address = '0.0.0.0'; diff --git a/flexiapi/app/Console/Commands/Spaces/ExpirationEmails.php b/flexiapi/app/Console/Commands/Spaces/ExpirationEmails.php new file mode 100644 index 0000000..a2e501b --- /dev/null +++ b/flexiapi/app/Console/Commands/Spaces/ExpirationEmails.php @@ -0,0 +1,57 @@ +argument('days')) { + preg_match_all('/\d++/', $this->argument('days'), $matches); + + if (!empty($matches[0])) { + $i = 0; + + while ($i + 1 < count($matches[0]) && (int)$matches[0][$i] > (int)$matches[0][$i + 1]) { + $i++; + } + + if ($i != count($matches[0]) - 1) { + $this->error('The days must be integer, ordered descending and comma separated'); + + return Command::FAILURE; + } + + $days = $matches[0]; + } + } + + $expiringSpaces = Space::whereNotNull('expire_at')->whereDate('expire_at', '>=', Carbon::now())->get(); + + foreach ($expiringSpaces as $expiringSpace) { + if (in_array($expiringSpace->daysLeft, $days)) { + $this->info($expiringSpace->name . ' (' . $expiringSpace->host . ') is expiring in ' . $expiringSpace->daysLeft . ' days'); + + $admins = $expiringSpace->admins()->withoutGlobalScopes()->whereNotNull('email')->get(); + + $this->info('Sending an email to the admins ' . $admins->implode('email', ',')); + + foreach ($admins as $admin) { + Mail::to($admin->email)->send(new ExpiringSpace($expiringSpace)); + } + } + } + } +} diff --git a/flexiapi/app/Mail/ExpiringSpace.php b/flexiapi/app/Mail/ExpiringSpace.php new file mode 100644 index 0000000..a692eb7 --- /dev/null +++ b/flexiapi/app/Mail/ExpiringSpace.php @@ -0,0 +1,36 @@ +space->name . ': '. __('Space is expiring in :days days', ['days' => $this->space->daysLeft]), + ); + } + + public function content(): Content + { + return new Content( + markdown: 'mails.expiring_space', + ); + } +} diff --git a/flexiapi/app/Space.php b/flexiapi/app/Space.php index b1ba02a..ede66ba 100644 --- a/flexiapi/app/Space.php +++ b/flexiapi/app/Space.php @@ -66,7 +66,7 @@ class Space extends Model ]; public const HOST_REGEX = '[\w\-]+'; - public const DOMAIN_REGEX = '(?=^.{4,253}$)(^((?!-)[a-zA-Z0-9-]{1,63}(?expire_at != null) { - return (int)$this->expire_at->diffInDays(Carbon::now()); + return (int)$this->expire_at->diffInDays(Carbon::now()) + 1; } return null; diff --git a/flexiapi/lang/fr.json b/flexiapi/lang/fr.json index 4895735..a751967 100644 --- a/flexiapi/lang/fr.json +++ b/flexiapi/lang/fr.json @@ -167,6 +167,7 @@ "Sip Adress": "Adresse SIP", "SIP Domain": "Domaine SIP", "Space": "Espace", + "Space is expiring in :days days": "Votre Espace expire dans %d jours", "Spaces": "Espaces", "Statistics": "Statistiques", "Subdomain": "Sous-domaine", diff --git a/flexiapi/resources/views/admin/account/activity/index.blade.php b/flexiapi/resources/views/admin/account/activity/index.blade.php index e4fe0ba..dec7e36 100644 --- a/flexiapi/resources/views/admin/account/activity/index.blade.php +++ b/flexiapi/resources/views/admin/account/activity/index.blade.php @@ -74,7 +74,7 @@ @endif - @if ($account->accountRecoveryTokens) + @if ($account->accountRecoveryTokens->isNotEmpty())

Account Recovery Tokens

diff --git a/flexiapi/resources/views/admin/space/index.blade.php b/flexiapi/resources/views/admin/space/index.blade.php index 47b2a95..7c20acf 100644 --- a/flexiapi/resources/views/admin/space/index.blade.php +++ b/flexiapi/resources/views/admin/space/index.blade.php @@ -40,6 +40,11 @@ @else infinity @endif + + @if ($space->expire_at) +
+ {{ $space->expire_at->format('d-m-Y') }} + @endif @endforeach diff --git a/flexiapi/resources/views/mails/expiring_space.blade.php b/flexiapi/resources/views/mails/expiring_space.blade.php new file mode 100644 index 0000000..54ae2d1 --- /dev/null +++ b/flexiapi/resources/views/mails/expiring_space.blade.php @@ -0,0 +1,14 @@ +@extends('mails.layout') + +@section('content') +# {{ $space->name }} is expiring in {{ $space->daysLeft }} days + +You are one of the administrator of the {{ $space->name }} space configured on our service. + +We inform you that this Space is officialy expiring on **{{ $space->expire_at->format('d-m-Y') }}**. + +After that day you and your registered users will not be able to use the features provided by your subscription anymore. + +Be sure to renew your subscription if you would like to continue to use our services. + +@endsection diff --git a/flexiapi/routes/web.php b/flexiapi/routes/web.php index 682cd9d..5f9ac18 100644 --- a/flexiapi/routes/web.php +++ b/flexiapi/routes/web.php @@ -203,6 +203,12 @@ Route::middleware(['web_panel_enabled', 'space.check'])->group(function () { }); Route::name('account.')->prefix('accounts')->group(function () { + Route::name('import.')->prefix('import')->controller(AccountImportController::class)->group(function () { + Route::get('/', 'create')->name('create'); + Route::post('/', 'store')->name('store'); + Route::post('handle', 'handle')->name('handle'); + }); + Route::middleware(['intercom_features'])->group(function () { Route::name('type.')->prefix('types')->controller(AccountTypeController::class)->group(function () { Route::get('/', 'index')->name('index'); @@ -260,12 +266,6 @@ Route::middleware(['web_panel_enabled', 'space.check'])->group(function () { Route::get('send', 'send')->name('send'); }); - Route::name('import.')->prefix('import')->controller(AccountImportController::class)->group(function () { - Route::get('/', 'create')->name('create'); - Route::post('/', 'store')->name('store'); - Route::post('handle', 'handle')->name('handle'); - }); - Route::name('contact.')->prefix('{account}/contacts')->controller(AccountContactController::class)->group(function () { Route::get('/', 'index')->name('index'); Route::get('create', 'create')->name('create');