Skip to content

Commit 95e3d45

Browse files
committed
#11779 Use FormRequest and templateResource for EditTaskTemplateController
1 parent 0683cfe commit 95e3d45

File tree

4 files changed

+145
-527
lines changed

4 files changed

+145
-527
lines changed

api/v1/editTaskTemplates/PKPEditTaskTemplateController.php

Lines changed: 19 additions & 198 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,18 @@
22

33
namespace PKP\API\v1\editTaskTemplates;
44

5-
use APP\facades\Repo;
65
use Illuminate\Http\JsonResponse;
7-
use Illuminate\Http\Request;
86
use Illuminate\Http\Response;
9-
use Illuminate\Support\Carbon;
107
use Illuminate\Support\Facades\DB;
118
use Illuminate\Support\Facades\Route;
12-
use Illuminate\Support\Facades\Validator;
13-
use Illuminate\Validation\Rule;
14-
use PKP\API\v1\submissions\resources\TaskResource;
159
use PKP\core\PKPBaseController;
1610
use PKP\core\PKPRequest;
17-
use PKP\editorialTask\EditorialTask;
18-
use PKP\editorialTask\enums\EditorialTaskType;
19-
use PKP\editorialTask\Participant;
2011
use PKP\security\authorization\CanAccessSettingsPolicy;
2112
use PKP\security\authorization\ContextAccessPolicy;
2213
use PKP\security\Role;
23-
use PKP\userGroup\UserGroup;
2414
use PKP\editorialTask\Template;
15+
use PKP\API\v1\editTaskTemplates\formRequests\AddEditTaskTemplate;
16+
use PKP\API\v1\editTaskTemplates\resources\EditTaskTemplateResource;
2517

