Fix MakerWorld 2FA duplicate email loop and add email SMTP diagnostics
This commit is contained in:
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Throwable;
|
||||
|
||||
class TestMailCommand extends Command
|
||||
{
|
||||
/**
|
||||
* The name and signature of the console command.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $signature = 'app:test-mail {email : Het e-mailadres van de ontvanger (bijv. je eigen Gmail)}';
|
||||
|
||||
/**
|
||||
* The console command description.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $description = 'Verstuur een test e-mail en controleer de mailer/SMTP verbinding';
|
||||
|
||||
/**
|
||||
* Execute the console command.
|
||||
*/
|
||||
public function handle(): int
|
||||
{
|
||||
$recipient = $this->argument('email');
|
||||
$defaultMailer = config('mail.default');
|
||||
$smtpConfig = config("mail.mailers.{$defaultMailer}", []);
|
||||
$fromAddress = config('mail.from.address');
|
||||
$fromName = config('mail.from.name');
|
||||
|
||||
$this->info('=== Jouwdriedee.nl E-mail & SMTP Diagnostiek ===');
|
||||
$this->table(['Instelling', 'Waarde'], [
|
||||
['Actieve Mailer (MAIL_MAILER)', $defaultMailer],
|
||||
['Verzender Adres (MAIL_FROM_ADDRESS)', $fromAddress],
|
||||
['Verzender Naam (MAIL_FROM_NAME)', $fromName],
|
||||
['SMTP Host', $smtpConfig['host'] ?? 'N.v.t. (geen smtp)'],
|
||||
['SMTP Poort', $smtpConfig['port'] ?? 'N.v.t.'],
|
||||
['SMTP Gebruiker', ! empty($smtpConfig['username']) ? $smtpConfig['username'] : '(geen / leeg)'],
|
||||
['SMTP Wachtwoord ingesteld?', ! empty($smtpConfig['password']) ? 'Ja' : 'Nee'],
|
||||
['Ontvanger', $recipient],
|
||||
]);
|
||||
|
||||
if ($defaultMailer === 'log') {
|
||||
$this->warn("⚠️ WAARSCHUWING: MAIL_MAILER staat momenteel op 'log'!");
|
||||
$this->warn('Dit betekent dat er GEEN echte mail via internet wordt verzonden naar Gmail.');
|
||||
$this->warn('De mail wordt weggeschreven naar storage/logs/laravel.log.');
|
||||
$this->warn('Stel MAIL_MAILER=smtp in met geldige SMTP-gegevens op Coolify om echte mails te ontvangen.');
|
||||
}
|
||||
|
||||
$this->line("\nVersturen van testmail naar {$recipient}...");
|
||||
|
||||
try {
|
||||
Mail::raw("Dit is een test e-mail vanaf Jouwdriedee.nl om te controleren of de mailserver en bezorging naar {$recipient} correct functioneert.\n\nVerzonden op: ".now()->toIso8601String(), function ($message) use ($recipient) {
|
||||
$message->to($recipient)
|
||||
->subject('Test E-mail vanaf Jouwdriedee.nl');
|
||||
});
|
||||
|
||||
$this->info("✓ Test e-mail succesvol verzonden via driver '{$defaultMailer}'!");
|
||||
if ($defaultMailer === 'log') {
|
||||
$this->comment('Controleer storage/logs/laravel.log om de gelogde e-mail te zien.');
|
||||
} else {
|
||||
$this->info("Controleer nu je inbox (en eventueel spambox) op {$recipient}.");
|
||||
}
|
||||
|
||||
return self::SUCCESS;
|
||||
} catch (Throwable $e) {
|
||||
$this->error('❌ FOUT BIJ HET VERZENDEN:');
|
||||
$this->error($e->getMessage());
|
||||
$this->line("\nStack trace:");
|
||||
$this->line($e->getTraceAsString());
|
||||
|
||||
return self::FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -6,6 +6,8 @@ use App\Http\Controllers\Controller;
|
||||
use App\Models\Setting;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class ContentController extends Controller
|
||||
@@ -132,4 +134,38 @@ class ContentController extends Controller
|
||||
return redirect()->route('admin.content.index')
|
||||
->with('success', 'Alle teksten en lay-out instellingen zijn hersteld naar de standaarden.');
|
||||
}
|
||||
|
||||
/**
|
||||
* Send a test email to verify mail delivery (e.g. to Gmail).
|
||||
*/
|
||||
public function sendTestMail(Request $request): RedirectResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'test_email' => 'required|email',
|
||||
]);
|
||||
|
||||
$recipient = $validated['test_email'];
|
||||
$defaultMailer = config('mail.default');
|
||||
$fromAddress = config('mail.from.address');
|
||||
|
||||
try {
|
||||
Mail::raw("Dit is een test e-mail vanaf Jouwdriedee.nl om de e-mail bezorging naar {$recipient} te controleren.\n\nActieve mailer: {$defaultMailer}\nAfzender: {$fromAddress}\nDatum: ".now()->format('d-m-Y H:i:s'), function ($message) use ($recipient) {
|
||||
$message->to($recipient)
|
||||
->subject('Test E-mail vanaf Jouwdriedee.nl');
|
||||
});
|
||||
|
||||
if ($defaultMailer === 'log') {
|
||||
return redirect()->back()
|
||||
->with('warning', "De testmail is weggeschreven naar de serverlogs (MAIL_MAILER staat op 'log'). Er is GEEN echte e-mail naar {$recipient} verzonden. Stel op Coolify geldige SMTP-gegevens in (bijv. Brevo, Resend of je hosting SMTP) om echte e-mails te bezorgen.");
|
||||
}
|
||||
|
||||
return redirect()->back()
|
||||
->with('success', "Test e-mail succesvol verzonden via driver '{$defaultMailer}' naar {$recipient}! Controleer je inbox en eventueel je spambox.");
|
||||
} catch (\Throwable $e) {
|
||||
Log::error('Test mail error: '.$e->getMessage(), ['trace' => $e->getTraceAsString()]);
|
||||
|
||||
return redirect()->back()
|
||||
->with('error', "Fout bij verzenden van e-mail via {$defaultMailer}: ".$e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -337,13 +337,13 @@ class MakerWorldController extends Controller
|
||||
|
||||
if ($result['status'] === '2fa_required') {
|
||||
return redirect()
|
||||
->route('admin.makerworld.index')
|
||||
->route('admin.makerworld.index', ['tab' => 'auth'])
|
||||
->with('warning', $result['message'])
|
||||
->with('makerworld_2fa_account', $result['account']);
|
||||
}
|
||||
|
||||
return redirect()
|
||||
->route('admin.makerworld.index')
|
||||
->route('admin.makerworld.index', ['tab' => 'auth'])
|
||||
->with('error', $result['message']);
|
||||
}
|
||||
|
||||
@@ -369,11 +369,28 @@ class MakerWorldController extends Controller
|
||||
}
|
||||
|
||||
return redirect()
|
||||
->route('admin.makerworld.index')
|
||||
->route('admin.makerworld.index', ['tab' => 'auth'])
|
||||
->with('error', $result['message'])
|
||||
->with('makerworld_2fa_account', $validated['account']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resend verification code for 2FA manually on request.
|
||||
*/
|
||||
public function resendCode(Request $request): RedirectResponse
|
||||
{
|
||||
$validated = $request->validate([
|
||||
'account' => 'required|string',
|
||||
]);
|
||||
|
||||
$sent = $this->makerWorld->sendEmailVerificationCode($validated['account']);
|
||||
|
||||
return redirect()
|
||||
->route('admin.makerworld.index', ['tab' => 'auth'])
|
||||
->with($sent ? 'success' : 'error', $sent ? 'Er is een nieuwe verificatiecode verstuurd naar je e-mail.' : 'Kon verificatiecode niet opnieuw verzenden.')
|
||||
->with('makerworld_2fa_account', $validated['account']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Save MakerWorld session / bearer token directly.
|
||||
*/
|
||||
|
||||
@@ -11,6 +11,7 @@ use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\Support\Str;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
@@ -61,6 +62,7 @@ class ForgotPasswordController extends Controller
|
||||
try {
|
||||
Mail::to($user->email)->send(new PasswordResetMail($user, $resetUrl));
|
||||
} catch (Throwable $e) {
|
||||
Log::error("Fout bij verzenden van wachtwoordherstel e-mail naar {$user->email}: ".$e->getMessage());
|
||||
report($e);
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
use Illuminate\View\View;
|
||||
use Throwable;
|
||||
@@ -56,6 +57,7 @@ class RegisterController extends Controller
|
||||
try {
|
||||
Mail::to($user->email)->send(new WelcomeMail($user));
|
||||
} catch (Throwable $e) {
|
||||
Log::error("Fout bij verzenden van welkomstmail naar {$user->email}: ".$e->getMessage());
|
||||
report($e);
|
||||
}
|
||||
|
||||
|
||||
@@ -111,14 +111,12 @@ class MakerWorldService
|
||||
];
|
||||
}
|
||||
|
||||
// Check if 2FA code is needed
|
||||
// Check if 2FA code is needed (Bambu Lab sends the code automatically when verifyCode is returned)
|
||||
if (isset($data['loginType']) && $data['loginType'] === 'verifyCode') {
|
||||
$this->sendEmailVerificationCode($account);
|
||||
|
||||
return [
|
||||
'status' => '2fa_required',
|
||||
'account' => $account,
|
||||
'message' => 'Verificatiecode vereist. We hebben een 6-cijferige code naar je e-mail gestuurd.',
|
||||
'message' => 'Verificatiecode vereist. Bambu Lab heeft een 6-cijferige verificatiecode naar je e-mail gestuurd.',
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -97,6 +97,16 @@
|
||||
<i data-lucide="settings" class="w-3.5 h-3.5"></i>
|
||||
<span>6. Algemeen & Thema</span>
|
||||
</button>
|
||||
|
||||
<button
|
||||
type="button"
|
||||
@click="activeTab = 'email'"
|
||||
:class="activeTab === 'email' ? 'bg-amber-400 text-slate-950 shadow-sm' : 'bg-slate-800 text-slate-300 hover:bg-slate-700'"
|
||||
class="px-4 py-2.5 rounded-xl transition flex items-center space-x-1.5 whitespace-nowrap cursor-pointer"
|
||||
>
|
||||
<i data-lucide="mail" class="w-3.5 h-3.5"></i>
|
||||
<span>7. E-mail & SMTP Testen</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<!-- ==================================================== -->
|
||||
@@ -508,6 +518,119 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ==================================================== -->
|
||||
<!-- TAB 7: E-MAIL & SMTP DIAGNOSTIEK -->
|
||||
<!-- ==================================================== -->
|
||||
<div x-show="activeTab === 'email'" class="space-y-6">
|
||||
<div class="p-6 rounded-3xl bg-slate-900 border border-slate-800 space-y-6">
|
||||
<div class="border-b border-slate-800 pb-3 flex items-center justify-between">
|
||||
<div>
|
||||
<h3 class="font-heading font-black text-lg text-white flex items-center space-x-2">
|
||||
<i data-lucide="mail-check" class="w-5 h-5 text-amber-400"></i>
|
||||
<span>E-mail & SMTP Status</span>
|
||||
</h3>
|
||||
<p class="text-xs text-slate-400">Controleer waarom wachtwoordherstel- en registratiemails wel of niet aankomen op Gmail.</p>
|
||||
</div>
|
||||
@php
|
||||
$activeMailer = config('mail.default');
|
||||
@endphp
|
||||
<span class="px-3 py-1 rounded-full text-xs font-black uppercase tracking-wider {{ $activeMailer === 'log' ? 'bg-amber-400/20 text-amber-400 border border-amber-400/40' : 'bg-emerald-500/20 text-emerald-400 border border-emerald-500/40' }}">
|
||||
Driver: {{ strtoupper($activeMailer) }}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@if($activeMailer === 'log')
|
||||
<div class="p-4 rounded-2xl bg-amber-950/60 border border-amber-400/50 text-amber-200 text-xs space-y-2">
|
||||
<div class="font-black text-sm flex items-center space-x-2 text-amber-300">
|
||||
<i data-lucide="alert-triangle" class="w-5 h-5 shrink-0"></i>
|
||||
<span>Belangrijke Oorzaak: MAIL_MAILER staat op 'log'</span>
|
||||
</div>
|
||||
<p>
|
||||
Momenteel worden uitgaande e-mails (zoals wachtwoord vergeten en welkomstmails) weggeschreven naar de serverlogbestanden en <strong>niet via internet naar Gmail verzonden</strong>.
|
||||
</p>
|
||||
<p>
|
||||
Om echte e-mails te versturen, moet op de server (Coolify Environment Variables) <code class="bg-slate-950 px-1.5 py-0.5 rounded text-amber-400 font-mono font-bold">MAIL_MAILER=smtp</code> ingesteld worden met de bijbehorende SMTP-host, poort en wachtwoord.
|
||||
</p>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Server SMTP Overview Table -->
|
||||
<div class="grid grid-cols-1 md:grid-cols-2 gap-4 text-xs">
|
||||
<div class="p-4 rounded-2xl bg-slate-950 border border-slate-800 space-y-2">
|
||||
<div class="font-bold text-slate-400 uppercase tracking-wider text-[10px]">Huidige Server Mail Instellingen</div>
|
||||
<div class="flex justify-between py-1 border-b border-slate-800">
|
||||
<span class="text-slate-400">MAIL_MAILER:</span>
|
||||
<span class="font-mono text-white font-bold">{{ config('mail.default') }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between py-1 border-b border-slate-800">
|
||||
<span class="text-slate-400">MAIL_HOST:</span>
|
||||
<span class="font-mono text-white font-bold">{{ config('mail.mailers.smtp.host') ?: '(geen)' }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between py-1 border-b border-slate-800">
|
||||
<span class="text-slate-400">MAIL_PORT:</span>
|
||||
<span class="font-mono text-white font-bold">{{ config('mail.mailers.smtp.port') ?: '(geen)' }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between py-1 border-b border-slate-800">
|
||||
<span class="text-slate-400">MAIL_USERNAME:</span>
|
||||
<span class="font-mono text-white font-bold">{{ config('mail.mailers.smtp.username') ?: '(geen)' }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between py-1 border-b border-slate-800">
|
||||
<span class="text-slate-400">MAIL_FROM_ADDRESS:</span>
|
||||
<span class="font-mono text-amber-400 font-bold">{{ config('mail.from.address') }}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="p-4 rounded-2xl bg-slate-950 border border-slate-800 space-y-2">
|
||||
<div class="font-bold text-slate-400 uppercase tracking-wider text-[10px]">Gmail Bezorging Checklist</div>
|
||||
<ul class="space-y-1.5 text-slate-300">
|
||||
<li class="flex items-start space-x-2">
|
||||
<span class="text-amber-400 font-bold shrink-0">1.</span>
|
||||
<span><strong>SMTP Provider:</strong> Gebruik een werkende SMTP server (bijv. Brevo, Resend, Mailgun of Versio mail).</span>
|
||||
</li>
|
||||
<li class="flex items-start space-x-2">
|
||||
<span class="text-amber-400 font-bold shrink-0">2.</span>
|
||||
<span><strong>SPF DNS Record:</strong> Google vereist een SPF TXT-record op <code class="font-mono text-amber-400">jouwdriedee.nl</code>.</span>
|
||||
</li>
|
||||
<li class="flex items-start space-x-2">
|
||||
<span class="text-amber-400 font-bold shrink-0">3.</span>
|
||||
<span><strong>DKIM & DMARC:</strong> Zonder DKIM plaatst Gmail emails van nieuwe domeinen direct in de Spammap.</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Test Email Form -->
|
||||
<div class="p-5 rounded-2xl bg-slate-950 border border-slate-800 space-y-3">
|
||||
<div class="font-bold text-white text-xs flex items-center space-x-2">
|
||||
<i data-lucide="send" class="w-4 h-4 text-amber-400"></i>
|
||||
<span>Direct een Test E-mail Versturen</span>
|
||||
</div>
|
||||
<p class="text-xs text-slate-400">
|
||||
Vul hier een e-mailadres in (bijv. je eigen Gmail) om direct te testen of e-mails aankomen en of de verbinding met de mailserver slaagt.
|
||||
</p>
|
||||
<div class="flex flex-col sm:flex-row gap-3 pt-1">
|
||||
<input
|
||||
type="email"
|
||||
name="test_email"
|
||||
value="{{ auth()->user()->email ?? 'info@jouwdriedee.nl' }}"
|
||||
placeholder="jouw-email@gmail.com"
|
||||
class="flex-1 bg-slate-900 border border-slate-700 rounded-xl px-3.5 py-2.5 text-xs text-white font-mono placeholder-slate-600 focus:outline-none focus:ring-2 focus:ring-amber-400"
|
||||
>
|
||||
<button
|
||||
type="submit"
|
||||
formaction="{{ route('admin.content.test-mail') }}"
|
||||
formmethod="POST"
|
||||
class="px-5 py-2.5 rounded-xl bg-amber-400 hover:bg-amber-300 text-slate-950 font-black text-xs uppercase tracking-wider transition flex items-center justify-center space-x-2 shrink-0 cursor-pointer shadow-lg shadow-amber-400/20"
|
||||
>
|
||||
<i data-lucide="send" class="w-4 h-4"></i>
|
||||
<span>Verstuur Testmail</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Sticky Save Action Bar -->
|
||||
<div class="sticky bottom-4 z-20 p-4 rounded-2xl bg-slate-900/95 backdrop-blur-md border border-amber-400/30 shadow-2xl flex items-center justify-between">
|
||||
<div class="flex items-center space-x-2 text-xs text-slate-300 font-bold">
|
||||
|
||||
@@ -62,7 +62,65 @@
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- Tab Bar -->
|
||||
<!-- 2FA Verificatiecode Invoerscherm (Bambu Lab) -->
|
||||
@if(session('makerworld_2fa_account'))
|
||||
<div class="bg-gradient-to-r from-slate-900 to-amber-950/80 p-6 sm:p-8 rounded-3xl border-2 border-amber-400 shadow-2xl">
|
||||
<div class="max-w-xl mx-auto text-center space-y-4">
|
||||
<div class="w-16 h-16 rounded-2xl bg-amber-400/20 text-amber-400 flex items-center justify-center mx-auto shadow-inner">
|
||||
<i data-lucide="shield-check" class="w-8 h-8"></i>
|
||||
</div>
|
||||
<div>
|
||||
<span class="px-3 py-1 rounded-full text-xs font-black uppercase tracking-wider bg-amber-400 text-slate-950">
|
||||
Stap 2: Twee-staps Verificatie (2FA)
|
||||
</span>
|
||||
<h2 class="text-2xl font-black text-white mt-2">Bambu Lab Verificatiecode</h2>
|
||||
<p class="text-xs text-slate-300 mt-1">
|
||||
Vul de 6-cijferige verificatiecode in die Bambu Lab zojuist heeft verzonden naar <strong class="text-amber-300 font-mono">{{ session('makerworld_2fa_account') }}</strong>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<form action="{{ route('admin.makerworld.verify-code') }}" method="POST" class="mt-4 space-y-4">
|
||||
@csrf
|
||||
<input type="hidden" name="account" value="{{ session('makerworld_2fa_account') }}">
|
||||
|
||||
<div class="flex justify-center">
|
||||
<input
|
||||
type="text"
|
||||
name="code"
|
||||
maxlength="6"
|
||||
placeholder="123456"
|
||||
autofocus
|
||||
required
|
||||
class="w-56 text-center text-3xl font-mono font-black tracking-widest px-4 py-3 bg-slate-950 border-2 border-amber-400 rounded-2xl text-amber-300 focus:outline-none focus:ring-4 focus:ring-amber-400/30 placeholder-slate-700"
|
||||
>
|
||||
</div>
|
||||
|
||||
<div class="flex items-center justify-center space-x-3 pt-2">
|
||||
<button type="submit" class="px-8 py-3 bg-amber-400 hover:bg-amber-300 text-slate-950 font-black rounded-2xl text-xs uppercase tracking-wider shadow-lg shadow-amber-400/20 transition flex items-center space-x-2">
|
||||
<i data-lucide="check" class="w-4 h-4"></i>
|
||||
<span>Verifieer Code & Inloggen</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="pt-3 border-t border-slate-800/80 flex items-center justify-center space-x-6 text-xs text-slate-400">
|
||||
<form action="{{ route('admin.makerworld.resend-code') }}" method="POST">
|
||||
@csrf
|
||||
<input type="hidden" name="account" value="{{ session('makerworld_2fa_account') }}">
|
||||
<button type="submit" class="hover:text-amber-400 underline font-bold transition">
|
||||
Geen code ontvangen? Verstuur opnieuw
|
||||
</button>
|
||||
</form>
|
||||
<span>•</span>
|
||||
<a href="{{ route('admin.makerworld.index', ['tab' => 'auth']) }}" class="hover:text-slate-300 underline font-bold transition">
|
||||
Ander account proberen
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<!-- TAB Bar -->
|
||||
<div class="flex items-center space-x-2 border-b border-slate-800 pb-2 overflow-x-auto text-sm font-bold">
|
||||
<a href="{{ route('admin.makerworld.index', ['tab' => 'collections']) }}" class="px-4 py-2 rounded-xl transition flex items-center space-x-2 {{ $currentTab === 'collections' ? 'bg-amber-400 text-slate-950 font-black' : 'text-slate-400 hover:text-white hover:bg-slate-900' }}">
|
||||
<i data-lucide="folder-sync" class="w-4 h-4"></i>
|
||||
|
||||
@@ -353,3 +353,4 @@ function artikelBeheerApp() {
|
||||
}
|
||||
</script>
|
||||
@endsection
|
||||
|
||||
|
||||
@@ -115,6 +115,7 @@ Route::prefix('admin')->name('admin.')->middleware(['auth', 'admin'])->group(fun
|
||||
Route::get('/content', [ContentController::class, 'index'])->name('content.index');
|
||||
Route::post('/content', [ContentController::class, 'update'])->name('content.update');
|
||||
Route::post('/content/reset', [ContentController::class, 'reset'])->name('content.reset');
|
||||
Route::post('/content/test-mail', [ContentController::class, 'sendTestMail'])->name('content.test-mail');
|
||||
|
||||
// Producten Beheer
|
||||
Route::resource('products', AdminProductController::class)->except(['show']);
|
||||
@@ -131,6 +132,7 @@ Route::prefix('admin')->name('admin.')->middleware(['auth', 'admin'])->group(fun
|
||||
Route::get('/makerworld', [MakerWorldController::class, 'index'])->name('makerworld.index');
|
||||
Route::post('/makerworld/login', [MakerWorldController::class, 'login'])->name('makerworld.login');
|
||||
Route::post('/makerworld/verify-code', [MakerWorldController::class, 'verifyCode'])->name('makerworld.verify-code');
|
||||
Route::post('/makerworld/resend-code', [MakerWorldController::class, 'resendCode'])->name('makerworld.resend-code');
|
||||
Route::post('/makerworld/token', [MakerWorldController::class, 'saveToken'])->name('makerworld.token');
|
||||
Route::post('/makerworld/disconnect', [MakerWorldController::class, 'disconnect'])->name('makerworld.disconnect');
|
||||
Route::get('/makerworld/preview', [MakerWorldController::class, 'preview'])->name('makerworld.preview');
|
||||
|
||||
@@ -10,6 +10,7 @@ use App\Models\Material;
|
||||
use App\Models\Product;
|
||||
use App\Models\User;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Illuminate\Support\Facades\Artisan;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Illuminate\Support\Facades\Hash;
|
||||
use Illuminate\Support\Facades\Mail;
|
||||
@@ -215,4 +216,33 @@ class AuthAndEmailTest extends TestCase
|
||||
&& str_contains($mail->envelope()->subject, 'Bestelbevestiging');
|
||||
});
|
||||
}
|
||||
|
||||
public function test_admin_can_trigger_test_email_via_web_and_cli(): void
|
||||
{
|
||||
Mail::fake();
|
||||
|
||||
$admin = User::create([
|
||||
'name' => 'Admin Jouwdriedee',
|
||||
'email' => 'info@jouwdriedee.nl',
|
||||
'password' => bcrypt('Jw3D!x9#QmK7$vR2'),
|
||||
'is_admin' => true,
|
||||
]);
|
||||
|
||||
$this->actingAs($admin);
|
||||
|
||||
// Web endpoint
|
||||
$response = $this->post(route('admin.content.test-mail'), [
|
||||
'test_email' => 'testgmail@gmail.com',
|
||||
]);
|
||||
|
||||
$response->assertRedirect();
|
||||
$response->assertSessionHas('success');
|
||||
|
||||
// CLI command
|
||||
$exitCode = Artisan::call('app:test-mail', [
|
||||
'email' => 'testcli@gmail.com',
|
||||
]);
|
||||
|
||||
$this->assertEquals(0, $exitCode);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -215,4 +215,72 @@ class MakerWorldImporterTest extends TestCase
|
||||
$disconnectResponse->assertRedirect();
|
||||
$this->assertNull(Setting::get('makerworld_token'));
|
||||
}
|
||||
|
||||
public function test_makerworld_login_with_2fa_redirects_to_auth_tab_without_duplicate_email(): void
|
||||
{
|
||||
Http::fake([
|
||||
'https://api.bambulab.com/v1/user-service/user/login' => Http::response([
|
||||
'loginType' => 'verifyCode',
|
||||
'message' => 'Verification code sent',
|
||||
], 200),
|
||||
'https://api.bambulab.com/v1/user-service/user/sendemail/code' => Http::response([
|
||||
'success' => true,
|
||||
], 200),
|
||||
]);
|
||||
|
||||
$response = $this->post(route('admin.makerworld.login'), [
|
||||
'account' => 'test2fa@jouwdriedee.nl',
|
||||
'password' => 'secret_pass',
|
||||
]);
|
||||
|
||||
$response->assertRedirect(route('admin.makerworld.index', ['tab' => 'auth']));
|
||||
$response->assertSessionHas('makerworld_2fa_account', 'test2fa@jouwdriedee.nl');
|
||||
|
||||
// Verify that sendemail/code was NOT called automatically (Bambu Lab already sent it on login)
|
||||
Http::assertNotSent(function ($request) {
|
||||
return str_contains($request->url(), 'sendemail/code');
|
||||
});
|
||||
}
|
||||
|
||||
public function test_makerworld_can_verify_2fa_code(): void
|
||||
{
|
||||
Http::fake([
|
||||
'https://api.bambulab.com/v1/user-service/user/login' => Http::response([
|
||||
'accessToken' => 'token_after_2fa_code_9999',
|
||||
], 200),
|
||||
'https://api.bambulab.com/v1/design-user-service/my/preference' => Http::response([
|
||||
'uid' => 12345,
|
||||
'name' => 'Verified User',
|
||||
], 200),
|
||||
]);
|
||||
|
||||
$response = $this->post(route('admin.makerworld.verify-code'), [
|
||||
'account' => 'test2fa@jouwdriedee.nl',
|
||||
'code' => '123456',
|
||||
]);
|
||||
|
||||
$response->assertRedirect(route('admin.makerworld.index', ['tab' => 'collections']));
|
||||
$this->assertSame('token_after_2fa_code_9999', Setting::get('makerworld_token'));
|
||||
}
|
||||
|
||||
public function test_makerworld_can_manually_resend_2fa_code(): void
|
||||
{
|
||||
Http::fake([
|
||||
'https://api.bambulab.com/v1/user-service/user/sendemail/code' => Http::response([
|
||||
'success' => true,
|
||||
], 200),
|
||||
]);
|
||||
|
||||
$response = $this->post(route('admin.makerworld.resend-code'), [
|
||||
'account' => 'test2fa@jouwdriedee.nl',
|
||||
]);
|
||||
|
||||
$response->assertRedirect(route('admin.makerworld.index', ['tab' => 'auth']));
|
||||
$response->assertSessionHas('success');
|
||||
|
||||
Http::assertSent(function ($request) {
|
||||
return str_contains($request->url(), 'sendemail/code') &&
|
||||
$request['email'] === 'test2fa@jouwdriedee.nl';
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user