PluginProbe
Yatra – Travel Booking & Tour Operator Software / trunk
Yatra – Travel Booking & Tour Operator Software vtrunk
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 / EnquiryController.php

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

356 lines 10.8 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\EnquiryService;
11
12 /**
13 * Enquiry REST API Controller
14 *
15 * Handles HTTP requests only - delegates business logic to EnquiryService.
16 *
17 * NO DATABASE QUERIES OR BUSINESS LOGIC IN THIS FILE.
18 *
19 * @package Yatra\Controllers
20 */
21 class EnquiryController extends BaseController
22 {
23 /**
24 * Enquiry service instance
25 */
26 private EnquiryService $enquiryService;
27
28 /**
29 * Constructor
30 */
31 public function __construct()
32 {
33 $this->enquiryService = new EnquiryService();
34 }
35
36 /**
37 * Register routes
38 */
39 public function register_routes(): void
40 {
41 $namespace = 'yatra/v1';
42 $base = 'enquiries';
43
44 // List & Create
45 register_rest_route($namespace, '/' . $base, [
46 [
47 'methods' => \WP_REST_Server::READABLE,
48 'callback' => [$this, 'getEnquiries'],
49 'permission_callback' => [$this, 'checkCanView'],
50 ],
51 [
52 'methods' => \WP_REST_Server::CREATABLE,
53 'callback' => [$this, 'createEnquiry'],
54 'permission_callback' => '__return_true', // Public endpoint
55 ],
56 ]);
57
58 // Single enquiry operations — read uses view, write uses respond,
59 // delete uses the dedicated delete cap (high sensitivity).
60 register_rest_route($namespace, '/' . $base . '/(?P<id>[\d]+)', [
61 [
62 'methods' => \WP_REST_Server::READABLE,
63 'callback' => [$this, 'getEnquiry'],
64 'permission_callback' => [$this, 'checkCanView'],
65 ],
66 [
67 'methods' => \WP_REST_Server::EDITABLE,
68 'callback' => [$this, 'updateEnquiry'],
69 'permission_callback' => [$this, 'checkCanRespond'],
70 ],
71 [
72 'methods' => \WP_REST_Server::DELETABLE,
73 'callback' => [$this, 'deleteEnquiry'],
74 'permission_callback' => [$this, 'checkCanDelete'],
75 ],
76 ]);
77
78 // Bulk actions — operations include status change, mark-read,
79 // delete, etc. Gate on respond (the broadest mutation cap
80 // short of delete). Bulk-delete callers should re-check
81 // delete-cap inside the handler when the action is "delete".
82 register_rest_route($namespace, '/' . $base . '/bulk', [
83 [
84 'methods' => \WP_REST_Server::EDITABLE,
85 'callback' => [$this, 'bulkAction'],
86 'permission_callback' => [$this, 'checkCanRespond'],
87 ],
88 ]);
89
90 // Stats endpoint — read-only aggregation, view cap is enough.
91 register_rest_route($namespace, '/' . $base . '/stats', [
92 [
93 'methods' => \WP_REST_Server::READABLE,
94 'callback' => [$this, 'getStats'],
95 'permission_callback' => [$this, 'checkCanView'],
96 ],
97 ]);
98
99 // Respond to enquiry — explicit respond-cap.
100 register_rest_route($namespace, '/' . $base . '/(?P<id>[\d]+)/respond', [
101 [
102 'methods' => \WP_REST_Server::CREATABLE,
103 'callback' => [$this, 'respondToEnquiry'],
104 'permission_callback' => [$this, 'checkCanRespond'],
105 ],
106 ]);
107 }
108
109 /**
110 * Granular permission checks — one per operation so role bundles
111 * (Sales Agent, Front Desk, etc.) can actually use the parts of
112 * the enquiry surface their role grants. WP administrators pass
113 * every cap automatically via the Team module's admin-fallback
114 * filter, so `manage_options` doesn't need an explicit check
115 * here — it's covered by the cap.
116 */
117 public function checkCanView(): bool
118 {
119 return current_user_can('yatra_view_enquiries');
120 }
121
122 public function checkCanRespond(): bool
123 {
124 return current_user_can('yatra_respond_to_enquiries');
125 }
126
127 public function checkCanDelete(): bool
128 {
129 return current_user_can('yatra_delete_enquiries');
130 }
131
132 /**
133 * @deprecated Kept for any external code (custom snippet, third-
134 * party integration) that hooked the old method name. New code
135 * should use checkCanView/Respond/Delete. Routes the call to
136 * the view-only cap so behaviour is at-least-as-strict as before
137 * for non-admin callers, and admin users keep passing via the
138 * admin-fallback layer.
139 */
140 public function checkAdminPermission(): bool
141 {
142 return $this->checkCanView();
143 }
144
145 /**
146 * GET /enquiries - List all enquiries
147 */
148 public function getEnquiries(WP_REST_Request $request): WP_REST_Response
149 {
150 $filters = [
151 'page' => (int) ($request->get_param('page') ?: 1),
152 'per_page' => (int) ($request->get_param('per_page') ?: 20),
153 'status' => $request->get_param('status') ?: '',
154 'trip_id' => (int) $request->get_param('trip_id'),
155 'search' => $request->get_param('search') ?: '',
156 'date_from' => $request->get_param('date_from') ?: '',
157 'date_to' => $request->get_param('date_to') ?: '',
158 ];
159
160 $result = $this->enquiryService->getEnquiries($filters);
161
162 return new WP_REST_Response([
163 'success' => true,
164 'data' => $result['data'],
165 'meta' => [
166 'total' => $result['total'],
167 'page' => $result['page'],
168 'per_page' => $result['per_page'],
169 'total_pages' => $result['total_pages'],
170 ],
171 ]);
172 }
173
174 /**
175 * GET /enquiries/{id} - Get single enquiry
176 */
177 public function getEnquiry(WP_REST_Request $request): WP_REST_Response
178 {
179 $id = (int) $request->get_param('id');
180
181 $enquiry = $this->enquiryService->getEnquiry($id);
182
183 if (!$enquiry) {
184 return new WP_REST_Response([
185 'success' => false,
186 'message' => __('Enquiry not found.', 'yatra'),
187 ], 404);
188 }
189
190 return new WP_REST_Response([
191 'success' => true,
192 'data' => $enquiry,
193 ]);
194 }
195
196 /**
197 * POST /enquiries - Create enquiry (public endpoint)
198 */
199 public function createEnquiry(WP_REST_Request $request): WP_REST_Response
200 {
201 $data = $request->get_json_params();
202
203 // Handle both JSON and form data
204 if (empty($data)) {
205 $data = $request->get_params();
206 }
207
208 // reCAPTCHA v3 (no-op unless the enquiry form is protected in settings).
209 $recaptcha = \Yatra\Services\RecaptchaService::verifyForm(
210 'enquiry',
211 (string) ($data['recaptcha_token'] ?? ''),
212 $_SERVER['REMOTE_ADDR'] ?? null
213 );
214 if (empty($recaptcha['success'])) {
215 return new WP_REST_Response([
216 'success' => false,
217 'message' => $recaptcha['message'] ?? __('reCAPTCHA verification failed.', 'yatra'),
218 ], 400);
219 }
220
221 $result = $this->enquiryService->createEnquiry($data);
222
223 if (!$result['success']) {
224 return new WP_REST_Response($result, 400);
225 }
226
227 return new WP_REST_Response($result, 201);
228 }
229
230 /**
231 * PUT /enquiries/{id} - Update enquiry
232 */
233 public function updateEnquiry(WP_REST_Request $request): WP_REST_Response
234 {
235 $id = (int) $request->get_param('id');
236 $data = $request->get_json_params();
237
238 $result = $this->enquiryService->updateEnquiry($id, $data);
239
240 if (!$result['success']) {
241 return new WP_REST_Response($result, 400);
242 }
243
244 return new WP_REST_Response($result);
245 }
246
247 /**
248 * DELETE /enquiries/{id} - Delete enquiry
249 */
250 public function deleteEnquiry(WP_REST_Request $request): WP_REST_Response
251 {
252 $id = (int) $request->get_param('id');
253
254 $result = $this->enquiryService->deleteEnquiry($id);
255
256 if (!$result['success']) {
257 return new WP_REST_Response($result, 400);
258 }
259
260 return new WP_REST_Response($result);
261 }
262
263 /**
264 * PUT /enquiries/bulk - Bulk actions
265 */
266 public function bulkAction(WP_REST_Request $request): WP_REST_Response
267 {
268 $data = $request->get_json_params();
269 $action = $data['action'] ?? '';
270 $ids = $data['ids'] ?? [];
271
272 if (empty($ids) || !is_array($ids)) {
273 return new WP_REST_Response([
274 'success' => false,
275 'message' => __('No items selected.', 'yatra'),
276 ], 400);
277 }
278
279 switch ($action) {
280 case 'delete':
281 $result = $this->enquiryService->bulkDelete($ids);
282 break;
283
284 case 'mark_read':
285 $result = $this->enquiryService->bulkUpdateStatus($ids, 'read');
286 break;
287
288 case 'mark_pending':
289 $result = $this->enquiryService->bulkUpdateStatus($ids, 'pending');
290 break;
291
292 case 'mark_completed':
293 $result = $this->enquiryService->bulkUpdateStatus($ids, 'completed');
294 break;
295
296 case 'mark_spam':
297 $result = $this->enquiryService->bulkUpdateStatus($ids, 'spam');
298 break;
299
300 case 'mark_trash':
301 $result = $this->enquiryService->bulkUpdateStatus($ids, 'trash');
302 break;
303
304 case 'archive':
305 $result = $this->enquiryService->bulkUpdateStatus($ids, 'archived');
306 break;
307
308 default:
309 return new WP_REST_Response([
310 'success' => false,
311 'message' => __('Invalid action.', 'yatra'),
312 ], 400);
313 }
314
315 return new WP_REST_Response($result);
316 }
317
318 /**
319 * GET /enquiries/stats - Get statistics
320 */
321 public function getStats(WP_REST_Request $request): WP_REST_Response
322 {
323 $stats = $this->enquiryService->getStats();
324
325 return new WP_REST_Response([
326 'success' => true,
327 'data' => $stats,
328 ]);
329 }
330
331 /**
332 * POST /enquiries/{id}/respond - Respond to enquiry
333 */
334 public function respondToEnquiry(WP_REST_Request $request): WP_REST_Response
335 {
336 $id = (int) $request->get_param('id');
337 $data = $request->get_json_params();
338 $response = $data['response'] ?? '';
339
340 if (empty(trim($response))) {
341 return new WP_REST_Response([
342 'success' => false,
343 'message' => __('Response message is required.', 'yatra'),
344 ], 400);
345 }
346
347 $result = $this->enquiryService->respondToEnquiry($id, $response);
348
349 if (!$result['success']) {
350 return new WP_REST_Response($result, 400);
351 }
352
353 return new WP_REST_Response($result);
354 }
355 }
356