|
2 | 2 |
|
3 | 3 | namespace PKP\API\v1\editTaskTemplates;
|
4 | 4 |
|
5 |
| -use APP\facades\Repo; |
6 | 5 | use Illuminate\Http\JsonResponse;
|
7 |
| -use Illuminate\Http\Request; |
8 | 6 | use Illuminate\Http\Response;
|
9 |
| -use Illuminate\Support\Carbon; |
10 | 7 | use Illuminate\Support\Facades\DB;
|
11 | 8 | use Illuminate\Support\Facades\Route;
|
12 |
| -use Illuminate\Support\Facades\Validator; |
13 |
| -use Illuminate\Validation\Rule; |
14 |
| -use PKP\API\v1\submissions\resources\TaskResource; |
15 | 9 | use PKP\core\PKPBaseController;
|
16 | 10 | use PKP\core\PKPRequest;
|
17 |
| -use PKP\editorialTask\EditorialTask; |
18 |
| -use PKP\editorialTask\enums\EditorialTaskType; |
19 |
| -use PKP\editorialTask\Participant; |
20 | 11 | use PKP\security\authorization\CanAccessSettingsPolicy;
|
21 | 12 | use PKP\security\authorization\ContextAccessPolicy;
|
22 | 13 | use PKP\security\Role;
|
23 |
| -use PKP\userGroup\UserGroup; |
24 | 14 | use PKP\editorialTask\Template;
|
| 15 | +use PKP\API\v1\editTaskTemplates\formRequests\AddEditTaskTemplate; |
| 16 | +use PKP\API\v1\editTaskTemplates\resources\EditTaskTemplateResource; |
25 | 17 |
|
26 | 18 | class PKPEditTaskTemplateController extends PKPBaseController
|
27 | 19 | {
|
@@ -56,203 +48,32 @@ public function getGroupRoutes(): void
|
56 | 48 |
|
57 | 49 | /**
|
58 | 50 | * POST /api/v1/editTaskTemplates
|
59 |
| - * Body: stageId, title, include, type, dateDue?, userGroupIds[], participants[] (userId,isResponsible?) |
60 | 51 | */
|
61 |
| - public function add(Request $illuminateRequest): JsonResponse |
| 52 | + public function add(AddEditTaskTemplate $illuminateRequest): JsonResponse |
62 | 53 | {
|
63 |
| - $request = $this->getRequest(); |
64 |
| - $context = $request->getContext(); |
65 |
| - $currentUser = $request->getUser(); |
| 54 | + $context = $this->getRequest()->getContext(); |
| 55 | + $validated = $illuminateRequest->validated(); |
66 | 56 |
|
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'], |
154 | 61 | '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, |
157 | 64 | ]);
|
158 | 65 |
|
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']); |
189 | 67 |
|
190 |
| - return $template->getKey(); |
| 68 | + return $tpl; |
191 | 69 | });
|
192 | 70 |
|
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 |
228 | 76 | );
|
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 |
| - |
257 | 77 | }
|
| 78 | + |
258 | 79 | }
|
0 commit comments