mirror of
https://github.com/crater-invoice/crater.git
synced 2025-10-28 04:01:10 -04:00
add mail sender in setting
This commit is contained in:
@ -3,80 +3,29 @@
|
|||||||
namespace Crater\Http\Controllers\V1\Admin\Settings;
|
namespace Crater\Http\Controllers\V1\Admin\Settings;
|
||||||
|
|
||||||
use Crater\Http\Controllers\Controller;
|
use Crater\Http\Controllers\Controller;
|
||||||
use Crater\Http\Requests\MailEnvironmentRequest;
|
use Crater\Http\Requests\TestMailDriverRequest;
|
||||||
use Crater\Mail\TestMail;
|
use Crater\Mail\TestMail;
|
||||||
use Crater\Models\Setting;
|
use Crater\Models\MailSender;
|
||||||
use Crater\Space\EnvironmentManager;
|
|
||||||
use Illuminate\Http\JsonResponse;
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Mail;
|
use Mail;
|
||||||
|
|
||||||
class MailConfigurationController extends Controller
|
class MailConfigurationController extends Controller
|
||||||
{
|
{
|
||||||
/**
|
public function TestMailDriver(TestMailDriverRequest $request)
|
||||||
* @var EnvironmentManager
|
|
||||||
*/
|
|
||||||
protected $environmentManager;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param EnvironmentManager $environmentManager
|
|
||||||
*/
|
|
||||||
public function __construct(EnvironmentManager $environmentManager)
|
|
||||||
{
|
|
||||||
$this->environmentManager = $environmentManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param MailEnvironmentRequest $request
|
|
||||||
* @return JsonResponse
|
|
||||||
*/
|
|
||||||
public function saveMailEnvironment(MailEnvironmentRequest $request)
|
|
||||||
{
|
{
|
||||||
$this->authorize('manage email config');
|
$this->authorize('manage email config');
|
||||||
|
|
||||||
$setting = Setting::getSetting('profile_complete');
|
MailSender::setMailConfiguration($request->mail_sender_id);
|
||||||
$results = $this->environmentManager->saveMailVariables($request);
|
|
||||||
|
|
||||||
if ($setting !== 'COMPLETED') {
|
Mail::to($request->to)->send(new TestMail($request->subject, $request->message));
|
||||||
Setting::setSetting('profile_complete', 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
return response()->json($results);
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getMailEnvironment()
|
public function getMailDrivers(Request $request)
|
||||||
{
|
{
|
||||||
$this->authorize('manage email config');
|
|
||||||
|
|
||||||
$MailData = [
|
|
||||||
'mail_driver' => config('mail.driver'),
|
|
||||||
'mail_host' => config('mail.host'),
|
|
||||||
'mail_port' => config('mail.port'),
|
|
||||||
'mail_username' => config('mail.username'),
|
|
||||||
'mail_password' => config('mail.password'),
|
|
||||||
'mail_encryption' => config('mail.encryption'),
|
|
||||||
'from_name' => config('mail.from.name'),
|
|
||||||
'from_mail' => config('mail.from.address'),
|
|
||||||
'mail_mailgun_endpoint' => config('services.mailgun.endpoint'),
|
|
||||||
'mail_mailgun_domain' => config('services.mailgun.domain'),
|
|
||||||
'mail_mailgun_secret' => config('services.mailgun.secret'),
|
|
||||||
'mail_ses_key' => config('services.ses.key'),
|
|
||||||
'mail_ses_secret' => config('services.ses.secret'),
|
|
||||||
];
|
|
||||||
|
|
||||||
|
|
||||||
return response()->json($MailData);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @return JsonResponse
|
|
||||||
*/
|
|
||||||
public function getMailDrivers()
|
|
||||||
{
|
|
||||||
$this->authorize('manage email config');
|
|
||||||
|
|
||||||
$drivers = [
|
$drivers = [
|
||||||
'smtp',
|
'smtp',
|
||||||
'mail',
|
'mail',
|
||||||
@ -87,21 +36,4 @@ class MailConfigurationController extends Controller
|
|||||||
|
|
||||||
return response()->json($drivers);
|
return response()->json($drivers);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testEmailConfig(Request $request)
|
|
||||||
{
|
|
||||||
$this->authorize('manage email config');
|
|
||||||
|
|
||||||
$this->validate($request, [
|
|
||||||
'to' => 'required|email',
|
|
||||||
'subject' => 'required',
|
|
||||||
'message' => 'required',
|
|
||||||
]);
|
|
||||||
|
|
||||||
Mail::to($request->to)->send(new TestMail($request->subject, $request->message));
|
|
||||||
|
|
||||||
return response()->json([
|
|
||||||
'success' => true,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ class MailSenderRequest extends FormRequest
|
|||||||
*/
|
*/
|
||||||
public function authorize()
|
public function authorize()
|
||||||
{
|
{
|
||||||
return false;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
39
app/Http/Requests/TestMailDriverRequest.php
Normal file
39
app/Http/Requests/TestMailDriverRequest.php
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Crater\Http\Requests;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class TestMailDriverRequest extends FormRequest
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Determine if the user is authorized to make this request.
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
public function authorize()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the validation rules that apply to the request.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function rules()
|
||||||
|
{
|
||||||
|
return [
|
||||||
|
'to' => [
|
||||||
|
'required',
|
||||||
|
'email'
|
||||||
|
],
|
||||||
|
'subject' => [
|
||||||
|
'required'
|
||||||
|
],
|
||||||
|
'message' => [
|
||||||
|
'required'
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,6 +5,7 @@ namespace Crater\Models;
|
|||||||
use Crater\Http\Requests\MailSenderRequest;
|
use Crater\Http\Requests\MailSenderRequest;
|
||||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||||
use Illuminate\Database\Eloquent\Model;
|
use Illuminate\Database\Eloquent\Model;
|
||||||
|
use Config;
|
||||||
|
|
||||||
class MailSender extends Model
|
class MailSender extends Model
|
||||||
{
|
{
|
||||||
@ -74,4 +75,25 @@ class MailSender extends Model
|
|||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static function setMailConfiguration($id, $check = null)
|
||||||
|
{
|
||||||
|
$mailSender = MailSender::find($id);
|
||||||
|
|
||||||
|
$settings = $mailSender->settings;
|
||||||
|
$settings['driver'] = $mailSender->driver;
|
||||||
|
$settings['from'] = [
|
||||||
|
'address' => $mailSender->from_address,
|
||||||
|
'name' => $mailSender->from_name
|
||||||
|
];
|
||||||
|
|
||||||
|
Config::set('mail', $settings);
|
||||||
|
|
||||||
|
if ($check) {
|
||||||
|
return $mailSender;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
123
app/Policies/MailSenderPolicy.php
Normal file
123
app/Policies/MailSenderPolicy.php
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Crater\Policies;
|
||||||
|
|
||||||
|
use Crater\Models\MailSender;
|
||||||
|
use Crater\Models\User;
|
||||||
|
use Illuminate\Auth\Access\HandlesAuthorization;
|
||||||
|
use Silber\Bouncer\BouncerFacade;
|
||||||
|
|
||||||
|
class MailSenderPolicy
|
||||||
|
{
|
||||||
|
use HandlesAuthorization;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view any models.
|
||||||
|
*
|
||||||
|
* @param \Crater\Models\User $user
|
||||||
|
* @return \Illuminate\Auth\Access\Response|bool
|
||||||
|
*/
|
||||||
|
public function viewAny(User $user)
|
||||||
|
{
|
||||||
|
if (BouncerFacade::can('view-mail-sender', MailSender::class)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can view the model.
|
||||||
|
*
|
||||||
|
* @param \Crater\Models\User $user
|
||||||
|
* @param \Crater\Models\MailSender $mailSender
|
||||||
|
* @return \Illuminate\Auth\Access\Response|bool
|
||||||
|
*/
|
||||||
|
public function view(User $user, MailSender $mailSender)
|
||||||
|
{
|
||||||
|
if (BouncerFacade::can('view-mail-sender', $mailSender) && $user->hasCompany($mailSender->company_id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can create models.
|
||||||
|
*
|
||||||
|
* @param \Crater\Models\User $user
|
||||||
|
* @return \Illuminate\Auth\Access\Response|bool
|
||||||
|
*/
|
||||||
|
public function create(User $user)
|
||||||
|
{
|
||||||
|
if (BouncerFacade::can('create-mail-sender', MailSender::class)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can update the model.
|
||||||
|
*
|
||||||
|
* @param \Crater\Models\User $user
|
||||||
|
* @param \Crater\Models\MailSender $mailSender
|
||||||
|
* @return \Illuminate\Auth\Access\Response|bool
|
||||||
|
*/
|
||||||
|
public function update(User $user, MailSender $mailSender)
|
||||||
|
{
|
||||||
|
if (BouncerFacade::can('edit-mail-sender', $mailSender) && $user->hasCompany($mailSender->company_id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can delete the model.
|
||||||
|
*
|
||||||
|
* @param \Crater\Models\User $user
|
||||||
|
* @param \Crater\Models\MailSender $mailSender
|
||||||
|
* @return \Illuminate\Auth\Access\Response|bool
|
||||||
|
*/
|
||||||
|
public function delete(User $user, MailSender $mailSender)
|
||||||
|
{
|
||||||
|
if (BouncerFacade::can('delete-mail-sender', $mailSender) && $user->hasCompany($mailSender->company_id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can restore the model.
|
||||||
|
*
|
||||||
|
* @param \Crater\Models\User $user
|
||||||
|
* @param \Crater\Models\MailSender $mailSender
|
||||||
|
* @return \Illuminate\Auth\Access\Response|bool
|
||||||
|
*/
|
||||||
|
public function restore(User $user, MailSender $mailSender)
|
||||||
|
{
|
||||||
|
if (BouncerFacade::can('delete-mail-sender', $mailSender) && $user->hasCompany($mailSender->company_id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine whether the user can permanently delete the model.
|
||||||
|
*
|
||||||
|
* @param \Crater\Models\User $user
|
||||||
|
* @param \Crater\Models\MailSender $mailSender
|
||||||
|
* @return \Illuminate\Auth\Access\Response|bool
|
||||||
|
*/
|
||||||
|
public function forceDelete(User $user, MailSender $mailSender)
|
||||||
|
{
|
||||||
|
if (BouncerFacade::can('delete-mail-sender', $mailSender) && $user->hasCompany($mailSender->company_id)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -39,6 +39,7 @@ class AuthServiceProvider extends ServiceProvider
|
|||||||
\Crater\Models\CustomField::class => \Crater\Policies\CustomFieldPolicy::class,
|
\Crater\Models\CustomField::class => \Crater\Policies\CustomFieldPolicy::class,
|
||||||
\Crater\Models\User::class => \Crater\Policies\UserPolicy::class,
|
\Crater\Models\User::class => \Crater\Policies\UserPolicy::class,
|
||||||
\Crater\Models\Item::class => \Crater\Policies\ItemPolicy::class,
|
\Crater\Models\Item::class => \Crater\Policies\ItemPolicy::class,
|
||||||
|
\Crater\Models\MailSender::class => \Crater\Policies\MailSenderPolicy::class,
|
||||||
\Silber\Bouncer\Database\Role::class => \Crater\Policies\RolePolicy::class,
|
\Silber\Bouncer\Database\Role::class => \Crater\Policies\RolePolicy::class,
|
||||||
\Crater\Models\Unit::class => \Crater\Policies\UnitPolicy::class,
|
\Crater\Models\Unit::class => \Crater\Policies\UnitPolicy::class,
|
||||||
\Crater\Models\RecurringInvoice::class => \Crater\Policies\RecurringInvoicePolicy::class,
|
\Crater\Models\RecurringInvoice::class => \Crater\Policies\RecurringInvoicePolicy::class,
|
||||||
|
|||||||
@ -7,6 +7,7 @@ use Crater\Models\ExchangeRateProvider;
|
|||||||
use Crater\Models\Expense;
|
use Crater\Models\Expense;
|
||||||
use Crater\Models\Invoice;
|
use Crater\Models\Invoice;
|
||||||
use Crater\Models\Item;
|
use Crater\Models\Item;
|
||||||
|
use Crater\Models\MailSender;
|
||||||
use Crater\Models\Note;
|
use Crater\Models\Note;
|
||||||
use Crater\Models\Payment;
|
use Crater\Models\Payment;
|
||||||
use Crater\Models\RecurringInvoice;
|
use Crater\Models\RecurringInvoice;
|
||||||
@ -225,6 +226,17 @@ return [
|
|||||||
'ability' => 'view-all-notes',
|
'ability' => 'view-all-notes',
|
||||||
'model' => Note::class
|
'model' => Note::class
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'title' => 'settings.menu_title.mail_sender',
|
||||||
|
'group' => '',
|
||||||
|
'name' => 'Mail Sender',
|
||||||
|
'link' => '/admin/settings/mail-sender',
|
||||||
|
'icon' => 'MailIcon',
|
||||||
|
'owner_only' => false,
|
||||||
|
'ability' => 'view-mail-sender',
|
||||||
|
'model' => MailSender::class
|
||||||
|
],
|
||||||
|
|
||||||
[
|
[
|
||||||
'title' => 'settings.menu_title.expense_category',
|
'title' => 'settings.menu_title.expense_category',
|
||||||
'group' => '',
|
'group' => '',
|
||||||
@ -235,16 +247,6 @@ return [
|
|||||||
'ability' => 'view-expense',
|
'ability' => 'view-expense',
|
||||||
'model' => Expense::class
|
'model' => Expense::class
|
||||||
],
|
],
|
||||||
[
|
|
||||||
'title' => 'settings.mail.mail_config',
|
|
||||||
'group' => '',
|
|
||||||
'name' => 'Mail Configuration',
|
|
||||||
'link' => '/admin/settings/mail-configuration',
|
|
||||||
'icon' => 'MailIcon',
|
|
||||||
'owner_only' => true,
|
|
||||||
'ability' => '',
|
|
||||||
'model' => ''
|
|
||||||
],
|
|
||||||
[
|
[
|
||||||
'title' => 'settings.menu_title.file_disk',
|
'title' => 'settings.menu_title.file_disk',
|
||||||
'group' => '',
|
'group' => '',
|
||||||
@ -275,6 +277,7 @@ return [
|
|||||||
'ability' => '',
|
'ability' => '',
|
||||||
'model' => ''
|
'model' => ''
|
||||||
],
|
],
|
||||||
|
|
||||||
],
|
],
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|||||||
@ -47,8 +47,6 @@ const ExpenseCategory = () =>
|
|||||||
import('@/scripts/admin/views/settings/ExpenseCategorySetting.vue')
|
import('@/scripts/admin/views/settings/ExpenseCategorySetting.vue')
|
||||||
const ExchangeRateSetting = () =>
|
const ExchangeRateSetting = () =>
|
||||||
import('@/scripts/admin/views/settings/ExchangeRateProviderSetting.vue')
|
import('@/scripts/admin/views/settings/ExchangeRateProviderSetting.vue')
|
||||||
const MailConfig = () =>
|
|
||||||
import('@/scripts/admin/views/settings/MailConfigSetting.vue')
|
|
||||||
const FileDisk = () =>
|
const FileDisk = () =>
|
||||||
import('@/scripts/admin/views/settings/FileDiskSetting.vue')
|
import('@/scripts/admin/views/settings/FileDiskSetting.vue')
|
||||||
const Backup = () => import('@/scripts/admin/views/settings/BackupSetting.vue')
|
const Backup = () => import('@/scripts/admin/views/settings/BackupSetting.vue')
|
||||||
@ -56,6 +54,8 @@ const UpdateApp = () =>
|
|||||||
import('@/scripts/admin/views/settings/UpdateAppSetting.vue')
|
import('@/scripts/admin/views/settings/UpdateAppSetting.vue')
|
||||||
const RolesSettings = () =>
|
const RolesSettings = () =>
|
||||||
import('@/scripts/admin/views/settings/RolesSettings.vue')
|
import('@/scripts/admin/views/settings/RolesSettings.vue')
|
||||||
|
const MailSender = () =>
|
||||||
|
import('@/scripts/admin/views/settings/mail-sender/Index.vue')
|
||||||
|
|
||||||
// Items
|
// Items
|
||||||
const ItemsIndex = () => import('@/scripts/admin/views/items/Index.vue')
|
const ItemsIndex = () => import('@/scripts/admin/views/items/Index.vue')
|
||||||
@ -302,13 +302,6 @@ export default [
|
|||||||
meta: { ability: abilities.VIEW_EXPENSE },
|
meta: { ability: abilities.VIEW_EXPENSE },
|
||||||
component: ExpenseCategory,
|
component: ExpenseCategory,
|
||||||
},
|
},
|
||||||
|
|
||||||
{
|
|
||||||
path: 'mail-configuration',
|
|
||||||
name: 'mailconfig',
|
|
||||||
meta: { isOwner: true },
|
|
||||||
component: MailConfig,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: 'file-disk',
|
path: 'file-disk',
|
||||||
name: 'file-disk',
|
name: 'file-disk',
|
||||||
@ -327,6 +320,13 @@ export default [
|
|||||||
meta: { isOwner: true },
|
meta: { isOwner: true },
|
||||||
component: UpdateApp,
|
component: UpdateApp,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: 'mail-sender',
|
||||||
|
name: 'mailsender',
|
||||||
|
meta: { ability: abilities.VIEW_MAIL_SENDER },
|
||||||
|
component: MailSender,
|
||||||
|
},
|
||||||
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@ -0,0 +1,111 @@
|
|||||||
|
<template>
|
||||||
|
<BaseDropdown>
|
||||||
|
<template #activator>
|
||||||
|
<BaseButton v-if="route.name === 'mailsender.view'" variant="primary">
|
||||||
|
<BaseIcon name="DotsHorizontalIcon" class="h-5 text-white" />
|
||||||
|
</BaseButton>
|
||||||
|
<BaseIcon v-else name="DotsHorizontalIcon" class="h-5 text-gray-500" />
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<!-- edit mail-sender -->
|
||||||
|
<BaseDropdownItem @click="editMailSender(row.id)">
|
||||||
|
<BaseIcon
|
||||||
|
name="PencilIcon"
|
||||||
|
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
||||||
|
/>
|
||||||
|
{{ $t('general.edit') }}
|
||||||
|
</BaseDropdownItem>
|
||||||
|
|
||||||
|
<!-- delete mail-sender -->
|
||||||
|
<BaseDropdownItem @click="removeMailSender(row.id)">
|
||||||
|
<BaseIcon
|
||||||
|
name="TrashIcon"
|
||||||
|
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
||||||
|
/>
|
||||||
|
{{ $t('general.delete') }}
|
||||||
|
</BaseDropdownItem>
|
||||||
|
|
||||||
|
<!-- send test mail-sender -->
|
||||||
|
<BaseDropdownItem @click="openMailSenderTestModal(row.id)">
|
||||||
|
<BaseIcon
|
||||||
|
name="PaperAirplaneIcon"
|
||||||
|
class="w-5 h-5 mr-3 text-gray-400 group-hover:text-gray-500"
|
||||||
|
/>
|
||||||
|
{{ $t('general.send_test_mail') }}
|
||||||
|
</BaseDropdownItem>
|
||||||
|
</BaseDropdown>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { useDialogStore } from '@/scripts/stores/dialog'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useMailSenderStore } from '@/scripts/admin/stores/mail-sender'
|
||||||
|
import { useRoute, useRouter } from 'vue-router'
|
||||||
|
import { inject } from 'vue'
|
||||||
|
import { useModalStore } from '@/scripts/stores/modal'
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
row: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
table: {
|
||||||
|
type: Object,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
loadData: {
|
||||||
|
type: Function,
|
||||||
|
default: null,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const pre_t = 'settings.mail_sender'
|
||||||
|
const dialogStore = useDialogStore()
|
||||||
|
const { t } = useI18n()
|
||||||
|
const mailSenderStore = useMailSenderStore()
|
||||||
|
const route = useRoute()
|
||||||
|
const modalStore = useModalStore()
|
||||||
|
|
||||||
|
async function editMailSender(id) {
|
||||||
|
await mailSenderStore.fetchMailSender(id)
|
||||||
|
modalStore.openModal({
|
||||||
|
title: t(`${pre_t}.edit_mail_sender`),
|
||||||
|
componentName: 'MailSenderModal',
|
||||||
|
size: 'md',
|
||||||
|
refreshData: props.loadData && props.loadData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeMailSender(id) {
|
||||||
|
dialogStore
|
||||||
|
.openDialog({
|
||||||
|
title: t('general.are_you_sure'),
|
||||||
|
message: t(`${pre_t}.confirm_delete`),
|
||||||
|
yesLabel: t('general.ok'),
|
||||||
|
noLabel: t('general.cancel'),
|
||||||
|
variant: 'danger',
|
||||||
|
hideNoButton: false,
|
||||||
|
size: 'lg',
|
||||||
|
})
|
||||||
|
.then(async (res) => {
|
||||||
|
if (res) {
|
||||||
|
let response = await mailSenderStore.deleteMailSender(id)
|
||||||
|
if (response.data.success) {
|
||||||
|
props.loadData && props.loadData()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
props.loadData && props.loadData()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async function openMailSenderTestModal(id) {
|
||||||
|
modalStore.openModal({
|
||||||
|
title: t(`general.send_test_mail`),
|
||||||
|
componentName: 'MailSenderTestModal',
|
||||||
|
size: 'md',
|
||||||
|
id: id,
|
||||||
|
refreshData: props.loadData && props.loadData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -0,0 +1,290 @@
|
|||||||
|
<template>
|
||||||
|
<BaseModal
|
||||||
|
:show="modalStore.active && modalStore.componentName === 'MailSenderModal'"
|
||||||
|
>
|
||||||
|
<template #header>
|
||||||
|
<div class="flex justify-between w-full">
|
||||||
|
{{ modalStore.title }}
|
||||||
|
<BaseIcon
|
||||||
|
name="XIcon"
|
||||||
|
class="h-6 w-6 text-gray-500 cursor-pointer"
|
||||||
|
@click="closeMailSenderModal"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<form action="" @submit.prevent="submitMailSenderData">
|
||||||
|
<div class="p-4 sm:p-6 my-2">
|
||||||
|
<!-- Name -->
|
||||||
|
<BaseInputGrid>
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.name`)"
|
||||||
|
:error="v$.name.$error && v$.name.$errors[0].$message"
|
||||||
|
:help-text="$t(`${pre_t}.name_help`)"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model.trim="mailSenderStore.currentMailSender.name"
|
||||||
|
:invalid="v$.name.$error"
|
||||||
|
type="text"
|
||||||
|
@input="v$.name.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<!-- From Name -->
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.from_name`)"
|
||||||
|
:error="v$.from_name.$error && v$.from_name.$errors[0].$message"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model="mailSenderStore.currentMailSender.from_name"
|
||||||
|
:invalid="v$.from_name.$error"
|
||||||
|
type="text"
|
||||||
|
@input="v$.from_name.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<!-- From Address -->
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.from_address`)"
|
||||||
|
:error="
|
||||||
|
v$.from_address.$error && v$.from_address.$errors[0].$message
|
||||||
|
"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model="mailSenderStore.currentMailSender.from_address"
|
||||||
|
:invalid="v$.from_address.$error"
|
||||||
|
type="text"
|
||||||
|
@input="v$.from_address.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<!-- CC -->
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.cc`)"
|
||||||
|
:error="v$.cc.$error && v$.cc.$errors[0].$message"
|
||||||
|
:help-text="$t(`${pre_t}.email_list`)"
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model="mailSenderStore.currentMailSender.cc"
|
||||||
|
:invalid="v$.cc.$error"
|
||||||
|
type="text"
|
||||||
|
@input="v$.cc.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<!-- BCC -->
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.bcc`)"
|
||||||
|
:error="v$.bcc.$error && v$.bcc.$errors[0].$message"
|
||||||
|
:help-text="$t(`${pre_t}.email_list`)"
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model="mailSenderStore.currentMailSender.bcc"
|
||||||
|
:invalid="v$.bcc.$error"
|
||||||
|
type="text"
|
||||||
|
@input="v$.bcc.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<!-- Mail Driver -->
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.driver`)"
|
||||||
|
:error="v$.driver.$error && v$.driver.$errors[0].$message"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseMultiselect
|
||||||
|
v-model="mailSenderStore.currentMailSender.driver"
|
||||||
|
:options="mailSenderStore.mail_drivers"
|
||||||
|
:can-deselect="false"
|
||||||
|
:invalid="v$.driver.$error"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<component
|
||||||
|
:is="loadMailDriver"
|
||||||
|
:mail-sender-store="mailSenderStore"
|
||||||
|
/>
|
||||||
|
</BaseInputGrid>
|
||||||
|
|
||||||
|
<BaseDivider class="mt-4 mb-0" />
|
||||||
|
|
||||||
|
<!-- Is Default? -->
|
||||||
|
<BaseSwitchSection
|
||||||
|
v-model="mailSenderStore.currentMailSender.is_default"
|
||||||
|
:title="$t(`${pre_t}.is_default`)"
|
||||||
|
:description="$t(`${pre_t}.is_default_description`)"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div
|
||||||
|
class="z-0 flex justify-end p-4 border-t border-solid border--200 border-modal-bg"
|
||||||
|
>
|
||||||
|
<BaseButton
|
||||||
|
class="mr-3 text-sm"
|
||||||
|
variant="primary-outline"
|
||||||
|
type="button"
|
||||||
|
@click="closeMailSenderModal"
|
||||||
|
>
|
||||||
|
{{ $t('general.cancel') }}
|
||||||
|
</BaseButton>
|
||||||
|
<BaseButton
|
||||||
|
:loading="isSaving"
|
||||||
|
:disabled="isSaving"
|
||||||
|
variant="primary"
|
||||||
|
type="submit"
|
||||||
|
>
|
||||||
|
<template #left="slotProps">
|
||||||
|
<BaseIcon
|
||||||
|
v-if="!isSaving"
|
||||||
|
name="SaveIcon"
|
||||||
|
:class="slotProps.class"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
{{
|
||||||
|
mailSenderStore.isEdit ? $t('general.update') : $t('general.save')
|
||||||
|
}}
|
||||||
|
</BaseButton>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</BaseModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, onMounted, ref } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { required, email, minLength, helpers } from '@vuelidate/validators'
|
||||||
|
import { useVuelidate } from '@vuelidate/core'
|
||||||
|
import { useModalStore } from '@/scripts/stores/modal'
|
||||||
|
import { useMailSenderStore } from '@/scripts/admin/stores/mail-sender'
|
||||||
|
import SmtpDriver from '@/scripts/admin/views/settings/mail-sender/SmtpDriver.vue'
|
||||||
|
import MailgunDriver from '@/scripts/admin/views/settings/mail-sender/MailgunDriver.vue'
|
||||||
|
import SesDriver from '@/scripts/admin/views/settings/mail-sender/SesDriver.vue'
|
||||||
|
|
||||||
|
const pre_t = 'settings.mail_sender'
|
||||||
|
const modalStore = useModalStore()
|
||||||
|
const mailSenderStore = useMailSenderStore()
|
||||||
|
const { t } = useI18n()
|
||||||
|
let isSaving = ref(false)
|
||||||
|
const loadMailDriver = computed(() => {
|
||||||
|
switch (mailSenderStore.currentMailSender.driver) {
|
||||||
|
case 'smtp':
|
||||||
|
return SmtpDriver
|
||||||
|
break
|
||||||
|
case 'mail':
|
||||||
|
return false
|
||||||
|
break
|
||||||
|
case 'sendmail':
|
||||||
|
return false
|
||||||
|
break
|
||||||
|
case 'mailgun':
|
||||||
|
return MailgunDriver
|
||||||
|
break
|
||||||
|
case 'ses':
|
||||||
|
return SesDriver
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// This is multiple email custom validation
|
||||||
|
const multiEmail = (value) => {
|
||||||
|
if (value == '' || value === null) return true
|
||||||
|
const emailRegex =
|
||||||
|
/^(?:[A-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[A-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9]{2,}(?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])$/i
|
||||||
|
|
||||||
|
const emailArr = value.split(',')
|
||||||
|
let isValid = emailArr.every((v) => {
|
||||||
|
return emailRegex.test(v)
|
||||||
|
})
|
||||||
|
return isValid
|
||||||
|
}
|
||||||
|
|
||||||
|
const rules = computed(() => {
|
||||||
|
return {
|
||||||
|
name: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
minLength: helpers.withMessage(
|
||||||
|
t('validation.name_min_length', { count: 3 }),
|
||||||
|
minLength(3)
|
||||||
|
),
|
||||||
|
},
|
||||||
|
from_name: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
},
|
||||||
|
from_address: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
email: helpers.withMessage(t('validation.email_incorrect'), email),
|
||||||
|
},
|
||||||
|
cc: {
|
||||||
|
multiEmail: helpers.withMessage(
|
||||||
|
t('validation.email_incorrect'),
|
||||||
|
multiEmail
|
||||||
|
),
|
||||||
|
},
|
||||||
|
bcc: {
|
||||||
|
multiEmail: helpers.withMessage(
|
||||||
|
t('validation.email_incorrect'),
|
||||||
|
multiEmail
|
||||||
|
),
|
||||||
|
},
|
||||||
|
driver: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const v$ = useVuelidate(
|
||||||
|
rules,
|
||||||
|
computed(() => mailSenderStore.currentMailSender)
|
||||||
|
)
|
||||||
|
|
||||||
|
async function submitMailSenderData() {
|
||||||
|
v$.value.$touch()
|
||||||
|
if (v$.value.$invalid) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
const action = mailSenderStore.isEdit
|
||||||
|
? mailSenderStore.updateMailSender
|
||||||
|
: mailSenderStore.addMailSender
|
||||||
|
isSaving.value = true
|
||||||
|
|
||||||
|
var mailDriverConfig = null
|
||||||
|
switch (mailSenderStore.currentMailSender.driver) {
|
||||||
|
case 'smtp':
|
||||||
|
mailDriverConfig = mailSenderStore.smtpConfig
|
||||||
|
break
|
||||||
|
case 'mailgun':
|
||||||
|
mailDriverConfig = mailSenderStore.mailgunConfig
|
||||||
|
break
|
||||||
|
case 'ses':
|
||||||
|
mailDriverConfig = mailSenderStore.sesConfig
|
||||||
|
break
|
||||||
|
}
|
||||||
|
mailSenderStore.currentMailSender.settings = mailDriverConfig
|
||||||
|
|
||||||
|
let res = await action(mailSenderStore.currentMailSender)
|
||||||
|
isSaving.value = false
|
||||||
|
modalStore.refreshData ? modalStore.refreshData(res.data.data) : ''
|
||||||
|
closeMailSenderModal()
|
||||||
|
} catch (err) {
|
||||||
|
isSaving.value = false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeMailSenderModal() {
|
||||||
|
modalStore.closeModal()
|
||||||
|
setTimeout(() => {
|
||||||
|
mailSenderStore.resetCurrentMailSender()
|
||||||
|
v$.value.$reset()
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await mailSenderStore.fetchMailDrivers()
|
||||||
|
})
|
||||||
|
</script>
|
||||||
@ -0,0 +1,208 @@
|
|||||||
|
<template>
|
||||||
|
<BaseModal :show="modalActive" @open="setInitialData">
|
||||||
|
<template #header>
|
||||||
|
<div class="flex justify-between w-full">
|
||||||
|
{{ modalStore.title }}
|
||||||
|
<BaseIcon
|
||||||
|
name="XIcon"
|
||||||
|
class="w-6 h-6 text-gray-500 cursor-pointer"
|
||||||
|
@click="closeTestModal"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<form action="" @submit.prevent="onTestMailSend">
|
||||||
|
<div class="p-4 md:p-8">
|
||||||
|
<BaseInputGrid layout="one-column">
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.title`)"
|
||||||
|
variant="horizontal"
|
||||||
|
:content-loading="isFetchingInitialData"
|
||||||
|
:error="
|
||||||
|
v$.mail_sender_id.$error && v$.mail_sender_id.$errors[0].$message
|
||||||
|
"
|
||||||
|
>
|
||||||
|
<BaseMultiselect
|
||||||
|
v-model="formData.mail_sender_id"
|
||||||
|
:invalid="v$.mail_sender_id.$error"
|
||||||
|
label="name"
|
||||||
|
:options="mailSenderStore.mailSenders"
|
||||||
|
value-prop="id"
|
||||||
|
:can-deselect="false"
|
||||||
|
:can-clear="false"
|
||||||
|
:placeholder="$t(`${pre_t}.select_mail_sender`)"
|
||||||
|
searchable
|
||||||
|
track-by="name"
|
||||||
|
:content-loading="isFetchingInitialData"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t('general.to')"
|
||||||
|
:error="v$.to.$error && v$.to.$errors[0].$message"
|
||||||
|
variant="horizontal"
|
||||||
|
required
|
||||||
|
:content-loading="isFetchingInitialData"
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model="formData.to"
|
||||||
|
type="text"
|
||||||
|
:invalid="v$.to.$error"
|
||||||
|
:content-loading="isFetchingInitialData"
|
||||||
|
@input="v$.to.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t('general.subject')"
|
||||||
|
:error="v$.subject.$error && v$.subject.$errors[0].$message"
|
||||||
|
variant="horizontal"
|
||||||
|
required
|
||||||
|
:content-loading="isFetchingInitialData"
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model="formData.subject"
|
||||||
|
type="text"
|
||||||
|
:invalid="v$.subject.$error"
|
||||||
|
:content-loading="isFetchingInitialData"
|
||||||
|
@input="v$.subject.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t('general.message')"
|
||||||
|
:error="v$.message.$error && v$.message.$errors[0].$message"
|
||||||
|
variant="horizontal"
|
||||||
|
required
|
||||||
|
:content-loading="isFetchingInitialData"
|
||||||
|
>
|
||||||
|
<BaseTextarea
|
||||||
|
v-model="formData.message"
|
||||||
|
rows="4"
|
||||||
|
cols="50"
|
||||||
|
:invalid="v$.message.$error"
|
||||||
|
:content-loading="isFetchingInitialData"
|
||||||
|
@input="v$.message.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
</BaseInputGrid>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
class="z-0 flex justify-end p-4 border-t border-gray-200 border-solid"
|
||||||
|
>
|
||||||
|
<BaseButton
|
||||||
|
variant="primary-outline"
|
||||||
|
type="button"
|
||||||
|
class="mr-3"
|
||||||
|
:content-loading="isFetchingInitialData"
|
||||||
|
@click="closeTestModal()"
|
||||||
|
>
|
||||||
|
{{ $t('general.cancel') }}
|
||||||
|
</BaseButton>
|
||||||
|
|
||||||
|
<BaseButton
|
||||||
|
:loading="isSaving"
|
||||||
|
variant="primary"
|
||||||
|
type="submit"
|
||||||
|
:content-loading="isFetchingInitialData"
|
||||||
|
>
|
||||||
|
<template #left="slotProps">
|
||||||
|
<BaseIcon
|
||||||
|
v-if="!isSaving"
|
||||||
|
name="PaperAirplaneIcon"
|
||||||
|
:class="slotProps.class"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
{{ $t('general.send') }}
|
||||||
|
</BaseButton>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</BaseModal>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { reactive, ref, computed } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { required, email, maxLength, helpers } from '@vuelidate/validators'
|
||||||
|
import useVuelidate from '@vuelidate/core'
|
||||||
|
import { useModalStore } from '@/scripts/stores/modal'
|
||||||
|
import { useMailSenderStore } from '@/scripts/admin/stores/mail-sender'
|
||||||
|
|
||||||
|
const pre_t = 'settings.mail_sender'
|
||||||
|
const modalStore = useModalStore()
|
||||||
|
const mailSenderStore = useMailSenderStore()
|
||||||
|
const { t } = useI18n()
|
||||||
|
let isSaving = ref(false)
|
||||||
|
let formData = reactive({
|
||||||
|
mail_sender_id: '',
|
||||||
|
to: '',
|
||||||
|
subject: '',
|
||||||
|
message: '',
|
||||||
|
})
|
||||||
|
const isFetchingInitialData = ref(false)
|
||||||
|
|
||||||
|
const modalActive = computed(() => {
|
||||||
|
return modalStore.active && modalStore.componentName === 'MailSenderTestModal'
|
||||||
|
})
|
||||||
|
|
||||||
|
function setInitialData() {
|
||||||
|
isFetchingInitialData.value = true
|
||||||
|
formData.mail_sender_id = modalStore.id
|
||||||
|
setTimeout(() => {
|
||||||
|
isFetchingInitialData.value = false
|
||||||
|
}, 100)
|
||||||
|
}
|
||||||
|
|
||||||
|
const rules = {
|
||||||
|
mail_sender_id: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
email: helpers.withMessage(t('validation.email_incorrect'), email),
|
||||||
|
},
|
||||||
|
subject: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
maxLength: helpers.withMessage(
|
||||||
|
t('validation.subject_maxlength'),
|
||||||
|
maxLength(100)
|
||||||
|
),
|
||||||
|
},
|
||||||
|
message: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
maxLength: helpers.withMessage(
|
||||||
|
t('validation.message_maxlength'),
|
||||||
|
maxLength(255)
|
||||||
|
),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const v$ = useVuelidate(rules, formData)
|
||||||
|
|
||||||
|
function resetFormData() {
|
||||||
|
formData.mail_sender_id = ''
|
||||||
|
formData.to = ''
|
||||||
|
formData.subject = ''
|
||||||
|
formData.message = ''
|
||||||
|
|
||||||
|
v$.value.$reset()
|
||||||
|
}
|
||||||
|
|
||||||
|
async function onTestMailSend() {
|
||||||
|
v$.value.$touch()
|
||||||
|
if (v$.value.$invalid) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
isSaving.value = true
|
||||||
|
let response = await mailSenderStore.sendTestMail(formData)
|
||||||
|
if (response.data) {
|
||||||
|
closeTestModal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function closeTestModal() {
|
||||||
|
modalStore.closeModal()
|
||||||
|
setTimeout(() => {
|
||||||
|
isSaving.value = false
|
||||||
|
modalStore.resetModalData()
|
||||||
|
resetFormData()
|
||||||
|
}, 300)
|
||||||
|
}
|
||||||
|
</script>
|
||||||
209
resources/scripts/admin/stores/mail-sender.js
Normal file
209
resources/scripts/admin/stores/mail-sender.js
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
import axios from 'axios'
|
||||||
|
import { defineStore } from 'pinia'
|
||||||
|
import { useNotificationStore } from '@/scripts/stores/notification'
|
||||||
|
import { handleError } from '@/scripts/helpers/error-handling'
|
||||||
|
import mailSenderStub from '@/scripts/admin/stub/mail-sender.js'
|
||||||
|
|
||||||
|
export const useMailSenderStore = (useWindow = false) => {
|
||||||
|
const pre_t = 'settings.mail_sender'
|
||||||
|
const defineStoreFunc = useWindow ? window.pinia.defineStore : defineStore
|
||||||
|
const { global } = window.i18n
|
||||||
|
|
||||||
|
return defineStoreFunc({
|
||||||
|
id: 'mailSender',
|
||||||
|
|
||||||
|
state: () => ({
|
||||||
|
mailSenders: [],
|
||||||
|
mail_drivers: [], // list of mail drivers
|
||||||
|
currentMailSender: { ...mailSenderStub.basicConfig },
|
||||||
|
smtpConfig: { ...mailSenderStub.smtpConfig },
|
||||||
|
mailgunConfig: { ...mailSenderStub.mailgunConfig },
|
||||||
|
sesConfig: { ...mailSenderStub.sesConfig },
|
||||||
|
mail_encryptions: ['none', 'tls', 'ssl', 'starttls'],
|
||||||
|
}),
|
||||||
|
|
||||||
|
getters: {
|
||||||
|
isEdit: (state) => (state.currentMailSender.id ? true : false),
|
||||||
|
},
|
||||||
|
|
||||||
|
actions: {
|
||||||
|
resetCurrentMailSender() {
|
||||||
|
this.currentMailSender = { ...mailSenderStub.basicConfig }
|
||||||
|
this.smtpConfig = { ...mailSenderStub.smtpConfig }
|
||||||
|
this.mailgunConfig = { ...mailSenderStub.mailgunConfig }
|
||||||
|
this.sesConfig = { ...mailSenderStub.sesConfig }
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchMailDrivers() {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axios
|
||||||
|
.get('/api/v1/mail-drivers')
|
||||||
|
.then((response) => {
|
||||||
|
if (response.data) {
|
||||||
|
this.mail_drivers = response.data
|
||||||
|
}
|
||||||
|
resolve(response)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
handleError(err)
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchMailSenderList(params) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axios
|
||||||
|
.get(`/api/v1/mail-senders`, { params })
|
||||||
|
.then((response) => {
|
||||||
|
resolve(response)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
handleError(err)
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchMailSenders(params) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axios
|
||||||
|
.get(`/api/v1/mail-sender`, { params })
|
||||||
|
.then((response) => {
|
||||||
|
this.mailSenders = response.data.data
|
||||||
|
resolve(response)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
handleError(err)
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
fetchMailSender(id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axios
|
||||||
|
.get(`/api/v1/mail-sender/${id}`)
|
||||||
|
.then((response) => {
|
||||||
|
this.currentMailSender = response.data.data
|
||||||
|
if (response.data.data.settings) {
|
||||||
|
var settings = response.data.data.settings
|
||||||
|
switch (response.data.data.driver) {
|
||||||
|
case 'smtp':
|
||||||
|
this.smtpConfig = settings
|
||||||
|
break
|
||||||
|
case 'mailgun':
|
||||||
|
this.mailgunConfig = settings
|
||||||
|
break
|
||||||
|
case 'ses':
|
||||||
|
this.sesConfig = settings
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resolve(response)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
handleError(err)
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
addMailSender(data) {
|
||||||
|
const notificationStore = useNotificationStore()
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axios
|
||||||
|
.post('/api/v1/mail-sender', data)
|
||||||
|
.then((response) => {
|
||||||
|
this.mailSenders.push(response.data.data)
|
||||||
|
notificationStore.showNotification({
|
||||||
|
type: 'success',
|
||||||
|
message: global.t(`${pre_t}.created_message`),
|
||||||
|
})
|
||||||
|
resolve(response)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
handleError(err)
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
updateMailSender(data) {
|
||||||
|
const notificationStore = useNotificationStore()
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axios
|
||||||
|
.put(`/api/v1/mail-sender/${data.id}`, data)
|
||||||
|
.then((response) => {
|
||||||
|
if (response.data) {
|
||||||
|
let pos = this.mailSenders.findIndex(
|
||||||
|
(mailSender) => mailSender.id === response.data.data.id
|
||||||
|
)
|
||||||
|
this.mailSenders[pos] = data
|
||||||
|
notificationStore.showNotification({
|
||||||
|
type: 'success',
|
||||||
|
message: global.t(`${pre_t}.updated_message`),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
resolve(response)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
handleError(err)
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
deleteMailSender(id) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axios
|
||||||
|
.delete(`/api/v1/mail-sender/${id}`)
|
||||||
|
.then((response) => {
|
||||||
|
if (response.data.success) {
|
||||||
|
let index = this.mailSenders.findIndex(
|
||||||
|
(mailSender) => mailSender.id === id
|
||||||
|
)
|
||||||
|
this.mailSenders.splice(index, 1)
|
||||||
|
const notificationStore = useNotificationStore()
|
||||||
|
notificationStore.showNotification({
|
||||||
|
type: 'success',
|
||||||
|
message: global.t(`${pre_t}.deleted_message`),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
resolve(response)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
handleError(err)
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
sendTestMail(data) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
axios
|
||||||
|
.post('/api/v1/mail-test', data)
|
||||||
|
.then((response) => {
|
||||||
|
const notificationStore = useNotificationStore()
|
||||||
|
if (response.data.success) {
|
||||||
|
notificationStore.showNotification({
|
||||||
|
type: 'success',
|
||||||
|
message: global.t('general.send_mail_successfully'),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
notificationStore.showNotification({
|
||||||
|
type: 'error',
|
||||||
|
message: global.t('validation.something_went_wrong'),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
resolve(response)
|
||||||
|
})
|
||||||
|
.catch((err) => {
|
||||||
|
handleError(err)
|
||||||
|
reject(err)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})()
|
||||||
|
}
|
||||||
@ -25,6 +25,7 @@ export const useUsersStore = (useWindow = false) => {
|
|||||||
password: null,
|
password: null,
|
||||||
phone: null,
|
phone: null,
|
||||||
companies: [],
|
companies: [],
|
||||||
|
sender_id: null,
|
||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
|||||||
@ -15,5 +15,6 @@ export default function () {
|
|||||||
customFields: [],
|
customFields: [],
|
||||||
fields: [],
|
fields: [],
|
||||||
enable_portal: false,
|
enable_portal: false,
|
||||||
|
mail_sender_id: null,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
31
resources/scripts/admin/stub/mail-sender.js
Normal file
31
resources/scripts/admin/stub/mail-sender.js
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
export default {
|
||||||
|
basicConfig: {
|
||||||
|
name: '',
|
||||||
|
from_name: '',
|
||||||
|
from_address: '',
|
||||||
|
cc: '',
|
||||||
|
bcc: '',
|
||||||
|
is_default: false,
|
||||||
|
driver: 'smtp', // 'smtp', 'mail', 'sendmail', 'mailgun', 'ses'
|
||||||
|
settings: '',
|
||||||
|
},
|
||||||
|
smtpConfig: {
|
||||||
|
host: '',
|
||||||
|
port: null,
|
||||||
|
username: '',
|
||||||
|
password: '',
|
||||||
|
encryption: 'tls', // 'tls', 'ssl', 'starttls'
|
||||||
|
},
|
||||||
|
mailgunConfig: {
|
||||||
|
domain: '',
|
||||||
|
secret: '',
|
||||||
|
endpoint: '',
|
||||||
|
},
|
||||||
|
sesConfig: {
|
||||||
|
host: '',
|
||||||
|
port: null,
|
||||||
|
encryption: 'tls', // 'tls', 'ssl', 'starttls'
|
||||||
|
ses_key: '',
|
||||||
|
ses_secret: '',
|
||||||
|
},
|
||||||
|
}
|
||||||
@ -256,6 +256,31 @@
|
|||||||
/> </template
|
/> </template
|
||||||
></BaseInput>
|
></BaseInput>
|
||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
|
<!-- && setPasswordMethod !== 'manual' -->
|
||||||
|
<BaseInputGroup
|
||||||
|
v-show="customerStore.currentCustomer.enable_portal"
|
||||||
|
:label="$t('customers.select_sender')"
|
||||||
|
class="pt-5"
|
||||||
|
:error="
|
||||||
|
v$.currentCustomer.mail_sender_id.$error &&
|
||||||
|
v$.currentCustomer.mail_sender_id.$errors[0].$message
|
||||||
|
"
|
||||||
|
:content-loading="isFetchingInitialData"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseMultiselect
|
||||||
|
v-model="customerStore.currentCustomer.mail_sender_id"
|
||||||
|
label="name"
|
||||||
|
value-prop="id"
|
||||||
|
:options="mailSenderStore.mailSenders"
|
||||||
|
:can-deselect="false"
|
||||||
|
:can-clear="false"
|
||||||
|
searchable
|
||||||
|
track-by="name"
|
||||||
|
:invalid="v$.currentCustomer.mail_sender_id.$error"
|
||||||
|
@input="v$.currentCustomer.mail_sender_id.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
</BaseInputGrid>
|
</BaseInputGrid>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -601,11 +626,13 @@ import CustomerCustomFields from '@/scripts/admin/components/custom-fields/Creat
|
|||||||
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
import { useGlobalStore } from '@/scripts/admin/stores/global'
|
||||||
import CopyInputField from '@/scripts/admin/components/CopyInputField.vue'
|
import CopyInputField from '@/scripts/admin/components/CopyInputField.vue'
|
||||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||||
|
import { useMailSenderStore } from '@/scripts/admin/stores/mail-sender'
|
||||||
|
|
||||||
const customerStore = useCustomerStore()
|
const customerStore = useCustomerStore()
|
||||||
const customFieldStore = useCustomFieldStore()
|
const customFieldStore = useCustomFieldStore()
|
||||||
const globalStore = useGlobalStore()
|
const globalStore = useGlobalStore()
|
||||||
const companyStore = useCompanyStore()
|
const companyStore = useCompanyStore()
|
||||||
|
const mailSenderStore = useMailSenderStore()
|
||||||
|
|
||||||
const customFieldValidationScope = 'customFields'
|
const customFieldValidationScope = 'customFields'
|
||||||
|
|
||||||
@ -617,6 +644,7 @@ const route = useRoute()
|
|||||||
let isFetchingInitialData = ref(false)
|
let isFetchingInitialData = ref(false)
|
||||||
let isShowPassword = ref(false)
|
let isShowPassword = ref(false)
|
||||||
let isShowConfirmPassword = ref(false)
|
let isShowConfirmPassword = ref(false)
|
||||||
|
const mailSenders = ref(null)
|
||||||
|
|
||||||
let active = ref(false)
|
let active = ref(false)
|
||||||
const isSaving = ref(false)
|
const isSaving = ref(false)
|
||||||
@ -679,6 +707,9 @@ const rules = computed(() => {
|
|||||||
website: {
|
website: {
|
||||||
url: helpers.withMessage(t('validation.invalid_url'), url),
|
url: helpers.withMessage(t('validation.invalid_url'), url),
|
||||||
},
|
},
|
||||||
|
mail_sender_id: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
},
|
||||||
billing: {
|
billing: {
|
||||||
address_street_1: {
|
address_street_1: {
|
||||||
maxLength: helpers.withMessage(
|
maxLength: helpers.withMessage(
|
||||||
@ -722,6 +753,20 @@ const v$ = useVuelidate(rules, customerStore, {
|
|||||||
$scope: customFieldValidationScope,
|
$scope: customFieldValidationScope,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await mailSenderStore.fetchMailSenders()
|
||||||
|
let mailSenderData = await mailSenderStore.fetchMailSenderList()
|
||||||
|
if (mailSenderData.data) {
|
||||||
|
mailSenders.value = mailSenderData.data.data
|
||||||
|
let defaultMailSender = mailSenderData.data.data.find(
|
||||||
|
(mailSender) => mailSender.is_default == true
|
||||||
|
)
|
||||||
|
customerStore.currentCustomer.mail_sender_id = defaultMailSender
|
||||||
|
? defaultMailSender.id
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
customerStore.resetCurrentCustomer()
|
customerStore.resetCurrentCustomer()
|
||||||
|
|
||||||
customerStore.fetchCustomerInitialSettings(isEdit.value)
|
customerStore.fetchCustomerInitialSettings(isEdit.value)
|
||||||
|
|||||||
136
resources/scripts/admin/views/settings/mail-sender/Index.vue
Normal file
136
resources/scripts/admin/views/settings/mail-sender/Index.vue
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
<template>
|
||||||
|
<BaseSettingCard
|
||||||
|
:title="$tc(`${pre_t}.title`, 2)"
|
||||||
|
:description="$t(`${pre_t}.description`)"
|
||||||
|
>
|
||||||
|
<MailSenderModal />
|
||||||
|
<MailSenderTestModal />
|
||||||
|
|
||||||
|
<template #action>
|
||||||
|
<BaseButton
|
||||||
|
type="submit"
|
||||||
|
variant="primary-outline"
|
||||||
|
@click="openMailSenderModal"
|
||||||
|
>
|
||||||
|
<template #left="slotProps">
|
||||||
|
<BaseIcon :class="slotProps.class" name="PlusIcon" />
|
||||||
|
</template>
|
||||||
|
{{ $t(`${pre_t}.add_new_mail_sender`) }}
|
||||||
|
</BaseButton>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<BaseTable
|
||||||
|
ref="table"
|
||||||
|
class="mt-16"
|
||||||
|
:data="fetchData"
|
||||||
|
:columns="mailSenderColumns"
|
||||||
|
>
|
||||||
|
<template #cell-is_default="{ row }">
|
||||||
|
<BaseBadge
|
||||||
|
:bg-color="
|
||||||
|
utils.getBadgeStatusColor(row.data.is_default ? 'YES' : 'NO')
|
||||||
|
.bgColor
|
||||||
|
"
|
||||||
|
:color="
|
||||||
|
utils.getBadgeStatusColor(row.data.is_default ? 'YES' : 'NO').color
|
||||||
|
"
|
||||||
|
>
|
||||||
|
{{ row.data.is_default ? $t('general.yes') : $t('general.no') }}
|
||||||
|
</BaseBadge>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<template #cell-actions="{ row }">
|
||||||
|
<MailSenderDropdown
|
||||||
|
:row="row.data"
|
||||||
|
:table="table"
|
||||||
|
:load-data="refreshTable"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</BaseTable>
|
||||||
|
</BaseSettingCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref, inject } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { useModalStore } from '@/scripts/stores/modal'
|
||||||
|
import MailSenderModal from '@/scripts/admin/components/modal-components/MailSenderModal.vue'
|
||||||
|
import { useMailSenderStore } from '@/scripts/admin/stores/mail-sender'
|
||||||
|
import MailSenderDropdown from '@/scripts/admin/components/dropdowns/MailSenderIndexDropdown.vue'
|
||||||
|
import MailSenderTestModal from '@/scripts/admin/components/modal-components/MailSenderTestModal.vue'
|
||||||
|
|
||||||
|
const pre_t = 'settings.mail_sender'
|
||||||
|
const modalStore = useModalStore()
|
||||||
|
const mailSenderStore = useMailSenderStore()
|
||||||
|
const { t } = useI18n()
|
||||||
|
const table = ref(null)
|
||||||
|
const utils = inject('utils')
|
||||||
|
|
||||||
|
function openMailSenderModal() {
|
||||||
|
modalStore.openModal({
|
||||||
|
title: t(`${pre_t}.add_new_mail_sender`),
|
||||||
|
componentName: 'MailSenderModal',
|
||||||
|
size: 'md',
|
||||||
|
refreshData: refreshTable,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const mailSenderColumns = computed(() => {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
key: 'name',
|
||||||
|
label: t(`${pre_t}.name`),
|
||||||
|
thClass: 'extra',
|
||||||
|
tdClass: 'font-medium text-gray-900',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'driver',
|
||||||
|
label: t(`${pre_t}.driver`),
|
||||||
|
thClass: 'extra',
|
||||||
|
tdClass: 'font-medium text-gray-900',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'from_address',
|
||||||
|
label: t(`${pre_t}.from_address`),
|
||||||
|
thClass: 'extra',
|
||||||
|
tdClass: 'font-medium text-gray-900',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'is_default',
|
||||||
|
label: t(`${pre_t}.is_default`),
|
||||||
|
thClass: 'extra',
|
||||||
|
tdClass: 'font-medium text-gray-900',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'actions',
|
||||||
|
label: '',
|
||||||
|
tdClass: 'text-right text-sm font-medium',
|
||||||
|
sortable: false,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
})
|
||||||
|
|
||||||
|
async function fetchData({ page, filter, sort }) {
|
||||||
|
let data = {
|
||||||
|
orderByField: sort.fieldName || 'created_at',
|
||||||
|
orderBy: sort.order || 'desc',
|
||||||
|
page,
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = await mailSenderStore.fetchMailSenders(data)
|
||||||
|
|
||||||
|
return {
|
||||||
|
data: response.data.data,
|
||||||
|
pagination: {
|
||||||
|
totalPages: response.data.meta.last_page,
|
||||||
|
currentPage: page,
|
||||||
|
totalCount: response.data.meta.total,
|
||||||
|
limit: response.data.meta.per_page ? response.data.meta.per_page : 10,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function refreshTable() {
|
||||||
|
table.value && table.value.refresh()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
@ -0,0 +1,104 @@
|
|||||||
|
<template>
|
||||||
|
<!-- Domain -->
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.domain`)"
|
||||||
|
:error="v$.domain.$error && v$.domain.$errors[0].$message"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model.trim="mailSenderStore.mailgunConfig.domain"
|
||||||
|
:invalid="v$.domain.$error"
|
||||||
|
type="text"
|
||||||
|
@input="v$.domain.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<!-- Mailgun Secret -->
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.secret`)"
|
||||||
|
:error="v$.secret.$error && v$.secret.$errors[0].$message"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model="mailSenderStore.mailgunConfig.secret"
|
||||||
|
:type="getInputType"
|
||||||
|
autocomplete="off"
|
||||||
|
:invalid="v$.secret.$error"
|
||||||
|
@input="v$.secret.$touch()"
|
||||||
|
>
|
||||||
|
<template #right>
|
||||||
|
<BaseIcon
|
||||||
|
v-if="isShowPassword"
|
||||||
|
class="mr-1 text-gray-500 cursor-pointer"
|
||||||
|
name="EyeOffIcon"
|
||||||
|
@click="isShowPassword = !isShowPassword"
|
||||||
|
/>
|
||||||
|
<BaseIcon
|
||||||
|
v-else
|
||||||
|
class="mr-1 text-gray-500 cursor-pointer"
|
||||||
|
name="EyeIcon"
|
||||||
|
@click="isShowPassword = !isShowPassword"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</BaseInput>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<!-- Mailgun Endpoint -->
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.endpoint`)"
|
||||||
|
:error="v$.endpoint.$error && v$.endpoint.$errors[0].$message"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model.trim="mailSenderStore.mailgunConfig.endpoint"
|
||||||
|
type="text"
|
||||||
|
:invalid="v$.endpoint.$error"
|
||||||
|
@input="v$.endpoint.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref } from "vue"
|
||||||
|
import { useI18n } from "vue-i18n"
|
||||||
|
import { required, email, numeric, helpers } from "@vuelidate/validators"
|
||||||
|
import { useVuelidate } from "@vuelidate/core"
|
||||||
|
|
||||||
|
const pre_t = "settings.mail_sender.mailgun_config"
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
mailSenderStore: {
|
||||||
|
type: Object,
|
||||||
|
require: true,
|
||||||
|
default: Object,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
let isShowPassword = ref(false)
|
||||||
|
const getInputType = computed(() => {
|
||||||
|
if (isShowPassword.value) {
|
||||||
|
return "text"
|
||||||
|
}
|
||||||
|
return "password"
|
||||||
|
})
|
||||||
|
|
||||||
|
const rules = computed(() => {
|
||||||
|
return {
|
||||||
|
domain: {
|
||||||
|
required: helpers.withMessage(t("validation.required"), required),
|
||||||
|
},
|
||||||
|
endpoint: {
|
||||||
|
required: helpers.withMessage(t("validation.required"), required),
|
||||||
|
},
|
||||||
|
secret: {
|
||||||
|
required: helpers.withMessage(t("validation.required"), required),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const v$ = useVuelidate(
|
||||||
|
rules,
|
||||||
|
computed(() => props.mailSenderStore.mailgunConfig)
|
||||||
|
)
|
||||||
|
</script>
|
||||||
143
resources/scripts/admin/views/settings/mail-sender/SesDriver.vue
Normal file
143
resources/scripts/admin/views/settings/mail-sender/SesDriver.vue
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
<template>
|
||||||
|
<!-- Host -->
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.host`)"
|
||||||
|
:error="v$.host.$error && v$.host.$errors[0].$message"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model.trim="mailSenderStore.sesConfig.host"
|
||||||
|
:invalid="v$.host.$error"
|
||||||
|
type="text"
|
||||||
|
@input="v$.host.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<!-- Port -->
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.port`)"
|
||||||
|
:error="v$.port.$error && v$.port.$errors[0].$message"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model.trim="mailSenderStore.sesConfig.port"
|
||||||
|
type="text"
|
||||||
|
:invalid="v$.port.$error"
|
||||||
|
@input="v$.port.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<!-- Encryption -->
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.encryption`)"
|
||||||
|
:error="v$.encryption.$error && v$.encryption.$errors[0].$message"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseMultiselect
|
||||||
|
v-model.trim="mailSenderStore.sesConfig.encryption"
|
||||||
|
:options="encryptions"
|
||||||
|
:searchable="true"
|
||||||
|
:show-labels="false"
|
||||||
|
:placeholder="$t('general.select_option')"
|
||||||
|
:invalid="v$.encryption.$error"
|
||||||
|
@input="v$.encryption.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<!-- SES Key -->
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.ses_key`)"
|
||||||
|
:error="v$.ses_key.$error && v$.ses_key.$errors[0].$message"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model.trim="mailSenderStore.sesConfig.ses_key"
|
||||||
|
type="text"
|
||||||
|
:invalid="v$.ses_key.$error"
|
||||||
|
@input="v$.ses_key.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<!-- SES Secret -->
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.ses_secret`)"
|
||||||
|
:error="v$.ses_secret.$error && v$.ses_secret.$errors[0].$message"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model="mailSenderStore.sesConfig.ses_secret"
|
||||||
|
:type="getInputType"
|
||||||
|
autocomplete="off"
|
||||||
|
:invalid="v$.ses_secret.$error"
|
||||||
|
@input="v$.ses_secret.$touch()"
|
||||||
|
>
|
||||||
|
<template #right>
|
||||||
|
<BaseIcon
|
||||||
|
v-if="isShowPassword"
|
||||||
|
class="mr-1 text-gray-500 cursor-pointer"
|
||||||
|
name="EyeOffIcon"
|
||||||
|
@click="isShowPassword = !isShowPassword"
|
||||||
|
/>
|
||||||
|
<BaseIcon
|
||||||
|
v-else
|
||||||
|
class="mr-1 text-gray-500 cursor-pointer"
|
||||||
|
name="EyeIcon"
|
||||||
|
@click="isShowPassword = !isShowPassword"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</BaseInput>
|
||||||
|
</BaseInputGroup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref, reactive } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { required, email, numeric, helpers } from '@vuelidate/validators'
|
||||||
|
import { useVuelidate } from '@vuelidate/core'
|
||||||
|
|
||||||
|
const pre_t = 'settings.mail_sender.ses_config'
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
mailSenderStore: {
|
||||||
|
type: Object,
|
||||||
|
require: true,
|
||||||
|
default: Object,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
let isShowPassword = ref(false)
|
||||||
|
const getInputType = computed(() => {
|
||||||
|
if (isShowPassword.value) {
|
||||||
|
return 'text'
|
||||||
|
}
|
||||||
|
return 'password'
|
||||||
|
})
|
||||||
|
const encryptions = props.mailSenderStore.mail_encryptions
|
||||||
|
|
||||||
|
const rules = computed(() => {
|
||||||
|
return {
|
||||||
|
host: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
},
|
||||||
|
port: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
numeric,
|
||||||
|
},
|
||||||
|
encryption: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
},
|
||||||
|
ses_key: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
},
|
||||||
|
ses_secret: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const v$ = useVuelidate(
|
||||||
|
rules,
|
||||||
|
computed(() => props.mailSenderStore.sesConfig)
|
||||||
|
)
|
||||||
|
</script>
|
||||||
@ -0,0 +1,120 @@
|
|||||||
|
<template>
|
||||||
|
<!-- Host -->
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.host`)"
|
||||||
|
:error="v$.host.$error && v$.host.$errors[0].$message"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model.trim="mailSenderStore.smtpConfig.host"
|
||||||
|
:invalid="v$.host.$error"
|
||||||
|
type="text"
|
||||||
|
@input="v$.host.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<!-- Port -->
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.port`)"
|
||||||
|
:error="v$.port.$error && v$.port.$errors[0].$message"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseInput
|
||||||
|
v-model.trim="mailSenderStore.smtpConfig.port"
|
||||||
|
type="text"
|
||||||
|
:invalid="v$.port.$error"
|
||||||
|
@input="v$.port.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<!-- Username -->
|
||||||
|
<BaseInputGroup :label="$t(`${pre_t}.username`)">
|
||||||
|
<BaseInput v-model.trim="mailSenderStore.smtpConfig.username" type="text" />
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<!-- Password -->
|
||||||
|
<BaseInputGroup :label="$t(`${pre_t}.password`)">
|
||||||
|
<BaseInput
|
||||||
|
v-model="mailSenderStore.smtpConfig.password"
|
||||||
|
:type="getInputType"
|
||||||
|
>
|
||||||
|
<template #right>
|
||||||
|
<BaseIcon
|
||||||
|
v-if="isShowPassword"
|
||||||
|
class="mr-1 text-gray-500 cursor-pointer"
|
||||||
|
name="EyeOffIcon"
|
||||||
|
@click="isShowPassword = !isShowPassword"
|
||||||
|
/>
|
||||||
|
<BaseIcon
|
||||||
|
v-else
|
||||||
|
class="mr-1 text-gray-500 cursor-pointer"
|
||||||
|
name="EyeIcon"
|
||||||
|
@click="isShowPassword = !isShowPassword"
|
||||||
|
/>
|
||||||
|
</template>
|
||||||
|
</BaseInput>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<!-- Encryption -->
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t(`${pre_t}.encryption`)"
|
||||||
|
:error="v$.encryption.$error && v$.encryption.$errors[0].$message"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseMultiselect
|
||||||
|
v-model.trim="mailSenderStore.smtpConfig.encryption"
|
||||||
|
:options="encryptions"
|
||||||
|
:searchable="true"
|
||||||
|
:show-labels="false"
|
||||||
|
:placeholder="$t('general.select_option')"
|
||||||
|
:invalid="v$.encryption.$error"
|
||||||
|
@input="v$.encryption.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
import { computed, ref, reactive } from 'vue'
|
||||||
|
import { useI18n } from 'vue-i18n'
|
||||||
|
import { required, numeric, helpers } from '@vuelidate/validators'
|
||||||
|
import { useVuelidate } from '@vuelidate/core'
|
||||||
|
|
||||||
|
const pre_t = 'settings.mail_sender.smtp_config'
|
||||||
|
const { t } = useI18n()
|
||||||
|
|
||||||
|
const props = defineProps({
|
||||||
|
mailSenderStore: {
|
||||||
|
type: Object,
|
||||||
|
require: true,
|
||||||
|
default: Object,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
let isShowPassword = ref(false)
|
||||||
|
const getInputType = computed(() => {
|
||||||
|
if (isShowPassword.value) {
|
||||||
|
return 'text'
|
||||||
|
}
|
||||||
|
return 'password'
|
||||||
|
})
|
||||||
|
const encryptions = props.mailSenderStore.mail_encryptions
|
||||||
|
|
||||||
|
const rules = computed(() => {
|
||||||
|
return {
|
||||||
|
host: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
},
|
||||||
|
port: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
numeric: helpers.withMessage(t('validation.numbers_only'), numeric),
|
||||||
|
},
|
||||||
|
encryption: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const v$ = useVuelidate(
|
||||||
|
rules,
|
||||||
|
computed(() => props.mailSenderStore.smtpConfig)
|
||||||
|
)
|
||||||
|
</script>
|
||||||
@ -128,6 +128,29 @@
|
|||||||
</BaseInput>
|
</BaseInput>
|
||||||
</BaseInputGroup>
|
</BaseInputGroup>
|
||||||
|
|
||||||
|
<BaseInputGroup
|
||||||
|
:label="$t('users.select_sender')"
|
||||||
|
:error="
|
||||||
|
v$.userData.mail_sender_id.$error &&
|
||||||
|
v$.userData.mail_sender_id.$errors[0].$message
|
||||||
|
"
|
||||||
|
:content-loading="isFetchingInitialData"
|
||||||
|
required
|
||||||
|
>
|
||||||
|
<BaseMultiselect
|
||||||
|
v-model="userStore.userData.mail_sender_id"
|
||||||
|
label="name"
|
||||||
|
value-prop="id"
|
||||||
|
:options="mailSenderStore.mailSenders"
|
||||||
|
:can-deselect="false"
|
||||||
|
:can-clear="false"
|
||||||
|
searchable
|
||||||
|
track-by="name"
|
||||||
|
:invalid="v$.userData.mail_sender_id.$error"
|
||||||
|
@input="v$.userData.mail_sender_id.$touch()"
|
||||||
|
/>
|
||||||
|
</BaseInputGroup>
|
||||||
|
|
||||||
<BaseInputGroup
|
<BaseInputGroup
|
||||||
:content-loading="isFetchingInitialData"
|
:content-loading="isFetchingInitialData"
|
||||||
:label="$t('users.phone')"
|
:label="$t('users.phone')"
|
||||||
@ -162,7 +185,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import { ref, computed, reactive } from 'vue'
|
import { ref, computed, reactive, onMounted } from 'vue'
|
||||||
import { useRouter, useRoute } from 'vue-router'
|
import { useRouter, useRoute } from 'vue-router'
|
||||||
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
import { useCompanyStore } from '@/scripts/admin/stores/company'
|
||||||
import {
|
import {
|
||||||
@ -176,6 +199,7 @@ import useVuelidate from '@vuelidate/core'
|
|||||||
import { ValidateEach } from '@vuelidate/components'
|
import { ValidateEach } from '@vuelidate/components'
|
||||||
import { useI18n } from 'vue-i18n'
|
import { useI18n } from 'vue-i18n'
|
||||||
import { useUsersStore } from '@/scripts/admin/stores/users'
|
import { useUsersStore } from '@/scripts/admin/stores/users'
|
||||||
|
import { useMailSenderStore } from '@/scripts/admin/stores/mail-sender'
|
||||||
|
|
||||||
const userStore = useUsersStore()
|
const userStore = useUsersStore()
|
||||||
|
|
||||||
@ -183,11 +207,13 @@ const { t } = useI18n()
|
|||||||
const route = useRoute()
|
const route = useRoute()
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
const companyStore = useCompanyStore()
|
const companyStore = useCompanyStore()
|
||||||
|
const mailSenderStore = useMailSenderStore()
|
||||||
|
|
||||||
let isSaving = ref(false)
|
let isSaving = ref(false)
|
||||||
let isFetchingInitialData = ref(false)
|
let isFetchingInitialData = ref(false)
|
||||||
let selectedCompanies = ref([])
|
let selectedCompanies = ref([])
|
||||||
let companies = ref([])
|
let companies = ref([])
|
||||||
|
const mailSenders = ref(null)
|
||||||
|
|
||||||
const isEdit = computed(() => route.name === 'users.edit')
|
const isEdit = computed(() => route.name === 'users.edit')
|
||||||
|
|
||||||
@ -222,6 +248,9 @@ const rules = computed(() => {
|
|||||||
companies: {
|
companies: {
|
||||||
required: helpers.withMessage(t('validation.required'), required),
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
},
|
},
|
||||||
|
mail_sender_id: {
|
||||||
|
required: helpers.withMessage(t('validation.required'), required),
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@ -236,6 +265,20 @@ const v$ = useVuelidate(rules, userStore, {
|
|||||||
$scope: true,
|
$scope: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
onMounted(async () => {
|
||||||
|
await mailSenderStore.fetchMailSenders()
|
||||||
|
let mailSenderData = await mailSenderStore.fetchMailSenderList()
|
||||||
|
if (mailSenderData.data) {
|
||||||
|
mailSenders.value = mailSenderData.data.data
|
||||||
|
let defaultMailSender = mailSenderData.data.data.find(
|
||||||
|
(mailSender) => mailSender.is_default == true
|
||||||
|
)
|
||||||
|
userStore.userData.mail_sender_id = defaultMailSender
|
||||||
|
? defaultMailSender.id
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
loadInitialData()
|
loadInitialData()
|
||||||
|
|
||||||
userStore.resetUserData()
|
userStore.resetUserData()
|
||||||
|
|||||||
@ -100,7 +100,8 @@
|
|||||||
"pay_invoice": "Pay Invoice",
|
"pay_invoice": "Pay Invoice",
|
||||||
"login_successfully": "Logged in successfully!",
|
"login_successfully": "Logged in successfully!",
|
||||||
"logged_out_successfully": "Logged out successfully",
|
"logged_out_successfully": "Logged out successfully",
|
||||||
"mark_as_default": "Mark as default"
|
"mark_as_default": "Mark as default",
|
||||||
|
"send_test_mail": "Send Test Mail"
|
||||||
},
|
},
|
||||||
"dashboard": {
|
"dashboard": {
|
||||||
"select_year": "Select year",
|
"select_year": "Select year",
|
||||||
@ -233,7 +234,8 @@
|
|||||||
"updated_message": "Customer updated successfully",
|
"updated_message": "Customer updated successfully",
|
||||||
"address_updated_message": "Address Information Updated succesfully",
|
"address_updated_message": "Address Information Updated succesfully",
|
||||||
"deleted_message": "Customer deleted successfully | Customers deleted successfully",
|
"deleted_message": "Customer deleted successfully | Customers deleted successfully",
|
||||||
"edit_currency_not_allowed": "Cannot change currency once transactions created."
|
"edit_currency_not_allowed": "Cannot change currency once transactions created.",
|
||||||
|
"select_sender": "Select Sender"
|
||||||
},
|
},
|
||||||
"items": {
|
"items": {
|
||||||
"title": "Items",
|
"title": "Items",
|
||||||
@ -728,7 +730,8 @@
|
|||||||
"updated_message": "User updated successfully",
|
"updated_message": "User updated successfully",
|
||||||
"deleted_message": "User deleted successfully | Users deleted successfully",
|
"deleted_message": "User deleted successfully | Users deleted successfully",
|
||||||
"select_company_role": "Select Role for {company}",
|
"select_company_role": "Select Role for {company}",
|
||||||
"companies": "Companies"
|
"companies": "Companies",
|
||||||
|
"select_sender": "Select Sender"
|
||||||
},
|
},
|
||||||
"reports": {
|
"reports": {
|
||||||
"title": "Report",
|
"title": "Report",
|
||||||
@ -807,7 +810,8 @@
|
|||||||
"payment_modes": "Payment Modes",
|
"payment_modes": "Payment Modes",
|
||||||
"notes": "Notes",
|
"notes": "Notes",
|
||||||
"exchange_rate": "Exchange Rate",
|
"exchange_rate": "Exchange Rate",
|
||||||
"address_information": "Address Information"
|
"address_information": "Address Information",
|
||||||
|
"mail_sender": "Mail Senders"
|
||||||
},
|
},
|
||||||
"address_information": {
|
"address_information": {
|
||||||
"section_description": " You can update Your Address information using form below."
|
"section_description": " You can update Your Address information using form below."
|
||||||
@ -1311,6 +1315,51 @@
|
|||||||
"state_placeholder": "Example: CA",
|
"state_placeholder": "Example: CA",
|
||||||
"zip_placeholder": "Example: 90024",
|
"zip_placeholder": "Example: 90024",
|
||||||
"invalid_address": "Please provide valid address details."
|
"invalid_address": "Please provide valid address details."
|
||||||
|
},
|
||||||
|
"mail_sender": {
|
||||||
|
"title": "Mail Sender | Mail Senders",
|
||||||
|
"description": "Configure & test your mail senders for the selected company.",
|
||||||
|
"add_new_mail_sender": "New Mail Sender",
|
||||||
|
"name": "Sender Name",
|
||||||
|
"name_help": "Type a name to identify the sender for users.",
|
||||||
|
"driver": "Mail Driver",
|
||||||
|
"is_default": "Set as default",
|
||||||
|
"is_default_description": "You can only set one sender as default at a given time.",
|
||||||
|
"cc": "CC",
|
||||||
|
"bcc": "BCC",
|
||||||
|
"from_address": "From Mail Address",
|
||||||
|
"from_name": "From Mail Name",
|
||||||
|
"edit_mail_sender": "Edit Mail Sender",
|
||||||
|
"delete_mail_sender": "Delete Mail Sender",
|
||||||
|
"confirm_delete": "You will not be able to recover this Mail Sender",
|
||||||
|
"created_message": "Mail Sender created successfully",
|
||||||
|
"updated_message": "Mail Sender updated successfully",
|
||||||
|
"deleted_message": "Mail Sender deleted successfully",
|
||||||
|
"default_record_exists": "Default mail sender already exist",
|
||||||
|
"email_list": "Supports a comma separated list of email addresses",
|
||||||
|
"select_mail_sender": "Select Mail Sender",
|
||||||
|
"manage_mail_sender": "Manage Mail Senders",
|
||||||
|
"no_mail_sender_found": "No mail senders found!",
|
||||||
|
"no_mail_sender_found_description": "You must configure at-least one mail sender for the selected company in order to continue.",
|
||||||
|
"smtp_config": {
|
||||||
|
"host": "Host",
|
||||||
|
"port": "Port",
|
||||||
|
"username": "Username",
|
||||||
|
"password": "Password",
|
||||||
|
"encryption": "Encryption"
|
||||||
|
},
|
||||||
|
"mailgun_config": {
|
||||||
|
"domain": "Domain",
|
||||||
|
"secret": "Maingun Secret",
|
||||||
|
"endpoint": "Mailgun Endpoint"
|
||||||
|
},
|
||||||
|
"ses_config": {
|
||||||
|
"host": "Host",
|
||||||
|
"port": "Port",
|
||||||
|
"encryption": "Encryption",
|
||||||
|
"ses_key": "SES Key",
|
||||||
|
"ses_secret": "SES Secret"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"wizard": {
|
"wizard": {
|
||||||
@ -1523,4 +1572,4 @@
|
|||||||
"pdf_ship_to": "Ship to,",
|
"pdf_ship_to": "Ship to,",
|
||||||
"pdf_received_from": "Received from:",
|
"pdf_received_from": "Received from:",
|
||||||
"pdf_tax_label": "Tax"
|
"pdf_tax_label": "Tax"
|
||||||
}
|
}
|
||||||
@ -403,15 +403,12 @@ Route::prefix('/v1')->group(function () {
|
|||||||
// Mails
|
// Mails
|
||||||
//----------------------------------
|
//----------------------------------
|
||||||
|
|
||||||
Route::get('/mail/drivers', [MailConfigurationController::class, 'getMailDrivers']);
|
|
||||||
|
|
||||||
Route::post('/mail/test', [MailConfigurationController::class, 'testEmailConfig']);
|
|
||||||
// Route::get('/mail/config', [MailConfigurationController::class, 'getMailEnvironment']);
|
|
||||||
|
|
||||||
// Route::post('/mail/config', [MailConfigurationController::class, 'saveMailEnvironment']);
|
|
||||||
|
|
||||||
Route::apiResource('mail-sender', MailSenderController::class);
|
Route::apiResource('mail-sender', MailSenderController::class);
|
||||||
|
|
||||||
|
Route::get('/mail-drivers', [MailConfigurationController::class, 'getMailDrivers']);
|
||||||
|
|
||||||
|
Route::post('/mail-test', [MailConfigurationController::class, 'TestMailDriver']);
|
||||||
|
|
||||||
Route::get('mail-senders', GetAllMailSendersController::class);
|
Route::get('mail-senders', GetAllMailSendersController::class);
|
||||||
|
|
||||||
Route::get('/company/mail/config', GetCompanyMailConfigurationController::class);
|
Route::get('/company/mail/config', GetCompanyMailConfigurationController::class);
|
||||||
|
|||||||
Reference in New Issue
Block a user