diff --git a/.env.example b/.env.example index 1e642cb..b25ec48 100644 --- a/.env.example +++ b/.env.example @@ -59,6 +59,7 @@ MAIL_USERNAME=null MAIL_PASSWORD=null MAIL_FROM_ADDRESS="hello@example.com" MAIL_FROM_NAME="${APP_NAME}" +CONTACT_EMAIL= AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= diff --git a/app/Http/Controllers/ContactController.php b/app/Http/Controllers/ContactController.php index dbad520..bcb5ca4 100644 --- a/app/Http/Controllers/ContactController.php +++ b/app/Http/Controllers/ContactController.php @@ -2,10 +2,71 @@ namespace App\Http\Controllers; +use App\Http\Requests\ContactRequest; +use App\Mail\ContactConfirmationMail; +use App\Mail\ContactMessageMail; +use Illuminate\Http\RedirectResponse; +use Illuminate\Support\Facades\Log; +use Illuminate\Support\Facades\Mail; +use Illuminate\Support\Facades\RateLimiter; +use Illuminate\View\View; +use Throwable; + +/** + * Contact form. Nothing is stored: the message is emailed to the store + * (CONTACT_EMAIL) and the sender gets a generic confirmation. Both are sent + * synchronously so a failed store email can be reported back on the form. + * + * Limited per IP in here rather than with throttle middleware, so the limit + * shows as a message on the form instead of a bare 429 page. + */ class ContactController extends Controller { - public function index(string $locale) + private const SEND_LIMIT = 3; + private const SEND_DECAY_SECONDS = 600; + + public function index(string $locale): View { return view('contact'); } + + public function send(string $locale, ContactRequest $request): RedirectResponse + { + $key = 'contact:'.$request->ip(); + + if (RateLimiter::tooManyAttempts($key, self::SEND_LIMIT)) { + return back()->withInput()->with('contact_error', __('storefront.contact.too_many')); + } + + RateLimiter::hit($key, self::SEND_DECAY_SECONDS); + + $data = $request->validated(); + $to = config('services.contact.email'); + + try { + if (blank($to)) { + throw new \RuntimeException('CONTACT_EMAIL is not set.'); + } + + Mail::to($to)->send(new ContactMessageMail( + $data['name'], + $data['email'], + $data['message'], + $locale, + )); + } catch (Throwable $e) { + Log::error('Contact form: store email failed', ['exception' => $e]); + + return back()->withInput()->with('contact_error', __('storefront.contact.send_failed')); + } + + // The store already has the message, so a failed confirmation is only logged. + try { + Mail::to($data['email'])->locale($locale)->send(new ContactConfirmationMail); + } catch (Throwable $e) { + Log::warning('Contact form: confirmation email failed', ['exception' => $e]); + } + + return redirect()->route('contact')->with('status', __('storefront.contact.sent')); + } } diff --git a/app/Http/Requests/ContactRequest.php b/app/Http/Requests/ContactRequest.php new file mode 100644 index 0000000..f79c293 --- /dev/null +++ b/app/Http/Requests/ContactRequest.php @@ -0,0 +1,22 @@ + ['required', 'string', 'max:100'], + 'email' => ['required', 'email', 'max:255'], + 'message' => ['required', 'string', 'max:5000'], + ]; + } +} diff --git a/app/Mail/ContactConfirmationMail.php b/app/Mail/ContactConfirmationMail.php new file mode 100644 index 0000000..4f3828e --- /dev/null +++ b/app/Mail/ContactConfirmationMail.php @@ -0,0 +1,25 @@ +senderEmail, $this->senderName)], + subject: "Νέο μήνυμα επικοινωνίας από {$this->senderName}", + ); + } + + public function content(): Content + { + return new Content(view: 'emails.contact-message'); + } +} diff --git a/config/services.php b/config/services.php index 7c13ec1..d7dbed7 100644 --- a/config/services.php +++ b/config/services.php @@ -35,6 +35,11 @@ ], ], + // Where contact-form messages are sent (ContactController). + 'contact' => [ + 'email' => env('CONTACT_EMAIL'), + ], + 'stoic' => [ 'sso_secret' => env('STOIC_SSO_SECRET'), 'host' => env('STOIC_HOST'), diff --git a/resources/views/account/orders/show.blade.php b/resources/views/account/orders/show.blade.php index dd87c84..5049a75 100644 --- a/resources/views/account/orders/show.blade.php +++ b/resources/views/account/orders/show.blade.php @@ -70,8 +70,15 @@
- {{ $line->description }} + @if ($lineProduct?->status === 'published') + {{ $line->description }} + @else + {{ $line->description }} + @endif × {{ $line->quantity }}
diff --git a/resources/views/components/review-card.blade.php b/resources/views/components/review-card.blade.php index 321cb60..0cddb91 100644 --- a/resources/views/components/review-card.blade.php +++ b/resources/views/components/review-card.blade.php @@ -15,11 +15,13 @@ @if (!empty($review['image']))