PluginProbe ʕ •ᴥ•ʔ
Superb Addons: Blocks, Patterns, Pre-built Pages, Sliders, Popups, Free Forms, Animations & More / 3.4.2
Superb Addons: Blocks, Patterns, Pre-built Pages, Sliders, Popups, Free Forms, Animations & More v3.4.2
4.0.6 4.0.5 4.0.4 4.0.3 4.0.2 4.0.1 4.0.0 trunk 1.0.0 2.0.0 2.0.1 2.0.2 2.0.3 3.0 3.0.1 3.0.2 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.2 3.1.3 3.2.0 3.2.1 3.2.2 3.2.4 3.2.5 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.4.0 3.4.1 3.4.2 3.4.5 3.4.6 3.5.0 3.5.1 3.5.2 3.5.3 3.5.4 3.5.6 3.5.7 3.5.8 3.5.9 3.6.0 3.6.1 3.6.2 3.7.0 3.7.1
superb-blocks / src / library / controllers / class-request-controller.php
superb-blocks / src / library / controllers Last commit date
class-library-controller.php 1 year ago class-request-controller.php 1 year ago
class-request-controller.php
288 lines
1 <?php
2
3 namespace SuperbAddons\Library\Controllers;
4
5 defined('ABSPATH') || exit();
6
7 use Exception;
8 use WP_Error;
9 use WP_REST_Server;
10 use SuperbAddons\Config\Capabilities;
11 use SuperbAddons\Data\Controllers\CacheController;
12 use SuperbAddons\Data\Controllers\DomainShiftController;
13 use SuperbAddons\Data\Controllers\KeyController;
14 use SuperbAddons\Data\Controllers\OptionController;
15 use SuperbAddons\Data\Controllers\RestController;
16 use SuperbAddons\Data\Utils\CacheException;
17 use SuperbAddons\Data\Utils\CacheTypes;
18 use SuperbAddons\Data\Utils\ElementorCache;
19 use SuperbAddons\Data\Utils\GutenbergCache;
20 use SuperbAddons\Data\Utils\RequestException;
21 use SuperbAddons\Elementor\Controllers\ElementorController;
22 use SuperbAddons\Gutenberg\Controllers\GutenbergController;
23
24
25 class LibraryRequestController
26 {
27 const ELEMENTOR_LIST_ROUTE = '/elementor-list';
28 const ELEMENTOR_INSERT_ROUTE = '/elementor-insert';
29 const GUTENBERG_LIST_ROUTE = '/gutenberg-list/';
30 const GUTENBERG_INSERT_ROUTE = '/gutenberg-insert/';
31
32 const GUTENBERG_ROUTE_TYPE_PATTERNS = 'patterns';
33 const GUTENBERG_ROUTE_TYPE_PAGES = 'pages';
34
35 const ELEMENTOR_ENDPOINT_BASE = 'elementor-library/';
36 const GUTENBERG_ENDPOINT_BASE = 'gutenberg-library/';
37
38 const PLUGIN_NAMES = array(
39 'woocommerce/woocommerce.php' => 'WooCommerce',
40 );
41
42 public function __construct()
43 {
44 RestController::AddRoute(self::ELEMENTOR_LIST_ROUTE, array(
45 'methods' => WP_REST_Server::READABLE,
46 'permission_callback' => array($this, 'LibraryCallbackPermissionCheck'),
47 'callback' => array($this, 'ElementorListCallback'),
48 ));
49 RestController::AddRoute(self::ELEMENTOR_INSERT_ROUTE, array(
50 'methods' => WP_REST_Server::READABLE,
51 'permission_callback' => array($this, 'LibraryCallbackPermissionCheck'),
52 'callback' => array($this, 'ElementorInsertCallback'),
53 ));
54 RestController::AddRoute(self::GUTENBERG_LIST_ROUTE . '(?P<route_type>[\w]+)', array(
55 'methods' => WP_REST_Server::READABLE,
56 'permission_callback' => array($this, 'LibraryCallbackPermissionCheck'),
57 'callback' => array($this, 'GutenbergListCallback'),
58 ));
59 RestController::AddRoute(self::GUTENBERG_INSERT_ROUTE . '(?P<route_type>[\w]+)', array(
60 'methods' => WP_REST_Server::READABLE,
61 'permission_callback' => array($this, 'LibraryCallbackPermissionCheck'),
62 'callback' => array($this, 'GutenbergInsertCallback'),
63 ));
64 }
65
66 public function LibraryCallbackPermissionCheck()
67 {
68 // Restrict endpoint to only users who have the proper capability.
69 if (!current_user_can(Capabilities::CONTRIBUTOR)) {
70 return new WP_Error('rest_forbidden', esc_html__('Unauthorized. Please check user permissions.', "superb-blocks"), array('status' => 401));
71 }
72
73 return true;
74 }
75
76 public function ElementorListCallback()
77 {
78 try {
79 $section_cache = CacheController::GetCache(ElementorCache::SECTIONS, CacheTypes::ELEMENTOR);
80 if (!!$section_cache) {
81 // Local cache accepted
82 $section_cache->premium = KeyController::HasValidPremiumKey();
83 return rest_ensure_response($section_cache);
84 }
85
86 return $this->ListHandler(self::ELEMENTOR_ENDPOINT_BASE, 'sections', ElementorCache::SECTIONS);
87 } catch (CacheException $cex) {
88 return new \WP_Error('internal_error_cache', 'Internal Cache Error: ' . esc_html($cex->getMessage()), array('status' => 500));
89 } catch (Exception $ex) {
90 LogController::HandleException($ex);
91 return new \WP_Error('internal_error_plugin', 'Internal Plugin Error', array('status' => 500));
92 }
93 }
94
95 public function GutenbergListCallback($request)
96 {
97 try {
98 if (!isset($request['route_type'])) {
99 return new \WP_Error('invalid_route_type', 'Invalid route type', array('status' => 400));
100 }
101 $route_type = $request['route_type'];
102 $gutenberg_cache_option = self::GetGutenbergCacheOptionByRouteType($route_type);
103 if (!$gutenberg_cache_option) {
104 return new \WP_Error('invalid_route_type', 'Invalid route type', array('status' => 400));
105 }
106
107 $pattern_cache = CacheController::GetCache($gutenberg_cache_option, CacheTypes::GUTENBERG);
108 if (!!$pattern_cache) {
109 // Local cache accepted
110 $pattern_cache->premium = KeyController::HasValidPremiumKey();
111 $this->UpdatePatternRequirementStatus($pattern_cache);
112 return rest_ensure_response($pattern_cache);
113 }
114
115 return $this->ListHandler(self::GUTENBERG_ENDPOINT_BASE, $route_type, $gutenberg_cache_option);
116 } catch (CacheException $cex) {
117 return new \WP_Error('internal_error_cache', 'Internal Cache Error: ' . esc_html($cex->getMessage()), array('status' => 500));
118 } catch (Exception $ex) {
119 LogController::HandleException($ex);
120 return new \WP_Error('internal_error_plugin', 'Internal Plugin Error', array('status' => 500));
121 }
122 }
123
124 private function GetGutenbergCacheOptionByRouteType($route_type)
125 {
126 // Sanitize route type
127 switch ($route_type) {
128 case self::GUTENBERG_ROUTE_TYPE_PATTERNS:
129 return GutenbergCache::PATTERNS;
130 case self::GUTENBERG_ROUTE_TYPE_PAGES:
131 return GutenbergCache::PAGES;
132 default:
133 return false;
134 }
135 }
136
137 private function ListHandler($endpoint, $item_type, $cache_option)
138 {
139 // Fetch data cache from service
140 $options_controller = new OptionController();
141 $license_key = $options_controller->GetKey();
142
143 $response = DomainShiftController::RemoteGet($endpoint . $item_type . '?action=list&key=' . $license_key);
144 ///
145 if (!is_array($response) || is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
146 return new \WP_Error('service_unavailable', 'Plugin Service Unavailable', array('status' => 503));
147 }
148 ///
149 $data = json_decode($response['body']);
150 if (isset($data->code) && isset($data->data) && isset($data->message)) {
151 $status = isset($data->data->status) ? $data->data->status : 500;
152 return new \WP_Error($data->code, $data->message, array('status' => $status));
153 }
154 if (isset($data->level)) {
155 KeyController::UpdateKeyType($data->level, $data->active, $data->expired, $data->exceeded);
156 }
157
158 // Sort items
159 if (isset($data->items) && is_array($data->items) && !empty($data->items)) {
160 usort($data->items, function ($a, $b) {
161 if (!isset($a->title) || !isset($b->title)) {
162 return 0;
163 }
164 return strnatcmp($a->title, $b->title);
165 });
166 }
167
168 // Cache data
169 CacheController::SetCache($cache_option, $data);
170
171 $this->UpdatePatternRequirementStatus($data);
172
173 $data->premium = KeyController::HasValidPremiumKey();
174 //
175 return rest_ensure_response($data);
176 }
177
178 private function UpdatePatternRequirementStatus(&$data)
179 {
180 if (!function_exists('is_plugin_active')) {
181 require_once(ABSPATH . 'wp-admin/includes/plugin.php');
182 }
183 // Check plugin and library version requirements
184 foreach ($data->items as $item) {
185 $item->external_plugin_required = false;
186 $item->plugin_update_required = false;
187 if (isset($item->required_plugins)) {
188 foreach ($item->required_plugins as $required_plugin) {
189 if (!is_plugin_active($required_plugin)) {
190 $item->external_plugin_required = true;
191 $item->required_plugin_names ??= array();
192 if (isset(self::PLUGIN_NAMES[$required_plugin])) {
193 $item->required_plugin_names[] = self::PLUGIN_NAMES[$required_plugin];
194 } else {
195 $item->required_plugin_names[] = esc_attr(explode('/', $required_plugin)[0]);
196 }
197 }
198 }
199 }
200 if (isset($item->required_library_version) && version_compare($item->required_library_version, SUPERBADDONS_LIBRARY_VERSION, '>')) {
201 $item->plugin_update_required = true;
202 }
203 }
204 }
205
206 public function ElementorInsertCallback($request)
207 {
208 return $this->InsertHandler($request, self::ELEMENTOR_ENDPOINT_BASE, 'sections');
209 }
210
211 public function GutenbergInsertCallback($request)
212 {
213 if (!isset($request['route_type'])) {
214 return new \WP_Error('invalid_route_type', 'Invalid route type', array('status' => 400));
215 }
216 $route_type = $request['route_type'];
217 $gutenberg_cache_option = self::GetGutenbergCacheOptionByRouteType($route_type);
218 if (!$gutenberg_cache_option) {
219 return new \WP_Error('invalid_route_type', 'Invalid route type', array('status' => 400));
220 }
221
222 return $this->InsertHandler($request, self::GUTENBERG_ENDPOINT_BASE, $route_type);
223 }
224
225 private function InsertHandler($request, $endpoint, $item_type)
226 {
227 try {
228 //
229 $data = self::GetInsertData($request, $endpoint, $item_type);
230
231 if (isset($data['access_failed'])) {
232 return rest_ensure_response($data);
233 }
234
235 switch ($endpoint) {
236 case self::ELEMENTOR_ENDPOINT_BASE:
237 $data = ElementorController::ElementorDataImportAction($data);
238 return rest_ensure_response($data['content']);
239 case self::GUTENBERG_ENDPOINT_BASE:
240 $data = GutenbergController::GutenbergDataImportAction($data);
241 return rest_ensure_response(["content" => $data['content'], "name" => esc_html(isset($data['title']) ? $data['title'] : '')]);
242 default:
243 throw new Exception(__("Invalid endpoint specifier. Unable to import data.", "superb-blocks"));
244 }
245
246 return new \WP_Error('internal_error_plugin', 'Unexpected Internal Plugin Error', array('status' => 500));
247 } catch (RequestException $rex) {
248 return new \WP_Error('internal_error_request', 'Internal Request Error: ' . esc_html($rex->getMessage()), array('status' => $rex->getCode()));
249 } catch (Exception $ex) {
250 LogController::HandleException($ex);
251 return new \WP_Error('internal_error_plugin', 'Internal Plugin Error', array('status' => 500));
252 }
253 }
254
255 public static function GetInsertData($request, $endpoint, $item_type)
256 {
257 $options_controller = new OptionController();
258 $license_key = $options_controller->GetKey();
259 if (!isset($request['id']) || !isset($request['package']) || $request['package'] === "premium" && !$license_key) {
260 throw new RequestException("Forbidden", 403);
261 }
262
263 $stamp = $options_controller->GetStamp();
264 $collection = $request['package'] === 'premium' ? "premium" : "free";
265 $response = DomainShiftController::RemoteGet($endpoint . $item_type . '?action=insert&id=' . $request['id'] . '&collection=' . $collection . '&dm=' . urlencode(\home_url()) . '&key=' . urlencode($license_key) . '&stamp=' . absint($stamp));
266 ///
267 if (!is_array($response) || is_wp_error($response) || wp_remote_retrieve_response_code($response) !== 200) {
268 throw new RequestException('Plugin Service Unavailable', 503);
269 }
270 ///
271 $data = json_decode($response['body'], true);
272 if (isset($data['code']) && isset($data['data']) && isset($data['message'])) {
273 $status = isset($data['data']['status']) ? $data['data']['status'] : 500;
274 throw new RequestException($data['message'], $status);
275 }
276 if (isset($data['level'])) {
277 KeyController::UpdateKeyType($data['level'], $data['active'], $data['expired'], $data['exceeded']);
278 }
279 if (!isset($data['verified']) || !$data['verified']) {
280 KeyController::VerificationFailed();
281 }
282
283 $data['premium'] = KeyController::HasValidPremiumKey();
284
285 return $data;
286 }
287 }
288