PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.16
Yatra – Travel Booking & Tour Operator Software v3.0.16
3.0.16 3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 All 84 releases
← All changes | app/Controllers/ItineraryController.php +91 -3 3.0.3 → 3.0.16 View file →
@@ -76,11 +76,52 @@
76 76 'callback' => [$this, 'get_day_entry_id_by_day_id'],
77 77 'permission_callback' => [$this, 'check_permission'],
78 78 ],
79 79 ]);
80 +
81 + // Bulk-update / -create activities for a single day in one request.
82 + // Replaces the React day-edit "save" path that previously fired one PUT
83 + // per activity (5 activities = 5 sequential round-trips). The endpoint
84 + // accepts an `activities` array carrying full payloads + optional `id`
85 + // per row; rows with `id` are PUTs, rows without are POSTs.
86 + register_rest_route($namespace, '/' . $base . '/day/(?P<day_id>[\d]+)/activities/bulk', [
87 + [
88 + 'methods' => \WP_REST_Server::EDITABLE,
89 + 'callback' => [$this, 'bulk_save_day_activities'],
90 + 'permission_callback' => [$this, 'check_permission'],
91 + ],
92 + ]);
80 93 }
81 94
82 95 /**
96 + * Itinerary endpoints are bound to a trip. Reads use the view-trips
97 + * cap (Sales Agent / Front Desk / Guide / Auditor all hold this);
98 + * writes use the edit-trips cap. WP admins pass via the Team
99 + * module's admin-fallback filter. Overrides BaseController's default
100 + * which was the coarse `manage_options` check.
101 + */
102 + public function check_permission(?WP_REST_Request $request = null): bool
103 + {
104 + if ($request === null) {
105 + return true;
106 + }
107 + if (!is_user_logged_in()) {
108 + return false;
109 + }
110 + switch ($request->get_method()) {
111 + case 'GET':
112 + return current_user_can('yatra_view_trips');
113 + case 'POST':
114 + case 'PUT':
115 + case 'PATCH':
116 + case 'DELETE':
117 + return current_user_can('yatra_edit_trips');
118 + default:
119 + return current_user_can('yatra_view_trips');
120 + }
121 + }
122 +
123 + /**
83 124 * Get items by trip ID
84 125 */
85 126 public function get_items_by_trip(WP_REST_Request $request)
86 127 {
@@ -202,8 +243,50 @@
202 243 }
203 244 }
204 245
205 246 /**
247 + * Bulk-save the activities of a single day in one request.
248 + *
249 + * Body shape:
250 + * {
251 + * "trip_id": 14,
252 + * "activities": [
253 + * { "id": 39, "title": "...", "order": 0, ...full activity fields... },
254 + * { "title": "...", "order": 1, ... } // no id => create
255 + * ]
256 + * }
257 + *
258 + * Each row goes through the same validation / sanitisation as a single
259 + * update / create — the difference is one HTTP round-trip and one cache
260 + * invalidation instead of N. Returns per-row results so the React layer
261 + * can surface partial failures without losing the rows that succeeded.
262 + */
263 + public function bulk_save_day_activities(WP_REST_Request $request)
264 + {
265 + try {
266 + $dayId = (int) $request->get_param('day_id');
267 + $body = $request->get_json_params() ?: [];
268 + $tripId = isset($body['trip_id']) ? (int) $body['trip_id'] : 0;
269 + $activities = $body['activities'] ?? [];
270 +
271 + if ($dayId <= 0) {
272 + return $this->error_response('Invalid day_id', 400);
273 + }
274 + if (!is_array($activities)) {
275 + return $this->error_response('activities must be an array', 400);
276 + }
277 +
278 + $result = $this->service->bulkSaveDayActivities($dayId, $tripId, $activities);
279 +
280 + return $this->success_response($result);
281 + } catch (\InvalidArgumentException $e) {
282 + return $this->error_response($e->getMessage(), 400);
283 + } catch (\Exception $e) {
284 + return $this->error_response($e->getMessage(), 500);
285 + }
286 + }
287 +
288 + /**
206 289 * Bulk delete items
207 290 */
208 291 public function bulk_delete_items(WP_REST_Request $request)
209 292 {
@@ -209,20 +292,25 @@
209 292 {
210 293 try {
211 294 $data = $request->get_json_params();
212 295 $ids = $data['ids'] ?? [];
296 + $dayIds = $data['day_ids'] ?? [];
213 297
214 - if (empty($ids) || !is_array($ids)) {
298 + $ids = is_array($ids) ? $ids : [];
299 + $dayIds = is_array($dayIds) ? $dayIds : [];
300 +
301 + if (empty($ids) && empty($dayIds)) {
215 302 return $this->error_response('No IDs provided for bulk delete', 400);
216 303 }
217 304
218 - $result = $this->service->bulkDelete($ids);
305 + $result = $this->service->bulkDelete($ids, $dayIds);
219 306
220 307 return $this->success_response([
221 308 'deleted' => $result['deleted'],
222 309 'failed' => $result['failed'],
223 310 'message' => sprintf(
224 - __('%d item(s) deleted successfully. %d item(s) failed to delete.', 'yatra'),
311 + /* translators: 1: number of items deleted, 2: number of items that failed to delete. */
312 + __('%1$d item(s) deleted successfully. %2$d item(s) failed to delete.', 'yatra'),
225 313 $result['deleted'],
226 314 $result['failed']
227 315 ),
228 316 ]);