2618
class PKPEditTaskTemplateController extends PKPBaseController
2719
{
@@ -56,203 +48,32 @@ public function getGroupRoutes(): void
5648

5749
/**
5850
* POST /api/v1/editTaskTemplates
59-
* Body: stageId, title, include, type, dateDue?, userGroupIds[], participants[] (userId,isResponsible?)
6051
*/
61-
public function add(Request $illuminateRequest): JsonResponse
52+
public function add(AddEditTaskTemplate $illuminateRequest): JsonResponse
6253
{
63-
$request = $this->getRequest();
64-
$context = $request->getContext();
65-
$currentUser = $request->getUser();
54+
$context = $this->getRequest()->getContext();
55+
$validated = $illuminateRequest->validated();
6656

67-
// gather payload
68-
$payload = [
69-
'stageId' => (int) $illuminateRequest->input('stageId'),
70-
'title' => (string) $illuminateRequest->input('title', ''),
71-
'include' => (bool) $illuminateRequest->boolean('include', false),
72-
'type' => (int) $illuminateRequest->input('type'), // see #2
73-
'emailTemplateId' => $illuminateRequest->input('emailTemplateId'),
74-
'userGroupIds' => array_values(array_map('intval', (array) $illuminateRequest->input('userGroupIds', []))),
75-
'participants' => (array) $illuminateRequest->input('participants', []),
76-
];
77-
78-
if ($illuminateRequest->has('dateDue')) {
79-
$payload['dateDue'] = $illuminateRequest->input('dateDue');
80-
}
81-
82-
// validation
83-
$typeValues = array_column(EditorialTaskType::cases(), 'value');
84-
$isTask = $payload['type'] === EditorialTaskType::TASK->value;
85-
$isDiscussion = $payload['type'] === EditorialTaskType::DISCUSSION->value;
86-
87-
$rules = [
88-
'stageId' => ['required', 'integer', 'min:1'],
89-
'title' => ['required', 'string', 'max:255'],
90-
'include' => ['boolean'],
91-
92-
'type' => ['required', Rule::in($typeValues)],
93-
'dateDue' => $isTask
94-
? ['required', 'date_format:Y-m-d', 'after:today']
95-
: ['prohibited'],
96-
97-
'emailTemplateId' => ['nullable', 'integer', Rule::exists('email_templates', 'email_id')],
98-
99-
'userGroupIds' => ['required', 'array', 'min:1'],
100-
'userGroupIds.*' => ['integer', 'distinct', Rule::exists('user_groups', 'user_group_id')],
101-
102-
'participants' => ['required', 'array'],
103-
'participants.*' => ['required', 'array:userId,isResponsible'],
104-
'participants.*.userId' => ['required', 'integer', 'distinct', Rule::exists('users', 'user_id')],
105-
'participants.*.isResponsible' => $isTask ? ['required', 'boolean'] : ['prohibited'],
106-
];
107-
108-
$validator = Validator::make($payload, $rules);
109-
110-
$validator->after(function ($v) use ($payload, $isTask, $isDiscussion) {
111-
$parts = $payload['participants'] ?? [];
112-
113-
if ($isTask && count($parts) < 1) {
114-
$v->errors()->add('participants', 'At least one participant is required for a task.');
115-
}
116-
if ($isDiscussion && count($parts) < 2) {
117-
$v->errors()->add('participants', 'At least two participants are required for a discussion.');
118-
}
119-
120-
if ($isTask) {
121-
$responsibles = 0;
122-
foreach ($parts as $p) {
123-
if (!empty($p['isResponsible'])) {
124-
$responsibles++;
125-
}
126-
}
127-
if ($responsibles > 1) {
128-
$v->errors()->add('participants', 'There should be the only one user responsible for the task');
129-
}
130-
}
131-
});
132-
133-
if ($validator->fails()) {
134-
return response()->json($validator->errors(), Response::HTTP_UNPROCESSABLE_ENTITY);
135-
}
136-
137-
// userGroupIds must belong to this context
138-
$validCount = DB::table('user_groups')
139-
->where('context_id', $context->getId())
140-
->whereIn('user_group_id', $payload['userGroupIds'])
141-
->count();
142-
143-
if ($validCount !== count($payload['userGroupIds'])) {
144-
return response()->json(
145-
['userGroupIds' => ['One or more userGroupIds do not belong to this context']],
146-
Response::HTTP_BAD_REQUEST
147-
);
148-
}
149-
150-
$templateId = DB::transaction(function () use ($context, $payload) {
151-
$template = Template::create([
152-
'stage_id' => $payload['stageId'],
153-
'title' => $payload['title'],
57+
$template = DB::transaction(function () use ($validated, $context) {
58+
$tpl = Template::create([
59+
'stage_id' => $validated['stageId'],
60+
'title' => $validated['title'],
15461
'context_id' => $context->getId(),
155-
'include' => $payload['include'],
156-
'email_template_id' => $payload['emailTemplateId'] ?? null,
62+
'include' => $validated['include'] ?? false,
63+
'email_template_id' => $validated['emailTemplateId'] ?? null,
15764
]);
15865

159-
// attach user groups via pivot
160-
$template->userGroups()->sync($payload['userGroupIds']);
161-
162-
// store extra template config in settings (non-localized)
163-
DB::table('edit_task_template_settings')->insert([
164-
[
165-
'edit_task_template_id' => $template->getKey(),
166-
'locale' => '',
167-
'setting_name' => 'type',
168-
'setting_value'=> (string) ((int) $payload['type']),
169-
],
170-
[
171-
'edit_task_template_id' => $template->getKey(),
172-
'locale' => '',
173-
'setting_name' => 'participants',
174-
'setting_value'=> json_encode(array_map(
175-
fn (array $p) => [
176-
'userId' => (int) $p['userId'],
177-
'isResponsible' => (bool) ($p['isResponsible'] ?? false)
178-
],
179-
$payload['participants']
180-
)),
181-
],
182-
[
183-
'edit_task_template_id' => $template->getKey(),
184-
'locale' => '',
185-
'setting_name' => 'dateDue',
186-
'setting_value'=> $payload['dateDue'] ? (string) $payload['dateDue'] : null,
187-
],
188-
]);
66+
$tpl->userGroups()->sync($validated['userGroupIds']);
18967

190-
return $template->getKey();
68+
return $tpl;
19169
});
19270

193-
// serialize with TaskResource
194-
$tpl = DB::table('edit_task_templates')->where('edit_task_template_id', $templateId)->first();
195-
196-
$settings = DB::table('edit_task_template_settings')
197-
->where('edit_task_template_id', $templateId)
198-
->pluck('setting_value', 'setting_name');
199-
200-
$type = (int) ($settings['type'] ?? $payload['type']);
201-
$dateDueStr = $settings['dateDue'] ?? ($payload['dateDue'] ?? null);
202-
$dateDue = !empty($dateDueStr) ? Carbon::createFromFormat('Y-m-d', $dateDueStr) : null;
203-
204-
205-
$participantsSetting = $settings['participants'] ?? '[]';
206-
$participantsData = json_decode($participantsSetting, true) ?: [];
207-
208-
// Build a transient EditorialTask that mirrors a real task
209-
$editorialTask = new EditorialTask([
210-
'edit_task_id' => (int) $templateId,
211-
'type' => $type,
212-
'assocType' => null,
213-
'assocId' => null,
214-
'stageId' => (int) $tpl->stage_id,
215-
'title' => $tpl->title,
216-
'createdBy' => $currentUser->getId(),
217-
'dateDue' => $dateDue,
218-
'dateStarted'=> null,
219-
'dateClosed' => null,
220-
]);
221-
222-
// attach participants relation for TaskResource
223-
$participantModels = collect($participantsData)->map(
224-
fn (array $p) => new Participant([
225-
'userId' => (int) $p['userId'],
226-
'isResponsible' => (bool) ($p['isResponsible'] ?? false),
227-
])
71+
// return via Resource
72+
return response()->json(
73+
(new EditTaskTemplateResource($template->refresh()->load('userGroups')))
74+
->toArray($illuminateRequest),
75+
Response::HTTP_OK
22876
);
229-
$editorialTask->setRelation('participants', $participantModels);
230-
231-
// build the data bundle required by TaskResource
232-
$participantIds = $participantModels->pluck('userId')->unique()->values()->all();
233-
if (!in_array($currentUser->getId(), $participantIds, true)) {
234-
$participantIds[] = $currentUser->getId();
235-
}
236-
237-
$users = Repo::user()->getCollector()
238-
->filterByUserIds($participantIds)
239-
->getMany();
240-
241-
$userGroups = UserGroup::with('userUserGroups')
242-
->withContextIds($context->getId())
243-
->withUserIds($participantIds)
244-
->get();
245-
246-
return (new TaskResource(
247-
resource: $editorialTask,
248-
data: [
249-
'submission' => null,
250-
'users' => $users,
251-
'userGroups' => $userGroups,
252-
'stageAssignments' => collect(),
253-
'reviewAssignments' => collect(),
254-
]
255-
))->response()->setStatusCode(Response::HTTP_CREATED);
256-
25777
}
78+
25879
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
<?php
2+
3+
namespace PKP\API\v1\editTaskTemplates\formRequests;
4+
5+
use APP\core\Application;
6+
use Illuminate\Foundation\Http\FormRequest;
7+
use Illuminate\Validation\Rule;
8+
9+
class AddEditTaskTemplate extends FormRequest
10+
{
11+
public function authorize(): bool
12+
{
13+
return true;
14+
}
15+
16+
public function rules(): array
17+
{
18+
$contextId = Application::get()->getRequest()->getContext()->getId();
19+
20+
return [
21+
'stageId' => ['required', 'integer', 'min:1'],
22+
'title' => ['required', 'string', 'max:255'],
23+
'include' => ['sometimes', 'boolean'],
24+
'emailTemplateId' => ['sometimes', 'nullable', 'integer', Rule::exists('email_templates', 'email_id')],
25+
'userGroupIds' => ['required', 'array', 'min:1'],
26+
'userGroupIds.*' => [
27+
'integer',
28+
'distinct',
29+
Rule::exists('user_groups', 'user_group_id')
30+
->where(fn ($q) => $q->where('context_id', $contextId)),
31+
],
32+
];
33+
}
34+
35+
protected function prepareForValidation(): void
36+
{
37+
$this->merge([
38+
'include' => filter_var($this->input('include', false), FILTER_VALIDATE_BOOLEAN),
39+
'userGroupIds' => array_values(array_map('intval', (array) $this->input('userGroupIds', []))),
40+
]);
41+
}
42+
43+
public function validated($key = null, $default = null)
44+
{
45+
$data = parent::validated();
46+
47+
return [
48+
'stageId' => (int) $data['stageId'],
49+
'title' => $data['title'],
50+
'include' => $data['include'] ?? false,
51+
'emailTemplateId' => $data['emailTemplateId'] ?? null,
52+
'userGroupIds' => $data['userGroupIds'],
53+
];
54+
}
55+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
namespace PKP\API\v1\editTaskTemplates\resources;
4+
5+
use Illuminate\Http\Request;
6+
use Illuminate\Http\Resources\Json\JsonResource;
7+
8+
class EditTaskTemplateResource extends JsonResource
9+
{
10+
public function toArray(Request $request)
11+
{
12+
13+
return [
14+
'id' => (int) $this->id,
15+
'stageId' => (int) $this->stage_id,
16+
'title' => $this->title,
17+
'include' => (bool) $this->include,
18+
'emailTemplateId' => $this->email_template_id ? (int) $this->email_template_id : null,
19+
'userGroupIds' => $this->whenLoaded('userGroups', fn () => $this->userGroups->pluck('user_group_id')->values()->all()),
20+
'userGroups' => $this->whenLoaded('userGroups', fn () => $this->userGroups->map(fn ($ug) => [
21+
'id' => (int) $ug->user_group_id,
22+
'name' => method_exists($ug, 'getLocalizedName') ? $ug->getLocalizedName() : ($ug->name ?? null),
23+
])),
24+
];
25+
}
26+
}

0 commit comments

Comments
 (0)