diff --git a/cron/flexiapi.cron b/cron/flexiapi.cron
new file mode 100644
index 0000000..1d1f40e
--- /dev/null
+++ b/cron/flexiapi.cron
@@ -0,0 +1 @@
+* * * * * cd /opt/belledonne-communications/share/flexisip-account-manager/flexiapi/ && php artisan schedule:run >> /dev/null 2>&1
\ No newline at end of file
diff --git a/flexiapi/app/AccountFile.php b/flexiapi/app/AccountFile.php
index 404f28f..25ec6e9 100644
--- a/flexiapi/app/AccountFile.php
+++ b/flexiapi/app/AccountFile.php
@@ -12,8 +12,11 @@ class AccountFile extends Model
public const VOICEMAIL_CONTENTTYPES = ['audio/opus', 'audio/wav'];
public const FILES_PATH = 'files';
- protected $hidden = ['account_id', 'updated_at'];
+ protected $hidden = ['account_id', 'updated_at', 'sending_by_mail_at', 'sent_by_mail_at', 'sending_by_mail_tryouts'];
protected $appends = ['download_url'];
+ protected $casts = [
+ 'uploaded_at' => 'datetime',
+ ];
protected static function booted()
{
@@ -24,7 +27,7 @@ class AccountFile extends Model
public function account()
{
- return $this->belongsTo(Account::class);
+ return $this->belongsTo(Account::class)->withoutGlobalScopes();
}
public function getMaxUploadSizeAttribute(): ?int
diff --git a/flexiapi/app/Console/Commands/Accounts/SendVoicemailsEmails.php b/flexiapi/app/Console/Commands/Accounts/SendVoicemailsEmails.php
new file mode 100644
index 0000000..a5ba5ad
--- /dev/null
+++ b/flexiapi/app/Console/Commands/Accounts/SendVoicemailsEmails.php
@@ -0,0 +1,40 @@
+whereNull('sent_by_mail_at')
+ ->where('sending_by_mail_tryouts', '<', is_int($this->option('tryout'))
+ ? $this->option('tryout')
+ : 3)
+ ->get();
+
+ foreach ($voicemails as $voicemail) {
+ $voicemail->sending_by_mail_at = Carbon::now();
+ $voicemail->save();
+
+ if (Mail::to(users: $voicemail->account)->send(new Voicemail($voicemail))) {
+ $voicemail->sent_by_mail_at = Carbon::now();
+ $this->info('Voicemail sent to ' . $voicemail->account->identifier);
+ } else {
+ $voicemail->sending_by_mail_tryouts++;
+ $this->info('Error sending voicemail to ' . $voicemail->account->identifier);
+ }
+
+ $voicemail->save();
+ }
+ }
+}
diff --git a/flexiapi/app/Mail/ExpiringSpace.php b/flexiapi/app/Mail/ExpiringSpace.php
index b540810..c315a54 100644
--- a/flexiapi/app/Mail/ExpiringSpace.php
+++ b/flexiapi/app/Mail/ExpiringSpace.php
@@ -5,7 +5,6 @@ namespace App\Mail;
use App\Space;
use Illuminate\Bus\Queueable;
-use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
diff --git a/flexiapi/app/Mail/NewsletterRegistration.php b/flexiapi/app/Mail/NewsletterRegistration.php
index bcd590d..b55c8d7 100644
--- a/flexiapi/app/Mail/NewsletterRegistration.php
+++ b/flexiapi/app/Mail/NewsletterRegistration.php
@@ -22,7 +22,6 @@ namespace App\Mail;
use App\Account;
use Illuminate\Bus\Queueable;
-use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
diff --git a/flexiapi/app/Mail/Provisioning.php b/flexiapi/app/Mail/Provisioning.php
index 097dd67..10995ef 100644
--- a/flexiapi/app/Mail/Provisioning.php
+++ b/flexiapi/app/Mail/Provisioning.php
@@ -22,7 +22,6 @@ namespace App\Mail;
use App\Account;
use Illuminate\Bus\Queueable;
-use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
diff --git a/flexiapi/app/Mail/RecoverByCode.php b/flexiapi/app/Mail/RecoverByCode.php
index 16f58ca..5aa0354 100644
--- a/flexiapi/app/Mail/RecoverByCode.php
+++ b/flexiapi/app/Mail/RecoverByCode.php
@@ -22,7 +22,6 @@ namespace App\Mail;
use App\Account;
use Illuminate\Bus\Queueable;
-use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
diff --git a/flexiapi/app/Mail/ResetPassword.php b/flexiapi/app/Mail/ResetPassword.php
index 4abc43a..e045bd7 100644
--- a/flexiapi/app/Mail/ResetPassword.php
+++ b/flexiapi/app/Mail/ResetPassword.php
@@ -20,10 +20,8 @@
namespace App\Mail;
use App\Account;
-use App\ResetPasswordEmailToken;
use Illuminate\Bus\Queueable;
-use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
diff --git a/flexiapi/app/Mail/Voicemail.php b/flexiapi/app/Mail/Voicemail.php
new file mode 100644
index 0000000..2a0e71f
--- /dev/null
+++ b/flexiapi/app/Mail/Voicemail.php
@@ -0,0 +1,40 @@
+accountFile->account->space->name .
+ ': ' .
+ __('New voice message from :sipfrom', ['sipfrom' => $this->accountFile->sip_from]),
+ );
+ }
+
+ public function content(): Content
+ {
+ return new Content(
+ markdown: 'mails.voicemail',
+ );
+ }
+
+ public function attachments(): array
+ {
+ return [];
+ }
+}
diff --git a/flexiapi/database/migrations/2025_10_20_093414_create_account_files_table.php b/flexiapi/database/migrations/2025_10_20_093414_create_account_files_table.php
index 6be05d2..cedde59 100644
--- a/flexiapi/database/migrations/2025_10_20_093414_create_account_files_table.php
+++ b/flexiapi/database/migrations/2025_10_20_093414_create_account_files_table.php
@@ -18,6 +18,9 @@ return new class extends Migration
$table->string('content_type')->index();
$table->text('sip_from')->nullable();
$table->dateTime('uploaded_at')->nullable();
+ $table->dateTime('sending_by_mail_at')->nullable();
+ $table->integer('sending_by_mail_tryouts')->default(0);
+ $table->dateTime('sent_by_mail_at')->nullable();
$table->timestamps();
});
}
diff --git a/flexiapi/lang/fr.json b/flexiapi/lang/fr.json
index 47a70d5..c390f6f 100644
--- a/flexiapi/lang/fr.json
+++ b/flexiapi/lang/fr.json
@@ -145,6 +145,7 @@
"New newsletter subscription": "Nouvelle inscription à votre newsletter",
"New Space": "Nouvel Espace",
"New user": "Nouvel utilisateur",
+ "New voice message from :sipfrom": "Nouveau message vocal de :sipfrom",
"Newsletter registration email address": "Addresse email d'inscription à la liste de diffusion",
"Next": "Suivant",
"No account yet?": "Pas encore de compte ?",
@@ -170,6 +171,7 @@
"QR Code scanning": "Scan de QR Code",
"Realm": "Royaume",
"Recover your account using your email": "Récupérer votre compte avec votre email",
+ "Recorded at": "Enregistré le",
"Register": "Inscription",
"Registrar": "Registrar",
"Registration confirmed": "Confirmation de l'inscription",
diff --git a/flexiapi/phpmd.xml b/flexiapi/phpmd.xml
index 953c29e..0b70f75 100644
--- a/flexiapi/phpmd.xml
+++ b/flexiapi/phpmd.xml
@@ -10,7 +10,6 @@
The Clean Code ruleset contains rules that enforce a clean code base. This includes rules from SOLID and object calisthenics.
-
diff --git a/flexiapi/resources/views/mails/voicemail.blade.php b/flexiapi/resources/views/mails/voicemail.blade.php
new file mode 100644
index 0000000..b727444
--- /dev/null
+++ b/flexiapi/resources/views/mails/voicemail.blade.php
@@ -0,0 +1,14 @@
+@extends('mails.layout')
+
+@section('content')
+# {{ __('New voice message from :sipfrom', ['sipfrom' => $accountFile->sip_from]) }}
+
+{{ __('New voice message') }}
+
+{{ __('From') }}: {{ $accountFile->sip_from }}
+
+{{ __('To') }}: {{ $accountFile->account->identifier }}
+
+{{ __('Recorded at') }}: {{ $accountFile->created_at->toDateTimeString() }}
+
+@endsection
diff --git a/flexiapi/routes/console.php b/flexiapi/routes/console.php
index 75dd0cd..e91e885 100644
--- a/flexiapi/routes/console.php
+++ b/flexiapi/routes/console.php
@@ -1,18 +1,8 @@
comment(Inspiring::quote());
-})->describe('Display an inspiring quote');
+Schedule::command(ClearFiles::class, [7, '--apply'])->daily();
+Schedule::command(SendVoicemailsEmails::class)->everyMinute();
diff --git a/flexisip-account-manager.spec b/flexisip-account-manager.spec
index b3ae4fa..a77dd99 100644
--- a/flexisip-account-manager.spec
+++ b/flexisip-account-manager.spec
@@ -54,6 +54,7 @@ cp flexiapi/composer.json "$RPM_BUILD_ROOT%{opt_dir}/flexiapi"
cp README* "$RPM_BUILD_ROOT%{opt_dir}/"
cp INSTALL* "$RPM_BUILD_ROOT%{opt_dir}/"
mkdir -p $RPM_BUILD_ROOT/etc/cron.daily
+mkdir -p $RPM_BUILD_ROOT/etc/cron.d
mkdir -p $RPM_BUILD_ROOT%{apache_conf_path}
cp httpd/flexisip-account-manager.conf "$RPM_BUILD_ROOT%{apache_conf_path}/"
@@ -66,6 +67,9 @@ cp httpd/flexisip-account-manager.conf "$RPM_BUILD_ROOT%{apache_conf_path}/"
chmod +x "$RPM_BUILD_ROOT/etc/cron.daily/flexiapi.redhat"
%endif
+cp cron/flexiapi.cron "$RPM_BUILD_ROOT/etc/cron.d/"
+chmod +x "$RPM_BUILD_ROOT/etc/cron.d/flexiapi.cron"
+
# POST INSTALLATION
%posttrans
@@ -161,6 +165,7 @@ fi
%exclude %{opt_dir}/flexiapi/storage/
+%config /etc/cron.d/flexiapi.cron
%config(noreplace) %{apache_conf_path}/flexisip-account-manager.conf
%if %{with deb}
%config(noreplace) /etc/cron.daily/flexiapi.debian