PluginProbe
WP Data Access – App Builder for Tables, Forms, Dashboards, Charts & Maps / 5.5.87
WP Data Access – App Builder for Tables, Forms, Dashboards, Charts & Maps v5.5.87
5.5.87 5.5.85 5.5.84 5.5.83 5.5.82 5.5.81 5.5.80 5.5.79 5.5.77 5.5.76 5.5.75 5.5.73 5.5.72 5.5.22 5.5.23 5.5.29 5.5.3 5.5.31 5.5.32 5.5.34 5.5.35 5.5.36 5.5.37 5.5.4 5.5.40 All 162 releases
← All changes | WPDataAccess/API/WPDA_Apps.php +1643 -117 5.5.3 → 5.5.87 View file →
@@ -5,12 +5,42 @@
5 5 use stdClass;
6 6 use WPDataAccess\Connection\WPDADB;
7 7 use WPDataAccess\Data_Dictionary\WPDA_List_Columns_Cache;
8 8 use WPDataAccess\Plugin_Table_Models\WPDA_App_Container_Model;
9 +use WPDataAccess\Plugin_Table_Models\WPDA_App_Apps_Model;
9 10 use WPDataAccess\Plugin_Table_Models\WPDA_App_Model;
10 11 use WPDataAccess\Plugin_Table_Models\WPDA_Table_Settings_Model;
12 +use WPDataAccess\Utilities\WPDA_App_Localization;
11 13 use WPDataAccess\WPDA;
12 14 class WPDA_Apps extends WPDA_API_Core {
15 + const METHODS = array('httpGet', 'httpPost', 'httpRequest');
16 +
17 + const WPDA_APP_DEFAULT_LANG = 'wpda_app_default_lang';
18 +
19 + private function sanitize_settings( $value ) {
20 + if ( is_array( $value ) ) {
21 + foreach ( $value as $index => $item ) {
22 + $value[$index] = $this->sanitize_settings( $item );
23 + }
24 + } elseif ( is_object( $value ) ) {
25 + $object_vars = get_object_vars( $value );
26 + foreach ( $object_vars as $property_name => $property_value ) {
27 + $value->{$property_name} = $this->sanitize_settings( $property_value );
28 + }
29 + } else {
30 + // Allow HTML and onclick for computed fields
31 + // phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
32 + $value = apply_filters(
33 + 'wp_kses_post',
34 + $value,
35 + "",
36 + ["onclick"]
37 + );
38 + // phpcs:enable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
39 + }
40 + return $value;
41 + }
42 +
13 43 public function register_rest_routes() {
14 44 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/init', array(
15 45 'methods' => array('POST'),
16 46 'callback' => array($this, 'app_init'),
@@ -28,8 +58,22 @@
28 58 'args' => array(
29 59 'app_id' => $this->get_param( 'app_id' ),
30 60 ),
31 61 ) );
62 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/lang', array(
63 + 'methods' => array('POST'),
64 + 'callback' => array($this, 'app_lang'),
65 + 'permission_callback' => '__return_true',
66 + 'args' => array(
67 + 'lang' => array(
68 + 'required' => true,
69 + 'type' => 'string',
70 + 'description' => __( 'App default language', 'wp-data-access' ),
71 + 'sanitize_callback' => 'sanitize_text_field',
72 + 'validate_callback' => 'rest_validate_request_arg',
73 + ),
74 + ),
75 + ) );
32 76 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/table/meta', array(
33 77 'methods' => array('POST'),
34 78 'callback' => array($this, 'app_table_meta'),
35 79 'permission_callback' => '__return_true',
@@ -57,14 +101,43 @@
57 101 'app_cls' => $this->get_param( 'app_cls' ),
58 102 'app_table' => array(
59 103 'required' => true,
60 104 'type' => 'string',
61 - 'description' => __( 'Table settings', 'wp-data-access' ),
105 + 'description' => __( 'App table', 'wp-data-access' ),
62 106 'sanitize_callback' => 'sanitize_text_field',
63 107 'validate_callback' => 'rest_validate_request_arg',
64 108 ),
109 + 'app_query' => $this->get_param( 'app_query' ),
65 110 ),
66 111 ) );
112 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/createapp', array(
113 + 'methods' => array('POST'),
114 + 'callback' => array($this, 'app_createapp'),
115 + 'permission_callback' => '__return_true',
116 + 'args' => array(
117 + 'app_name' => $this->get_param( 'app_name' ),
118 + 'app_title' => $this->get_param( 'app_title' ),
119 + 'app_type' => $this->get_param( 'app_type' ),
120 + 'app_settings' => $this->get_param( 'app_settings' ),
121 + 'app_apps' => $this->get_param( 'app_apps' ),
122 + ),
123 + ) );
124 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/copy', array(
125 + 'methods' => array('POST'),
126 + 'callback' => array($this, 'app_copy'),
127 + 'permission_callback' => '__return_true',
128 + 'args' => array(
129 + 'app_id' => $this->get_param( 'app_id' ),
130 + ),
131 + ) );
132 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/export', array(
133 + 'methods' => array('POST'),
134 + 'callback' => array($this, 'app_export'),
135 + 'permission_callback' => '__return_true',
136 + 'args' => array(
137 + 'app_id' => $this->get_param( 'app_id' ),
138 + ),
139 + ) );
67 140 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/details', array(
68 141 'methods' => array('POST'),
69 142 'callback' => array($this, 'app_details'),
70 143 'permission_callback' => '__return_true',
@@ -69,8 +142,9 @@
69 142 'callback' => array($this, 'app_details'),
70 143 'permission_callback' => '__return_true',
71 144 'args' => array(
72 145 'app_id' => $this->get_param( 'app_id' ),
146 + 'cnt_id' => $this->get_param( 'cnt_id' ),
73 147 ),
74 148 ) );
75 149 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/detailmeta', array(
76 150 'methods' => array('POST'),
@@ -76,12 +150,23 @@
76 150 'methods' => array('POST'),
77 151 'callback' => array($this, 'app_detail_meta'),
78 152 'permission_callback' => '__return_true',
79 153 'args' => array(
80 - 'app_id' => $this->get_param( 'app_id' ),
81 - 'cnt_id' => $this->get_param( 'cnt_id' ),
154 + 'app_id' => $this->get_param( 'app_id' ),
155 + 'cnt_id' => $this->get_param( 'cnt_id' ),
156 + 'rel_tab' => $this->get_param( 'rel_tab' ),
82 157 ),
83 158 ) );
159 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/detailreorder', array(
160 + 'methods' => array('POST'),
161 + 'callback' => array($this, 'app_detail_reorder'),
162 + 'permission_callback' => '__return_true',
163 + 'args' => array(
164 + 'app_id' => $this->get_param( 'app_id' ),
165 + 'cnt_id_from' => $this->get_param( 'cnt_id' ),
166 + 'cnt_id_to' => $this->get_param( 'cnt_id' ),
167 + ),
168 + ) );
84 169 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/relationship/create', array(
85 170 'methods' => array('POST'),
86 171 'callback' => array($this, 'app_relationship_create'),
87 172 'permission_callback' => '__return_true',
@@ -137,20 +222,29 @@
137 222 'app_name' => $this->get_param( 'app_name' ),
138 223 'app_title' => $this->get_param( 'app_title' ),
139 224 'app_type' => $this->get_param( 'app_type' ),
140 225 'app_settings' => $this->get_param( 'app_settings' ),
141 - 'app_add_to_menu' => array(
142 - 'required' => true,
143 - 'type' => 'integer',
144 - 'description' => __( 'Add app to dashboard menu', 'wp-data-access' ),
145 - 'sanitize_callback' => 'absint',
146 - 'validate_callback' => 'rest_validate_request_arg',
147 - ),
226 + 'app_add_to_menu' => $this->get_param( 'app_add_to_menu' ),
148 227 'app_dbs' => $this->get_param( 'dbs' ),
149 228 'app_tbl' => $this->get_param( 'tbl' ),
150 229 'app_cls' => $this->get_param( 'app_cls' ),
230 + 'app_query' => $this->get_param( 'app_query' ),
151 231 ),
152 232 ) );
233 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/saveapp', array(
234 + 'methods' => array('POST'),
235 + 'callback' => array($this, 'app_saveapp'),
236 + 'permission_callback' => '__return_true',
237 + 'args' => array(
238 + 'app_id' => $this->get_param( 'app_id' ),
239 + 'app_name' => $this->get_param( 'app_name' ),
240 + 'app_title' => $this->get_param( 'app_title' ),
241 + 'app_type' => $this->get_param( 'app_type' ),
242 + 'app_settings' => $this->get_param( 'app_settings' ),
243 + 'app_add_to_menu' => $this->get_param( 'app_add_to_menu' ),
244 + 'app_apps' => $this->get_param( 'app_apps' ),
245 + ),
246 + ) );
153 247 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/remove', array(
154 248 'methods' => array('POST'),
155 249 'callback' => array($this, 'app_remove'),
156 250 'permission_callback' => '__return_true',
@@ -174,9 +268,31 @@
174 268 ),
175 269 'settings' => array(
176 270 'required' => false,
177 271 'type' => 'string',
178 - 'description' => __( 'Settings - JSON string', 'wp-data-access' ),
272 + 'description' => __( 'App settings - JSON string', 'wp-data-access' ),
273 + 'sanitize_callback' => function ( $param ) {
274 + $sanitized_settings = $this->sanitize_settings( json_decode( (string) $param, true ) );
275 + // Save sanitized JSON as string
276 + return json_encode( $sanitized_settings );
277 + },
278 + 'validate_callback' => 'rest_validate_request_arg',
279 + ),
280 + 'map' => array(
281 + 'required' => false,
282 + 'type' => 'string',
283 + 'description' => __( 'Map settings - JSON string', 'wp-data-access' ),
284 + 'sanitize_callback' => function ( $param ) {
285 + $sanitized_settings = $this->sanitize_settings( json_decode( (string) $param, true ) );
286 + // Save sanitized JSON as string
287 + return json_encode( $sanitized_settings );
288 + },
289 + 'validate_callback' => 'rest_validate_request_arg',
290 + ),
291 + 'chart' => array(
292 + 'required' => false,
293 + 'type' => 'string',
294 + 'description' => __( 'Chart settings - JSON string', 'wp-data-access' ),
179 295 'sanitize_callback' => 'sanitize_text_field',
180 296 'validate_callback' => 'rest_validate_request_arg',
181 297 ),
182 298 'theme' => array(
@@ -202,27 +318,43 @@
202 318 'search' => $this->get_param( 'search' ),
203 319 'search_columns' => $this->get_param( 'search_columns' ),
204 320 'search_column_fns' => $this->get_param( 'search_column_fns' ),
205 321 'search_column_lov' => $this->get_param( 'search_column_lov' ),
206 - 'md' => array(
322 + 'search_data_types' => $this->get_param( 'search_data_types' ),
323 + 'search_custom' => $this->get_param( 'search_custom' ),
324 + 'search_params' => $this->get_param( 'search_params' ),
325 + 'shortcode_params' => $this->get_param( 'search_params' ),
326 + 'md' => $this->get_param( 'md' ),
327 + 'sorting' => $this->get_param( 'sorting' ),
328 + 'row_count' => $this->get_param( 'row_count' ),
329 + 'row_count_estimate' => $this->get_param( 'row_count_estimate' ),
330 + 'media' => $this->get_param( 'media' ),
331 + 'rel_tab' => $this->get_param( 'rel_tab' ),
332 + 'client_side' => $this->get_param( 'client_side' ),
333 + 'geo_radius' => array(
207 334 'required' => false,
208 335 'type' => 'mixed',
209 - 'description' => __( 'Master detail join conditions', 'wp-data-access' ),
336 + 'description' => __( 'Geo radius segment', 'wp-data-access' ),
210 337 'sanitize_callback' => function ( $param ) {
211 - $columns = array();
212 - foreach ( rest_sanitize_object( $param ) as $column_name => $value ) {
213 - $columns[$this->sanitize_db_identifier( $column_name )] = sanitize_text_field( wp_unslash( $value ) );
338 + $geo_radius = array();
339 + if ( isset(
340 + $param['col']['lat'],
341 + $param['col']['lng'],
342 + $param['loc']['lat'],
343 + $param['loc']['lng'],
344 + $param['radius'],
345 + $param['unit']
346 + ) && is_numeric( $param['loc']['lat'] ) && is_numeric( $param['loc']['lng'] ) && is_numeric( $param['radius'] ) && ('km' === $param['unit'] || 'miles' === $param['unit']) ) {
347 + $geo_radius['col']['lat'] = WPDA::remove_backticks( sanitize_text_field( $param['col']['lat'] ) );
348 + $geo_radius['col']['lng'] = WPDA::remove_backticks( sanitize_text_field( $param['col']['lng'] ) );
349 + $geo_radius['loc']['lat'] = (float) sanitize_text_field( $param['loc']['lat'] );
350 + $geo_radius['loc']['lng'] = (float) sanitize_text_field( $param['loc']['lng'] );
351 + $geo_radius['radius'] = (float) sanitize_text_field( $param['radius'] );
352 + $geo_radius['unit'] = sanitize_text_field( $param['unit'] );
214 353 }
215 - return $columns;
354 + return $geo_radius;
216 355 },
217 - 'validate_callback' => function ( $param ) {
218 - return is_array( $param );
219 - },
220 356 ),
221 - 'sorting' => $this->get_param( 'sorting' ),
222 - 'row_count' => $this->get_param( 'row_count' ),
223 - 'row_count_estimate' => $this->get_param( 'row_count_estimate' ),
224 - 'media' => $this->get_param( 'media' ),
225 357 ),
226 358 ) );
227 359 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/get', array(
228 360 'methods' => array('POST'),
@@ -228,12 +360,13 @@
228 360 'methods' => array('POST'),
229 361 'callback' => array($this, 'app_get'),
230 362 'permission_callback' => '__return_true',
231 363 'args' => array(
232 - 'app_id' => $this->get_param( 'app_id' ),
233 - 'cnt_id' => $this->get_param( 'cnt_id' ),
234 - 'key' => $this->get_param( 'key' ),
235 - 'media' => $this->get_param( 'media' ),
364 + 'app_id' => $this->get_param( 'app_id' ),
365 + 'cnt_id' => $this->get_param( 'cnt_id' ),
366 + 'key' => $this->get_param( 'key' ),
367 + 'media' => $this->get_param( 'media' ),
368 + 'rel_tab' => $this->get_param( 'rel_tab' ),
236 369 ),
237 370 ) );
238 371 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/insert', array(
239 372 'methods' => array('POST'),
@@ -239,11 +372,13 @@
239 372 'methods' => array('POST'),
240 373 'callback' => array($this, 'app_insert'),
241 374 'permission_callback' => '__return_true',
242 375 'args' => array(
243 - 'app_id' => $this->get_param( 'app_id' ),
244 - 'cnt_id' => $this->get_param( 'cnt_id' ),
245 - 'val' => $this->get_param( 'val' ),
376 + 'app_id' => $this->get_param( 'app_id' ),
377 + 'cnt_id' => $this->get_param( 'cnt_id' ),
378 + 'val' => $this->get_param( 'val' ),
379 + 'join_tab' => $this->get_param( 'join_tab' ),
380 + 'rel_tab' => $this->get_param( 'rel_tab' ),
246 381 ),
247 382 ) );
248 383 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/update', array(
249 384 'methods' => array('POST'),
@@ -249,8 +384,21 @@
249 384 'methods' => array('POST'),
250 385 'callback' => array($this, 'app_update'),
251 386 'permission_callback' => '__return_true',
252 387 'args' => array(
388 + 'app_id' => $this->get_param( 'app_id' ),
389 + 'cnt_id' => $this->get_param( 'cnt_id' ),
390 + 'key' => $this->get_param( 'key' ),
391 + 'val' => $this->get_param( 'val' ),
392 + 'join_tab' => $this->get_param( 'join_tab' ),
393 + 'rel_tab' => $this->get_param( 'rel_tab' ),
394 + ),
395 + ) );
396 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/update/inline', array(
397 + 'methods' => array('POST'),
398 + 'callback' => array($this, 'app_update_inline'),
399 + 'permission_callback' => '__return_true',
400 + 'args' => array(
253 401 'app_id' => $this->get_param( 'app_id' ),
254 402 'cnt_id' => $this->get_param( 'cnt_id' ),
255 403 'key' => $this->get_param( 'key' ),
256 404 'val' => $this->get_param( 'val' ),
@@ -273,12 +421,19 @@
273 421 'args' => array(
274 422 'app_id' => $this->get_param( 'app_id' ),
275 423 'cnt_id' => $this->get_param( 'cnt_id' ),
276 424 'col' => $this->get_param( 'col' ),
425 + 'cols' => $this->get_param( 'cols' ),
277 426 'search' => $this->get_param( 'search' ),
278 427 'search_columns' => $this->get_param( 'search_columns' ),
279 428 'search_column_fns' => $this->get_param( 'search_column_fns' ),
280 429 'search_column_lov' => $this->get_param( 'search_column_lov' ),
430 + 'search_data_types' => $this->get_param( 'search_data_types' ),
431 + 'search_custom' => $this->get_param( 'search_custom' ),
432 + 'search_params' => $this->get_param( 'search_params' ),
433 + 'shortcode_params' => $this->get_param( 'search_params' ),
434 + 'md' => $this->get_param( 'md' ),
435 + 'cascade' => $this->get_param( 'cascade' ),
281 436 ),
282 437 ) );
283 438 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/lookup', array(
284 439 'methods' => array('POST'),
@@ -284,21 +439,33 @@
284 439 'methods' => array('POST'),
285 440 'callback' => array($this, 'app_lookup'),
286 441 'permission_callback' => '__return_true',
287 442 'args' => array(
288 - 'app_id' => $this->get_param( 'app_id' ),
289 - 'cnt_id' => $this->get_param( 'cnt_id' ),
290 - 'target' => array(
443 + 'app_id' => $this->get_param( 'app_id' ),
444 + 'cnt_id' => $this->get_param( 'cnt_id' ),
445 + 'target' => array(
291 446 'required' => true,
292 447 'type' => 'string',
293 - 'description' => __( 'Target: table or form', 'wp-data-access' ),
448 + 'description' => __( 'Target: table or (r)form', 'wp-data-access' ),
294 449 'sanitize_callback' => 'sanitize_text_field',
295 450 'validate_callback' => 'rest_validate_request_arg',
296 451 ),
297 - 'col' => $this->get_param( 'col' ),
298 - 'colk' => $this->get_param( 'col' ),
299 - 'colv' => $this->get_param( 'col' ),
300 - 'cold' => $this->get_param( 'key' ),
452 + 'col' => $this->get_param( 'col' ),
453 + 'colk' => $this->get_param( 'col' ),
454 + 'colv' => $this->get_param( 'col' ),
455 + 'cold' => $this->get_param( 'key' ),
456 + 'cols' => $this->get_param( 'cols' ),
457 + 'search' => $this->get_param( 'search' ),
458 + 'search_columns' => $this->get_param( 'search_columns' ),
459 + 'search_column_fns' => $this->get_param( 'search_column_fns' ),
460 + 'search_column_lov' => $this->get_param( 'search_column_lov' ),
461 + 'search_data_types' => $this->get_param( 'search_data_types' ),
462 + 'search_custom' => $this->get_param( 'search_custom' ),
463 + 'search_params' => $this->get_param( 'search_params' ),
464 + 'shortcode_params' => $this->get_param( 'search_params' ),
465 + 'md' => $this->get_param( 'md' ),
466 + 'cascade' => $this->get_param( 'cascade' ),
467 + 'values' => $this->get_param( 'md' ),
301 468 ),
302 469 ) );
303 470 register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/lookup/dbs', array(
304 471 'methods' => array('POST'),
@@ -329,10 +496,249 @@
329 496 'dbs' => $this->get_param( 'dbs' ),
330 497 'tbl' => $this->get_param( 'tbl' ),
331 498 ),
332 499 ) );
500 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/qb/list', array(
501 + 'methods' => array('POST'),
502 + 'callback' => array($this, 'app_qb_list'),
503 + 'permission_callback' => '__return_true',
504 + ) );
505 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/chart/data', array(
506 + 'methods' => array('POST'),
507 + 'callback' => array($this, 'app_chart_data'),
508 + 'permission_callback' => '__return_true',
509 + 'args' => array(
510 + 'app_id' => $this->get_param( 'app_id' ),
511 + 'search_custom' => $this->get_param( 'search_custom' ),
512 + 'shortcode_params' => $this->get_param( 'search_params' ),
513 + ),
514 + ) );
515 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/dbs/rename', array(
516 + 'methods' => array('POST'),
517 + 'callback' => array($this, 'app_dbs_rename'),
518 + 'permission_callback' => '__return_true',
519 + 'args' => array(
520 + 'dbs_source' => $this->get_param( 'dbs' ),
521 + 'dbs_destination' => $this->get_param( 'dbs' ),
522 + 'appDbId' => array(
523 + 'required' => false,
524 + 'type' => 'integer',
525 + 'description' => __( 'App Id', 'wp-data-access' ),
526 + 'sanitize_callback' => 'absint',
527 + 'validate_callback' => 'rest_validate_request_arg',
528 + ),
529 + ),
530 + ) );
531 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/lang/get', array(
532 + 'methods' => array('POST'),
533 + 'callback' => array($this, 'app_lang_get'),
534 + 'permission_callback' => '__return_true',
535 + ) );
536 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/lang/set', array(
537 + 'methods' => array('POST'),
538 + 'callback' => array($this, 'app_lang_set'),
539 + 'permission_callback' => '__return_true',
540 + 'args' => array(
541 + 'localizations' => array(
542 + 'required' => true,
543 + 'type' => 'mixed',
544 + 'description' => __( 'Custom side translations (JSON as string)', 'wp-data-access' ),
545 + 'sanitize_callback' => 'sanitize_text_field',
546 + 'validate_callback' => 'rest_validate_request_arg',
547 + ),
548 + ),
549 + ) );
550 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/call', array(
551 + 'methods' => array('POST'),
552 + 'callback' => array($this, 'app_call'),
553 + 'permission_callback' => '__return_true',
554 + 'args' => array(
555 + 'app_id' => $this->get_param( 'app_id' ),
556 + 'cls' => array(
557 + 'required' => true,
558 + 'type' => 'string',
559 + 'description' => __( 'Class name', 'wp-data-access' ),
560 + 'sanitize_callback' => 'sanitize_text_field',
561 + 'validate_callback' => 'rest_validate_request_arg',
562 + ),
563 + 'fnc' => array(
564 + 'required' => true,
565 + 'type' => 'string',
566 + 'description' => __( 'Function name', 'wp-data-access' ),
567 + 'sanitize_callback' => 'sanitize_text_field',
568 + 'validate_callback' => 'rest_validate_request_arg',
569 + ),
570 + 'arg' => array(
571 + 'required' => true,
572 + 'type' => 'mixed',
573 + 'description' => __( 'Arguments', 'wp-data-access' ),
574 + 'sanitize_callback' => 'sanitize_text_field',
575 + 'validate_callback' => 'rest_validate_request_arg',
576 + ),
577 + ),
578 + ) );
579 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/proxy', array(
580 + 'methods' => array('GET'),
581 + 'callback' => array($this, 'app_proxy'),
582 + 'permission_callback' => '__return_true',
583 + 'args' => array(
584 + 'app_id' => $this->get_param( 'app_id' ),
585 + 'cnt_id' => $this->get_param( 'cnt_id' ),
586 + 'url' => array(
587 + 'required' => true,
588 + 'type' => 'string',
589 + 'description' => __( 'URL', 'wp-data-access' ),
590 + 'sanitize_callback' => 'sanitize_text_field',
591 + 'validate_callback' => 'rest_validate_request_arg',
592 + ),
593 + ),
594 + ) );
595 + // PWA
596 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/pwa/get', array(
597 + 'methods' => array('POST'),
598 + 'callback' => array($this, 'app_wpa_get'),
599 + 'permission_callback' => '__return_true',
600 + 'args' => array(
601 + 'app_id' => $this->get_param( 'app_id' ),
602 + ),
603 + ) );
604 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/pwa/activate', array(
605 + 'methods' => array('POST'),
606 + 'callback' => array($this, 'app_wpa_activate'),
607 + 'permission_callback' => '__return_true',
608 + 'args' => array(
609 + 'app_id' => $this->get_param( 'app_id' ),
610 + ),
611 + ) );
612 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/pwa/deactivate', array(
613 + 'methods' => array('POST'),
614 + 'callback' => array($this, 'app_wpa_deactivate'),
615 + 'permission_callback' => '__return_true',
616 + 'args' => array(
617 + 'app_id' => $this->get_param( 'app_id' ),
618 + ),
619 + ) );
620 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/upload', array(
621 + 'methods' => array('POST'),
622 + 'callback' => array($this, 'app_upload'),
623 + 'permission_callback' => '__return_true',
624 + 'args' => array(
625 + 'app_id' => $this->get_param( 'app_id' ),
626 + 'cnt_id' => $this->get_param( 'cnt_id' ),
627 + 'pk' => array(
628 + 'required' => true,
629 + 'type' => 'string',
630 + 'description' => __( 'Primary key in JSON format', 'wp-data-access' ),
631 + 'sanitize_callback' => 'sanitize_text_field',
632 + 'validate_callback' => 'rest_validate_request_arg',
633 + ),
634 + 'col' => $this->get_param( 'col' ),
635 + ),
636 + ) );
637 + register_rest_route( WPDA_API::WPDA_NAMESPACE, 'app/download', array(
638 + 'methods' => array('POST'),
639 + 'callback' => array($this, 'app_download'),
640 + 'permission_callback' => '__return_true',
641 + 'args' => array(
642 + 'app_id' => $this->get_param( 'app_id' ),
643 + 'cnt_id' => $this->get_param( 'cnt_id' ),
644 + 'pk' => array(
645 + 'required' => true,
646 + 'type' => 'string',
647 + 'description' => __( 'Primary key in JSON format', 'wp-data-access' ),
648 + 'sanitize_callback' => 'sanitize_text_field',
649 + 'validate_callback' => 'rest_validate_request_arg',
650 + ),
651 + 'col' => $this->get_param( 'col' ),
652 + ),
653 + ) );
333 654 }
334 655
656 + public function app_proxy( $request ) {
657 + wp_die();
658 + }
659 +
660 + private function detect_image_mime( $body ) {
661 + return null;
662 + }
663 +
664 + private function is_safe_remote_url( $url, $allowed_hosts ) {
665 + return false;
666 + }
667 +
668 + private function is_public_ip( $ip ) {
669 + return false;
670 + }
671 +
672 + public function app_download( $request ) {
673 + return $this->WPDA_Rest_Response( 'OK' );
674 + }
675 +
676 + public function app_upload( $request ) {
677 + return $this->WPDA_Rest_Response( 'OK' );
678 + }
679 +
680 + public function app_wpa_deactivate( $request ) {
681 + if ( !$this->current_user_can_access() ) {
682 + // Only admins
683 + return $this->unauthorized();
684 + }
685 + if ( !$this->current_user_token_valid( $request ) ) {
686 + return $this->invalid_nonce();
687 + }
688 + return $this->WPDA_Rest_Response( 'OK' );
689 + }
690 +
691 + public function app_wpa_activate( $request ) {
692 + if ( !$this->current_user_can_access() ) {
693 + // Only admins
694 + return $this->unauthorized();
695 + }
696 + if ( !$this->current_user_token_valid( $request ) ) {
697 + return $this->invalid_nonce();
698 + }
699 + return $this->WPDA_Rest_Response( 'OK' );
700 + }
701 +
702 + public function app_wpa_get( $request ) {
703 + if ( !$this->current_user_can_access() ) {
704 + // Only admins
705 + return $this->unauthorized();
706 + }
707 + if ( !$this->current_user_token_valid( $request ) ) {
708 + return $this->invalid_nonce();
709 + }
710 + return $this->WPDA_Rest_Response( 'NOT FOUND' );
711 + }
712 +
713 + public function app_call( $request ) {
714 + return $this->bad_request();
715 + }
716 +
717 + public function app_lang_get( $request ) {
718 + if ( !$this->current_user_can_access() ) {
719 + // Only admins
720 + return $this->unauthorized();
721 + }
722 + if ( !$this->current_user_token_valid( $request ) ) {
723 + return $this->invalid_nonce();
724 + }
725 + return $this->WPDA_Rest_Response( '', WPDA_App_Localization::get() );
726 + }
727 +
728 + public function app_lang_set( $request ) {
729 + if ( !$this->current_user_can_access() ) {
730 + // Only admins
731 + return $this->unauthorized();
732 + }
733 + if ( !$this->current_user_token_valid( $request ) ) {
734 + return $this->invalid_nonce();
735 + }
736 + $localizations = $request->get_param( 'localizations' );
737 + WPDA_App_Localization::set( $localizations );
738 + return $this->WPDA_Rest_Response( 'Translation successfully saved' );
739 + }
740 +
335 741 private function get_app_columns( $columns ) {
336 742 if ( !is_array( $columns ) ) {
337 743 return false;
338 744 }
@@ -382,35 +788,122 @@
382 788 }
383 789 return $this->get_app_columns( $settings['columns'] );
384 790 }
385 791
386 - public function app_details( $request ) {
387 - if ( !$this->current_user_can_access() ) {
792 + public function app_export( $request ) {
793 + $app_id = $request->get_param( 'app_id' );
794 + if ( !$this->main_app_access( $app_id, $msg ) ) {
795 + if ( 'rest_cookie_invalid_nonce' === $msg ) {
796 + return $this->invalid_nonce();
797 + }
388 798 return $this->unauthorized();
389 799 }
390 800 if ( !$this->current_user_token_valid( $request ) ) {
391 801 return $this->invalid_nonce();
392 802 }
393 - $app_id = $request->get_param( 'app_id' );
394 - return $this->WPDA_Rest_Response( '', WPDA_App_Container_Model::select( $app_id, 1 ) );
803 + return $this->do_app_export( $app_id );
395 804 }
396 805
397 - public function app_detail_meta( $request ) {
398 - if ( !$this->current_user_can_access() ) {
806 + public function app_copy( $request ) {
807 + $app_id = $request->get_param( 'app_id' );
808 + if ( !$this->main_app_access( $app_id, $msg ) ) {
809 + if ( 'rest_cookie_invalid_nonce' === $msg ) {
810 + return $this->invalid_nonce();
811 + }
399 812 return $this->unauthorized();
400 813 }
401 814 if ( !$this->current_user_token_valid( $request ) ) {
402 815 return $this->invalid_nonce();
403 816 }
817 + return $this->do_app_copy( $app_id );
818 + }
819 +
820 + public function app_details( $request ) {
404 821 $app_id = $request->get_param( 'app_id' );
405 822 $cnt_id = $request->get_param( 'cnt_id' );
406 - $container = WPDA_App_Container_Model::get_container( $cnt_id );
407 - if ( !isset( $container[0] ) ) {
408 - return $this->bad_request();
823 + if ( $this->check_app_access(
824 + $app_id,
825 + $cnt_id,
826 + 'select',
827 + $dbs,
828 + $tbl,
829 + $msg,
830 + $settings
831 + ) ) {
832 + return $this->WPDA_Rest_Response( '', WPDA_App_Container_Model::select( $app_id, 1 ) );
833 + } else {
834 + if ( 'rest_cookie_invalid_nonce' === $msg ) {
835 + return $this->invalid_nonce();
836 + } else {
837 + return new \WP_Error('error', $msg, array(
838 + 'status' => 401,
839 + ));
840 + }
409 841 }
410 - return $this->get_app_container_meta( $app_id, $container );
411 842 }
412 843
844 + public function app_detail_meta( $request ) {
845 + $app_id = $request->get_param( 'app_id' );
846 + $cnt_id = $request->get_param( 'cnt_id' );
847 + $rel_tab = $request->get_param( 'rel_tab' );
848 + if ( $this->check_app_access(
849 + $app_id,
850 + $cnt_id,
851 + 'select',
852 + $dbs,
853 + $tbl,
854 + $msg,
855 + $settings
856 + ) ) {
857 + $container = WPDA_App_Container_Model::get_container( $app_id, $cnt_id );
858 + if ( !isset( $container[0] ) ) {
859 + return $this->bad_request();
860 + }
861 + return $this->get_app_container_meta( $app_id, $container, $rel_tab );
862 + } else {
863 + if ( 'rest_cookie_invalid_nonce' === $msg ) {
864 + return $this->invalid_nonce();
865 + } else {
866 + return new \WP_Error('error', $msg, array(
867 + 'status' => 401,
868 + ));
869 + }
870 + }
871 + }
872 +
873 + public function app_detail_reorder( $request ) {
874 + $app_id = $request->get_param( 'app_id' );
875 + $cnt_id_from = $request->get_param( 'cnt_id_from' );
876 + $cnt_id_to = $request->get_param( 'cnt_id_to' );
877 + if ( $this->check_app_access(
878 + $app_id,
879 + $cnt_id_from,
880 + 'select',
881 + $dbs,
882 + $tbl,
883 + $msg,
884 + $settings
885 + ) ) {
886 + $container = WPDA_App_Container_Model::get_container( $app_id, $cnt_id_from );
887 + if ( !isset( $container[0] ) ) {
888 + return $this->bad_request();
889 + }
890 + $container = WPDA_App_Container_Model::get_container( $app_id, $cnt_id_to );
891 + if ( !isset( $container[0] ) ) {
892 + return $this->bad_request();
893 + }
894 + return $this->reorder_details( $app_id, $cnt_id_from, $cnt_id_to );
895 + } else {
896 + if ( 'rest_cookie_invalid_nonce' === $msg ) {
897 + return $this->invalid_nonce();
898 + } else {
899 + return new \WP_Error('error', $msg, array(
900 + 'status' => 401,
901 + ));
902 + }
903 + }
904 + }
905 +
413 906 public function app_relationship_create( $request ) {
414 907 if ( !$this->current_user_can_access() ) {
415 908 return $this->unauthorized();
416 909 }
@@ -455,10 +948,8 @@
455 948 $app_dbs,
456 949 $app_tbl,
457 950 json_encode( $app_cls ),
458 951 $app_title,
459 - 1,
460 - null,
461 952 $app_relation
462 953 ) );
463 954 }
464 955
@@ -472,8 +963,29 @@
472 963 $cnt_id = $request->get_param( 'cnt_id' );
473 964 return $this->WPDA_Rest_Response( '', WPDA_App_Container_Model::delete_container( $cnt_id ) );
474 965 }
475 966
967 + private function build_lookups(
968 + $table_settings,
969 + $dbs,
970 + &$search_columns,
971 + $search_column_lov,
972 + $search_column_fns,
973 + &$default_where,
974 + &$lookups
975 + ) {
976 + return $this->bad_request();
977 + }
978 +
979 + private function build_relationships(
980 + $container,
981 + &$m2m_relationship,
982 + $tbl,
983 + &$default_where
984 + ) {
985 + return $this->bad_request();
986 + }
987 +
476 988 public function app_select( $request ) {
477 989 $app_id = $request->get_param( 'app_id' );
478 990 $cnt_id = $request->get_param( 'cnt_id' );
479 991 $col = $request->get_param( 'col' );
@@ -482,16 +994,30 @@
482 994 $search = $request->get_param( 'search' );
483 995 $search_columns = $request->get_param( 'search_columns' );
484 996 $search_column_fns = $request->get_param( 'search_column_fns' );
485 997 $search_column_lov = $request->get_param( 'search_column_lov' );
998 + $search_data_types = $request->get_param( 'search_data_types' );
999 + $search_custom = $request->get_param( 'search_custom' );
1000 + $search_params = $request->get_param( 'search_params' );
1001 + $shortcode_params = $request->get_param( 'shortcode_params' );
486 1002 $md = $request->get_param( 'md' );
487 1003 $sorting = $request->get_param( 'sorting' );
488 1004 $row_count = $request->get_param( 'row_count' );
489 1005 $row_count_estimate = $request->get_param( 'row_count_estimate' );
490 1006 $media = $request->get_param( 'media' );
1007 + $rel_tab = $request->get_param( 'rel_tab' );
1008 + $client_side = '1' === $request->get_param( 'client_side' );
1009 + $geo_radius = $request->get_param( 'geo_radius' );
1010 + $docs = array();
491 1011 $default_where = '';
492 1012 $default_orderby = '';
493 1013 $lookups = array();
1014 + $m2m_relationship = array();
1015 + if ( $client_side ) {
1016 + // Delete search values on refresh
1017 + $search = '';
1018 + $search_columns = array();
1019 + }
494 1020 if ( $this->check_app_access(
495 1021 $app_id,
496 1022 $cnt_id,
497 1023 'select',
@@ -499,23 +1025,57 @@
499 1025 $tbl,
500 1026 $msg,
501 1027 $settings
502 1028 ) ) {
503 - $table_settings = $settings['table'] ?? array();
504 - // Get default where clause
505 - if ( isset( $table_settings['table']['defaultWhere'] ) ) {
506 - $default_where = $table_settings['table']['defaultWhere'];
1029 + $container = WPDA_App_Container_Model::get_container( $app_id, $cnt_id );
1030 + $app = WPDA_App_Model::get_by_id( $app_id );
1031 + if ( isset( $app[0]['app_type'], $container[0]['cnt_map'] ) && '2' == $app[0]['app_type'] && null !== $container[0]['cnt_map'] ) {
1032 + // App = Map
1033 + // Get default where map
1034 + $map_json = json_decode( (string) $container[0]['cnt_map'], true );
1035 + if ( isset( $map_json['setup']['defaultWhere'] ) && null !== $map_json['setup']['defaultWhere'] && '' !== trim( $map_json['setup']['defaultWhere'] ) ) {
1036 + $default_where = $map_json['setup']['defaultWhere'];
1037 + }
1038 + } else {
1039 + // All other apps (not being a map)
1040 + if ( '1' === $rel_tab ) {
1041 + } else {
1042 + $table_settings = $settings['table'] ?? array();
1043 + // Get default where clause
1044 + if ( isset( $table_settings['table']['defaultWhere'] ) ) {
1045 + $default_where = $table_settings['table']['defaultWhere'];
1046 + }
1047 + // Get default order by
1048 + if ( isset( $table_settings['table']['defaultOrderBy'] ) ) {
1049 + $default_orderby_db = $table_settings['table']['defaultOrderBy'];
1050 + if ( is_array( $default_orderby_db ) ) {
1051 + foreach ( $default_orderby_db as $orderby ) {
1052 + if ( isset( $orderby['columnName'], $orderby['order'] ) && '' !== trim( $orderby['columnName'] ) ) {
1053 + $default_orderby .= (( '' === $default_orderby ? 'order by ' : ',' )) . '`' . WPDA::remove_backticks( $orderby['columnName'] ) . '` ' . (( 'desc' === $orderby['order'] ? 'desc' : 'asc' ));
1054 + }
1055 + }
1056 + }
1057 + }
1058 + }
507 1059 }
508 - // Get default order by
509 - if ( isset( $table_settings['table']['defaultOrderBy'] ) ) {
510 - $default_orderby_db = $table_settings['table']['defaultOrderBy'];
511 - if ( is_array( $default_orderby_db ) ) {
512 - foreach ( $default_orderby_db as $orderby ) {
513 - if ( isset( $orderby['columnName'], $orderby['order'] ) && '' !== trim( $orderby['columnName'] ) ) {
514 - $default_orderby .= (( '' === $default_orderby ? 'order by ' : ',' )) . '`' . WPDA::remove_backticks( $orderby['columnName'] ) . '` ' . (( 'desc' === $orderby['order'] ? 'desc' : 'asc' ));
1060 + if ( isset( $settings['columns'] ) && is_array( $settings['columns'] ) && '1' !== $rel_tab ) {
1061 + $queryable_columns = array();
1062 + if ( isset( $settings['table']['columns'] ) && is_array( $settings['table']['columns'] ) ) {
1063 + foreach ( $settings['table']['columns'] as $column ) {
1064 + if ( isset( $column['queryable'] ) && $column['queryable'] ) {
1065 + $queryable_columns[] = $column['columnName'];
515 1066 }
516 1067 }
517 1068 }
1069 + $app_columns = array();
1070 + foreach ( $settings['columns'] as $column ) {
1071 + if ( isset( $column['columnName'], $column['isSelected'] ) && $column['isSelected'] ) {
1072 + $app_columns[$column['columnName']] = in_array( $column['columnName'], $queryable_columns );
1073 + }
1074 + }
1075 + if ( 0 < count( $app_columns ) ) {
1076 + $col = $app_columns;
1077 + }
518 1078 }
519 1079 $table_api = new WPDA_Table();
520 1080 return $table_api->select(
521 1081 $dbs,
@@ -529,12 +1089,22 @@
529 1089 $sorting,
530 1090 $row_count,
531 1091 $row_count_estimate,
532 1092 $media,
533 - $default_where,
1093 + $this->process_params(
1094 + $default_where,
1095 + $search_custom,
1096 + $search_params,
1097 + $shortcode_params
1098 + ),
534 1099 $default_orderby,
535 1100 $lookups,
536 - $md
1101 + $md,
1102 + $m2m_relationship,
1103 + $search_data_types,
1104 + $client_side,
1105 + $geo_radius,
1106 + $docs
537 1107 );
538 1108 } else {
539 1109 if ( 'rest_cookie_invalid_nonce' === $msg ) {
540 1110 return $this->invalid_nonce();
@@ -545,17 +1115,32 @@
545 1115 }
546 1116 }
547 1117 }
548 1118
1119 + private function get_m2m_relationship( $relationship, $tbl, $cols ) {
1120 + return array();
1121 + }
1122 +
549 1123 private function get_lookup_lov( $column_lookup, $search_value, $search_type ) {
550 1124 return null;
551 1125 }
552 1126
1127 + private function convert_relation_columns( $columns ) {
1128 + return array_map( function ( $value ) {
1129 + if ( true === $value['isSelected'] ) {
1130 + return $value['columnName'];
1131 + }
1132 + return null;
1133 + }, $columns );
1134 + }
1135 +
553 1136 public function app_get( $request ) {
554 1137 $app_id = $request->get_param( 'app_id' );
555 1138 $cnt_id = $request->get_param( 'cnt_id' );
556 1139 $key = $request->get_param( 'key' );
557 1140 $media = $request->get_param( 'media' );
1141 + $rel_tab = $request->get_param( 'rel_tab' );
1142 + $docs = array();
558 1143 if ( $this->check_app_access(
559 1144 $app_id,
560 1145 $cnt_id,
561 1146 'select',
@@ -575,9 +1160,10 @@
575 1160 $tbl,
576 1161 $key,
577 1162 $media,
578 1163 $column_names,
579 - $default_where
1164 + $default_where,
1165 + $docs
580 1166 );
581 1167 } else {
582 1168 if ( 'rest_cookie_invalid_nonce' === $msg ) {
583 1169 return $this->invalid_nonce();
@@ -592,8 +1178,10 @@
592 1178 public function app_insert( $request ) {
593 1179 $app_id = $request->get_param( 'app_id' );
594 1180 $cnt_id = $request->get_param( 'cnt_id' );
595 1181 $val = $request->get_param( 'val' );
1182 + $join_tab = $request->get_param( 'join_tab' );
1183 + $rel_tab = $request->get_param( 'rel_tab' );
596 1184 if ( $this->check_app_access(
597 1185 $app_id,
598 1186 $cnt_id,
599 1187 'insert',
@@ -618,8 +1206,10 @@
618 1206 $app_id = $request->get_param( 'app_id' );
619 1207 $cnt_id = $request->get_param( 'cnt_id' );
620 1208 $key = $request->get_param( 'key' );
621 1209 $val = $request->get_param( 'val' );
1210 + $join_tab = $request->get_param( 'join_tab' );
1211 + $rel_tab = $request->get_param( 'rel_tab' );
622 1212 if ( $this->check_app_access(
623 1213 $app_id,
624 1214 $cnt_id,
625 1215 'update',
@@ -624,16 +1214,33 @@
624 1214 $cnt_id,
625 1215 'update',
626 1216 $dbs,
627 1217 $tbl,
628 - $msg
1218 + $msg,
1219 + $settings
629 1220 ) ) {
1221 + $column_names = $this->get_app_form_columns( $settings );
1222 + if ( false === $column_names ) {
1223 + $column_names = array();
1224 + }
1225 + $code_columns = array();
1226 + $html_columns = array();
1227 + if ( isset( $settings['form']['columns'] ) ) {
1228 + foreach ( $settings['form']['columns'] as $column ) {
1229 + if ( isset( $column['allowHtml'] ) && false === $column['allowHtml'] ) {
1230 + $html_columns[] = $column['columnName'];
1231 + }
1232 + }
1233 + }
630 1234 $table_api = new WPDA_Table();
631 1235 return $table_api->update(
632 1236 $dbs,
633 1237 $tbl,
634 1238 $key,
635 - $val
1239 + $val,
1240 + $column_names,
1241 + $code_columns,
1242 + $html_columns
636 1243 );
637 1244 } else {
638 1245 if ( 'rest_cookie_invalid_nonce' === $msg ) {
639 1246 return $this->invalid_nonce();
@@ -644,8 +1251,12 @@
644 1251 }
645 1252 }
646 1253 }
647 1254
1255 + public function app_update_inline( $request ) {
1256 + return $this->bad_request();
1257 + }
1258 +
648 1259 public function app_delete( $request ) {
649 1260 $app_id = $request->get_param( 'app_id' );
650 1261 $cnt_id = $request->get_param( 'cnt_id' );
651 1262 $key = $request->get_param( 'key' );
@@ -681,8 +1292,24 @@
681 1292 $col = $request->get_param( 'col' );
682 1293 $colk = $request->get_param( 'colk' );
683 1294 $colv = $request->get_param( 'colv' );
684 1295 $cold = $request->get_param( 'cold' );
1296 + $cols = $request->get_param( 'cols' );
1297 + $search = $request->get_param( 'search' );
1298 + $search_columns = $request->get_param( 'search_columns' );
1299 + $search_column_fns = $request->get_param( 'search_column_fns' );
1300 + $search_column_lov = $request->get_param( 'search_column_lov' );
1301 + $search_data_types = $request->get_param( 'search_data_types' );
1302 + $search_custom = $request->get_param( 'search_custom' );
1303 + $search_params = $request->get_param( 'search_params' );
1304 + $shortcode_params = $request->get_param( 'shortcode_params' );
1305 + $md = $request->get_param( 'md' );
1306 + $cascade = $request->get_param( 'cascade' );
1307 + $values = $request->get_param( 'values' );
1308 + $default_where = '';
1309 + $default_where_lookup = '';
1310 + $lookups = array();
1311 + $m2m_relationship = array();
685 1312 if ( $this->check_app_access(
686 1313 $app_id,
687 1314 $cnt_id,
688 1315 'select',
@@ -687,15 +1314,15 @@
687 1314 $cnt_id,
688 1315 'select',
689 1316 $dbs,
690 1317 $tbl,
691 - $msg
1318 + $msg,
1319 + $settings
692 1320 ) ) {
693 - $container = WPDA_App_Container_Model::get_container( $cnt_id );
1321 + $container = WPDA_App_Container_Model::get_container( $app_id, $cnt_id );
694 1322 if ( !isset( $container[0] ) ) {
695 1323 return $this->bad_request();
696 1324 }
697 - $default_where = '';
698 1325 $lookup = array();
699 1326 $lookup_dbs = "";
700 1327 $lookup_tbl = "";
701 1328 if ( 'form' === $target ) {
@@ -703,11 +1330,18 @@
703 1330 if ( isset( $container[0]['cnt_form'] ) ) {
704 1331 $lookup = json_decode( (string) $container[0]['cnt_form'], true );
705 1332 }
706 1333 } else {
707 - // Handle table lookup
708 - if ( isset( $container[0]['cnt_table'] ) ) {
709 - $lookup = json_decode( (string) $container[0]['cnt_table'], true );
1334 + if ( 'rform' === $target ) {
1335 + // Handle form lookup
1336 + if ( isset( $container[0]['cnt_rform'] ) ) {
1337 + $lookup = json_decode( (string) $container[0]['cnt_rform'], true );
1338 + }
1339 + } else {
1340 + // Handle table lookup
1341 + if ( isset( $container[0]['cnt_table'] ) ) {
1342 + $lookup = json_decode( (string) $container[0]['cnt_table'], true );
1343 + }
710 1344 }
711 1345 }
712 1346 if ( isset( $lookup['columns'] ) && is_array( $lookup['columns'] ) ) {
713 1347 foreach ( $lookup['columns'] as $column ) {
@@ -717,9 +1351,9 @@
717 1351 }
718 1352 $lookup_dbs = $column['lookup']['dbs'];
719 1353 $lookup_tbl = $column['lookup']['tbl'];
720 1354 if ( isset( $column['columnName'], $column['lookup']['defaultWhere'] ) ) {
721 - $default_where = $column['lookup']['defaultWhere'];
1355 + $default_where_lookup = $column['lookup']['defaultWhere'];
722 1356 }
723 1357 }
724 1358 }
725 1359 }
@@ -732,9 +1366,33 @@
732 1366 $lookup_tbl,
733 1367 $colk,
734 1368 $colv,
735 1369 $cold,
736 - $default_where
1370 + $this->process_params(
1371 + $default_where_lookup,
1372 + $search_custom,
1373 + $search_params,
1374 + $shortcode_params,
1375 + $values
1376 + ),
1377 + '1' === $cascade,
1378 + $tbl,
1379 + $col,
1380 + $this->process_params(
1381 + $default_where,
1382 + $search_custom,
1383 + $search_params,
1384 + $shortcode_params,
1385 + $values
1386 + ),
1387 + $search,
1388 + $cols,
1389 + $search_columns,
1390 + $search_column_fns,
1391 + $lookups,
1392 + $md,
1393 + $m2m_relationship,
1394 + $search_data_types
737 1395 );
738 1396 } else {
739 1397 if ( 'rest_cookie_invalid_nonce' === $msg ) {
740 1398 return $this->invalid_nonce();
@@ -746,8 +1404,12 @@
746 1404 }
747 1405 }
748 1406
749 1407 public function app_lookup_dbs( $request ) {
1408 + // Only admins are allowed to configre lookups
1409 + if ( !$this->current_user_can_access() ) {
1410 + return $this->unauthorized();
1411 + }
750 1412 $app_id = $request->get_param( 'app_id' );
751 1413 $cnt_id = $request->get_param( 'cnt_id' );
752 1414 if ( $this->check_app_access(
753 1415 $app_id,
@@ -770,8 +1432,12 @@
770 1432 }
771 1433 }
772 1434
773 1435 public function app_lookup_tbl( $request ) {
1436 + // Only admins are allowed to configre lookups
1437 + if ( !$this->current_user_can_access() ) {
1438 + return $this->unauthorized();
1439 + }
774 1440 $app_id = $request->get_param( 'app_id' );
775 1441 $cnt_id = $request->get_param( 'cnt_id' );
776 1442 $dbs = $request->get_param( 'dbs' );
777 1443 if ( $this->check_app_access(
@@ -795,8 +1461,12 @@
795 1461 }
796 1462 }
797 1463
798 1464 public function app_lookup_cls( $request ) {
1465 + // Only admins are allowed to configre lookups
1466 + if ( !$this->current_user_can_access() ) {
1467 + return $this->unauthorized();
1468 + }
799 1469 $app_id = $request->get_param( 'app_id' );
800 1470 $cnt_id = $request->get_param( 'cnt_id' );
801 1471 $dbs = $request->get_param( 'dbs' );
802 1472 $tbl = $request->get_param( 'tbl' );
@@ -820,8 +1490,227 @@
820 1490 }
821 1491 }
822 1492 }
823 1493
1494 + public function app_qb_list( $request ) {
1495 + $qb = new WPDA_QB();
1496 + return $qb->open( $request );
1497 + }
1498 +
1499 + public function app_dbs_rename( $request ) {
1500 + if ( !$this->current_user_can_access() ) {
1501 + // Only admins
1502 + return $this->unauthorized();
1503 + }
1504 + if ( !$this->current_user_token_valid( $request ) ) {
1505 + return $this->invalid_nonce();
1506 + }
1507 + $dbs_source = $request->get_param( 'dbs_source' );
1508 + $dbs_destination = $request->get_param( 'dbs_destination' );
1509 + if ( '' === trim( $dbs_source ) || '' === trim( $dbs_destination ) ) {
1510 + return new \WP_Error('error', 'Invalid arguments', array(
1511 + 'status' => 401,
1512 + ));
1513 + }
1514 + global $wpdb;
1515 + $renamed = 0;
1516 + $debug_mode = 'on' === WPDA::get_option( WPDA::OPTION_PLUGIN_DEBUG );
1517 + $debug = array();
1518 + $errors = array();
1519 + if ( $request->get_param( 'appDbId' ) ) {
1520 + // Update app only
1521 + $appDbId = $request->get_param( 'appDbId' );
1522 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- plugin table
1523 + $sql = $wpdb->prepare( "update `{$wpdb->prefix}wpda_app_container` set `cnt_dbs` = %s where `cnt_dbs` = %s and app_id = %d", array($dbs_destination, $dbs_source, $appDbId) );
1524 + $result = $wpdb->query( $sql );
1525 + // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
1526 + $renamed += $result;
1527 + if ( $debug_mode ) {
1528 + $debug[] = array(
1529 + 'sql' => $sql,
1530 + 'result' => $result,
1531 + );
1532 + }
1533 + if ( '' !== $wpdb->last_error ) {
1534 + $errors[] = array(
1535 + 'sql' => $sql,
1536 + 'error' => $wpdb->last_error,
1537 + );
1538 + }
1539 + $sql_content = array("update `{$wpdb->prefix}wpda_app_container` set `cnt_table` = replace(`cnt_table`, '\"dbs\":\"%1s\"', '\"dbs\":\"%1s\"') where `cnt_table` like '%\"dbs\":\"%1s\"%' and app_id = %d", "update `{$wpdb->prefix}wpda_app_container` set `cnt_form` = replace(`cnt_form`, '\"dbs\":\"%1s\"', '\"dbs\":\"%1s\"') where `cnt_form` like '%\"dbs\":\"%1s\"%' and app_id = %d");
1540 + foreach ( $sql_content as $sql ) {
1541 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- plugin table
1542 + $result = $wpdb->query( $wpdb->prepare( $sql, array(
1543 + $dbs_source,
1544 + $dbs_destination,
1545 + $dbs_source,
1546 + $appDbId
1547 + ) ) );
1548 + $renamed += $result;
1549 + if ( $debug_mode ) {
1550 + $debug[] = array(
1551 + 'sql' => $sql,
1552 + 'result' => $result,
1553 + );
1554 + }
1555 + if ( '' !== $wpdb->last_error ) {
1556 + $errors[] = array(
1557 + 'sql' => $sql,
1558 + 'error' => $wpdb->last_error,
1559 + );
1560 + }
1561 + }
1562 + $context = array();
1563 + if ( $debug_mode ) {
1564 + $context['debug'] = $debug;
1565 + }
1566 + if ( 0 < count( $errors ) ) {
1567 + $context['errors'] = $errors;
1568 + return new \WP_Error('error', 'Failed renaming database', array(
1569 + 'status' => 401,
1570 + 'context' => $context,
1571 + ));
1572 + }
1573 + return $this->WPDA_Rest_Response( sprintf(
1574 + /* translators: %s = number of database substitutions */
1575 + __( 'Successfully renamed %s database occurrences', 'wp-data-access' ),
1576 + $renamed
1577 + ), null, $context );
1578 + }
1579 + // Rename all occurrences in repository tables and apps
1580 + $sqls = array(
1581 + "update `{$wpdb->prefix}wpda_publisher` set `pub_schema_name` = %s where `pub_schema_name` = %s",
1582 + "update `{$wpdb->prefix}wpda_project_page` set `page_schema_name` = %s where `page_schema_name` = %s",
1583 + "update `{$wpdb->prefix}wpda_project_table` set `wpda_schema_name` = %s where `wpda_schema_name` = %s",
1584 + "update `{$wpdb->prefix}wpda_media` set `media_schema_name` = %s where `media_schema_name` = %s",
1585 + "update `{$wpdb->prefix}wpda_menus` set `menu_schema_name` = %s where `menu_schema_name` = %s",
1586 + "update `{$wpdb->prefix}wpda_table_design` set `wpda_schema_name` = %s where `wpda_schema_name` = %s",
1587 + "update `{$wpdb->prefix}wpda_table_settings` set `wpda_schema_name` = %s where `wpda_schema_name` = %s",
1588 + "update `{$wpdb->prefix}wpda_app_container` set `cnt_dbs` = %s where `cnt_dbs` = %s"
1589 + );
1590 + foreach ( $sqls as $sql ) {
1591 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- plugin table
1592 + $result = $wpdb->query( $wpdb->prepare( $sql, array($dbs_destination, $dbs_source) ) );
1593 + // phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
1594 + $renamed += $result;
1595 + if ( $debug_mode ) {
1596 + $debug[] = array(
1597 + 'sql' => $sql,
1598 + 'result' => $result,
1599 + );
1600 + }
1601 + if ( '' !== $wpdb->last_error ) {
1602 + $errors[] = array(
1603 + 'sql' => $sql,
1604 + 'error' => $wpdb->last_error,
1605 + );
1606 + }
1607 + }
1608 + $sql_content = array("update `{$wpdb->prefix}wpda_app_container` set `cnt_table` = replace(`cnt_table`, '\"dbs\":\"%1s\"', '\"dbs\":\"%1s\"') where `cnt_table` like '%\"dbs\":\"%1s\"%'", "update `{$wpdb->prefix}wpda_app_container` set `cnt_form` = replace(`cnt_form`, '\"dbs\":\"%1s\"', '\"dbs\":\"%1s\"') where `cnt_form` like '%\"dbs\":\"%1s\"%'");
1609 + foreach ( $sql_content as $sql ) {
1610 + // phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared -- plugin table
1611 + $result = $wpdb->query( $wpdb->prepare( $sql, array($dbs_source, $dbs_destination, $dbs_source) ) );
1612 + $renamed += $result;
1613 + if ( $debug_mode ) {
1614 + $debug[] = array(
1615 + 'sql' => $sql,
1616 + 'result' => $result,
1617 + );
1618 + }
1619 + if ( '' !== $wpdb->last_error ) {
1620 + $errors[] = array(
1621 + 'sql' => $sql,
1622 + 'error' => $wpdb->last_error,
1623 + );
1624 + }
1625 + }
1626 + $context = array();
1627 + if ( $debug_mode ) {
1628 + $context['debug'] = $debug;
1629 + }
1630 + if ( 0 < count( $errors ) ) {
1631 + $context['errors'] = $errors;
1632 + return new \WP_Error('error', 'Failed renaming database', array(
1633 + 'status' => 401,
1634 + 'context' => $context,
1635 + ));
1636 + }
1637 + return $this->WPDA_Rest_Response( sprintf(
1638 + /* translators: %s = number of database substitutions */
1639 + __( 'Successfully renamed %s database occurrences', 'wp-data-access' ),
1640 + $renamed
1641 + ), null, $context );
1642 + }
1643 +
1644 + public function app_chart_data( $request ) {
1645 + $app_id = $request->get_param( 'app_id' );
1646 + $search_custom = $request->get_param( 'search_custom' );
1647 + $shortcode_params = $request->get_param( 'shortcode_params' );
1648 + if ( !$this->main_app_access( $app_id, $msg ) ) {
1649 + if ( 'rest_cookie_invalid_nonce' === $msg ) {
1650 + return $this->invalid_nonce();
1651 + }
1652 + return $this->unauthorized();
1653 + }
1654 + if ( !$this->current_user_token_valid( $request ) ) {
1655 + return $this->invalid_nonce();
1656 + }
1657 + $app_container = WPDA_App_Container_Model::select( $app_id, 0 );
1658 + if ( 1 === count( $app_container ) && null !== $app_container[0]['cnt_query'] && '' !== trim( (string) $app_container[0]['cnt_query'] ) ) {
1659 + $dbs = $app_container[0]['cnt_dbs'];
1660 + $query = $app_container[0]['cnt_query'];
1661 + // Process shortcode and url parameters
1662 + $query = $this->process_params(
1663 + $query,
1664 + $search_custom,
1665 + null,
1666 + $shortcode_params
1667 + );
1668 + $wpdadb = WPDADB::get_db_connection( $dbs );
1669 + if ( null === $wpdadb ) {
1670 + // Error connecting.
1671 + return new \WP_Error('error', "Error connecting to database {$dbs}", array(
1672 + 'status' => 420,
1673 + ));
1674 + }
1675 + $suppress = $wpdadb->suppress_errors( true );
1676 + $chart_data = $wpdadb->get_results( $query, 'ARRAY_A' );
1677 + // Add an * before each label to support numeric labels
1678 + $chart_data_converted = array();
1679 + foreach ( $chart_data as $data ) {
1680 + $row = array();
1681 + foreach ( $data as $key => $value ) {
1682 + $row['*' . $key] = $value;
1683 + }
1684 + $chart_data_converted[] = $row;
1685 + }
1686 + $wpdadb->get_results( "create temporary table `wpda_chart_data_types` as {$query}", 'ARRAY_A' );
1687 + $explain = $wpdadb->get_results( "desc `wpda_chart_data_types`", 'ARRAY_A' );
1688 + $wpdadb->get_results( "drop temporary table `wpda_chart_data_types`", 'ARRAY_A' );
1689 + $wpdadb->suppress_errors( $suppress );
1690 + return array(
1691 + 'data' => $chart_data_converted,
1692 + 'explain' => $explain,
1693 + );
1694 + } else {
1695 + return new \WP_Error('error', $msg, array(
1696 + 'status' => 401,
1697 + ));
1698 + }
1699 + }
1700 +
1701 + public function app_lang( $request ) {
1702 + if ( !$this->current_user_can_access() ) {
1703 + return $this->unauthorized();
1704 + }
1705 + if ( !$this->current_user_token_valid( $request ) ) {
1706 + return $this->invalid_nonce();
1707 + }
1708 + $lang = $request->get_param( 'lang' );
1709 + update_option( self::WPDA_APP_DEFAULT_LANG, $lang );
1710 + return $this->WPDA_Rest_Response( __( 'Successfully saved changes', 'wp-data-access' ) );
1711 + }
1712 +
824 1713 public function app_meta( $request ) {
825 1714 $app_id = $request->get_param( 'app_id' );
826 1715 if ( !$this->main_app_access( $app_id, $msg ) ) {
827 1716 if ( 'rest_cookie_invalid_nonce' === $msg ) {
@@ -845,8 +1734,10 @@
845 1734 $app_id = $request->get_param( 'app_id' );
846 1735 $cnt_id = $request->get_param( 'cnt_id' );
847 1736 $target = $request->get_param( 'target' );
848 1737 $settings = $request->get_param( 'settings' );
1738 + $chart = $request->get_param( 'chart' );
1739 + $map = $request->get_param( 'map' );
849 1740 $theme = $request->get_param( 'theme' );
850 1741 return $this->do_app_settings(
851 1742 $app_id,
852 1743 $cnt_id,
@@ -851,8 +1742,10 @@
851 1742 $app_id,
852 1743 $cnt_id,
853 1744 $target,
854 1745 $settings,
1746 + $chart,
1747 + $map,
855 1748 $theme
856 1749 );
857 1750 }
858 1751
@@ -906,8 +1799,9 @@
906 1799 $app_dbs = $request->get_param( 'app_dbs' );
907 1800 $app_tbl = $request->get_param( 'app_tbl' );
908 1801 $app_cls = $request->get_param( 'app_cls' );
909 1802 $app_table = $request->get_param( 'app_table' );
1803 + $app_query = $request->get_param( 'app_query' );
910 1804 return $this->do_app_create(
911 1805 $app_name,
912 1806 $app_title,
913 1807 $app_type,
@@ -914,12 +1808,34 @@
914 1808 $app_settings,
915 1809 $app_dbs,
916 1810 $app_tbl,
917 1811 $app_cls,
918 - $app_table
1812 + $app_table,
1813 + $app_query
919 1814 );
920 1815 }
921 1816
1817 + public function app_createapp( $request ) {
1818 + if ( !$this->current_user_can_access() ) {
1819 + return $this->unauthorized();
1820 + }
1821 + if ( !$this->current_user_token_valid( $request ) ) {
1822 + return $this->invalid_nonce();
1823 + }
1824 + $app_name = $request->get_param( 'app_name' );
1825 + $app_title = $request->get_param( 'app_title' );
1826 + $app_type = $request->get_param( 'app_type' );
1827 + $app_settings = $request->get_param( 'app_settings' );
1828 + $app_apps = $request->get_param( 'app_apps' );
1829 + return $this->do_app_createapp(
1830 + $app_name,
1831 + $app_title,
1832 + $app_type,
1833 + $app_settings,
1834 + $app_apps
1835 + );
1836 + }
1837 +
922 1838 public function app_remove( $request ) {
923 1839 if ( !$this->current_user_can_access() ) {
924 1840 return $this->unauthorized();
925 1841 }
@@ -947,8 +1863,9 @@
947 1863 // App container
948 1864 $app_dbs = $request->get_param( 'app_dbs' );
949 1865 $app_tbl = $request->get_param( 'app_tbl' );
950 1866 $app_cls = $request->get_param( 'app_cls' );
1867 + $app_query = $request->get_param( 'app_query' );
951 1868 return $this->do_app_save(
952 1869 $app_id,
953 1870 $app_name,
954 1871 $app_title,
@@ -956,20 +1873,48 @@
956 1873 $app_settings,
957 1874 $app_add_to_menu,
958 1875 $app_dbs,
959 1876 $app_tbl,
960 - $app_cls
1877 + $app_cls,
1878 + $app_query
961 1879 );
962 1880 }
963 1881
1882 + public function app_saveapp( $request ) {
1883 + if ( !$this->current_user_can_access() ) {
1884 + return $this->unauthorized();
1885 + }
1886 + if ( !$this->current_user_token_valid( $request ) ) {
1887 + return $this->invalid_nonce();
1888 + }
1889 + $app_id = $request->get_param( 'app_id' );
1890 + $app_name = $request->get_param( 'app_name' );
1891 + $app_title = $request->get_param( 'app_title' );
1892 + $app_type = $request->get_param( 'app_type' );
1893 + $app_settings = $request->get_param( 'app_settings' );
1894 + $app_add_to_menu = $request->get_param( 'app_add_to_menu' );
1895 + $app_apps = $request->get_param( 'app_apps' );
1896 + return $this->do_app_saveapp(
1897 + $app_id,
1898 + $app_name,
1899 + $app_title,
1900 + $app_type,
1901 + $app_settings,
1902 + $app_add_to_menu,
1903 + $app_apps
1904 + );
1905 + }
1906 +
964 1907 private function do_app_settings(
965 1908 $app_id,
966 1909 $cnt_id,
967 1910 $target,
968 1911 $settings,
1912 + $chart,
1913 + $map,
969 1914 $theme
970 1915 ) {
971 - if ( 1 > $app_id || 1 > $cnt_id || 'table' !== $target && 'form' !== $target && 'theme' !== $target ) {
1916 + if ( 1 > $app_id || 1 > $cnt_id || 'table' !== $target && 'form' !== $target && 'rform' !== $target && 'theme' !== $target && 'chart' !== $target && 'map' !== $target && 'dashboard' !== $target ) {
972 1917 return $this->bad_request();
973 1918 }
974 1919 if ( null === $settings || '' === $settings ) {
975 1920 // Perform reset
@@ -989,8 +1934,24 @@
989 1934 'status' => 403,
990 1935 ));
991 1936 }
992 1937 break;
1938 + case 'chart':
1939 + $error_msg = WPDA_App_Container_Model::update_chart_settings( $cnt_id, null );
1940 + if ( '' !== $error_msg ) {
1941 + return new \WP_Error('error', $error_msg, array(
1942 + 'status' => 403,
1943 + ));
1944 + }
1945 + break;
1946 + case 'map':
1947 + $error_msg = WPDA_App_Container_Model::update_map_settings( $cnt_id, null );
1948 + if ( '' !== $error_msg ) {
1949 + return new \WP_Error('error', $error_msg, array(
1950 + 'status' => 403,
1951 + ));
1952 + }
1953 + break;
993 1954 case 'theme':
994 1955 $error_msg = WPDA_App_Model::update_theme( $app_id, null );
995 1956 if ( '' !== $error_msg ) {
996 1957 return new \WP_Error('error', $error_msg, array(
@@ -997,8 +1958,16 @@
997 1958 'status' => 403,
998 1959 ));
999 1960 }
1000 1961 break;
1962 + case 'dashboard':
1963 + $error_msg = WPDA_App_Container_Model::update_dashboard_settings( $app_id, null );
1964 + if ( '' !== $error_msg ) {
1965 + return new \WP_Error('error', $error_msg, array(
1966 + 'status' => 403,
1967 + ));
1968 + }
1969 + break;
1001 1970 default:
1002 1971 return $this->bad_request();
1003 1972 }
1004 1973 return $this->WPDA_Rest_Response( __( 'Reset was successful', 'wp-data-access' ) );
@@ -1010,16 +1979,71 @@
1010 1979 return new \WP_Error('error', $error_msg, array(
1011 1980 'status' => 403,
1012 1981 ));
1013 1982 }
1014 - } else {
1015 - // Update form settings
1016 - $error_msg = WPDA_App_Container_Model::update_form_settings( $cnt_id, $settings );
1983 + // Update chart settings
1984 + $error_msg = WPDA_App_Container_Model::update_chart_settings( $cnt_id, $chart );
1017 1985 if ( '' !== $error_msg ) {
1018 1986 return new \WP_Error('error', $error_msg, array(
1019 1987 'status' => 403,
1020 1988 ));
1021 1989 }
1990 + // Update map settings
1991 + $error_msg = WPDA_App_Container_Model::update_map_settings( $cnt_id, $map );
1992 + if ( '' !== $error_msg ) {
1993 + return new \WP_Error('error', $error_msg, array(
1994 + 'status' => 403,
1995 + ));
1996 + }
1997 + } else {
1998 + if ( 'rform' === $target ) {
1999 + // Update rform settings
2000 + $error_msg = WPDA_App_Container_Model::update_rform_settings( $cnt_id, $settings );
2001 + if ( '' !== $error_msg ) {
2002 + return new \WP_Error('error', $error_msg, array(
2003 + 'status' => 403,
2004 + ));
2005 + }
2006 + } else {
2007 + if ( 'chart' === $target ) {
2008 + // Update chart settings
2009 + $error_msg = WPDA_App_Container_Model::update_chart_settings( $cnt_id, $settings );
2010 + if ( '' !== $error_msg ) {
2011 + return new \WP_Error('error', $error_msg, array(
2012 + 'status' => 403,
2013 + ));
2014 + }
2015 + } else {
2016 + if ( 'map' === $target ) {
2017 + // Update chart settings
2018 + $error_msg = WPDA_App_Container_Model::update_map_settings( $cnt_id, $settings );
2019 + if ( '' !== $error_msg ) {
2020 + return new \WP_Error('error', $error_msg, array(
2021 + 'status' => 403,
2022 + ));
2023 + }
2024 + } else {
2025 + if ( 'form' === $target ) {
2026 + // Update form settings
2027 + $error_msg = WPDA_App_Container_Model::update_form_settings( $cnt_id, $settings );
2028 + if ( '' !== $error_msg ) {
2029 + return new \WP_Error('error', $error_msg, array(
2030 + 'status' => 403,
2031 + ));
2032 + }
2033 + } else {
2034 + if ( 'dashboard' === $target ) {
2035 + $error_msg = WPDA_App_Container_Model::update_dashboard_settings( $cnt_id, $settings );
2036 + if ( '' !== $error_msg ) {
2037 + return new \WP_Error('error', $error_msg, array(
2038 + 'status' => 403,
2039 + ));
2040 + }
2041 + }
2042 + }
2043 + }
2044 + }
2045 + }
1022 2046 }
1023 2047 $error_msg = WPDA_App_Model::update_theme( $app_id, $theme );
1024 2048 if ( '' !== $error_msg ) {
1025 2049 return new \WP_Error('error', $error_msg, array(
@@ -1029,10 +2053,11 @@
1029 2053 return $this->WPDA_Rest_Response( __( 'Successfully saved settings', 'wp-data-access' ) );
1030 2054 }
1031 2055
1032 2056 private function do_app_remove( $app_id ) {
2057 + WPDA_App_Apps_Model::delete( $app_id, true );
2058 + WPDA_App_Container_Model::delete( $app_id );
1033 2059 WPDA_App_Model::delete( $app_id );
1034 - WPDA_App_Container_Model::delete( $app_id );
1035 2060 return $this->WPDA_Rest_Response( __( 'Successfully deleted app', 'wp-data-access' ) );
1036 2061 }
1037 2062
1038 2063 private function do_app_create(
@@ -1042,9 +2067,10 @@
1042 2067 $app_settings,
1043 2068 $app_dbs,
1044 2069 $app_tbl,
1045 2070 $app_cls,
1046 - $app_table
2071 + $app_table,
2072 + $app_query
1047 2073 ) {
1048 2074 // Add app
1049 2075 $insert = WPDA_App_Model::create(
1050 2076 $app_name,
@@ -1061,9 +2087,11 @@
1061 2087 $app_tbl,
1062 2088 json_encode( $app_cls ),
1063 2089 $app_title,
1064 2090 0,
1065 - $app_table
2091 + $app_table,
2092 + null,
2093 + $app_query
1066 2094 );
1067 2095 if ( false !== $container['cnt_id'] ) {
1068 2096 // App and container successfully saved
1069 2097 return $this->WPDA_Rest_Response( __( 'Successfully saved changes', 'wp-data-access' ) );
@@ -1082,21 +2110,144 @@
1082 2110 ));
1083 2111 }
1084 2112 }
1085 2113
2114 + private function do_app_createapp(
2115 + $app_name,
2116 + $app_title,
2117 + $app_type,
2118 + $app_settings,
2119 + $app_apps
2120 + ) {
2121 + // Add app
2122 + $insert = WPDA_App_Model::create(
2123 + $app_name,
2124 + $app_title,
2125 + $app_type,
2126 + $app_settings
2127 + );
2128 + if ( false !== $insert['app_id'] ) {
2129 + // Add apps
2130 + if ( is_array( $app_apps ) ) {
2131 + $app_id = $insert['app_id'];
2132 + foreach ( $app_apps as $index => $app_id_detail ) {
2133 + // Insert app
2134 + WPDA_App_Apps_Model::create( $app_id, $app_id_detail, $index );
2135 + }
2136 + }
2137 + // App and details successfully saved
2138 + return $this->WPDA_Rest_Response( __( 'Successfully saved changes', 'wp-data-access' ) );
2139 + } else {
2140 + // Insert failed
2141 + return new \WP_Error('error', $insert['msg'], array(
2142 + 'status' => 403,
2143 + ));
2144 + }
2145 + }
2146 +
1086 2147 private function get_app_init() {
1087 2148 return $this->WPDA_Rest_Response( '', array(
1088 2149 'roles' => $this->get_wp_roles(),
1089 2150 'users' => $this->get_wp_users(),
2151 + 'lang' => get_option( self::WPDA_APP_DEFAULT_LANG ),
1090 2152 ) );
1091 2153 }
1092 2154
1093 2155 private function get_app_list() {
1094 2156 $dataset = WPDA_App_Model::list();
1095 - return $this->WPDA_Rest_Response( '', $dataset );
2157 + $context = WPDA_App_Apps_Model::list();
2158 + return $this->WPDA_Rest_Response( '', $dataset, $context );
1096 2159 }
1097 2160
1098 - private function get_app_container_meta( $app_id, $container ) {
2161 + private function get_relation_columns( $container ) {
2162 + return null;
2163 + }
2164 +
2165 + private function reorder_details( $app_id, $cnt_id_from, $cnt_id_to ) {
2166 + return $this->bad_request();
2167 + }
2168 +
2169 + private function get_app_apps_meta( $app, $apps ) {
2170 + $app_id_details = array_map( function ( $e ) {
2171 + if ( isset( $e['app_id_detail'] ) ) {
2172 + return $e['app_id_detail'];
2173 + }
2174 + return null;
2175 + }, $apps );
2176 + $app_titles = array();
2177 + foreach ( $app_id_details as $app_id_detail ) {
2178 + $app_detail = WPDA_App_Model::get_by_id( $app_id_detail );
2179 + if ( isset( $app_detail[0]['app_title'] ) ) {
2180 + $app_titles[$app_id_detail] = $app_detail[0]['app_title'];
2181 + }
2182 + }
2183 + $response = array(
2184 + 'app' => array(
2185 + 'app' => $app,
2186 + 'container' => array(),
2187 + 'apps' => $app_id_details,
2188 + 'titles' => $app_titles,
2189 + ),
2190 + );
2191 + $response['settings'] = $this->get_table_settings();
2192 + return $this->WPDA_Rest_Response( '', $response );
2193 + }
2194 +
2195 + private function get_table_settings( $tbl = null, $dbs = null ) {
2196 + $settings = new stdClass();
2197 + if ( null !== $dbs && null !== $tbl ) {
2198 + $settings_db = WPDA_Table_Settings_Model::query( $tbl, $dbs );
2199 + if ( isset( $settings_db[0]['wpda_table_settings'] ) ) {
2200 + $settings = json_decode( (string) $settings_db[0]['wpda_table_settings'] );
2201 + // Remove old settings from response.
2202 + unset($settings->form_labels);
2203 + unset($settings->list_labels);
2204 + unset($settings->custom_settings);
2205 + unset($settings->search_settings);
2206 + }
2207 + }
2208 + $settings->env = $this->get_env();
2209 + global $wpdb;
2210 + $settings->wp = [
2211 + 'roles' => $this->get_wp_roles(),
2212 + 'users' => $this->get_wp_users(),
2213 + 'home' => admin_url( 'admin.php' ),
2214 + 'siteurl' => site_url(),
2215 + 'tables' => array_values( $wpdb->tables() ),
2216 + 'date_format' => get_option( 'date_format' ),
2217 + 'time_format' => get_option( 'time_format' ),
2218 + 'scroll_offset' => WPDA::get_option( WPDA::OPTION_APPS_SCROLL_OFFSET ),
2219 + 'upload' => @ini_get( 'upload_max_filesize' ),
2220 + 'uploadBytes' => $this->uploadToBytes( @ini_get( 'upload_max_filesize' ) ),
2221 + 'locale' => get_locale(),
2222 + ];
2223 + return $settings;
2224 + }
2225 +
2226 + /**
2227 + * Convert a PHP shorthand notation (e.g., "2M", "512K", "1G") to bytes.
2228 + *
2229 + * @param string $val The shorthand size string.
2230 + *
2231 + * @return int The size in bytes.
2232 + */
2233 + private function uploadToBytes( $val ) : int {
2234 + $val = trim( $val );
2235 + $lastChar = strtolower( $val[strlen( $val ) - 1] );
2236 + $num = (float) $val;
2237 + switch ( $lastChar ) {
2238 + case 'g':
2239 + $num *= 1024;
2240 + case 'm':
2241 + $num *= 1024;
2242 + case 'k':
2243 + $num *= 1024;
2244 + break;
2245 + }
2246 + return (int) round( $num );
2247 + }
2248 +
2249 + private function get_app_container_meta( $app_id, $container, $rel_tab = false ) {
1099 2250 $app = WPDA_App_Model::get_by_id( $app_id );
1100 2251 if ( false === $app ) {
1101 2252 return $this->bad_request();
1102 2253 }
@@ -1102,13 +2253,15 @@
1102 2253 }
1103 2254 if ( !isset( $container[0]['cnt_dbs'], $container[0]['cnt_tbl'], $container[0]['cnt_cls'] ) ) {
1104 2255 return $this->bad_request();
1105 2256 }
2257 + $dbs = $container[0]['cnt_dbs'];
2258 + $tbl = $container[0]['cnt_tbl'];
1106 2259 $response = array(
1107 2260 'app' => array(
1108 2261 'app' => $app,
1109 2262 'container' => array_map( function ( $value ) {
1110 - $show = current_user_can( 'manage_options' );
2263 + $show = WPDA::current_user_is_admin();
1111 2264 if ( !$show ) {
1112 2265 // Hide database and table name in responses for non admin users.
1113 2266 unset($value['cnt_dbs']);
1114 2267 unset($value['cnt_tbl']);
@@ -1114,13 +2267,11 @@
1114 2267 unset($value['cnt_tbl']);
1115 2268 }
1116 2269 return $value;
1117 2270 }, $container ),
2271 + 'apps' => array(),
1118 2272 ),
1119 2273 );
1120 - $dbs = $container[0]['cnt_dbs'];
1121 - $tbl = $container[0]['cnt_tbl'];
1122 - $cls = WPDA_List_Columns_Cache::get_list_columns( $dbs, $tbl );
1123 2274 $access = array(
1124 2275 'select' => array(),
1125 2276 'insert' => array(),
1126 2277 'update' => array(),
@@ -1125,26 +2276,24 @@
1125 2276 'insert' => array(),
1126 2277 'update' => array(),
1127 2278 'delete' => array(),
1128 2279 );
1129 - $settings = new stdClass();
1130 - $settings_db = WPDA_Table_Settings_Model::query( $tbl, $dbs );
1131 - if ( isset( $settings_db[0]['wpda_table_settings'] ) ) {
1132 - $settings = json_decode( (string) $settings_db[0]['wpda_table_settings'] );
1133 - // Remove old settings from response.
1134 - unset($settings->form_labels);
1135 - unset($settings->list_labels);
1136 - unset($settings->custom_settings);
1137 - unset($settings->search_settings);
2280 + $cls = WPDA_List_Columns_Cache::get_list_columns( $dbs, $tbl );
2281 + $columns = $cls->get_table_columns();
2282 + $columns_sorted = array();
2283 + foreach ( $columns as $column ) {
2284 + if ( isset( $column['column_name'] ) ) {
2285 + $columns_sorted[$column['column_name']] = $column;
2286 + }
1138 2287 }
1139 - $settings->env = $this->get_env();
1140 2288 $media = $this->get_media( $dbs, $tbl, $cls->get_table_columns() );
1141 - $response['columns'] = $cls->get_table_columns();
2289 + $response['columns'] = $columns;
2290 + $response['columns_sorted'] = $columns_sorted;
1142 2291 $response['table_labels'] = $cls->get_table_header_labels();
1143 2292 $response['form_labels'] = $cls->get_table_column_headers();
1144 2293 $response['primary_key'] = $cls->get_table_primary_key();
1145 2294 $response['access'] = $access;
1146 - $response['settings'] = $settings;
2295 + $response['settings'] = $this->get_table_settings( $tbl, $dbs );
1147 2296 $response['media'] = $media['media'];
1148 2297 $response['wp_media'] = $media['wp_media'];
1149 2298 $table_settings = json_decode( (string) $container[0]['cnt_table'], true );
1150 2299 if ( isset( $table_settings['table']['defaultWhere'] ) ) {
@@ -1155,16 +2304,280 @@
1155 2304 $response['table_info'] = $this->get_table_info( $dbs, $tbl, $default_where );
1156 2305 return $this->WPDA_Rest_Response( '', $response );
1157 2306 }
1158 2307
1159 - private function get_app_meta( $app_id ) {
1160 - $container = WPDA_App_Container_Model::select( $app_id, 0 );
1161 - if ( !isset( $container[0] ) ) {
2308 + public function get_app_meta( $app_id ) {
2309 + $app = WPDA_App_Model::get_by_id( $app_id );
2310 + if ( !isset( $app[0]['app_type'] ) ) {
1162 2311 return $this->bad_request();
1163 2312 }
1164 - return $this->get_app_container_meta( $app_id, $container );
2313 + if ( '5' === $app[0]['app_type'] || 5 === $app[0]['app_type'] ) {
2314 + // App container
2315 + $apps = WPDA_App_Apps_Model::select_all( $app_id, 0 );
2316 + return $this->get_app_apps_meta( $app, $apps );
2317 + } else {
2318 + // Other container
2319 + $container = WPDA_App_Container_Model::select( $app_id, 0 );
2320 + if ( !isset( $container[0] ) ) {
2321 + return $this->bad_request();
2322 + }
2323 + return $this->get_app_container_meta( $app_id, $container );
2324 + }
1165 2325 }
1166 2326
2327 + private function escapeUnicodeForExport( $str ) {
2328 + if ( empty( $str ) ) {
2329 + return $str;
2330 + }
2331 + return preg_replace_callback( '/\\\\(u[0-9a-fA-F]{4})/', function ( $matches ) {
2332 + return '\\\\' . $matches[1];
2333 + }, $str );
2334 + }
2335 +
2336 + private function do_app_export_app( $app_id, $main_app_id ) {
2337 + global $wpdb;
2338 + $quotes = function ( $value ) {
2339 + return str_replace( array(
2340 + "'",
2341 + '\\"',
2342 + "\\\\t",
2343 + "\\t",
2344 + "\\\\n",
2345 + "\\n",
2346 + "\\r\\n",
2347 + "\\r",
2348 + "\\d"
2349 + ), array(
2350 + "''",
2351 + '\\\\"',
2352 + "\\\\\\t",
2353 + "\\\\t",
2354 + "\\\\\\n",
2355 + "\\\\n",
2356 + "\\\\r\\\\n",
2357 + "\\\\r",
2358 + "\\\\\\\\\\d"
2359 + ), $value );
2360 + };
2361 + $app = WPDA_App_Model::get_by_id( $app_id );
2362 + $app_settings = ( null === $app[0]['app_settings'] ? 'null' : "{$quotes( $app[0]['app_settings'] )}" );
2363 + $app_theme = ( null === $app[0]['app_theme'] ? 'null' : "{$quotes( $app[0]['app_theme'] )}" );
2364 + // phpcs:ignore PluginCheck.CodeAnalysis.Heredoc.NotAllowed
2365 + $app_sql = <<<SQL
2366 +# Import app
2367 +insert into `{wp_prefix}wpda_app`
2368 +\t(`app_name`
2369 +\t,`app_title`
2370 +\t,`app_type`
2371 +\t,`app_settings`
2372 +\t,`app_theme`
2373 +\t,`app_add_to_menu`
2374 +\t)
2375 +values
2376 +\t('{$quotes( $app[0]['app_name'] )}'
2377 +\t,'{$quotes( $app[0]['app_title'] )}'
2378 +\t,{$app[0]['app_type']}
2379 +\t,'{$app_settings}'
2380 +\t,'{$app_theme}'
2381 +\t,{$app[0]['app_add_to_menu']}
2382 +\t);
2383 +
2384 +SET @APP_ID = LAST_INSERT_ID();
2385 +insert into `wpda_transfer_apps_{$main_app_id}`
2386 +values
2387 + ({$app[0]['app_id']}
2388 + ,(select LAST_INSERT_ID(`app_id`) from `{wp_prefix}wpda_app` order by 1 desc limit 1)
2389 + );
2390 +
2391 +
2392 +SQL;
2393 + $containers = WPDA_App_Container_Model::select_all( $app_id );
2394 + $containers_sql = '';
2395 + foreach ( $containers as $container ) {
2396 + $cnt_table = ( null === $container['cnt_table'] ? 'null' : "'{$quotes( $container['cnt_table'] )}'" );
2397 + $cnt_form = ( null === $container['cnt_form'] ? 'null' : "'{$quotes( $container['cnt_form'] )}'" );
2398 + $cnt_relation = ( null === $container['cnt_relation'] ? 'null' : "'{$quotes( $container['cnt_relation'] )}'" );
2399 + $cnt_rform = ( null === $container['cnt_rform'] ? 'null' : "'{$quotes( $container['cnt_rform'] )}'" );
2400 + $cnt_chart = ( null === $container['cnt_chart'] ? 'null' : "'{$quotes( $container['cnt_chart'] )}'" );
2401 + $cnt_map = ( null === $container['cnt_map'] ? 'null' : "'{$quotes( $container['cnt_map'] )}'" );
2402 + $cnt_query = ( null === $container['cnt_query'] ? 'null' : "'{$quotes( $container['cnt_query'] )}'" );
2403 + // Replace default WordPress database with conversion string
2404 + $cnt_dbs = ( $wpdb->dbname === $container['cnt_dbs'] ? '{wp_schema}' : "{$quotes( $container['cnt_dbs'] )}" );
2405 + $cnt_table = str_replace( "\"dbs\":\"{$wpdb->dbname}\"", "\"dbs\":\"{wp_schema}\"", $cnt_table );
2406 + $cnt_form = str_replace( "\"dbs\":\"{$wpdb->dbname}\"", "\"dbs\":\"{wp_schema}\"", $cnt_form );
2407 + // Replace Unicode characters
2408 + $cnt_table = $this->escapeUnicodeForExport( $cnt_table );
2409 + $cnt_form = $this->escapeUnicodeForExport( $cnt_form );
2410 + // phpcs:ignore PluginCheck.CodeAnalysis.Heredoc.NotAllowed
2411 + $containers_sql .= <<<SQL
2412 +# Import app container
2413 +insert into `{wp_prefix}wpda_app_container`
2414 +\t(`cnt_dbs`
2415 +\t,`cnt_tbl`
2416 +\t,`cnt_cls`
2417 +\t,`cnt_title`
2418 +\t,`app_id`
2419 +\t,`cnt_seq_nr`
2420 +\t,`cnt_table`
2421 +\t,`cnt_form`
2422 +\t,`cnt_relation`
2423 + ,`cnt_rform`
2424 + ,`cnt_chart`
2425 + ,`cnt_map`
2426 + ,`cnt_query`
2427 +\t)
2428 +values
2429 +\t('{$cnt_dbs}'
2430 +\t,'{$quotes( $container['cnt_tbl'] )}'
2431 +\t,'{$quotes( $container['cnt_cls'] )}'
2432 +\t,'{$quotes( $container['cnt_title'] )}'
2433 +\t,@APP_ID
2434 +\t,{$container['cnt_seq_nr']}
2435 +\t,{$cnt_table}
2436 +\t,{$cnt_form}
2437 +\t,{$cnt_relation}
2438 +\t,{$cnt_rform}
2439 +\t,{$cnt_chart}
2440 +\t,{$cnt_map}
2441 +\t,{$cnt_query}
2442 +\t);
2443 +
2444 +insert into `wpda_transfer_containers_{$main_app_id}`
2445 +values
2446 + ({$container['cnt_id']}
2447 + ,(select LAST_INSERT_ID(`cnt_id`) from `{wp_prefix}wpda_app_container` order by 1 desc limit 1)
2448 + );
2449 +
2450 +
2451 +SQL;
2452 + }
2453 + // Post update: update master container ids
2454 + // phpcs:ignore PluginCheck.CodeAnalysis.Heredoc.NotAllowed
2455 + $containers_sql .= <<<SQL
2456 +# Update app master container IDs
2457 +update `{wp_prefix}wpda_app_container` as a
2458 +set a.`cnt_relation` =
2459 + (
2460 + select replace(
2461 + a.`cnt_relation`,
2462 + concat('"cnt_id_master":"', b.cnt_id_old, '"'),
2463 + concat('"cnt_id_master":"', b.cnt_id_new, '"')
2464 + )
2465 + from `wpda_transfer_containers_{$main_app_id}` as b
2466 + where a.`cnt_relation` like concat('%"cnt_id_master":"', b.cnt_id_old, '"%')
2467 + )
2468 +where a.`app_id` = @APP_ID
2469 + and a.`cnt_relation` is not null;
2470 +
2471 +
2472 +SQL;
2473 + $apps = WPDA_App_Apps_Model::select_all( $app_id );
2474 + $apps_sql = '';
2475 + foreach ( $apps as $app ) {
2476 + $apps_sql .= $this->do_app_export_app( $app['app_id_detail'], $main_app_id );
2477 + }
2478 + foreach ( $apps as $app ) {
2479 + // phpcs:ignore PluginCheck.CodeAnalysis.Heredoc.NotAllowed
2480 + $apps_sql .= <<<SQL
2481 +# Import app relationships
2482 +insert into `{wp_prefix}wpda_app_apps`
2483 +\t(`app_id`
2484 +\t,`app_id_detail`
2485 +\t,`seq_nr`\t\t\t\t\t
2486 +\t)
2487 +values
2488 +\t((select `app_id_new` from `wpda_transfer_apps_{$main_app_id}` where `app_id_old` = {$app['app_id']})
2489 +\t,(select `app_id_new` from `wpda_transfer_apps_{$main_app_id}` where `app_id_old` = {$app['app_id_detail']})
2490 +\t,{$app['seq_nr']}\t\t\t\t\t
2491 +\t);
2492 +
2493 +
2494 +SQL;
2495 + }
2496 + return $app_sql . $containers_sql . $apps_sql;
2497 + }
2498 +
2499 + private function do_app_export( $app_id ) {
2500 + global $wpdb;
2501 + $sql = '';
2502 + // phpcs:ignore PluginCheck.CodeAnalysis.Heredoc.NotAllowed
2503 + $begin_sql = <<<SQL
2504 +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
2505 +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
2506 +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
2507 +/*!40101 SET NAMES {$wpdb->charset} */;
2508 +
2509 +# Create temporary table
2510 +CREATE TABLE `wpda_transfer_containers_{$app_id}`
2511 +(cnt_id_old bigint(20) unsigned
2512 +,cnt_id_new bigint(20) unsigned
2513 +);
2514 +
2515 +CREATE TABLE `wpda_transfer_apps_{$app_id}`
2516 +(app_id_old bigint(20) unsigned
2517 +,app_id_new bigint(20) unsigned
2518 +);
2519 +
2520 +SET @APP_ID = NULL;
2521 +
2522 +
2523 +SQL;
2524 + $sql .= $this->do_app_export_app( $app_id, $app_id );
2525 + // phpcs:ignore PluginCheck.CodeAnalysis.Heredoc.NotAllowed
2526 + $end_sql = <<<SQL
2527 +# Drop temporary table
2528 +DROP TABLE `wpda_transfer_containers_{$app_id}`;
2529 +DROP TABLE `wpda_transfer_apps_{$app_id}`;
2530 +
2531 +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
2532 +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
2533 +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
2534 +
2535 +
2536 +SQL;
2537 + $data = array(
2538 + 'data' => $begin_sql . $sql . $end_sql,
2539 + );
2540 + return $this->WPDA_Rest_Response( __( 'App successfully exported', 'wp-data-access' ), $data );
2541 + }
2542 +
2543 + private function do_app_copy( $app_id ) {
2544 + $copy = WPDA_App_Model::copy( $app_id );
2545 + if ( false === $copy['app_id'] ) {
2546 + return new \WP_Error('error', $copy['msg'], array(
2547 + 'status' => 403,
2548 + ));
2549 + } else {
2550 + return $this->WPDA_Rest_Response( __( 'App successfully copied', 'wp-data-access' ) );
2551 + }
2552 + }
2553 +
2554 + private function do_app_saveapp(
2555 + $app_id,
2556 + $app_name,
2557 + $app_title,
2558 + $app_type,
2559 + $app_settings,
2560 + $app_add_to_menu,
2561 + $app_apps
2562 + ) {
2563 + $error_msg = WPDA_App_Model::update(
2564 + $app_id,
2565 + $app_name,
2566 + $app_title,
2567 + $app_type,
2568 + $app_settings,
2569 + $app_add_to_menu
2570 + );
2571 + if ( '' !== $error_msg ) {
2572 + return new \WP_Error('error', $error_msg, array(
2573 + 'status' => 403,
2574 + ));
2575 + }
2576 + WPDA_App_Apps_Model::update( $app_id, $app_apps );
2577 + return $this->WPDA_Rest_Response( __( 'Changes successfully saved', 'wp-data-access' ) );
2578 + }
2579 +
1167 2580 private function do_app_save(
1168 2581 $app_id,
1169 2582 $app_name,
1170 2583 $app_title,
@@ -1172,9 +2585,10 @@
1172 2585 $app_settings,
1173 2586 $app_add_to_menu,
1174 2587 $app_dbs,
1175 2588 $app_tbl,
1176 - $app_cls
2589 + $app_cls,
2590 + $app_query
1177 2591 ) {
1178 2592 $error_msg = WPDA_App_Model::update(
1179 2593 $app_id,
1180 2594 $app_name,
@@ -1192,9 +2606,9 @@
1192 2606 $app_id,
1193 2607 $app_dbs,
1194 2608 $app_tbl,
1195 2609 json_encode( $app_cls ),
1196 - 0
2610 + $app_query
1197 2611 );
1198 2612 if ( '' !== $error_msg ) {
1199 2613 return new \WP_Error('error', $error_msg, array(
1200 2614 'status' => 403,
@@ -1202,9 +2616,9 @@
1202 2616 }
1203 2617 return $this->WPDA_Rest_Response( __( 'Changes successfully saved', 'wp-data-access' ) );
1204 2618 }
1205 2619
1206 - private function main_app_access( $app_id, &$msg = '' ) {
2620 + private function main_app_access( $app_id, &$msg = '', &$app = null ) {
1207 2621 // Get app info
1208 2622 $app = WPDA_App_Model::get_by_id( $app_id );
1209 2623 if ( false === $app ) {
1210 2624 // App not found
@@ -1247,9 +2661,9 @@
1247 2661 if ( !$this->main_app_access( $app_id, $msg ) ) {
1248 2662 return false;
1249 2663 }
1250 2664 // Get container
1251 - $container = WPDA_App_Container_Model::get_container( $cnt_id );
2665 + $container = WPDA_App_Container_Model::get_container( $app_id, $cnt_id );
1252 2666 if ( !is_array( $container ) || 0 === count( $container ) ) {
1253 2667 // Container not found
1254 2668 $msg = __( 'Bad request', 'wp-data-access' );
1255 2669 return false;
@@ -1256,12 +2670,14 @@
1256 2670 }
1257 2671 if ( 'select' !== $action ) {
1258 2672 $cnt_table = json_decode( (string) $container[0]['cnt_table'], true );
1259 2673 if ( !isset( $cnt_table['table']['transactions'][$action] ) || false === $cnt_table['table']['transactions'][$action] ) {
1260 - $cnt_relation = json_decode( (string) $container[0]['cnt_relation'], true );
1261 - if ( !(isset( $cnt_relation['cnt_id_master'] ) && $this->check_master_container_access( $cnt_relation['cnt_id_master'], $action )) ) {
1262 - $msg = __( 'Unauthorized', 'wp-data-access' );
1263 - return false;
2674 + if ( !isset( $cnt_table['table']['bulkActions'][$action] ) || false === $cnt_table['table']['bulkActions'][$action] ) {
2675 + $cnt_relation = json_decode( (string) $container[0]['cnt_relation'], true );
2676 + if ( !(isset( $cnt_relation['cnt_id_master'] ) && $this->check_master_container_access( $app_id, $cnt_relation['cnt_id_master'], $action )) ) {
2677 + $msg = __( 'Unauthorized', 'wp-data-access' );
2678 + return false;
2679 + }
1264 2680 }
1265 2681 }
1266 2682 }
1267 2683 // Return database name, table name and columns
@@ -1274,10 +2690,10 @@
1274 2690 );
1275 2691 return true;
1276 2692 }
1277 2693
1278 - private function check_master_container_access( $cnt_id, $action ) {
1279 - $container = WPDA_App_Container_Model::get_container( $cnt_id );
2694 + private function check_master_container_access( $app_id, $cnt_id, $action ) {
2695 + $container = WPDA_App_Container_Model::get_container( $app_id, $cnt_id );
1280 2696 if ( !is_array( $container ) || 0 === count( $container ) ) {
1281 2697 // Container not found
1282 2698 return false;
1283 2699 }
@@ -1283,12 +2699,122 @@
1283 2699 }
1284 2700 $cnt_table = json_decode( (string) $container[0]['cnt_table'], true );
1285 2701 if ( !isset( $cnt_table['table']['transactions'][$action] ) || false === $cnt_table['table']['transactions'][$action] ) {
1286 2702 $cnt_relation = json_decode( (string) $container[0]['cnt_relation'], true );
1287 - if ( !(isset( $cnt_relation['cnt_id_master'] ) && $this->check_master_container_access( $cnt_relation['cnt_id_master'], $action )) ) {
2703 + if ( !(isset( $cnt_relation['cnt_id_master'] ) && $this->check_master_container_access( $app_id, $cnt_relation['cnt_id_master'], $action )) ) {
1288 2704 return false;
1289 2705 }
1290 2706 }
1291 2707 return true;
2708 + }
2709 +
2710 + private function process_params(
2711 + $where,
2712 + $search_custom,
2713 + $search_params,
2714 + $shortcode_params,
2715 + $dynamic_params = array()
2716 + ) {
2717 + // Process $search_custom > URL parameters
2718 + global $wpdb;
2719 + $replacements = array();
2720 + $nonce = bin2hex( random_bytes( 8 ) );
2721 + foreach ( self::METHODS as $method ) {
2722 + $offset = 0;
2723 + $search = $method . '[';
2724 + // Get filter
2725 + while ( ($pos_start = stripos( $where, $search, $offset )) !== false ) {
2726 + if ( ($pos_end = stripos( $where, ']', $pos_start )) !== false ) {
2727 + $filter = substr( $where, $pos_start, $pos_end - $pos_start + 1 );
2728 + // Get name
2729 + $arg_name = substr( $where, $pos_start + strlen( $search ), $pos_end - $pos_start - strlen( $search ) );
2730 + // Remove quotes from name
2731 + if ( substr( $arg_name, 0, 1 ) === "'" && substr( $arg_name, -1 ) === "'" ) {
2732 + $arg_name = substr( $arg_name, 1, -1 );
2733 + }
2734 + // Remove quotes from name
2735 + if ( substr( $arg_name, 0, 1 ) === '"' && substr( $arg_name, -1 ) === '"' ) {
2736 + $arg_name = substr( $arg_name, 1, -1 );
2737 + }
2738 + $arg_value = null;
2739 + // Handle GET args
2740 + if ( $method === self::METHODS[0] && isset( $search_custom['get'][$arg_name] ) ) {
2741 + $arg_value = sanitize_text_field( wp_unslash( $search_custom['get'][$arg_name] ) );
2742 + } elseif ( $method === self::METHODS[1] && isset( $search_custom['post'][$arg_name] ) ) {
2743 + $arg_value = sanitize_text_field( wp_unslash( $search_custom['post'][$arg_name] ) );
2744 + } elseif ( $method === self::METHODS[2] ) {
2745 + if ( isset( $search_custom['get'][$arg_name] ) ) {
2746 + $arg_value = sanitize_text_field( wp_unslash( $search_custom['get'][$arg_name] ) );
2747 + } elseif ( isset( $search_custom['post'][$arg_name] ) ) {
2748 + $arg_value = sanitize_text_field( wp_unslash( $search_custom['post'][$arg_name] ) );
2749 + }
2750 + }
2751 + // Handle POST args
2752 + $placeholder = '###URL_PLACEHOLDER_' . $nonce . '_' . md5( $filter ) . '###';
2753 + $where = str_replace( $filter, $placeholder, $where );
2754 + // Handle REQUEST args
2755 + if ( $arg_value !== null ) {
2756 + $replacements[$placeholder] = $wpdb->prepare( '%s', $arg_value );
2757 + } else {
2758 + $replacements[$placeholder] = 'null';
2759 + }
2760 + }
2761 + $offset = $pos_start + 1;
2762 + if ( $offset > strlen( $where ) ) {
2763 + $offset = strlen( $where ) - 1;
2764 + }
2765 + }
2766 + }
2767 + // Process $search_params > shortcode parameters
2768 + if ( is_array( $search_params ) && 1 === count( $search_params ) ) {
2769 + $filter_field_name = $this->sanitize_db_identifier( array_keys( $search_params )[0] );
2770 + $filter_field_value = sanitize_text_field( $search_params[$filter_field_name] );
2771 + $filter_field_name_array = array_map( 'trim', explode( ',', $filter_field_name ) );
2772 + $filter_field_value_array = array_map( 'trim', explode( ',', $filter_field_value ) );
2773 + if ( count( $filter_field_name_array ) === count( $filter_field_value_array ) ) {
2774 + // Add filter to where clause.
2775 + for ($i = 0; $i < count( $filter_field_name_array ); $i++) {
2776 + $where .= ( '' === $where ? '' : ' and ' );
2777 + $placeholder = '###SHORTCODE_PARAM_' . $nonce . '_' . md5( $filter_field_name_array[$i] ) . '###';
2778 + $where .= ' `' . $filter_field_name_array[$i] . '` like ' . $placeholder;
2779 + $replacements[$placeholder] = $wpdb->prepare( '%s', $filter_field_value_array[$i] );
2780 + }
2781 + }
2782 + }
2783 + // Substitute all shortcode parameters
2784 + if ( is_array( $shortcode_params ) ) {
2785 + foreach ( $shortcode_params as $column_name => $column_value ) {
2786 + $occurences = substr_count( strtolower( $where ), strtolower( "shortcodeParam['{$column_name}']" ) );
2787 + if ( 0 < $occurences ) {
2788 + $placeholder = '###SHORTCODE_PARAM_' . $nonce . '_' . md5( $column_name ) . '###';
2789 + $where = str_ireplace( "shortcodeParam['{$column_name}']", $placeholder, $where );
2790 + $replacements[$placeholder] = $wpdb->prepare( '%s', sanitize_text_field( $column_value ) );
2791 + }
2792 + }
2793 + }
2794 + // Substitute all unused shortcode parameter calls with null
2795 + $offset = 0;
2796 + $search = "shortcodeParam['";
2797 + while ( ($pos_start = stripos( $where, $search, $offset )) !== false ) {
2798 + if ( ($pos_end = stripos( $where, "']", $pos_start )) !== false ) {
2799 + $shortcode_value = substr( $where, $pos_start, $pos_end - $pos_start + 2 );
2800 + $where = str_ireplace( $shortcode_value, 'null', $where );
2801 + }
2802 + $offset = $pos_start + 4;
2803 + if ( $offset > strlen( $where ) ) {
2804 + $offset = strlen( $where ) - 1;
2805 + }
2806 + }
2807 + // Substitute all dynamic parameters
2808 + if ( is_array( $dynamic_params ) && 0 < count( $dynamic_params ) ) {
2809 + foreach ( $dynamic_params as $column_name => $column_value ) {
2810 + if ( stripos( $where, "{:{$column_name}}" ) !== false ) {
2811 + $placeholder = '###DYNAMIC_PARAM_' . $nonce . '_' . md5( $column_name ) . '###';
2812 + $where = str_ireplace( "{:{$column_name}}", $placeholder, $where );
2813 + $replacements[$placeholder] = $wpdb->prepare( '%s', $column_value );
2814 + }
2815 + }
2816 + }
2817 + return strtr( $where, $replacements );
1292 2818 }
1293 2819
1294 2820 }