Answer the inbox from the panel, with templates

A reply starts from a template filled in the language the person wrote in,
is sent by the application when it has a mailer that delivers or handed to
the replier's mail program otherwise, and is recorded on the submission.
The same is available through the API.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-01 10:45:47 +02:00
parent 697d333ad4
commit 76d022053b
27 changed files with 1096 additions and 0 deletions

View File

@@ -0,0 +1,28 @@
<?php
declare(strict_types=1);
namespace Database\Factories;
use App\Models\ReplyTemplate;
use Illuminate\Database\Eloquent\Factories\Factory;
/**
* @extends Factory<ReplyTemplate>
*/
class ReplyTemplateFactory extends Factory
{
public function definition(): array
{
return [
'name' => $this->faker->words(3, true),
'kind' => null,
'subject' => ['es' => 'Gracias, {name}', 'en' => 'Thank you, {name}', 'ca' => 'Gràcies, {name}'],
'body' => [
'es' => "Hola {name}:\n\nGracias por escribirnos sobre «{subject}».\n\n{sender}",
'en' => "Hi {name},\n\nThank you for writing to us about \"{subject}\".\n\n{sender}",
'ca' => "Hola {name}:\n\nGràcies per escriure'ns sobre «{subject}».\n\n{sender}",
],
];
}
}

View File

@@ -0,0 +1,50 @@
<?php
declare(strict_types=1);
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
/**
* Answering the inbox from the panel: templates for the answers that are
* nearly always the same, and a record of each answer sent.
*/
return new class extends Migration
{
public function up(): void
{
Schema::create('reply_templates', function (Blueprint $table): void {
$table->id();
$table->string('name');
// `contribute` or `request`, or null for either.
$table->string('kind', 20)->nullable();
$table->jsonb('subject');
$table->jsonb('body');
$table->unsignedInteger('position')->default(0);
$table->timestamps();
});
Schema::create('application_replies', function (Blueprint $table): void {
$table->id();
$table->foreignId('application_id')->constrained()->cascadeOnDelete();
$table->foreignId('user_id')->nullable()->constrained()->nullOnDelete();
$table->string('user_name')->nullable();
$table->string('subject');
$table->text('body');
// `mail` when this application sent it, `mailto` when it was
// handed to the person's own mail program to send.
$table->string('channel', 10);
$table->timestamp('created_at')->useCurrent();
});
}
public function down(): void
{
Schema::dropIfExists('application_replies');
Schema::dropIfExists('reply_templates');
}
};