Compare commits
1 Commits
91caa16e70
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 845665c8be |
@@ -8,6 +8,8 @@ use App\Http\Controllers\Controller;
|
|||||||
use App\Http\Requests\Admin\DestroySubscriberRequest;
|
use App\Http\Requests\Admin\DestroySubscriberRequest;
|
||||||
use App\Http\Requests\Admin\IndexSubscriberRequest;
|
use App\Http\Requests\Admin\IndexSubscriberRequest;
|
||||||
use App\Http\Requests\Admin\QueueMailwizzSyncRequest;
|
use App\Http\Requests\Admin\QueueMailwizzSyncRequest;
|
||||||
|
use App\Http\Requests\Admin\SyncSubscriberMailwizzRequest;
|
||||||
|
use App\Jobs\SyncSubscriberToMailwizz;
|
||||||
use App\Models\PreregistrationPage;
|
use App\Models\PreregistrationPage;
|
||||||
use App\Models\Subscriber;
|
use App\Models\Subscriber;
|
||||||
use App\Services\CleanupSubscriberIntegrationsService;
|
use App\Services\CleanupSubscriberIntegrationsService;
|
||||||
@@ -79,6 +81,26 @@ class SubscriberController extends Controller
|
|||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function syncSubscriberMailwizz(
|
||||||
|
SyncSubscriberMailwizzRequest $request,
|
||||||
|
PreregistrationPage $page,
|
||||||
|
Subscriber $subscriber
|
||||||
|
): RedirectResponse {
|
||||||
|
$page->loadMissing('mailwizzConfig');
|
||||||
|
|
||||||
|
if ($page->mailwizzConfig === null) {
|
||||||
|
return redirect()
|
||||||
|
->route('admin.pages.subscribers.index', $page)
|
||||||
|
->with('error', __('This page has no Mailwizz integration.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
SyncSubscriberToMailwizz::dispatch($subscriber->fresh());
|
||||||
|
|
||||||
|
return redirect()
|
||||||
|
->route('admin.pages.subscribers.index', $page)
|
||||||
|
->with('status', __('Mailwizz sync has been queued for this subscriber.'));
|
||||||
|
}
|
||||||
|
|
||||||
public function export(IndexSubscriberRequest $request, PreregistrationPage $page): StreamedResponse
|
public function export(IndexSubscriberRequest $request, PreregistrationPage $page): StreamedResponse
|
||||||
{
|
{
|
||||||
$search = $request->validated('search');
|
$search = $request->validated('search');
|
||||||
|
|||||||
36
app/Http/Requests/Admin/SyncSubscriberMailwizzRequest.php
Normal file
36
app/Http/Requests/Admin/SyncSubscriberMailwizzRequest.php
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace App\Http\Requests\Admin;
|
||||||
|
|
||||||
|
use App\Models\PreregistrationPage;
|
||||||
|
use App\Models\Subscriber;
|
||||||
|
use Illuminate\Contracts\Validation\ValidationRule;
|
||||||
|
use Illuminate\Foundation\Http\FormRequest;
|
||||||
|
|
||||||
|
class SyncSubscriberMailwizzRequest extends FormRequest
|
||||||
|
{
|
||||||
|
public function authorize(): bool
|
||||||
|
{
|
||||||
|
$page = $this->route('page');
|
||||||
|
$subscriber = $this->route('subscriber');
|
||||||
|
if (! $page instanceof PreregistrationPage || ! $subscriber instanceof Subscriber) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($subscriber->preregistration_page_id !== $page->id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->user()?->can('update', $page) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return array<string, array<int, ValidationRule|string>>
|
||||||
|
*/
|
||||||
|
public function rules(): array
|
||||||
|
{
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -24,6 +24,9 @@
|
|||||||
"Subscriber removed.": "Abonnee verwijderd.",
|
"Subscriber removed.": "Abonnee verwijderd.",
|
||||||
"Delete this subscriber? This cannot be undone.": "Deze abonnee verwijderen? Dit kan niet ongedaan worden gemaakt.",
|
"Delete this subscriber? This cannot be undone.": "Deze abonnee verwijderen? Dit kan niet ongedaan worden gemaakt.",
|
||||||
"Remove": "Verwijderen",
|
"Remove": "Verwijderen",
|
||||||
|
"Sync Mailwizz": "Mailwizz sync",
|
||||||
|
"Mailwizz sync has been queued for this subscriber.": "Mailwizz-synchronisatie is in de wachtrij gezet voor deze abonnee.",
|
||||||
|
"Queue a Mailwizz sync for this subscriber? The tag and coupon code will be sent when the queue worker runs.": "Mailwizz-synchronisatie voor deze abonnee in de wachtrij zetten? De tag en kortingscode worden verstuurd zodra de queue-worker draait.",
|
||||||
"Actions": "Acties",
|
"Actions": "Acties",
|
||||||
"Fix background to viewport": "Achtergrond vastzetten op het scherm",
|
"Fix background to viewport": "Achtergrond vastzetten op het scherm",
|
||||||
"When enabled, the background image and overlay stay fixed while visitors scroll long content.": "Als dit aan staat, blijven de achtergrondafbeelding en de overlay stilstaan terwijl bezoekers door lange inhoud scrollen."
|
"When enabled, the background image and overlay stay fixed while visitors scroll long content.": "Als dit aan staat, blijven de achtergrondafbeelding en de overlay stilstaan terwijl bezoekers door lange inhoud scrollen."
|
||||||
|
|||||||
@@ -82,21 +82,39 @@
|
|||||||
</td>
|
</td>
|
||||||
<td class="whitespace-nowrap px-4 py-3 text-right">
|
<td class="whitespace-nowrap px-4 py-3 text-right">
|
||||||
@can('update', $page)
|
@can('update', $page)
|
||||||
<form
|
<div class="inline-flex flex-wrap items-center justify-end gap-1.5">
|
||||||
method="post"
|
@if ($page->mailwizzConfig !== null)
|
||||||
action="{{ route('admin.pages.subscribers.destroy', [$page, $subscriber]) }}"
|
<form
|
||||||
class="inline"
|
method="post"
|
||||||
onsubmit="return confirm(@js(__('Delete this subscriber? This cannot be undone.')));"
|
action="{{ route('admin.pages.subscribers.sync-mailwizz', [$page, $subscriber]) }}"
|
||||||
>
|
class="inline"
|
||||||
@csrf
|
onsubmit="return confirm(@js(__('Queue a Mailwizz sync for this subscriber? The tag and coupon code will be sent when the queue worker runs.')));"
|
||||||
@method('DELETE')
|
>
|
||||||
<button
|
@csrf
|
||||||
type="submit"
|
<button
|
||||||
class="rounded-lg border border-red-200 bg-white px-2.5 py-1 text-xs font-semibold text-red-700 hover:bg-red-50"
|
type="submit"
|
||||||
|
class="rounded-lg border border-indigo-200 bg-white px-2.5 py-1 text-xs font-semibold text-indigo-700 hover:bg-indigo-50"
|
||||||
|
>
|
||||||
|
{{ __('Sync Mailwizz') }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
@endif
|
||||||
|
<form
|
||||||
|
method="post"
|
||||||
|
action="{{ route('admin.pages.subscribers.destroy', [$page, $subscriber]) }}"
|
||||||
|
class="inline"
|
||||||
|
onsubmit="return confirm(@js(__('Delete this subscriber? This cannot be undone.')));"
|
||||||
>
|
>
|
||||||
{{ __('Remove') }}
|
@csrf
|
||||||
</button>
|
@method('DELETE')
|
||||||
</form>
|
<button
|
||||||
|
type="submit"
|
||||||
|
class="rounded-lg border border-red-200 bg-white px-2.5 py-1 text-xs font-semibold text-red-700 hover:bg-red-50"
|
||||||
|
>
|
||||||
|
{{ __('Remove') }}
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
@endcan
|
@endcan
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ Route::middleware(['auth', 'verified'])->prefix('admin')->name('admin.')->group(
|
|||||||
Route::get('pages/{page}/subscribers/export', [SubscriberController::class, 'export'])->name('pages.subscribers.export');
|
Route::get('pages/{page}/subscribers/export', [SubscriberController::class, 'export'])->name('pages.subscribers.export');
|
||||||
Route::delete('pages/{page}/subscribers/{subscriber}', [SubscriberController::class, 'destroy'])->name('pages.subscribers.destroy');
|
Route::delete('pages/{page}/subscribers/{subscriber}', [SubscriberController::class, 'destroy'])->name('pages.subscribers.destroy');
|
||||||
Route::post('pages/{page}/subscribers/queue-mailwizz-sync', [SubscriberController::class, 'queueMailwizzSync'])->name('pages.subscribers.queue-mailwizz-sync');
|
Route::post('pages/{page}/subscribers/queue-mailwizz-sync', [SubscriberController::class, 'queueMailwizzSync'])->name('pages.subscribers.queue-mailwizz-sync');
|
||||||
|
Route::post('pages/{page}/subscribers/{subscriber}/sync-mailwizz', [SubscriberController::class, 'syncSubscriberMailwizz'])->name('pages.subscribers.sync-mailwizz');
|
||||||
Route::get('pages/{page}/subscribers', [SubscriberController::class, 'index'])->name('pages.subscribers.index');
|
Route::get('pages/{page}/subscribers', [SubscriberController::class, 'index'])->name('pages.subscribers.index');
|
||||||
|
|
||||||
// Mailwizz configuration (nested under pages)
|
// Mailwizz configuration (nested under pages)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||||||
|
|
||||||
namespace Tests\Feature;
|
namespace Tests\Feature;
|
||||||
|
|
||||||
|
use App\Jobs\SyncSubscriberToMailwizz;
|
||||||
use App\Models\MailwizzConfig;
|
use App\Models\MailwizzConfig;
|
||||||
use App\Models\PreregistrationPage;
|
use App\Models\PreregistrationPage;
|
||||||
use App\Models\Subscriber;
|
use App\Models\Subscriber;
|
||||||
@@ -12,6 +13,7 @@ use Illuminate\Foundation\Testing\RefreshDatabase;
|
|||||||
use Illuminate\Http\Client\Request;
|
use Illuminate\Http\Client\Request;
|
||||||
use Illuminate\Support\Facades\Artisan;
|
use Illuminate\Support\Facades\Artisan;
|
||||||
use Illuminate\Support\Facades\Http;
|
use Illuminate\Support\Facades\Http;
|
||||||
|
use Illuminate\Support\Facades\Queue;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
|
|
||||||
@@ -80,6 +82,135 @@ class QueueUnsyncedMailwizzSubscribersTest extends TestCase
|
|||||||
$response->assertForbidden();
|
$response->assertForbidden();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function test_owner_can_queue_single_subscriber_mailwizz_sync(): void
|
||||||
|
{
|
||||||
|
Queue::fake();
|
||||||
|
|
||||||
|
$user = User::factory()->create(['role' => 'user']);
|
||||||
|
$page = $this->makePageWithMailwizzForUser($user);
|
||||||
|
$subscriber = Subscriber::query()->create([
|
||||||
|
'preregistration_page_id' => $page->id,
|
||||||
|
'first_name' => 'One',
|
||||||
|
'last_name' => 'Off',
|
||||||
|
'email' => 'oneoff@example.com',
|
||||||
|
'synced_to_mailwizz' => true,
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = $this->actingAs($user)->post(
|
||||||
|
route('admin.pages.subscribers.sync-mailwizz', [$page, $subscriber])
|
||||||
|
);
|
||||||
|
|
||||||
|
$response->assertRedirect(route('admin.pages.subscribers.index', $page));
|
||||||
|
$response->assertSessionHas('status');
|
||||||
|
Queue::assertPushed(SyncSubscriberToMailwizz::class, function (SyncSubscriberToMailwizz $job) use ($subscriber): bool {
|
||||||
|
return $job->subscriberId === $subscriber->id;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_other_user_cannot_queue_single_subscriber_mailwizz_sync(): void
|
||||||
|
{
|
||||||
|
Queue::fake();
|
||||||
|
|
||||||
|
$owner = User::factory()->create(['role' => 'user']);
|
||||||
|
$intruder = User::factory()->create(['role' => 'user']);
|
||||||
|
$page = $this->makePageWithMailwizzForUser($owner);
|
||||||
|
$subscriber = Subscriber::query()->create([
|
||||||
|
'preregistration_page_id' => $page->id,
|
||||||
|
'first_name' => 'A',
|
||||||
|
'last_name' => 'B',
|
||||||
|
'email' => 'ab@example.com',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = $this->actingAs($intruder)->post(
|
||||||
|
route('admin.pages.subscribers.sync-mailwizz', [$page, $subscriber])
|
||||||
|
);
|
||||||
|
|
||||||
|
$response->assertForbidden();
|
||||||
|
Queue::assertNothingPushed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_single_subscriber_mailwizz_sync_redirects_with_error_when_page_has_no_mailwizz(): void
|
||||||
|
{
|
||||||
|
Queue::fake();
|
||||||
|
|
||||||
|
$user = User::factory()->create(['role' => 'user']);
|
||||||
|
$page = PreregistrationPage::query()->create([
|
||||||
|
'slug' => (string) Str::uuid(),
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'title' => 'Fest',
|
||||||
|
'heading' => 'Join',
|
||||||
|
'intro_text' => null,
|
||||||
|
'thank_you_message' => null,
|
||||||
|
'expired_message' => null,
|
||||||
|
'ticketshop_url' => null,
|
||||||
|
'start_date' => now()->subHour(),
|
||||||
|
'end_date' => now()->addMonth(),
|
||||||
|
'phone_enabled' => false,
|
||||||
|
'is_active' => true,
|
||||||
|
]);
|
||||||
|
$subscriber = Subscriber::query()->create([
|
||||||
|
'preregistration_page_id' => $page->id,
|
||||||
|
'first_name' => 'A',
|
||||||
|
'last_name' => 'B',
|
||||||
|
'email' => 'nomw@example.com',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = $this->actingAs($user)->post(
|
||||||
|
route('admin.pages.subscribers.sync-mailwizz', [$page, $subscriber])
|
||||||
|
);
|
||||||
|
|
||||||
|
$response->assertRedirect(route('admin.pages.subscribers.index', $page));
|
||||||
|
$response->assertSessionHas('error');
|
||||||
|
Queue::assertNothingPushed();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function test_cannot_queue_single_subscriber_mailwizz_sync_with_mismatched_page(): void
|
||||||
|
{
|
||||||
|
Queue::fake();
|
||||||
|
|
||||||
|
$user = User::factory()->create(['role' => 'user']);
|
||||||
|
$pageA = $this->makePageWithMailwizzForUser($user);
|
||||||
|
$pageB = PreregistrationPage::query()->create([
|
||||||
|
'slug' => (string) Str::uuid(),
|
||||||
|
'user_id' => $user->id,
|
||||||
|
'title' => 'Other',
|
||||||
|
'heading' => 'Other',
|
||||||
|
'intro_text' => null,
|
||||||
|
'thank_you_message' => null,
|
||||||
|
'expired_message' => null,
|
||||||
|
'ticketshop_url' => null,
|
||||||
|
'start_date' => now()->subHour(),
|
||||||
|
'end_date' => now()->addMonth(),
|
||||||
|
'phone_enabled' => false,
|
||||||
|
'is_active' => true,
|
||||||
|
]);
|
||||||
|
MailwizzConfig::query()->create([
|
||||||
|
'preregistration_page_id' => $pageB->id,
|
||||||
|
'api_key' => 'fake-api-key',
|
||||||
|
'list_uid' => 'list-uid-2',
|
||||||
|
'list_name' => 'List B',
|
||||||
|
'field_email' => 'EMAIL',
|
||||||
|
'field_first_name' => 'FNAME',
|
||||||
|
'field_last_name' => 'LNAME',
|
||||||
|
'field_phone' => null,
|
||||||
|
'tag_field' => 'TAGS',
|
||||||
|
'tag_value' => 'b-source',
|
||||||
|
]);
|
||||||
|
$subscriber = Subscriber::query()->create([
|
||||||
|
'preregistration_page_id' => $pageB->id,
|
||||||
|
'first_name' => 'A',
|
||||||
|
'last_name' => 'B',
|
||||||
|
'email' => 'on-b@example.com',
|
||||||
|
]);
|
||||||
|
|
||||||
|
$response = $this->actingAs($user)->post(
|
||||||
|
route('admin.pages.subscribers.sync-mailwizz', [$pageA, $subscriber])
|
||||||
|
);
|
||||||
|
|
||||||
|
$response->assertForbidden();
|
||||||
|
Queue::assertNothingPushed();
|
||||||
|
}
|
||||||
|
|
||||||
private function makePageWithMailwizz(): PreregistrationPage
|
private function makePageWithMailwizz(): PreregistrationPage
|
||||||
{
|
{
|
||||||
$user = User::factory()->create(['role' => 'user']);
|
$user = User::factory()->create(['role' => 'user']);
|
||||||
|
|||||||
Reference in New Issue
Block a user