PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.2.8
Yatra – Travel Booking & Tour Operator Software v3.0.2.8
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 2.0.10 2.0.11 All 82 releases
yatra / app / Controllers / ActivityController.php

ActivityController.php in Yatra – Travel Booking & Tour Operator Software 3.0.2.8, at app/Controllers/ActivityController.php

364 lines 11.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace Yatra\Controllers;
6
7 use WP_REST_Request;
8 use WP_REST_Response;
9 use WP_Error;
10 use Yatra\Services\ActivityService;
11 use Yatra\Database\Tables\TripsTable;
12 use Yatra\Database\Tables\TripClassificationsTable;
13 use Yatra\Validators\ActivityValidator;
14 use Yatra\Exceptions\ValidationException;
15 use Yatra\Utils\Logger;
16 use Yatra\Helpers\FormatHelper;
17
18 /**
19 * Activity REST API Controller
20 *
21 * Endpoints:
22 * - GET /activities - List activities
23 * - POST /activities - Create activity
24 * - GET /activities/{id} - Get single activity
25 * - PUT /activities/{id} - Update activity
26 * - DELETE /activities/{id} - Delete activity
27 */
28 class ActivityController extends BaseController
29 {
30 /**
31 * REST API base
32 */
33 protected string $rest_base = 'activities';
34
35 /**
36 * @var ActivityService
37 */
38 private ActivityService $service;
39
40 /**
41 * Constructor
42 */
43 public function __construct()
44 {
45 $this->service = new ActivityService();
46 }
47
48 /**
49 * Register routes
50 */
51 public function register_routes(): void
52 {
53 // Register standard CRUD routes with status filter
54 $this->registerCrudRoutes($this->getStatusArg());
55
56 register_rest_route($this->namespace, '/' . $this->rest_base . '/bulk', [
57 'methods' => \WP_REST_Server::CREATABLE,
58 'callback' => [$this, 'bulkAction'],
59 'permission_callback' => [$this, 'check_permission'],
60 ]);
61
62 register_rest_route($this->namespace, '/' . $this->rest_base . '/stats', [
63 'methods' => \WP_REST_Server::READABLE,
64 'callback' => [$this, 'getStats'],
65 'permission_callback' => [$this, 'check_permission'],
66 ]);
67 }
68
69 /**
70 * Check permissions for activity endpoints
71 */
72 public function check_permission(?WP_REST_Request $request = null): bool
73 {
74 if ($request === null) {
75 return true;
76 }
77
78 if (!is_user_logged_in()) {
79 return false;
80 }
81
82 if (current_user_can('manage_options')) {
83 return true;
84 }
85
86 $method = $request->get_method();
87
88 switch ($method) {
89 case 'GET':
90 return current_user_can('yatra_view_trips');
91 case 'POST':
92 case 'PUT':
93 case 'PATCH':
94 case 'DELETE':
95 return current_user_can('yatra_edit_trips');
96 default:
97 return current_user_can('manage_options');
98 }
99 }
100
101 /**
102 * Get items
103 */
104 public function get_items(WP_REST_Request $request)
105 {
106 try {
107 $params = $this->getPaginationParams($request);
108
109 Logger::apiRequest('/activities', 'GET', $params);
110
111 $args = [
112 'limit' => $params['per_page'],
113 'offset' => ($params['page'] - 1) * $params['per_page'],
114 'order_by' => $params['orderby'],
115 'order' => $params['order'],
116 ];
117
118 if (!empty($params['search'])) {
119 $args['search'] = $params['search'];
120 }
121
122 $status = $request->get_param('status');
123 if ($status && $status !== 'all') {
124 $args['status'] = sanitize_text_field($status);
125 }
126
127 $items = $this->service->getAll($args);
128 $total = $this->service->count($args);
129
130 // Attach trip counts for each activity
131 if (!empty($items)) {
132 foreach ($items as $item) {
133 $activityId = isset($item->id) ? (int) $item->id : 0;
134 if ($activityId <= 0) {
135 continue;
136 }
137
138 $tripCount = $this->service->getTripCount($activityId);
139 $item->trip_count = $tripCount;
140 }
141 }
142
143 $prepared = array_map([$this, 'prepareActivity'], $items);
144
145 Logger::info("Activities retrieved successfully", ['count' => count($prepared), 'total' => $total]);
146 return $this->paginated_response($prepared, $total, $params['page'], $params['per_page']);
147
148 } catch (\Exception $e) {
149 Logger::error("Failed to get activities", ['error' => $e->getMessage(), 'params' => $params ?? []]);
150 return $this->handle_exception($e);
151 }
152 }
153
154 /**
155 * Get single item
156 */
157 public function get_item(WP_REST_Request $request)
158 {
159 try {
160 $id = $this->getId($request);
161
162 if ($id <= 0) {
163 throw new ValidationException('Invalid activity ID', ['id' => ['Activity ID must be a positive integer']]);
164 }
165
166 Logger::apiRequest("/activities/{$id}", 'GET');
167
168 $item = $this->service->getById($id);
169
170 if (!$item) {
171 Logger::warning("Activity not found", ['activity_id' => $id]);
172 return $this->not_found(__('Activity not found', 'yatra'));
173 }
174
175 // Attach trip count for single activity
176 $activityId = isset($item->id) ? (int) $item->id : 0;
177 if ($activityId > 0) {
178 $tripCount = $this->service->getTripCount($activityId);
179 $item->trip_count = $tripCount;
180 }
181
182 Logger::info("Activity retrieved successfully", ['activity_id' => $id]);
183 return $this->success_response($this->prepareActivity($item));
184
185 } catch (\Exception $e) {
186 Logger::error("Failed to get activity", ['activity_id' => isset($id) ? $id : 0, 'error' => $e->getMessage()]);
187 return $this->handle_exception($e);
188 }
189 }
190
191 /**
192 * Create item
193 */
194 public function create_item(WP_REST_Request $request)
195 {
196 try {
197 $data = $this->getBody($request);
198
199 // Validate and sanitize input data
200 ActivityValidator::validateCreate($data);
201 $data = ActivityValidator::sanitize($data);
202
203 // Description will be sanitized in the Service layer with FormatHelper::sanitizeQuillHtml()
204
205 Logger::apiRequest('/activities', 'POST', $data);
206
207 $id = $this->service->create($data);
208
209 Logger::info("Activity created successfully", ['activity_id' => $id]);
210 return $this->success_response([
211 'id' => $id,
212 'message' => __('Activity created successfully', 'yatra'),
213 ], 201);
214
215 } catch (\Exception $e) {
216 Logger::error("Failed to create activity", ['data' => $data ?? [], 'error' => $e->getMessage()]);
217 return $this->handle_exception($e);
218 }
219 }
220
221 /**
222 * Update item
223 */
224 public function update_item(WP_REST_Request $request)
225 {
226 try {
227 $id = $this->getId($request);
228 $data = $this->getBody($request);
229
230
231 // Description will be sanitized in the Service layer with FormatHelper::sanitizeQuillHtml()
232
233 $result = $this->service->update($id, $data);
234
235 if (!$result) {
236 return $this->error_response(__('Failed to update activity', 'yatra'), 500);
237 }
238
239 return $this->success_response([
240 'message' => __('Activity updated successfully', 'yatra'),
241 ]);
242 } catch (\InvalidArgumentException $e) {
243 return $this->validation_error($e->getMessage());
244 } catch (\Exception $e) {
245 return $this->error_response($e->getMessage(), 500);
246 }
247 }
248
249 /**
250 * Delete item
251 */
252 public function delete_item(WP_REST_Request $request)
253 {
254 try {
255 $result = $this->service->delete($this->getId($request));
256
257 if (!$result) {
258 return $this->error_response(__('Failed to delete activity', 'yatra'), 500);
259 }
260
261 return $this->success_response([
262 'message' => __('Activity deleted successfully', 'yatra'),
263 ]);
264 } catch (\Exception $e) {
265 return $this->error_response($e->getMessage(), 500);
266 }
267 }
268
269 /**
270 * Bulk actions endpoint
271 */
272 public function bulkAction(WP_REST_Request $request)
273 {
274 try {
275 $data = $request->get_json_params();
276 $action = sanitize_text_field($data['action'] ?? '');
277 $ids = array_filter(array_map('absint', $data['ids'] ?? []));
278
279 if (empty($action)) {
280 return $this->validation_error(__('Action is required', 'yatra'));
281 }
282
283 if (empty($ids)) {
284 return $this->validation_error(__('No activities selected', 'yatra'));
285 }
286
287 switch ($action) {
288 case 'trash':
289 $result = $this->service->bulkUpdateStatus($ids, 'trash');
290 break;
291 case 'publish':
292 $result = $this->service->bulkUpdateStatus($ids, 'publish');
293 break;
294 case 'draft':
295 $result = $this->service->bulkUpdateStatus($ids, 'draft');
296 break;
297 case 'restore':
298 $result = $this->service->bulkUpdateStatus($ids, 'publish');
299 break;
300 case 'delete':
301 $result = $this->service->bulkDelete($ids);
302 break;
303 default:
304 throw new \InvalidArgumentException(__('Invalid action', 'yatra'));
305 }
306
307 return $this->success_response($result);
308 } catch (\InvalidArgumentException $e) {
309 return $this->validation_error($e->getMessage());
310 } catch (\Exception $e) {
311 return $this->error_response($e->getMessage(), 500);
312 }
313 }
314
315 /**
316 * Get statistics for admin views
317 */
318 public function getStats(WP_REST_Request $request)
319 {
320 try {
321 $stats = $this->service->getStatusCounts();
322 return $this->success_response($stats);
323 } catch (\Exception $e) {
324 return $this->error_response($e->getMessage(), 500);
325 }
326 }
327
328 /**
329 * Prepare activity for response
330 */
331 private function prepareActivity($item): array
332 {
333 $prepared = (array) $item;
334
335
336 // Handle icon
337 if (isset($prepared['icon']) && is_string($prepared['icon'])) {
338 $prepared['icon'] = maybe_unserialize($prepared['icon']);
339 }
340 if (isset($prepared['icon'])) {
341 $prepared['icon'] = $this->convert_icon_attachment_id_to_url($prepared['icon']);
342 }
343
344 // Handle metadata
345 if (isset($prepared['metadata']) && is_string($prepared['metadata'])) {
346 $prepared['metadata'] = maybe_unserialize($prepared['metadata']);
347 }
348
349
350 // Add user names
351 if (!empty($prepared['created_by'])) {
352 $user = get_userdata((int) $prepared['created_by']);
353 $prepared['created_by_name'] = $user ? esc_html($user->display_name) : null;
354 }
355
356 if (!empty($prepared['updated_by'])) {
357 $user = get_userdata((int) $prepared['updated_by']);
358 $prepared['updated_by_name'] = $user ? esc_html($user->display_name) : null;
359 }
360
361 return $prepared;
362 }
363 }
364