From 4377a0571643e77080ffcf775151970bb7157ad0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?=
Date: Wed, 17 Jan 2024 17:41:54 +0100
Subject: [PATCH 01/18] wip
---
.../EmailPreferencesController.php | 45 +++++++++++++++++++
app/Services/Email/Email.php | 8 ++++
app/Utils/HtmlEngine.php | 2 +
.../views/email/template/plain.blade.php | 5 +++
.../generic/email_preferences.blade.php | 37 +++++++++++++++
routes/client.php | 5 +++
6 files changed, 102 insertions(+)
create mode 100644 app/Http/Controllers/ClientPortal/EmailPreferencesController.php
create mode 100644 resources/views/portal/ninja2020/generic/email_preferences.blade.php
diff --git a/app/Http/Controllers/ClientPortal/EmailPreferencesController.php b/app/Http/Controllers/ClientPortal/EmailPreferencesController.php
new file mode 100644
index 000000000000..247b3bba7446
--- /dev/null
+++ b/app/Http/Controllers/ClientPortal/EmailPreferencesController.php
@@ -0,0 +1,45 @@
+hasValidSignature()) {
+ abort(404);
+ }
+
+ $data['recieve_emails'] = $clientContact->is_locked ? false : true;
+ $data['logo'] = $clientContact->company->present()->logo();
+
+ return $this->render('generic.email_preferences', $data);
+ }
+
+ public function update(ClientContact $clientContact, Request $request): \Illuminate\Http\RedirectResponse
+ {
+ if (!$request->hasValidSignature()) {
+ abort(404);
+ }
+
+ $clientContact->is_locked = $request->has('recieve_emails') ? false : true;
+ $clientContact->save();
+
+ return back()->with('message', ctrans('texts.updated_settings'));
+ }
+}
+
diff --git a/app/Services/Email/Email.php b/app/Services/Email/Email.php
index cfe56bfb2f9e..d529eedf0b5a 100644
--- a/app/Services/Email/Email.php
+++ b/app/Services/Email/Email.php
@@ -99,6 +99,8 @@ class Email implements ShouldQueue
{
MultiDB::setDb($this->company->db);
+ info('here 1');
+
$this->setOverride()
->initModels()
->setDefaults()
@@ -241,6 +243,8 @@ class Email implements ShouldQueue
{
$this->mailable = new EmailMailable($this->email_object);
+ info('here 2');
+
return $this;
}
@@ -264,6 +268,10 @@ class Email implements ShouldQueue
$mailer->mailgun_config($this->client_mailgun_secret, $this->client_mailgun_domain, $this->client_mailgun_endpoint);
}
+ info("here 4");
+ info($this->mailable->view);
+ info(print_r($this->mailable));
+
/* Attempt the send! */
try {
nlog("Using mailer => ". $this->mailer. " ". now()->toDateTimeString());
diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php
index d4fe57993252..232d66995bf8 100644
--- a/app/Utils/HtmlEngine.php
+++ b/app/Utils/HtmlEngine.php
@@ -765,6 +765,8 @@ class HtmlEngine
$data[$key] = $value['value'];
}
+ info("here 3");
+
return $data;
}
diff --git a/resources/views/email/template/plain.blade.php b/resources/views/email/template/plain.blade.php
index 270144bf7931..7ee4034ea7b4 100644
--- a/resources/views/email/template/plain.blade.php
+++ b/resources/views/email/template/plain.blade.php
@@ -44,6 +44,11 @@
@endif
@endisset
+
+Hello world
+@isset($portal_url) {{ $portal_url }} @endisset
+After portal
+
@if(isset($unsubscribe_link))
{{ ctrans('texts.unsubscribe') }}
@endif
\ No newline at end of file
diff --git a/resources/views/portal/ninja2020/generic/email_preferences.blade.php b/resources/views/portal/ninja2020/generic/email_preferences.blade.php
new file mode 100644
index 000000000000..2c32ee9db0d5
--- /dev/null
+++ b/resources/views/portal/ninja2020/generic/email_preferences.blade.php
@@ -0,0 +1,37 @@
+@extends('portal.ninja2020.layout.clean') @section('meta_title',
+ctrans('texts.preferences')) @section('body')
+
+
+
+

