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>
99 lines
3.5 KiB
PHP
99 lines
3.5 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
namespace App\Http\Controllers\Api\V1;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Models\Application;
|
|
use App\Models\ApplicationReply;
|
|
use App\Models\ReplyTemplate;
|
|
use App\Support\Inbox\Replier;
|
|
use Illuminate\Http\JsonResponse;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Validation\ValidationException;
|
|
|
|
/**
|
|
* Answering the inbox through the API: what was already said, the templates
|
|
* to start from, and sending an answer — the panel's "Reply".
|
|
*/
|
|
class ApplicationReplyController extends Controller
|
|
{
|
|
public function index(Application $application): JsonResponse
|
|
{
|
|
$this->authorize('view', $application);
|
|
|
|
return response()->json([
|
|
'data' => $application->replies()->get()->map(fn (ApplicationReply $reply) => $this->present($reply))->values(),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* `subject` and `body`, or a `template_id` to fill them from — in the
|
|
* language the person wrote in. Sent when this installation can send
|
|
* mail; otherwise recorded, with a `mailto` link to send it by hand.
|
|
*/
|
|
public function store(Request $request, Application $application): JsonResponse
|
|
{
|
|
$this->authorize('update', $application);
|
|
|
|
$data = $request->validate([
|
|
'template_id' => ['sometimes', 'nullable', 'integer', 'exists:reply_templates,id'],
|
|
'subject' => ['required_without:template_id', 'nullable', 'string', 'max:255'],
|
|
'body' => ['required_without:template_id', 'nullable', 'string', 'max:20000'],
|
|
]);
|
|
|
|
$text = ['subject' => $data['subject'] ?? null, 'body' => $data['body'] ?? null];
|
|
|
|
if (filled($data['template_id'] ?? null)) {
|
|
$rendered = ReplyTemplate::query()->findOrFail($data['template_id'])->renderFor($application, $request->user());
|
|
$text = ['subject' => $text['subject'] ?: $rendered['subject'], 'body' => $text['body'] ?: $rendered['body']];
|
|
}
|
|
|
|
if (blank($text['subject']) || blank($text['body'])) {
|
|
throw ValidationException::withMessages(['template_id' => [__('panel.replies.empty_template')]]);
|
|
}
|
|
|
|
$reply = Replier::reply($application, $text['subject'], $text['body'], $request->user());
|
|
|
|
return response()->json([
|
|
'data' => [
|
|
...$this->present($reply),
|
|
'mailto' => $reply->channel === ApplicationReply::MAILTO
|
|
? Replier::mailto($application, $text['subject'], $text['body'])
|
|
: null,
|
|
],
|
|
], 201);
|
|
}
|
|
|
|
public function templates(Request $request): JsonResponse
|
|
{
|
|
$this->authorize('viewAny', ReplyTemplate::class);
|
|
|
|
return response()->json([
|
|
'data' => ReplyTemplate::query()->orderBy('position')->orderBy('name')->get()->map(fn (ReplyTemplate $template) => [
|
|
'id' => $template->id,
|
|
'name' => $template->name,
|
|
'kind' => $template->kind,
|
|
'subject' => (object) $template->getTranslations('subject'),
|
|
'body' => (object) $template->getTranslations('body'),
|
|
])->values(),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
protected function present(ApplicationReply $reply): array
|
|
{
|
|
return [
|
|
'id' => $reply->id,
|
|
'subject' => $reply->subject,
|
|
'body' => $reply->body,
|
|
'channel' => $reply->channel,
|
|
'author' => ['id' => $reply->user_id, 'name' => $reply->user_name],
|
|
'created_at' => $reply->created_at?->toIso8601String(),
|
|
];
|
|
}
|
|
}
|