Feature : ajout IMAP gmail pour teste
This commit is contained in:
parent
9440098815
commit
cab2de09ff
@ -264,6 +264,36 @@ class WebmailController extends Controller
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testSmtp(): JsonResponse
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$user = Auth::user();
|
||||||
|
|
||||||
|
if (! $user) {
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Utilisateur non authentifie.',
|
||||||
|
], 401);
|
||||||
|
}
|
||||||
|
|
||||||
|
$result = $this->webmailService->testSmtp($user->loadMissing('mailboxSetting'));
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'data' => $result,
|
||||||
|
'message' => 'Test SMTP envoye avec succes.',
|
||||||
|
]);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
Log::error('Error testing mailbox SMTP: ' . $e->getMessage(), [
|
||||||
|
'exception' => $e,
|
||||||
|
'user_id' => Auth::id(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'message' => 'Une erreur est survenue lors du test SMTP.',
|
||||||
|
'error' => config('app.debug') ? $e->getMessage() : null,
|
||||||
|
], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function mailboxSettings(): JsonResponse
|
public function mailboxSettings(): JsonResponse
|
||||||
{
|
{
|
||||||
$user = Auth::user();
|
$user = Auth::user();
|
||||||
|
|||||||
@ -37,7 +37,7 @@ class WebmailService
|
|||||||
{
|
{
|
||||||
$fromEmail = $user->email ?: config('mail.from.address');
|
$fromEmail = $user->email ?: config('mail.from.address');
|
||||||
$fromName = $user->name ?: config('mail.from.name');
|
$fromName = $user->name ?: config('mail.from.name');
|
||||||
$mailboxSetting = $user->mailboxSetting;
|
$mailboxSetting = $this->resolveMailboxSetting($user);
|
||||||
|
|
||||||
$message = $this->webmailRepository->create([
|
$message = $this->webmailRepository->create([
|
||||||
'user_id' => $user->id,
|
'user_id' => $user->id,
|
||||||
@ -60,6 +60,8 @@ class WebmailService
|
|||||||
try {
|
try {
|
||||||
if ($mailboxSetting instanceof UserMailboxSetting && $mailboxSetting->hasSmtpConfiguration()) {
|
if ($mailboxSetting instanceof UserMailboxSetting && $mailboxSetting->hasSmtpConfiguration()) {
|
||||||
$this->sendUsingUserSmtp($payload, $mailboxSetting, $fromEmail, $fromName);
|
$this->sendUsingUserSmtp($payload, $mailboxSetting, $fromEmail, $fromName);
|
||||||
|
} elseif ($mailboxSetting instanceof UserMailboxSetting) {
|
||||||
|
throw new \RuntimeException('La configuration SMTP utilisateur est incomplete. Renseignez smtp_host, smtp_port, smtp_username et smtp_password dans le parametrage emails.');
|
||||||
} else {
|
} else {
|
||||||
$mailable = new WebmailMessageMail([
|
$mailable = new WebmailMessageMail([
|
||||||
'subject' => $payload['subject'] ?? '',
|
'subject' => $payload['subject'] ?? '',
|
||||||
@ -116,16 +118,51 @@ class WebmailService
|
|||||||
*/
|
*/
|
||||||
public function syncMailbox(User $user, int $limit = 30): array
|
public function syncMailbox(User $user, int $limit = 30): array
|
||||||
{
|
{
|
||||||
$mailboxSetting = $user->mailboxSetting;
|
$mailboxSetting = $this->resolveMailboxSetting($user);
|
||||||
|
|
||||||
if ($mailboxSetting instanceof UserMailboxSetting && $mailboxSetting->hasImapConfiguration()) {
|
if ($mailboxSetting instanceof UserMailboxSetting && $mailboxSetting->hasImapConfiguration()) {
|
||||||
return $this->syncImapInbox($user, $mailboxSetting, $limit);
|
return $this->syncImapInbox($user, $mailboxSetting, $limit);
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $this->syncMailtrapInbox($user, $limit);
|
if ($mailboxSetting instanceof UserMailboxSetting) {
|
||||||
$result['source'] = 'mailtrap';
|
throw new \RuntimeException('La configuration IMAP utilisateur est incomplete. Renseignez imap_host, imap_port, imap_username et imap_password dans le parametrage emails.');
|
||||||
|
}
|
||||||
|
|
||||||
return $result;
|
throw new \RuntimeException('Aucune configuration mailbox utilisateur n\'est enregistree. Configurez votre boite mail dans le parametrage emails.');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array{recipient:string, source:string}
|
||||||
|
*/
|
||||||
|
public function testSmtp(User $user): array
|
||||||
|
{
|
||||||
|
$mailboxSetting = $this->resolveMailboxSetting($user);
|
||||||
|
|
||||||
|
if (! $mailboxSetting instanceof UserMailboxSetting) {
|
||||||
|
throw new \RuntimeException('Aucune configuration mailbox utilisateur n\'est enregistree. Configurez votre boite mail dans le parametrage emails.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! $mailboxSetting->hasSmtpConfiguration()) {
|
||||||
|
throw new \RuntimeException('La configuration SMTP utilisateur est incomplete. Renseignez smtp_host, smtp_port, smtp_username et smtp_password dans le parametrage emails.');
|
||||||
|
}
|
||||||
|
|
||||||
|
$recipient = $this->resolveSmtpTestRecipient($user, $mailboxSetting);
|
||||||
|
$fromEmail = $user->email ?: config('mail.from.address');
|
||||||
|
$fromName = $user->name ?: config('mail.from.name');
|
||||||
|
$timestamp = now()->format('d/m/Y H:i:s');
|
||||||
|
|
||||||
|
$this->sendUsingUserSmtp([
|
||||||
|
'to' => [$recipient],
|
||||||
|
'cc' => [],
|
||||||
|
'bcc' => [],
|
||||||
|
'subject' => 'Test SMTP Thanasoft',
|
||||||
|
'body' => "Ceci est un email de test SMTP envoye depuis Thanasoft le {$timestamp}.",
|
||||||
|
], $mailboxSetting, $fromEmail, $fromName);
|
||||||
|
|
||||||
|
return [
|
||||||
|
'recipient' => $recipient,
|
||||||
|
'source' => 'user_smtp',
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -245,6 +282,38 @@ class WebmailService
|
|||||||
return Str::limit(trim(strip_tags($body)), 160, '...');
|
return Str::limit(trim(strip_tags($body)), 160, '...');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function resolveMailboxSetting(User $user): ?UserMailboxSetting
|
||||||
|
{
|
||||||
|
if ($user->relationLoaded('mailboxSetting')) {
|
||||||
|
$mailboxSetting = $user->mailboxSetting;
|
||||||
|
|
||||||
|
return $mailboxSetting instanceof UserMailboxSetting ? $mailboxSetting : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$mailboxSetting = $user->mailboxSetting()->first();
|
||||||
|
|
||||||
|
return $mailboxSetting instanceof UserMailboxSetting ? $mailboxSetting : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function resolveSmtpTestRecipient(User $user, UserMailboxSetting $mailboxSetting): string
|
||||||
|
{
|
||||||
|
$candidates = [
|
||||||
|
$mailboxSetting->smtp_from_address,
|
||||||
|
$user->email,
|
||||||
|
$mailboxSetting->smtp_username,
|
||||||
|
];
|
||||||
|
|
||||||
|
foreach ($candidates as $candidate) {
|
||||||
|
$email = is_string($candidate) ? trim($candidate) : '';
|
||||||
|
|
||||||
|
if ($email !== '') {
|
||||||
|
return $email;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \RuntimeException('Impossible de determiner l\'adresse de destination du test SMTP. Renseignez smtp_from_address ou l\'email utilisateur.');
|
||||||
|
}
|
||||||
|
|
||||||
private function sendUsingUserSmtp(
|
private function sendUsingUserSmtp(
|
||||||
array $payload,
|
array $payload,
|
||||||
UserMailboxSetting $mailboxSetting,
|
UserMailboxSetting $mailboxSetting,
|
||||||
@ -289,6 +358,7 @@ class WebmailService
|
|||||||
{
|
{
|
||||||
$imported = 0;
|
$imported = 0;
|
||||||
$skipped = 0;
|
$skipped = 0;
|
||||||
|
$syncedSince = $mailboxSetting->last_synced_at?->copy()->subDay();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$clientManager = new ClientManager([
|
$clientManager = new ClientManager([
|
||||||
@ -313,18 +383,21 @@ class WebmailService
|
|||||||
|
|
||||||
$folder = $client->getFolder($mailboxSetting->imap_folder ?: 'INBOX');
|
$folder = $client->getFolder($mailboxSetting->imap_folder ?: 'INBOX');
|
||||||
$query = $folder->query()
|
$query = $folder->query()
|
||||||
->leaveUnread()
|
->all()
|
||||||
->setFetchOrderDesc()
|
->setFetchOrderDesc()
|
||||||
->limit(max(1, $limit));
|
->limit(max(1, $limit));
|
||||||
|
|
||||||
if ($mailboxSetting->last_synced_at) {
|
|
||||||
$query->whereSince($mailboxSetting->last_synced_at->copy()->subDay());
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @var iterable<int, ImapMessage> $messages */
|
/** @var iterable<int, ImapMessage> $messages */
|
||||||
$messages = $query->get();
|
$messages = $query->get();
|
||||||
|
|
||||||
foreach ($messages as $imapMessage) {
|
foreach ($messages as $imapMessage) {
|
||||||
|
$messageDate = $imapMessage->getDate()?->toDate();
|
||||||
|
|
||||||
|
if ($syncedSince && $messageDate && $messageDate->lt($syncedSince)) {
|
||||||
|
$skipped++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
$messageUid = 'imap-' . (string) $imapMessage->getUid();
|
$messageUid = 'imap-' . (string) $imapMessage->getUid();
|
||||||
|
|
||||||
$alreadyExists = WebmailMessage::query()
|
$alreadyExists = WebmailMessage::query()
|
||||||
@ -358,7 +431,7 @@ class WebmailService
|
|||||||
'body' => $body,
|
'body' => $body,
|
||||||
'status' => 'received',
|
'status' => 'received',
|
||||||
'folder' => 'inbox',
|
'folder' => 'inbox',
|
||||||
'received_at' => $imapMessage->getDate()->toDate()->toDateTimeString(),
|
'received_at' => ($messageDate ?? now())->toDateTimeString(),
|
||||||
'attachments' => [],
|
'attachments' => [],
|
||||||
'metadata' => [
|
'metadata' => [
|
||||||
'provider' => 'imap',
|
'provider' => 'imap',
|
||||||
|
|||||||
@ -70,6 +70,7 @@ Route::middleware('auth:sanctum')->group(function () {
|
|||||||
Route::prefix('webmail')->group(function () {
|
Route::prefix('webmail')->group(function () {
|
||||||
Route::get('settings', [WebmailController::class, 'mailboxSettings']);
|
Route::get('settings', [WebmailController::class, 'mailboxSettings']);
|
||||||
Route::put('settings', [WebmailController::class, 'upsertMailboxSettings']);
|
Route::put('settings', [WebmailController::class, 'upsertMailboxSettings']);
|
||||||
|
Route::post('settings/test-smtp', [WebmailController::class, 'testSmtp']);
|
||||||
Route::get('messages/stats', [WebmailController::class, 'stats']);
|
Route::get('messages/stats', [WebmailController::class, 'stats']);
|
||||||
Route::get('messages', [WebmailController::class, 'index']);
|
Route::get('messages', [WebmailController::class, 'index']);
|
||||||
Route::post('messages/send', [WebmailController::class, 'send']);
|
Route::post('messages/send', [WebmailController::class, 'send']);
|
||||||
|
|||||||
@ -0,0 +1,234 @@
|
|||||||
|
<template>
|
||||||
|
<ClientDetailTemplate>
|
||||||
|
<template #button-return>
|
||||||
|
<div class="col-12">
|
||||||
|
<router-link
|
||||||
|
to="/webmailing"
|
||||||
|
class="btn btn-outline-secondary btn-sm mb-3"
|
||||||
|
>
|
||||||
|
<i class="fas fa-arrow-left me-2"></i>Retour au webmail
|
||||||
|
</router-link>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #client-detail-sidebar>
|
||||||
|
<div class="card position-sticky top-1 email-sidebar-card">
|
||||||
|
<div class="card-body text-center">
|
||||||
|
<div class="avatar avatar-xxl position-relative mx-auto mb-3">
|
||||||
|
<div
|
||||||
|
class="avatar-placeholder w-100 border-radius-lg shadow-sm d-flex align-items-center justify-content-center bg-gradient-dark"
|
||||||
|
>
|
||||||
|
<span class="text-white text-lg font-weight-bold">
|
||||||
|
<i class="fas fa-envelope"></i>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<h5 class="mb-1">Paramétrage mailbox</h5>
|
||||||
|
<p class="text-sm text-muted mb-0">
|
||||||
|
Préparer la réception IMAP et l'envoi SMTP avec la même logique
|
||||||
|
visuelle que la création utilisateur.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #client-detail-content>
|
||||||
|
<div v-if="error" class="alert alert-danger text-white">
|
||||||
|
{{ error }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-4">
|
||||||
|
<div class="col-12 col-xl-8">
|
||||||
|
<MailboxSettingsFormPanel
|
||||||
|
:form="form"
|
||||||
|
:disabled="submitDisabled"
|
||||||
|
:sync-disabled="syncDisabled"
|
||||||
|
:smtp-test-disabled="smtpTestDisabled"
|
||||||
|
:submit-label="
|
||||||
|
saving ? 'Enregistrement...' : 'Enregistrer la configuration'
|
||||||
|
"
|
||||||
|
:sync-label="
|
||||||
|
syncing ? 'Synchronisation...' : 'Synchroniser la boîte'
|
||||||
|
"
|
||||||
|
:smtp-test-label="
|
||||||
|
smtpTesting ? 'Test SMTP...' : 'Tester le SMTP'
|
||||||
|
"
|
||||||
|
@update:field="$emit('update:field', $event)"
|
||||||
|
@submit="$emit('submit-settings')"
|
||||||
|
@sync="$emit('sync-mailbox')"
|
||||||
|
@test-smtp="$emit('test-smtp')"
|
||||||
|
@reset="$emit('reset-form')"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-12 col-xl-4">
|
||||||
|
<div class="card email-help-card h-100">
|
||||||
|
<div class="card-header pb-0">
|
||||||
|
<h5 class="mb-1">État de la boîte</h5>
|
||||||
|
<p class="text-sm text-muted mb-0">
|
||||||
|
Vérifier rapidement si le compte est prêt à être utilisé.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="card-body pt-3">
|
||||||
|
<div class="status-block mb-3">
|
||||||
|
<span class="status-block__label">Réception IMAP</span>
|
||||||
|
<span
|
||||||
|
class="badge"
|
||||||
|
:class="
|
||||||
|
settings?.has_imap_configuration
|
||||||
|
? 'bg-gradient-success'
|
||||||
|
: 'bg-gradient-secondary'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
settings?.has_imap_configuration
|
||||||
|
? "Configurée"
|
||||||
|
: "Incomplète"
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-block mb-3">
|
||||||
|
<span class="status-block__label">Envoi SMTP</span>
|
||||||
|
<span
|
||||||
|
class="badge"
|
||||||
|
:class="
|
||||||
|
settings?.has_smtp_configuration
|
||||||
|
? 'bg-gradient-success'
|
||||||
|
: 'bg-gradient-secondary'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
settings?.has_smtp_configuration
|
||||||
|
? "Configurée"
|
||||||
|
: "Incomplète"
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="status-block mb-3">
|
||||||
|
<span class="status-block__label"
|
||||||
|
>Dernière synchronisation</span
|
||||||
|
>
|
||||||
|
<span class="text-sm text-muted">
|
||||||
|
{{ lastSyncedLabel }}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
v-if="settings?.last_sync_error"
|
||||||
|
class="alert alert-warning text-white py-2 px-3 mb-0"
|
||||||
|
>
|
||||||
|
{{ settings.last_sync_error }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="help-block mt-4">
|
||||||
|
<p class="text-sm mb-2">
|
||||||
|
<strong>1.</strong> Renseigner IMAP pour lire les messages.
|
||||||
|
</p>
|
||||||
|
<p class="text-sm mb-2">
|
||||||
|
<strong>2.</strong> Renseigner SMTP pour envoyer depuis
|
||||||
|
l'utilisateur.
|
||||||
|
</p>
|
||||||
|
<p class="text-sm mb-0">
|
||||||
|
<strong>3.</strong> Lancer une synchronisation depuis cette
|
||||||
|
page ou depuis le webmail.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</ClientDetailTemplate>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed } from "vue";
|
||||||
|
import ClientDetailTemplate from "@/components/templates/CRM/ClientDetailTemplate.vue";
|
||||||
|
import MailboxSettingsFormPanel from "@/components/molecules/parametrage/emails/MailboxSettingsFormPanel.vue";
|
||||||
|
import { defineEmits, defineProps } from "vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
form: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
settings: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
error: {
|
||||||
|
type: String,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
submitDisabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
syncDisabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
smtpTestDisabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
saving: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
syncing: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
smtpTesting: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
defineEmits(["update:field", "submit-settings", "sync-mailbox", "test-smtp", "reset-form"]);
|
||||||
|
|
||||||
|
const lastSyncedLabel = computed(() => {
|
||||||
|
if (!props.settings?.last_synced_at) {
|
||||||
|
return "Jamais synchronisée";
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Date(props.settings.last_synced_at).toLocaleString("fr-FR", {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "2-digit",
|
||||||
|
year: "numeric",
|
||||||
|
hour: "2-digit",
|
||||||
|
minute: "2-digit",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.position-sticky {
|
||||||
|
top: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.email-sidebar-card,
|
||||||
|
.email-help-card {
|
||||||
|
border: 0;
|
||||||
|
box-shadow: 0 0 2rem 0 rgba(136, 152, 170, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar-placeholder {
|
||||||
|
width: 100px;
|
||||||
|
height: 100px;
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-block {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.status-block__label {
|
||||||
|
font-size: 0.875rem;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #344767;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@ -0,0 +1,377 @@
|
|||||||
|
<template>
|
||||||
|
<div class="card mailbox-settings-card h-100">
|
||||||
|
<div
|
||||||
|
class="card-header pb-0 d-flex justify-content-between align-items-start"
|
||||||
|
>
|
||||||
|
<div>
|
||||||
|
<h5 class="mb-1">{{ heading }}</h5>
|
||||||
|
<p class="text-sm text-muted mb-0">{{ description }}</p>
|
||||||
|
</div>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-outline-secondary btn-sm mb-0"
|
||||||
|
@click="$emit('reset')"
|
||||||
|
>
|
||||||
|
Réinitialiser
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="card-body pt-3">
|
||||||
|
<div class="mailbox-section">
|
||||||
|
<div class="mailbox-section__head">
|
||||||
|
<div>
|
||||||
|
<h6 class="mb-1">IMAP réception</h6>
|
||||||
|
<p class="text-sm text-muted mb-0">
|
||||||
|
Configuration de lecture des emails de l'utilisateur.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="badge"
|
||||||
|
:class="
|
||||||
|
form.imap_password_configured
|
||||||
|
? 'bg-gradient-success'
|
||||||
|
: 'bg-gradient-secondary'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
form.imap_password_configured
|
||||||
|
? "Mot de passe enregistré"
|
||||||
|
: "Mot de passe non défini"
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-3 mt-1">
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<label class="form-label">Serveur IMAP</label>
|
||||||
|
<SoftInput
|
||||||
|
:model-value="form.imap_host"
|
||||||
|
placeholder="Ex: imap.gmail.com"
|
||||||
|
@update:model-value="updateField('imap_host', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-3">
|
||||||
|
<label class="form-label">Port IMAP</label>
|
||||||
|
<SoftInput
|
||||||
|
:model-value="form.imap_port"
|
||||||
|
type="number"
|
||||||
|
placeholder="993"
|
||||||
|
@update:model-value="updateField('imap_port', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-3">
|
||||||
|
<label class="form-label">Chiffrement</label>
|
||||||
|
<select
|
||||||
|
class="form-select mailbox-select"
|
||||||
|
:value="form.imap_encryption"
|
||||||
|
@change="updateField('imap_encryption', $event.target.value)"
|
||||||
|
>
|
||||||
|
<option value="">Aucun</option>
|
||||||
|
<option value="ssl">SSL</option>
|
||||||
|
<option value="tls">TLS</option>
|
||||||
|
<option value="starttls">STARTTLS</option>
|
||||||
|
<option value="none">none</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<label class="form-label">Utilisateur IMAP</label>
|
||||||
|
<SoftInput
|
||||||
|
:model-value="form.imap_username"
|
||||||
|
placeholder="Ex: user@domaine.com"
|
||||||
|
@update:model-value="updateField('imap_username', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<label class="form-label">Mot de passe IMAP</label>
|
||||||
|
<SoftInput
|
||||||
|
:model-value="form.imap_password"
|
||||||
|
type="password"
|
||||||
|
placeholder="Laisser vide pour conserver"
|
||||||
|
@update:model-value="updateField('imap_password', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<label class="form-label">Dossier</label>
|
||||||
|
<SoftInput
|
||||||
|
:model-value="form.imap_folder"
|
||||||
|
placeholder="INBOX"
|
||||||
|
@update:model-value="updateField('imap_folder', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6 d-flex align-items-end">
|
||||||
|
<label class="mailbox-checkbox mb-0">
|
||||||
|
<input
|
||||||
|
:checked="form.imap_validate_cert"
|
||||||
|
type="checkbox"
|
||||||
|
@change="
|
||||||
|
updateField('imap_validate_cert', $event.target.checked)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<span>Valider le certificat IMAP</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<label class="mailbox-checkbox mb-0">
|
||||||
|
<input
|
||||||
|
:checked="form.clear_imap_password"
|
||||||
|
type="checkbox"
|
||||||
|
@change="
|
||||||
|
updateField('clear_imap_password', $event.target.checked)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<span>Effacer le mot de passe IMAP enregistré</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="mailbox-section mt-4">
|
||||||
|
<div class="mailbox-section__head">
|
||||||
|
<div>
|
||||||
|
<h6 class="mb-1">SMTP envoi</h6>
|
||||||
|
<p class="text-sm text-muted mb-0">
|
||||||
|
Configuration d'envoi au nom de l'utilisateur connecté.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<span
|
||||||
|
class="badge"
|
||||||
|
:class="
|
||||||
|
form.smtp_password_configured
|
||||||
|
? 'bg-gradient-success'
|
||||||
|
: 'bg-gradient-secondary'
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
form.smtp_password_configured
|
||||||
|
? "Mot de passe enregistré"
|
||||||
|
: "Mot de passe non défini"
|
||||||
|
}}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row g-3 mt-1">
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<label class="form-label">Serveur SMTP</label>
|
||||||
|
<SoftInput
|
||||||
|
:model-value="form.smtp_host"
|
||||||
|
placeholder="Ex: smtp.office365.com"
|
||||||
|
@update:model-value="updateField('smtp_host', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-3">
|
||||||
|
<label class="form-label">Port SMTP</label>
|
||||||
|
<SoftInput
|
||||||
|
:model-value="form.smtp_port"
|
||||||
|
type="number"
|
||||||
|
placeholder="587"
|
||||||
|
@update:model-value="updateField('smtp_port', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-3">
|
||||||
|
<label class="form-label">Chiffrement</label>
|
||||||
|
<select
|
||||||
|
class="form-select mailbox-select"
|
||||||
|
:value="form.smtp_encryption"
|
||||||
|
@change="updateField('smtp_encryption', $event.target.value)"
|
||||||
|
>
|
||||||
|
<option value="">Aucun</option>
|
||||||
|
<option value="ssl">SSL</option>
|
||||||
|
<option value="tls">TLS</option>
|
||||||
|
<option value="none">none</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<label class="form-label">Utilisateur SMTP</label>
|
||||||
|
<SoftInput
|
||||||
|
:model-value="form.smtp_username"
|
||||||
|
placeholder="Ex: user@domaine.com"
|
||||||
|
@update:model-value="updateField('smtp_username', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<label class="form-label">Mot de passe SMTP</label>
|
||||||
|
<SoftInput
|
||||||
|
:model-value="form.smtp_password"
|
||||||
|
type="password"
|
||||||
|
placeholder="Laisser vide pour conserver"
|
||||||
|
@update:model-value="updateField('smtp_password', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<label class="form-label">Adresse d'envoi</label>
|
||||||
|
<SoftInput
|
||||||
|
:model-value="form.smtp_from_address"
|
||||||
|
placeholder="Ex: user@domaine.com"
|
||||||
|
@update:model-value="updateField('smtp_from_address', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6">
|
||||||
|
<label class="form-label">Nom d'envoi</label>
|
||||||
|
<SoftInput
|
||||||
|
:model-value="form.smtp_from_name"
|
||||||
|
placeholder="Ex: Jean Dupont"
|
||||||
|
@update:model-value="updateField('smtp_from_name', $event)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6 d-flex align-items-end">
|
||||||
|
<label class="mailbox-checkbox mb-0">
|
||||||
|
<input
|
||||||
|
:checked="form.smtp_validate_cert"
|
||||||
|
type="checkbox"
|
||||||
|
@change="
|
||||||
|
updateField('smtp_validate_cert', $event.target.checked)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<span>Valider le certificat SMTP</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
<div class="col-12">
|
||||||
|
<label class="mailbox-checkbox mb-0">
|
||||||
|
<input
|
||||||
|
:checked="form.clear_smtp_password"
|
||||||
|
type="checkbox"
|
||||||
|
@change="
|
||||||
|
updateField('clear_smtp_password', $event.target.checked)
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<span>Effacer le mot de passe SMTP enregistré</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="d-flex gap-2 mt-4 flex-wrap">
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn bg-gradient-success mb-0"
|
||||||
|
:disabled="disabled"
|
||||||
|
@click="$emit('submit')"
|
||||||
|
>
|
||||||
|
{{ submitLabel }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-outline-info mb-0"
|
||||||
|
:disabled="syncDisabled"
|
||||||
|
@click="$emit('sync')"
|
||||||
|
>
|
||||||
|
{{ syncLabel }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-outline-primary mb-0"
|
||||||
|
:disabled="smtpTestDisabled"
|
||||||
|
@click="$emit('test-smtp')"
|
||||||
|
>
|
||||||
|
{{ smtpTestLabel }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
class="btn btn-outline-secondary mb-0"
|
||||||
|
@click="$emit('reset')"
|
||||||
|
>
|
||||||
|
Annuler
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { defineEmits, defineProps } from "vue";
|
||||||
|
import SoftInput from "@/components/SoftInput.vue";
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
form: {
|
||||||
|
type: Object,
|
||||||
|
required: true,
|
||||||
|
},
|
||||||
|
heading: {
|
||||||
|
type: String,
|
||||||
|
default: "Configurer la boîte mail",
|
||||||
|
},
|
||||||
|
description: {
|
||||||
|
type: String,
|
||||||
|
default: "Renseigner les paramètres de réception IMAP et d'envoi SMTP.",
|
||||||
|
},
|
||||||
|
submitLabel: {
|
||||||
|
type: String,
|
||||||
|
default: "Enregistrer la configuration",
|
||||||
|
},
|
||||||
|
syncLabel: {
|
||||||
|
type: String,
|
||||||
|
default: "Synchroniser la boîte",
|
||||||
|
},
|
||||||
|
smtpTestLabel: {
|
||||||
|
type: String,
|
||||||
|
default: "Tester le SMTP",
|
||||||
|
},
|
||||||
|
disabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
syncDisabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
smtpTestDisabled: {
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const emit = defineEmits(["update:field", "submit", "sync", "test-smtp", "reset"]);
|
||||||
|
|
||||||
|
const updateField = (field, value) => {
|
||||||
|
emit("update:field", { field, value });
|
||||||
|
};
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.mailbox-settings-card {
|
||||||
|
border: 0;
|
||||||
|
box-shadow: 0 0 2rem 0 rgba(136, 152, 170, 0.15);
|
||||||
|
}
|
||||||
|
|
||||||
|
.mailbox-section {
|
||||||
|
padding: 1rem;
|
||||||
|
border: 1px solid rgba(103, 116, 142, 0.15);
|
||||||
|
border-radius: 1rem;
|
||||||
|
background: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mailbox-section__head {
|
||||||
|
display: flex;
|
||||||
|
align-items: flex-start;
|
||||||
|
justify-content: space-between;
|
||||||
|
gap: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mailbox-select {
|
||||||
|
min-height: 40px;
|
||||||
|
border: 1px solid #d2d6da;
|
||||||
|
color: #344767;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mailbox-checkbox {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.65rem;
|
||||||
|
padding: 0.75rem 0.9rem;
|
||||||
|
border-radius: 0.85rem;
|
||||||
|
border: 1px solid rgba(103, 116, 142, 0.15);
|
||||||
|
background: #fff;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
color: #344767;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mailbox-checkbox input {
|
||||||
|
accent-color: #17c1e8;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 991.98px) {
|
||||||
|
.mailbox-section__head {
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
115
thanasoft-front/src/services/mailboxSettings.ts
Normal file
115
thanasoft-front/src/services/mailboxSettings.ts
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
import { request } from "./http";
|
||||||
|
|
||||||
|
export interface MailboxSettings {
|
||||||
|
id: number;
|
||||||
|
user_id: number;
|
||||||
|
imap_host: string | null;
|
||||||
|
imap_port: number | null;
|
||||||
|
imap_encryption: string | null;
|
||||||
|
imap_validate_cert: boolean;
|
||||||
|
imap_username: string | null;
|
||||||
|
imap_folder: string | null;
|
||||||
|
imap_password_configured: boolean;
|
||||||
|
smtp_host: string | null;
|
||||||
|
smtp_port: number | null;
|
||||||
|
smtp_encryption: string | null;
|
||||||
|
smtp_validate_cert: boolean;
|
||||||
|
smtp_username: string | null;
|
||||||
|
smtp_from_address: string | null;
|
||||||
|
smtp_from_name: string | null;
|
||||||
|
smtp_password_configured: boolean;
|
||||||
|
has_imap_configuration: boolean;
|
||||||
|
has_smtp_configuration: boolean;
|
||||||
|
last_synced_at: string | null;
|
||||||
|
last_sync_error: string | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MailboxSettingsResponse {
|
||||||
|
data: MailboxSettings | null;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MailboxSyncResult {
|
||||||
|
imported: number;
|
||||||
|
skipped: number;
|
||||||
|
source: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MailboxSyncResponse {
|
||||||
|
data: MailboxSyncResult;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MailboxSmtpTestResult {
|
||||||
|
recipient: string;
|
||||||
|
source: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface MailboxSmtpTestResponse {
|
||||||
|
data: MailboxSmtpTestResult;
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface UpsertMailboxSettingsPayload {
|
||||||
|
imap_host?: string | null;
|
||||||
|
imap_port?: number | null;
|
||||||
|
imap_encryption?: string | null;
|
||||||
|
imap_validate_cert?: boolean;
|
||||||
|
imap_username?: string | null;
|
||||||
|
imap_password?: string | null;
|
||||||
|
imap_folder?: string | null;
|
||||||
|
smtp_host?: string | null;
|
||||||
|
smtp_port?: number | null;
|
||||||
|
smtp_encryption?: string | null;
|
||||||
|
smtp_validate_cert?: boolean;
|
||||||
|
smtp_username?: string | null;
|
||||||
|
smtp_password?: string | null;
|
||||||
|
smtp_from_address?: string | null;
|
||||||
|
smtp_from_name?: string | null;
|
||||||
|
clear_imap_password?: boolean;
|
||||||
|
clear_smtp_password?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const MailboxSettingsService = {
|
||||||
|
async getMailboxSettings(): Promise<MailboxSettings | null> {
|
||||||
|
const response = await request<MailboxSettingsResponse>({
|
||||||
|
url: "/api/webmail/settings",
|
||||||
|
method: "get",
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
async updateMailboxSettings(
|
||||||
|
payload: UpsertMailboxSettingsPayload
|
||||||
|
): Promise<MailboxSettings | null> {
|
||||||
|
const response = await request<MailboxSettingsResponse>({
|
||||||
|
url: "/api/webmail/settings",
|
||||||
|
method: "put",
|
||||||
|
data: payload,
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
async syncMailbox(limit = 30): Promise<MailboxSyncResult> {
|
||||||
|
const response = await request<MailboxSyncResponse>({
|
||||||
|
url: "/api/webmail/messages/sync",
|
||||||
|
method: "post",
|
||||||
|
params: { limit },
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
|
||||||
|
async testSmtp(): Promise<MailboxSmtpTestResult> {
|
||||||
|
const response = await request<MailboxSmtpTestResponse>({
|
||||||
|
url: "/api/webmail/settings/test-smtp",
|
||||||
|
method: "post",
|
||||||
|
});
|
||||||
|
|
||||||
|
return response.data;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
export default MailboxSettingsService;
|
||||||
117
thanasoft-front/src/stores/mailboxSettingsStore.ts
Normal file
117
thanasoft-front/src/stores/mailboxSettingsStore.ts
Normal file
@ -0,0 +1,117 @@
|
|||||||
|
import { defineStore } from "pinia";
|
||||||
|
import { computed, ref } from "vue";
|
||||||
|
import MailboxSettingsService from "@/services/mailboxSettings";
|
||||||
|
import type {
|
||||||
|
MailboxSettings,
|
||||||
|
MailboxSmtpTestResult,
|
||||||
|
MailboxSyncResult,
|
||||||
|
UpsertMailboxSettingsPayload,
|
||||||
|
} from "@/services/mailboxSettings";
|
||||||
|
|
||||||
|
export const useMailboxSettingsStore = defineStore("mailboxSettings", () => {
|
||||||
|
const loading = ref(false);
|
||||||
|
const saving = ref(false);
|
||||||
|
const syncing = ref(false);
|
||||||
|
const smtpTesting = ref(false);
|
||||||
|
const error = ref<string | null>(null);
|
||||||
|
const settings = ref<MailboxSettings | null>(null);
|
||||||
|
|
||||||
|
const isLoading = computed(() => loading.value);
|
||||||
|
const isSaving = computed(() => saving.value);
|
||||||
|
const isSyncing = computed(() => syncing.value);
|
||||||
|
const isSmtpTesting = computed(() => smtpTesting.value);
|
||||||
|
const currentSettings = computed(() => settings.value);
|
||||||
|
|
||||||
|
const fetchMailboxSettings = async () => {
|
||||||
|
loading.value = true;
|
||||||
|
error.value = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
settings.value = await MailboxSettingsService.getMailboxSettings();
|
||||||
|
return settings.value;
|
||||||
|
} catch (err: any) {
|
||||||
|
error.value =
|
||||||
|
err.response?.data?.message ||
|
||||||
|
err.message ||
|
||||||
|
"Failed to fetch mailbox settings";
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
loading.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const saveMailboxSettings = async (payload: UpsertMailboxSettingsPayload) => {
|
||||||
|
saving.value = true;
|
||||||
|
error.value = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
settings.value = await MailboxSettingsService.updateMailboxSettings(
|
||||||
|
payload
|
||||||
|
);
|
||||||
|
return settings.value;
|
||||||
|
} catch (err: any) {
|
||||||
|
error.value =
|
||||||
|
err.response?.data?.message ||
|
||||||
|
err.message ||
|
||||||
|
"Failed to save mailbox settings";
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
saving.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const syncMailbox = async (limit = 30): Promise<MailboxSyncResult> => {
|
||||||
|
syncing.value = true;
|
||||||
|
error.value = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
const result = await MailboxSettingsService.syncMailbox(limit);
|
||||||
|
await fetchMailboxSettings();
|
||||||
|
return result;
|
||||||
|
} catch (err: any) {
|
||||||
|
error.value =
|
||||||
|
err.response?.data?.message || err.message || "Failed to sync mailbox";
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
syncing.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const testSmtp = async (): Promise<MailboxSmtpTestResult> => {
|
||||||
|
smtpTesting.value = true;
|
||||||
|
error.value = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
return await MailboxSettingsService.testSmtp();
|
||||||
|
} catch (err: any) {
|
||||||
|
error.value =
|
||||||
|
err.response?.data?.error ||
|
||||||
|
err.response?.data?.message ||
|
||||||
|
err.message ||
|
||||||
|
"Failed to test SMTP";
|
||||||
|
throw err;
|
||||||
|
} finally {
|
||||||
|
smtpTesting.value = false;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
loading,
|
||||||
|
saving,
|
||||||
|
syncing,
|
||||||
|
smtpTesting,
|
||||||
|
error,
|
||||||
|
settings,
|
||||||
|
isLoading,
|
||||||
|
isSaving,
|
||||||
|
isSyncing,
|
||||||
|
isSmtpTesting,
|
||||||
|
currentSettings,
|
||||||
|
fetchMailboxSettings,
|
||||||
|
saveMailboxSettings,
|
||||||
|
syncMailbox,
|
||||||
|
testSmtp,
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
export default useMailboxSettingsStore;
|
||||||
@ -1,11 +1,213 @@
|
|||||||
<template>
|
<template>
|
||||||
<div>
|
<EmailSettingsPresentation
|
||||||
<h1>Gestion des emails</h1>
|
:form="form"
|
||||||
</div>
|
:settings="mailboxSettingsStore.currentSettings"
|
||||||
|
:error="pageError"
|
||||||
|
:submit-disabled="submitDisabled"
|
||||||
|
:sync-disabled="syncDisabled"
|
||||||
|
:smtp-test-disabled="smtpTestDisabled"
|
||||||
|
:saving="mailboxSettingsStore.isSaving"
|
||||||
|
:syncing="mailboxSettingsStore.isSyncing"
|
||||||
|
:smtp-testing="mailboxSettingsStore.isSmtpTesting"
|
||||||
|
@update:field="updateField"
|
||||||
|
@submit-settings="submitSettings"
|
||||||
|
@sync-mailbox="syncMailbox"
|
||||||
|
@test-smtp="testSmtp"
|
||||||
|
@reset-form="resetForm"
|
||||||
|
/>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script setup>
|
||||||
export default {
|
import { computed, onMounted, reactive } from "vue";
|
||||||
name: "GestionEmails",
|
import EmailSettingsPresentation from "@/components/Organism/Parametrage/Emails/EmailSettingsPresentation.vue";
|
||||||
|
import { useMailboxSettingsStore } from "@/stores/mailboxSettingsStore";
|
||||||
|
import { useNotificationStore } from "@/stores/notification";
|
||||||
|
|
||||||
|
const mailboxSettingsStore = useMailboxSettingsStore();
|
||||||
|
const notificationStore = useNotificationStore();
|
||||||
|
|
||||||
|
const createDefaultForm = () => ({
|
||||||
|
imap_host: "",
|
||||||
|
imap_port: "",
|
||||||
|
imap_encryption: "ssl",
|
||||||
|
imap_validate_cert: true,
|
||||||
|
imap_username: "",
|
||||||
|
imap_password: "",
|
||||||
|
imap_folder: "INBOX",
|
||||||
|
imap_password_configured: false,
|
||||||
|
clear_imap_password: false,
|
||||||
|
smtp_host: "",
|
||||||
|
smtp_port: "",
|
||||||
|
smtp_encryption: "tls",
|
||||||
|
smtp_validate_cert: true,
|
||||||
|
smtp_username: "",
|
||||||
|
smtp_password: "",
|
||||||
|
smtp_from_address: "",
|
||||||
|
smtp_from_name: "",
|
||||||
|
smtp_password_configured: false,
|
||||||
|
clear_smtp_password: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
const form = reactive(createDefaultForm());
|
||||||
|
|
||||||
|
const pageError = computed(() => mailboxSettingsStore.error);
|
||||||
|
const submitDisabled = computed(
|
||||||
|
() => mailboxSettingsStore.isLoading || mailboxSettingsStore.isSaving
|
||||||
|
);
|
||||||
|
const syncDisabled = computed(
|
||||||
|
() =>
|
||||||
|
mailboxSettingsStore.isLoading ||
|
||||||
|
mailboxSettingsStore.isSaving ||
|
||||||
|
mailboxSettingsStore.isSyncing
|
||||||
|
);
|
||||||
|
const smtpTestDisabled = computed(
|
||||||
|
() =>
|
||||||
|
mailboxSettingsStore.isLoading ||
|
||||||
|
mailboxSettingsStore.isSaving ||
|
||||||
|
mailboxSettingsStore.isSmtpTesting
|
||||||
|
);
|
||||||
|
|
||||||
|
const assignForm = (settings) => {
|
||||||
|
const defaults = createDefaultForm();
|
||||||
|
const source = settings || {};
|
||||||
|
|
||||||
|
Object.assign(form, defaults, {
|
||||||
|
imap_host: source.imap_host || "",
|
||||||
|
imap_port: source.imap_port ? String(source.imap_port) : "",
|
||||||
|
imap_encryption: source.imap_encryption || defaults.imap_encryption,
|
||||||
|
imap_validate_cert:
|
||||||
|
source.imap_validate_cert ?? defaults.imap_validate_cert,
|
||||||
|
imap_username: source.imap_username || "",
|
||||||
|
imap_folder: source.imap_folder || defaults.imap_folder,
|
||||||
|
imap_password_configured: Boolean(source.imap_password_configured),
|
||||||
|
smtp_host: source.smtp_host || "",
|
||||||
|
smtp_port: source.smtp_port ? String(source.smtp_port) : "",
|
||||||
|
smtp_encryption: source.smtp_encryption || defaults.smtp_encryption,
|
||||||
|
smtp_validate_cert:
|
||||||
|
source.smtp_validate_cert ?? defaults.smtp_validate_cert,
|
||||||
|
smtp_username: source.smtp_username || "",
|
||||||
|
smtp_from_address: source.smtp_from_address || "",
|
||||||
|
smtp_from_name: source.smtp_from_name || "",
|
||||||
|
smtp_password_configured: Boolean(source.smtp_password_configured),
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const resetForm = () => {
|
||||||
|
assignForm(mailboxSettingsStore.currentSettings);
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateField = ({ field, value }) => {
|
||||||
|
form[field] = value;
|
||||||
|
|
||||||
|
if (field === "clear_imap_password" && value) {
|
||||||
|
form.imap_password = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (field === "clear_smtp_password" && value) {
|
||||||
|
form.smtp_password = "";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizeString = (value) => {
|
||||||
|
const normalized = String(value || "").trim();
|
||||||
|
return normalized ? normalized : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const normalizePort = (value) => {
|
||||||
|
const normalized = String(value || "").trim();
|
||||||
|
return normalized ? Number(normalized) : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const buildPayload = () => {
|
||||||
|
const payload = {
|
||||||
|
imap_host: normalizeString(form.imap_host),
|
||||||
|
imap_port: normalizePort(form.imap_port),
|
||||||
|
imap_encryption: normalizeString(form.imap_encryption),
|
||||||
|
imap_validate_cert: Boolean(form.imap_validate_cert),
|
||||||
|
imap_username: normalizeString(form.imap_username),
|
||||||
|
imap_folder: normalizeString(form.imap_folder),
|
||||||
|
smtp_host: normalizeString(form.smtp_host),
|
||||||
|
smtp_port: normalizePort(form.smtp_port),
|
||||||
|
smtp_encryption: normalizeString(form.smtp_encryption),
|
||||||
|
smtp_validate_cert: Boolean(form.smtp_validate_cert),
|
||||||
|
smtp_username: normalizeString(form.smtp_username),
|
||||||
|
smtp_from_address: normalizeString(form.smtp_from_address),
|
||||||
|
smtp_from_name: normalizeString(form.smtp_from_name),
|
||||||
|
clear_imap_password: Boolean(form.clear_imap_password),
|
||||||
|
clear_smtp_password: Boolean(form.clear_smtp_password),
|
||||||
|
};
|
||||||
|
|
||||||
|
const imapPassword = normalizeString(form.imap_password);
|
||||||
|
const smtpPassword = normalizeString(form.smtp_password);
|
||||||
|
|
||||||
|
if (imapPassword) {
|
||||||
|
payload.imap_password = imapPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (smtpPassword) {
|
||||||
|
payload.smtp_password = smtpPassword;
|
||||||
|
}
|
||||||
|
|
||||||
|
return payload;
|
||||||
|
};
|
||||||
|
|
||||||
|
const submitSettings = async () => {
|
||||||
|
try {
|
||||||
|
const settings = await mailboxSettingsStore.saveMailboxSettings(
|
||||||
|
buildPayload()
|
||||||
|
);
|
||||||
|
assignForm(settings);
|
||||||
|
notificationStore.updated("La configuration mailbox");
|
||||||
|
} catch {
|
||||||
|
notificationStore.error(
|
||||||
|
"Erreur de configuration",
|
||||||
|
mailboxSettingsStore.error ||
|
||||||
|
"Impossible d'enregistrer la configuration mailbox."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const syncMailbox = async () => {
|
||||||
|
try {
|
||||||
|
const result = await mailboxSettingsStore.syncMailbox();
|
||||||
|
assignForm(mailboxSettingsStore.currentSettings);
|
||||||
|
notificationStore.success(
|
||||||
|
"Synchronisation terminée",
|
||||||
|
`${result.imported} message(s) importé(s), ${result.skipped} ignoré(s) depuis ${result.source}.`
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
notificationStore.error(
|
||||||
|
"Erreur de synchronisation",
|
||||||
|
mailboxSettingsStore.error || "Impossible de synchroniser la boîte mail."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const testSmtp = async () => {
|
||||||
|
try {
|
||||||
|
const result = await mailboxSettingsStore.testSmtp();
|
||||||
|
notificationStore.success(
|
||||||
|
"Test SMTP envoyé",
|
||||||
|
`Un email de test a été envoyé vers ${result.recipient}.`
|
||||||
|
);
|
||||||
|
} catch {
|
||||||
|
notificationStore.error(
|
||||||
|
"Erreur de test SMTP",
|
||||||
|
mailboxSettingsStore.error || "Impossible de tester la configuration SMTP."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
try {
|
||||||
|
const settings = await mailboxSettingsStore.fetchMailboxSettings();
|
||||||
|
assignForm(settings);
|
||||||
|
} catch {
|
||||||
|
notificationStore.error(
|
||||||
|
"Erreur de chargement",
|
||||||
|
mailboxSettingsStore.error ||
|
||||||
|
"Impossible de charger la configuration mailbox."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user