+
+ {{ ctrans('texts.email_settings') }}
+
+
+
+
+
+
+@stop
diff --git a/routes/client.php b/routes/client.php
index 870b3514abdb..95956d4e5df4 100644
--- a/routes/client.php
+++ b/routes/client.php
@@ -1,5 +1,6 @@
middleware('throttle:404');
+
+
+Route::get('client/email_preferences/{clientContact}', [EmailPreferencesController::class, 'index'])->name('client.email_preferences');
+Route::put('client/email_preferences/{clientContact}', [EmailPreferencesController::class, 'update']);
From 5fba841ce68d0fe81dfdea6ae28135ebd54efce1 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?=
Date: Thu, 18 Jan 2024 16:52:19 +0100
Subject: [PATCH 02/18] Add email notification for client unsubscribe
---
.../ClientPortal/EmailPreferencesController.php | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/app/Http/Controllers/ClientPortal/EmailPreferencesController.php b/app/Http/Controllers/ClientPortal/EmailPreferencesController.php
index 247b3bba7446..e8400553ef5b 100644
--- a/app/Http/Controllers/ClientPortal/EmailPreferencesController.php
+++ b/app/Http/Controllers/ClientPortal/EmailPreferencesController.php
@@ -13,6 +13,10 @@
namespace App\Http\Controllers\ClientPortal;
use App\Http\Controllers\Controller;
+use App\Jobs\Mail\NinjaMailer;
+use App\Jobs\Mail\NinjaMailerJob;
+use App\Jobs\Mail\NinjaMailerObject;
+use App\Mail\Admin\ClientUnsubscribedObject;
use App\Models\ClientContact;
use Illuminate\Http\Request;
@@ -39,6 +43,16 @@ class EmailPreferencesController extends Controller
$clientContact->is_locked = $request->has('recieve_emails') ? false : true;
$clientContact->save();
+ if ($clientContact->is_locked) {
+ $nmo = new NinjaMailerObject();
+ $nmo->mailable = new NinjaMailer((new ClientUnsubscribedObject($clientContact, $clientContact->company))->build());
+ $nmo->company = $clientContact->company;
+ $nmo->to_user = $clientContact->company->owner();
+ $nmo->settings = $clientContact->company->settings;
+
+ (new NinjaMailerJob($nmo))->handle();
+ }
+
return back()->with('message', ctrans('texts.updated_settings'));
}
}
From b0a45f49d2eb6ddb7464cf6e9ba064e287959074 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?=
Date: Thu, 18 Jan 2024 16:52:25 +0100
Subject: [PATCH 03/18] Add URL dependency for email preferences
---
app/Mail/TemplateEmail.php | 2 ++
1 file changed, 2 insertions(+)
diff --git a/app/Mail/TemplateEmail.php b/app/Mail/TemplateEmail.php
index 1530ce9a4f8a..2abd4d52e71b 100644
--- a/app/Mail/TemplateEmail.php
+++ b/app/Mail/TemplateEmail.php
@@ -18,6 +18,7 @@ use App\Services\PdfMaker\Designs\Utilities\DesignHelpers;
use App\Utils\HtmlEngine;
use App\Utils\Ninja;
use Illuminate\Mail\Mailable;
+use Illuminate\Support\Facades\URL;
class TemplateEmail extends Mailable
{
@@ -138,6 +139,7 @@ class TemplateEmail extends Mailable
'whitelabel' => $this->client->user->account->isPaid() ? true : false,
'logo' => $this->company->present()->logo($settings),
'links' => $this->build_email->getAttachmentLinks(),
+ 'email_preferences' => URL::signedRoute('client.email_preferences', ['invitation_key' => $this->invitation->key, 'clientContact' => $this->contact->hashed_id]),
]);
foreach ($this->build_email->getAttachments() as $file) {
From c4ab87ade5585dae70550abf8b9d0733602f5b8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?=
Date: Thu, 18 Jan 2024 16:52:31 +0100
Subject: [PATCH 04/18] Add ClientUnsubscribedObject class for admin email
---
app/Mail/Admin/ClientUnsubscribedObject.php | 55 +++++++++++++++++++++
1 file changed, 55 insertions(+)
create mode 100644 app/Mail/Admin/ClientUnsubscribedObject.php
diff --git a/app/Mail/Admin/ClientUnsubscribedObject.php b/app/Mail/Admin/ClientUnsubscribedObject.php
new file mode 100644
index 000000000000..e884840acb82
--- /dev/null
+++ b/app/Mail/Admin/ClientUnsubscribedObject.php
@@ -0,0 +1,55 @@
+company->getLocale());
+ /* Set customized translations _NOW_ */
+ $t->replace(Ninja::transformTranslations($this->company->settings));
+
+ $data = [
+ 'title' => ctrans('texts.client_unsubscribed'),
+ 'message' => ctrans('texts.client_unsubscribed_help', ['client' => $this->contact->present()->name()]),
+ 'url' => $this->contact->client->portalUrl(false),
+ 'button' => ctrans('texts.view_client'),
+ 'signature' => $this->company->settings->email_signature,
+ 'settings' => $this->company->settings,
+ 'logo' => $this->company->present()->logo(),
+ ];
+
+ $mail_obj = new \stdClass();
+ $mail_obj->subject = ctrans('texts.client_unsubscribed');
+ $mail_obj->data = $data;
+ $mail_obj->markdown = 'email.admin.generic';
+ $mail_obj->tag = $this->company->company_key;
+
+ return $mail_obj;
+ }
+}
From d5d73b4a13f23a38d657ce5ecfd241071d5e36c7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?=
Date: Thu, 18 Jan 2024 16:52:38 +0100
Subject: [PATCH 05/18] Remove debug info statements from Email class
---
app/Services/Email/Email.php | 8 --------
1 file changed, 8 deletions(-)
diff --git a/app/Services/Email/Email.php b/app/Services/Email/Email.php
index d529eedf0b5a..cfe56bfb2f9e 100644
--- a/app/Services/Email/Email.php
+++ b/app/Services/Email/Email.php
@@ -99,8 +99,6 @@ class Email implements ShouldQueue
{
MultiDB::setDb($this->company->db);
- info('here 1');
-
$this->setOverride()
->initModels()
->setDefaults()
@@ -243,8 +241,6 @@ class Email implements ShouldQueue
{
$this->mailable = new EmailMailable($this->email_object);
- info('here 2');
-
return $this;
}
@@ -268,10 +264,6 @@ class Email implements ShouldQueue
$mailer->mailgun_config($this->client_mailgun_secret, $this->client_mailgun_domain, $this->client_mailgun_endpoint);
}
- info("here 4");
- info($this->mailable->view);
- info(print_r($this->mailable));
-
/* Attempt the send! */
try {
nlog("Using mailer => ". $this->mailer. " ". now()->toDateTimeString());
From e2cbe85cc0ce81bc6cd965deeb1074e2930427b6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?=
Date: Thu, 18 Jan 2024 16:52:43 +0100
Subject: [PATCH 06/18] Remove unnecessary debug statement in HtmlEngine.php
---
app/Utils/HtmlEngine.php | 2 --
1 file changed, 2 deletions(-)
diff --git a/app/Utils/HtmlEngine.php b/app/Utils/HtmlEngine.php
index 232d66995bf8..d4fe57993252 100644
--- a/app/Utils/HtmlEngine.php
+++ b/app/Utils/HtmlEngine.php
@@ -765,8 +765,6 @@ class HtmlEngine
$data[$key] = $value['value'];
}
- info("here 3");
-
return $data;
}
From 0b2e17b9d2cfd7fc922a890d0f8b4267b8fdedd2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?=
Date: Thu, 18 Jan 2024 16:52:48 +0100
Subject: [PATCH 07/18] Add client_unsubscribed message to texts.php
---
lang/en/texts.php | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lang/en/texts.php b/lang/en/texts.php
index b7df2cdddbbd..d8625e588a5c 100644
--- a/lang/en/texts.php
+++ b/lang/en/texts.php
@@ -5213,6 +5213,8 @@ $lang = array(
'nordigen_requisition_body' => 'Access to bank account feeds has expired as set in End User Agreement.
Please log into Invoice Ninja and re-authenticate with your banks to continue receiving transactions.',
'participant' => 'Participant',
'participant_name' => 'Participant name',
+ 'client_unsubscribed' => 'Client changed e-mail preferences',
+ 'client_unsubscribed_help' => 'Client :client changed preferences and unsubscribed from e-mails.',
);
return $lang;
From c68b1c07c77368fea17aeab6caed7fefd38d07da Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?=
Date: Thu, 18 Jan 2024 16:52:53 +0100
Subject: [PATCH 08/18] Add email preferences link to client email template
---
resources/views/email/template/client.blade.php | 17 ++++++++++++++++-
1 file changed, 16 insertions(+), 1 deletion(-)
diff --git a/resources/views/email/template/client.blade.php b/resources/views/email/template/client.blade.php
index 4d9462b2b370..7a4177cdc2e9 100644
--- a/resources/views/email/template/client.blade.php
+++ b/resources/views/email/template/client.blade.php
@@ -163,7 +163,7 @@
{{ $slot ?? '' }}
{!! $body ?? '' !!}
-
+
+
+ @isset($email_preferences)
+
+
+
+ |
+
+ @endisset
From 9fee6ed6da93fa3e59b5a4a6da637ac0c88c099f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?=
Date: Thu, 18 Jan 2024 16:52:57 +0100
Subject: [PATCH 09/18] Add email preferences link to dark email template
---
resources/views/email/template/dark.blade.php | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/resources/views/email/template/dark.blade.php b/resources/views/email/template/dark.blade.php
index c96087dd12f5..faaf2b30acce 100644
--- a/resources/views/email/template/dark.blade.php
+++ b/resources/views/email/template/dark.blade.php
@@ -14,4 +14,12 @@
@endif
+@isset($email_preferences)
+
+
+ {{ ctrans('texts.email_preferences') }}
+
+
+@endif
+
@endcomponent
From ca15f284cd81bc6d1fa561363523ebc609469ec2 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?=
Date: Thu, 18 Jan 2024 16:53:01 +0100
Subject: [PATCH 10/18] Add email preferences link to light email template
---
resources/views/email/template/light.blade.php | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/resources/views/email/template/light.blade.php b/resources/views/email/template/light.blade.php
index 43b495cf4452..9a82f9c9e21a 100644
--- a/resources/views/email/template/light.blade.php
+++ b/resources/views/email/template/light.blade.php
@@ -14,4 +14,12 @@
@endif
+@isset($email_preferences)
+
+
+ {{ ctrans('texts.email_preferences') }}
+
+
+@endif
+
@endcomponent
From 9f671a294785b54acbcf5d0aed8dfa213aa8242d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?=
Date: Thu, 18 Jan 2024 16:53:04 +0100
Subject: [PATCH 11/18] Add email preferences link and update unsubscribe link
---
resources/views/email/template/plain.blade.php | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/resources/views/email/template/plain.blade.php b/resources/views/email/template/plain.blade.php
index 7ee4034ea7b4..1ae5fe70b167 100644
--- a/resources/views/email/template/plain.blade.php
+++ b/resources/views/email/template/plain.blade.php
@@ -45,9 +45,12 @@
@endif
@endisset
-Hello world
-@isset($portal_url) {{ $portal_url }} @endisset
-After portal
+@if(isset($email_preferences))
+
+ {{ ctrans('texts.email_preferences') }}
+
+@endif
+
@if(isset($unsubscribe_link))
{{ ctrans('texts.unsubscribe') }}
From 4328413a15420d37cf67018475262b3d56d50c52 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?=
Date: Thu, 18 Jan 2024 16:53:08 +0100
Subject: [PATCH 12/18] Fix route middleware for email preferences
---
routes/client.php | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/routes/client.php b/routes/client.php
index 95956d4e5df4..eff978f740b0 100644
--- a/routes/client.php
+++ b/routes/client.php
@@ -161,6 +161,6 @@ Route::fallback(function () {
})->middleware('throttle:404');
-
-Route::get('client/email_preferences/{clientContact}', [EmailPreferencesController::class, 'index'])->name('client.email_preferences');
-Route::put('client/email_preferences/{clientContact}', [EmailPreferencesController::class, 'update']);
+// Fix me: Move into invite_db middleware group.
+Route::get('client/email_preferences/{clientContact}/{invitation_key}', [EmailPreferencesController::class, 'index'])->name('client.email_preferences');
+Route::put('client/email_preferences/{clientContact}/{invitation_key}', [EmailPreferencesController::class, 'update']);
From f6402f87a559a7f193cc9dfb71593186cd1db729 Mon Sep 17 00:00:00 2001
From: David Bomba
Date: Fri, 19 Jan 2024 13:45:24 +1100
Subject: [PATCH 13/18] Improvements for unsubscribe links
---
.../EmailPreferencesController.php | 36 +++++++++----------
app/Mail/TemplateEmail.php | 2 +-
app/Models/CreditInvitation.php | 5 +++
app/Models/InvoiceInvitation.php | 5 +++
app/Models/PurchaseOrderInvitation.php | 5 +++
app/Models/QuoteInvitation.php | 5 +++
app/Models/RecurringInvoiceInvitation.php | 6 ++++
lang/en/texts.php | 1 +
.../views/email/template/client.blade.php | 2 +-
.../generic/email_preferences.blade.php | 14 ++++----
routes/client.php | 5 +--
11 files changed, 57 insertions(+), 29 deletions(-)
diff --git a/app/Http/Controllers/ClientPortal/EmailPreferencesController.php b/app/Http/Controllers/ClientPortal/EmailPreferencesController.php
index e8400553ef5b..5ed1311b0e3c 100644
--- a/app/Http/Controllers/ClientPortal/EmailPreferencesController.php
+++ b/app/Http/Controllers/ClientPortal/EmailPreferencesController.php
@@ -19,38 +19,38 @@ use App\Jobs\Mail\NinjaMailerObject;
use App\Mail\Admin\ClientUnsubscribedObject;
use App\Models\ClientContact;
use Illuminate\Http\Request;
+use Illuminate\Support\Str;
class EmailPreferencesController extends Controller
{
- public function index(ClientContact $clientContact, Request $request): \Illuminate\View\View
+ public function index(string $entity, string $invitation_key, Request $request): \Illuminate\View\View
{
- if (!$request->hasValidSignature()) {
- abort(404);
- }
+ $class = "\\App\\Models\\".ucfirst(Str::camel($entity)).'Invitation';
+ $invitation = $class::where('key', $invitation_key)->firstOrFail();
- $data['recieve_emails'] = $clientContact->is_locked ? false : true;
- $data['logo'] = $clientContact->company->present()->logo();
+ $data['receive_emails'] = $invitation->contact->is_locked ? false : true;
+ $data['company'] = $invitation->company;
return $this->render('generic.email_preferences', $data);
}
- public function update(ClientContact $clientContact, Request $request): \Illuminate\Http\RedirectResponse
+ public function update(string $entity, string $invitation_key, Request $request): \Illuminate\Http\RedirectResponse
{
- if (!$request->hasValidSignature()) {
- abort(404);
- }
+
+ $class = "\\App\\Models\\" . ucfirst(Str::camel($entity)) . 'Invitation';
+ $invitation = $class::withTrashed()->where('key', $invitation_key)->firstOrFail();
- $clientContact->is_locked = $request->has('recieve_emails') ? false : true;
- $clientContact->save();
+ $invitation->contact->is_locked = $request->has('receive_emails') ? false : true;
+ $invitation->contact->push();
- if ($clientContact->is_locked) {
+ if ($invitation->contact->is_locked) {
$nmo = new NinjaMailerObject();
- $nmo->mailable = new NinjaMailer((new ClientUnsubscribedObject($clientContact, $clientContact->company))->build());
- $nmo->company = $clientContact->company;
- $nmo->to_user = $clientContact->company->owner();
- $nmo->settings = $clientContact->company->settings;
+ $nmo->mailable = new NinjaMailer((new ClientUnsubscribedObject($invitation->contact, $invitation->contact->company))->build());
+ $nmo->company = $invitation->contact->company;
+ $nmo->to_user = $invitation->contact->company->owner();
+ $nmo->settings = $invitation->contact->company->settings;
- (new NinjaMailerJob($nmo))->handle();
+ NinjaMailerJob::dispatch($nmo);
}
return back()->with('message', ctrans('texts.updated_settings'));
diff --git a/app/Mail/TemplateEmail.php b/app/Mail/TemplateEmail.php
index 2abd4d52e71b..f9f4b1562a21 100644
--- a/app/Mail/TemplateEmail.php
+++ b/app/Mail/TemplateEmail.php
@@ -139,7 +139,7 @@ class TemplateEmail extends Mailable
'whitelabel' => $this->client->user->account->isPaid() ? true : false,
'logo' => $this->company->present()->logo($settings),
'links' => $this->build_email->getAttachmentLinks(),
- 'email_preferences' => URL::signedRoute('client.email_preferences', ['invitation_key' => $this->invitation->key, 'clientContact' => $this->contact->hashed_id]),
+ 'email_preferences' => URL::signedRoute('client.email_preferences', ['entity' => $this->invitation->getEntityString(), 'invitation_key' => $this->invitation->key]),
]);
foreach ($this->build_email->getAttachments() as $file) {
diff --git a/app/Models/CreditInvitation.php b/app/Models/CreditInvitation.php
index 545585bcc5e3..83656270280f 100644
--- a/app/Models/CreditInvitation.php
+++ b/app/Models/CreditInvitation.php
@@ -97,6 +97,11 @@ class CreditInvitation extends BaseModel
return self::class;
}
+ public function getEntityString(): string
+ {
+ return 'credit';
+ }
+
public function entityType()
{
return Credit::class;
diff --git a/app/Models/InvoiceInvitation.php b/app/Models/InvoiceInvitation.php
index 2f5c6c08a1df..58c191fc4a41 100644
--- a/app/Models/InvoiceInvitation.php
+++ b/app/Models/InvoiceInvitation.php
@@ -97,6 +97,11 @@ class InvoiceInvitation extends BaseModel
return self::class;
}
+ public function getEntityString(): string
+ {
+ return 'invoice';
+ }
+
public function entityType()
{
return Invoice::class;
diff --git a/app/Models/PurchaseOrderInvitation.php b/app/Models/PurchaseOrderInvitation.php
index a1702ea6b926..7584256f72c9 100644
--- a/app/Models/PurchaseOrderInvitation.php
+++ b/app/Models/PurchaseOrderInvitation.php
@@ -97,6 +97,11 @@ class PurchaseOrderInvitation extends BaseModel
return self::class;
}
+ public function getEntityString(): string
+ {
+ return 'purchase_order';
+ }
+
public function entityType()
{
return PurchaseOrder::class;
diff --git a/app/Models/QuoteInvitation.php b/app/Models/QuoteInvitation.php
index 65aef2e2556a..e1c3c726973c 100644
--- a/app/Models/QuoteInvitation.php
+++ b/app/Models/QuoteInvitation.php
@@ -78,6 +78,11 @@ class QuoteInvitation extends BaseModel
return self::class;
}
+ public function getEntityString(): string
+ {
+ return 'quote';
+ }
+
public function entityType()
{
return Quote::class;
diff --git a/app/Models/RecurringInvoiceInvitation.php b/app/Models/RecurringInvoiceInvitation.php
index 34928a155c1d..a5fe7868db4e 100644
--- a/app/Models/RecurringInvoiceInvitation.php
+++ b/app/Models/RecurringInvoiceInvitation.php
@@ -91,6 +91,12 @@ class RecurringInvoiceInvitation extends BaseModel
return self::class;
}
+
+ public function getEntityString(): string
+ {
+ return 'recurring_invoice';
+ }
+
public function entityType()
{
return RecurringInvoice::class;
diff --git a/lang/en/texts.php b/lang/en/texts.php
index d8625e588a5c..4a0f3c5c20aa 100644
--- a/lang/en/texts.php
+++ b/lang/en/texts.php
@@ -5215,6 +5215,7 @@ $lang = array(
'participant_name' => 'Participant name',
'client_unsubscribed' => 'Client changed e-mail preferences',
'client_unsubscribed_help' => 'Client :client changed preferences and unsubscribed from e-mails.',
+ 'resubscribe' => 'Resubscribe',
);
return $lang;
diff --git a/resources/views/email/template/client.blade.php b/resources/views/email/template/client.blade.php
index 7a4177cdc2e9..2986b35345fb 100644
--- a/resources/views/email/template/client.blade.php
+++ b/resources/views/email/template/client.blade.php
@@ -240,7 +240,7 @@
style="padding-top: 10px;padding-bottom: 10px; background-color: #242424; border: 1px solid #c2c2c2; border-top-color: #242424; border-bottom-color: #242424;">
- {{ ctrans('texts.email_preferences') }}
+ {{ ctrans('texts.unsubscribe') }}
diff --git a/resources/views/portal/ninja2020/generic/email_preferences.blade.php b/resources/views/portal/ninja2020/generic/email_preferences.blade.php
index 2c32ee9db0d5..492c42e2fce5 100644
--- a/resources/views/portal/ninja2020/generic/email_preferences.blade.php
+++ b/resources/views/portal/ninja2020/generic/email_preferences.blade.php
@@ -4,9 +4,9 @@ ctrans('texts.preferences')) @section('body')
{{ ctrans('texts.email_settings') }}
@@ -15,13 +15,13 @@ ctrans('texts.preferences')) @section('body')
From 27dd844f7928b22a0411ecc06db016b43474df97 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?=
Date: Fri, 19 Jan 2024 15:20:27 +0100
Subject: [PATCH 16/18] Add email preferences link to EmailMailable class
---
app/Services/Email/EmailMailable.php | 3 +++
1 file changed, 3 insertions(+)
diff --git a/app/Services/Email/EmailMailable.php b/app/Services/Email/EmailMailable.php
index 2599d7d30161..ada43bab730d 100644
--- a/app/Services/Email/EmailMailable.php
+++ b/app/Services/Email/EmailMailable.php
@@ -77,6 +77,9 @@ class EmailMailable extends Mailable
'company' => $this->email_object->company,
'greeting' => '',
'links' => array_merge($this->email_object->links, $links->toArray()),
+ 'email_preferences' => $this->email_object->invitation
+ ? URL::signedRoute('client.email_preferences', ['entity' => $this->email_object->invitation->getEntityString(), 'invitation_key' => $this->email_object->invitation->key])
+ : false,
]
);
}
From 6052e4418615e2a965a1d0f10b8d33e8c9984c92 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Benjamin=20Beganovi=C4=87?=
Date: Fri, 19 Jan 2024 15:20:31 +0100
Subject: [PATCH 17/18] Add subscribe and unsubscribe help messages
---
lang/en/texts.php | 3 +++
1 file changed, 3 insertions(+)
diff --git a/lang/en/texts.php b/lang/en/texts.php
index 4a0f3c5c20aa..4fc584147e40 100644
--- a/lang/en/texts.php
+++ b/lang/en/texts.php
@@ -5216,6 +5216,9 @@ $lang = array(
'client_unsubscribed' => 'Client changed e-mail preferences',
'client_unsubscribed_help' => 'Client :client changed preferences and unsubscribed from e-mails.',
'resubscribe' => 'Resubscribe',
+ 'subscribe' => 'Subscribe',
+ 'subscribe_help' => 'You are currently subscribed and will continue to receive email communications.',
+ 'unsubscribe_help' => 'You are currently not subscribed, and therefore, will not receive emails at this time.',
);
return $lang;
From 48374cf009eec5a73e48bdd297aea4d346e30b52 Mon Sep 17 00:00:00 2001
From: David Bomba
Date: Mon, 22 Jan 2024 10:52:30 +1100
Subject: [PATCH 18/18] Updates for unsubscribe
---
.../EmailPreferencesController.php | 15 ++++----
app/Mail/Admin/ClientUnsubscribedObject.php | 9 +++--
app/Models/ClientContact.php | 35 +++++++++++++------
lang/en/texts.php | 4 +--
4 files changed, 41 insertions(+), 22 deletions(-)
diff --git a/app/Http/Controllers/ClientPortal/EmailPreferencesController.php b/app/Http/Controllers/ClientPortal/EmailPreferencesController.php
index f7b1417aa516..6fd5063756aa 100644
--- a/app/Http/Controllers/ClientPortal/EmailPreferencesController.php
+++ b/app/Http/Controllers/ClientPortal/EmailPreferencesController.php
@@ -12,14 +12,15 @@
namespace App\Http\Controllers\ClientPortal;
-use App\Http\Controllers\Controller;
+use Illuminate\Support\Str;
+use Illuminate\Http\Request;
+use App\Models\ClientContact;
use App\Jobs\Mail\NinjaMailer;
use App\Jobs\Mail\NinjaMailerJob;
+use App\Http\Controllers\Controller;
use App\Jobs\Mail\NinjaMailerObject;
+use Illuminate\Support\Facades\Cache;
use App\Mail\Admin\ClientUnsubscribedObject;
-use App\Models\ClientContact;
-use Illuminate\Http\Request;
-use Illuminate\Support\Str;
class EmailPreferencesController extends Controller
{
@@ -42,14 +43,16 @@ class EmailPreferencesController extends Controller
$invitation->contact->is_locked = $request->action === 'unsubscribe' ? true : false;
$invitation->contact->push();
- if ($invitation->contact->is_locked) {
+ if ($invitation->contact->is_locked && !Cache::has("unsubscribe_notitfication_suppression:{$invitation_key}")) {
$nmo = new NinjaMailerObject();
- $nmo->mailable = new NinjaMailer((new ClientUnsubscribedObject($invitation->contact, $invitation->contact->company))->build());
+ $nmo->mailable = new NinjaMailer((new ClientUnsubscribedObject($invitation->contact, $invitation->contact->company, $invitation->contact->company->owner()->company_users()->first()->portalType() ?? true))->build());
$nmo->company = $invitation->contact->company;
$nmo->to_user = $invitation->contact->company->owner();
$nmo->settings = $invitation->contact->company->settings;
NinjaMailerJob::dispatch($nmo);
+
+ Cache::put("unsubscribe_notitfication_suppression:{$invitation_key}", true, 3600);
}
return back()->with('message', ctrans('texts.updated_settings'));
diff --git a/app/Mail/Admin/ClientUnsubscribedObject.php b/app/Mail/Admin/ClientUnsubscribedObject.php
index e884840acb82..eb0190ab161f 100644
--- a/app/Mail/Admin/ClientUnsubscribedObject.php
+++ b/app/Mail/Admin/ClientUnsubscribedObject.php
@@ -20,7 +20,8 @@ class ClientUnsubscribedObject
{
public function __construct(
public ClientContact $contact,
- public Company $company
+ public Company $company,
+ private bool $use_react_link = false
) {
}
@@ -36,12 +37,13 @@ class ClientUnsubscribedObject
$data = [
'title' => ctrans('texts.client_unsubscribed'),
- 'message' => ctrans('texts.client_unsubscribed_help', ['client' => $this->contact->present()->name()]),
- 'url' => $this->contact->client->portalUrl(false),
+ 'content' => ctrans('texts.client_unsubscribed_help', ['client' => $this->contact->present()->name()]),
+ 'url' => $this->contact->getAdminLink($this->use_react_link),
'button' => ctrans('texts.view_client'),
'signature' => $this->company->settings->email_signature,
'settings' => $this->company->settings,
'logo' => $this->company->present()->logo(),
+ 'text_body' => "\n\n".ctrans('texts.client_unsubscribed_help', ['client' => $this->contact->present()->name()])."\n\n",
];
$mail_obj = new \stdClass();
@@ -49,6 +51,7 @@ class ClientUnsubscribedObject
$mail_obj->data = $data;
$mail_obj->markdown = 'email.admin.generic';
$mail_obj->tag = $this->company->company_key;
+ $mail_obj->text_view = 'email.template.text';
return $mail_obj;
}
diff --git a/app/Models/ClientContact.php b/app/Models/ClientContact.php
index 0acdfb09cf42..2f5a948feae8 100644
--- a/app/Models/ClientContact.php
+++ b/app/Models/ClientContact.php
@@ -11,22 +11,23 @@
namespace App\Models;
-use App\Jobs\Mail\NinjaMailer;
-use App\Jobs\Mail\NinjaMailerJob;
-use App\Jobs\Mail\NinjaMailerObject;
-use App\Mail\ClientContact\ClientContactResetPasswordObject;
-use App\Models\Presenters\ClientContactPresenter;
use App\Utils\Ninja;
+use Illuminate\Support\Str;
+use App\Jobs\Mail\NinjaMailer;
use App\Utils\Traits\AppSetup;
use App\Utils\Traits\MakesHash;
-use Illuminate\Contracts\Translation\HasLocalePreference;
-use Illuminate\Database\Eloquent\Factories\HasFactory;
-use Illuminate\Database\Eloquent\Model;
-use Illuminate\Database\Eloquent\SoftDeletes;
-use Illuminate\Foundation\Auth\User as Authenticatable;
-use Illuminate\Notifications\Notifiable;
+use App\Jobs\Mail\NinjaMailerJob;
+use App\Jobs\Mail\NinjaMailerObject;
use Illuminate\Support\Facades\Cache;
+use Illuminate\Database\Eloquent\Model;
+use Illuminate\Notifications\Notifiable;
use Laracasts\Presenter\PresentableTrait;
+use Illuminate\Database\Eloquent\SoftDeletes;
+use App\Models\Presenters\ClientContactPresenter;
+use Illuminate\Database\Eloquent\Factories\HasFactory;
+use Illuminate\Foundation\Auth\User as Authenticatable;
+use Illuminate\Contracts\Translation\HasLocalePreference;
+use App\Mail\ClientContact\ClientContactResetPasswordObject;
/**
* Class ClientContact
@@ -339,4 +340,16 @@ class ClientContact extends Authenticatable implements HasLocalePreference
return '';
}
}
+
+ public function getAdminLink($use_react_link = false): string
+ {
+ return $use_react_link ? $this->getReactLink() : config('ninja.app_url');
+ }
+
+ private function getReactLink(): string
+ {
+ return config('ninja.react_url')."/#/clients/{$this->client->hashed_id}";
+ }
+
+
}
diff --git a/lang/en/texts.php b/lang/en/texts.php
index 4fc584147e40..ceb0e221993e 100644
--- a/lang/en/texts.php
+++ b/lang/en/texts.php
@@ -5213,8 +5213,8 @@ $lang = array(
'nordigen_requisition_body' => 'Access to bank account feeds has expired as set in End User Agreement.
Please log into Invoice Ninja and re-authenticate with your banks to continue receiving transactions.',
'participant' => 'Participant',
'participant_name' => 'Participant name',
- 'client_unsubscribed' => 'Client changed e-mail preferences',
- 'client_unsubscribed_help' => 'Client :client changed preferences and unsubscribed from e-mails.',
+ 'client_unsubscribed' => 'Client unsubscribed from emails.',
+ 'client_unsubscribed_help' => 'Client :client has unsubscribed from your e-mails. The client needs to consent to receive future emails from you.',
'resubscribe' => 'Resubscribe',
'subscribe' => 'Subscribe',
'subscribe_help' => 'You are currently subscribed and will continue to receive email communications.',