PluginProbe
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! / 3.7.3
Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! v3.7.3
3.7.5 3.7.4 3.7.3 3.7.2 1-final 3.7.1 3.7.0 3.6.8 3.6.7 3.6.6 3.6.5 3.6.4 3.6.3 3.6.2 3.6.1 3.0.3 3.0.4 3.0.5 3.0.6 3.0.7 3.0.8 3.0.9 3.1.0 3.1.1 3.1.10 All 111 releases
templately / includes / API / Login.php

Login.php in Templately – Elementor & Gutenberg Template Library: 6500+ Free & Pro Ready Templates And Cloud! 3.7.3, at includes/API/Login.php

345 lines 11.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Templately\API;
4
5 use WP_REST_Request;
6 use Templately\Utils\Helper;
7 use Templately\Utils\Options;
8
9 class Login extends API {
10 public function permission_check( WP_REST_Request $request ) {
11 $this->request = $request;
12 $_route = $request->get_route();
13 if ( '/templately/v1/login' === $_route ) {
14 return true;
15 }
16
17 if ( '/templately/v1/pricing' === $_route ) {
18 return true;
19 }
20
21 if ( '/templately/v1/google-auth-url' === $_route ) {
22 return true;
23 }
24
25 return parent::permission_check( $request );
26 }
27
28 public function register_routes() {
29 $this->post( 'login', [$this, 'login'] );
30 $this->post( 'logout', [$this, 'logout'] );
31 $this->get( 'is-signed', [$this, 'is_signed'] );
32 $this->get( 'pricing', [$this, 'pricing'] );
33 $this->get( 'google-auth-url', [$this, 'google_auth_url'] );
34 }
35
36 public function google_auth_url() {
37 // Get redirect_to parameter from request if provided
38 $redirect_to = $this->get_param( 'redirect-to', '' );
39
40 // Use client-provided current_url instead of HTTP_REFERER for reliability
41 $current_url = $this->get_param( 'current_url', '' );
42
43 $url = $this->http()->google_auth_url( $redirect_to, $current_url );
44 return [
45 'status' => 'success',
46 'url' => $url
47 ];
48 }
49
50 public function pricing(){
51 $data = get_transient( "templately_subscriptions_v2" );
52
53 if( is_array( $data ) && ! empty( $data ) ) {
54 return $data;
55 }
56
57 // Field set drives the Subscription screen's plan comparison grid, so it
58 // carries the per-plan limits too, not just price/sites.
59 $query = 'id, price, name, slug, discounted_price, type, sites, coupon, my_cloud_items, pro_items, workspace, fsi_limit, ai_credit, description';
60 $response = $this->http()->query(
61 'subscriptionPlans',
62 $query
63 )->post();
64
65 set_transient( "templately_subscriptions_v2", $response, WEEK_IN_SECONDS );
66
67 return $response;
68 }
69
70 public function login() {
71 $errors = [];
72 $_ip = Helper::get_ip();
73 $_site_url = home_url( '/' );
74
75 $global_signin = (bool) $this->get_param( 'global_signin', false );
76 $viaAPI = (bool) $this->get_param( 'viaAPI', false );
77 $email = $this->get_param( 'email', '', 'sanitize_email' );
78 $password = $this->get_param( 'password' );
79
80 $funcArgs = [
81 'ip' => $_ip,
82 'site_url' => $_site_url
83 ];
84
85 $postArgs = [];
86
87 if ( $viaAPI ) {
88 $api_key = $this->get_param( 'api_key' );
89 $funcArgs['api_key'] = $api_key;
90
91 if ( empty( $api_key ) ) {
92 $errors['api_key'] = __( 'API Key field cannot be empty.', 'templately' );
93 }
94 } else {
95 $funcArgs['email'] = $email;
96 $funcArgs['password'] = addcslashes( $password, '"' );
97
98 if ( ! filter_var( $email, FILTER_VALIDATE_EMAIL ) ) {
99 $errors['email'] = __( 'Make sure you have given a valid email address.', 'templately' );
100 }
101
102 if ( empty( $password ) ) {
103 $errors['password'] = __( 'Password field cannot be empty.', 'templately' );
104 }
105 }
106
107 if ( ! empty( $errors ) ) {
108 return $this->error( 'login_error', $errors, 'login', 400 );
109 }
110
111 // `ends_at`, `plan_type` and `cancel_at_period_end` drive the Subscription
112 // screen's renewal line. They are asked for instead of leaning on
113 // `plan_expire_at`, which the API resolves with `empty($subscription->ends_at)
114 // ?? …` — a boolean that never falls through, so it never carries a date.
115 $query = 'status, message, user{ id, name, first_name, last_name, display_name, email, profile_photo, joined, is_verified, is_company_user, is_restricted_company_user, api_key, plan, plan_expire_at, my_cloud{ limit, usages, last_pushed }, favourites{ id, type }, show_notice, reviews{ type, type_id, rating }, subscription { id, name, sites, subscription_plan_id, ends_at, plan_type, cancel_at_period_end } }';
116
117 $response = $this->http()->mutation(
118 $viaAPI ? 'connectWithApiKey' : 'connect',
119 $query,
120 $funcArgs
121 )->post($postArgs);
122
123 if ( is_wp_error( $response ) ) {
124 return $response;
125 }
126
127 if ( empty( $response['user']['api_key'] ) ) {
128 return $this->error( 'login_error', $response['message'] ?? __('Invalid API key.', 'templately'), 'login', 400 );
129 }
130
131 $options = $this->utils( 'options' );
132 $options->use_current_user( true );
133
134 try {
135 return $this->store_connection( $response, $global_signin, $_ip, $_site_url );
136 } finally {
137 $options->use_current_user( false );
138 }
139 }
140
141 /**
142 * Persist an authenticated connection against the acting user.
143 *
144 * @param array $response Cloud response, already validated.
145 * @param bool $global_signin Whether the user asked to sign in globally.
146 * @param string $_ip Request IP, echoed back into the profile.
147 * @param string $_site_url Site URL, echoed back into the profile.
148 *
149 * @return array
150 */
151 private function store_connection( $response, $global_signin, $_ip, $_site_url ) {
152
153 if ( $global_signin && ! Login::is_globally_signed() ) {
154 Options::set_global_login();
155 }
156
157 if ( ! empty( $response['user']['api_key'] ) ) {
158 $this->utils( 'options' )->set( 'api_key', $response['user']['api_key'] );
159 unset( $response['user']['api_key'] );
160 }
161
162 $meta = [
163 'is_globally_signed' => Login::is_globally_signed(),
164 'signed_as_global' => Login::signed_as_global()
165 ];
166
167 if ( ! empty( $response['user']['my_cloud']['last_pushed'] ) ) {
168 $_cloud_activity = unserialize( $response['user']['my_cloud']['last_pushed'] );
169 $this->utils( 'options' )->set( 'cloud_activity', $_cloud_activity );
170 $meta['cloud_activity'] = $_cloud_activity;
171 unset( $response['user']['my_cloud']['last_pushed'] );
172 }
173
174 if ( ! empty( $response['user']['favourites'] ) ) {
175 $_favourites = $this->utils( 'helper' )->normalizeFavourites( $response['user']['favourites'] );
176 $this->utils( 'options' )->set( 'favourites', $_favourites );
177
178 unset( $response['user']['favourites'] );
179 $meta['favourites'] = $_favourites;
180 }
181
182 if ( ! empty( $response['user']['reviews'] ) ) {
183 $_reviews = $this->utils( 'helper' )->normalizeReviews( $response['user']['reviews'] );
184 $this->utils( 'options' )->set( 'reviews', $_reviews );
185
186 unset( $response['user']['reviews'] );
187 $meta['reviews'] = $_reviews;
188 }
189
190 if(Helper::is_dev_api()){
191 $response['user']['is_dev_api'] = true;
192 }
193
194 if(! empty( $response['user'] ) && is_array($response['user'])){
195 $response['user']['ip'] = $_ip;
196 $response['user']['site_url'] = base64_encode( $_site_url );
197 }
198
199 $this->utils( 'options' )->set( 'user', $response['user'] );
200 $response['user']['meta'] = $this->user_meta( $meta );
201
202 return $response;
203 }
204
205 public function logout() {
206 // Read the key off the acting user's own record. Options::get() falls back to
207 // the global-login administrator when no target is given, so $this->api_key
208 // resolves to the administrator's key for any linked user — disconnecting the
209 // administrator's account on the cloud as well as locally.
210 $api_key = $this->utils( 'options' )->get( 'api_key', '', get_current_user_id() );
211
212 if ( empty( $api_key ) ) {
213 return $this->error(
214 'logout_error',
215 __( 'You are not connected to Templately.', 'templately' ),
216 'logout',
217 403
218 );
219 }
220
221 $response = $this->http()->mutation(
222 'disconnect',
223 'status, message, data',
224 [
225 'api_key' => $api_key,
226 "site_url" => home_url( '/' )
227 ]
228 )->post();
229
230 if ( is_wp_error( $response ) ) {
231 return $response;
232 }
233
234 if ( ! isset( $response['status'] ) || $response['status'] !== 'success' ) {
235 return $this->error( 'logout_error', $response['message'], 'logout', 404 );
236 }
237
238 // Remove All Metas
239 $global_user = $this->delete();
240
241 $response = [
242 'status' => 'success',
243 'message' => __( 'Logged out.', 'templately' )
244 ];
245
246 if ( ! empty( $global_user ) ) {
247 $response['global_user'] = $global_user;
248 }
249
250 return $response;
251 }
252
253 public function delete(){
254 $options = $this->utils( 'options' );
255
256 // Pin the removals to the acting user. Without the pin, Options::user_id()
257 // resolves a linked user to the global-login administrator and the delete
258 // path wipes the administrator's connection instead of the caller's.
259 $options->use_current_user( true );
260
261 try {
262 $options
263 ->remove( 'user' )
264 ->remove( 'favourites' )
265 ->remove( 'reviews' )
266 ->remove( 'cloud_activity' )
267 ->remove( 'api_key' )
268 ->remove( 'global_login' )
269 ->remove( 'total_download_counts' )
270 ->remove( 'templates_in_clouds' );
271
272 if ( $options->who_am_i() === 'global' ) {
273 $options->remove_global_login();
274 }
275 } finally {
276 $options->use_current_user( false );
277 }
278
279 $global_user_id = $this->utils( 'options' )->is_global();
280 $global_user = null;
281
282 if ( $global_user_id !== $this->utils( 'options' )->current_user_id() ) {
283 $global_user = $this->utils( 'options' )->get( 'user', false, $global_user_id );
284
285 if ( ! empty( $global_user ) ) {
286 if ( is_array( $global_user ) ) {
287 unset( $global_user['api_key'] );
288 }
289
290 $global_user['meta'] = $this->user_meta();
291 }
292 }
293
294 return $global_user;
295 }
296
297 public static function is_signed(): array {
298 $_response = [
299 'status' => 'success'
300 ];
301
302 $_user = ( new static )->utils( 'options' )->get( 'user', null );
303
304 if ( ! is_null( $_user ) ) {
305 // Profiles stored before 3.7.1 may still carry the cloud API key.
306 if ( is_array( $_user ) ) {
307 unset( $_user['api_key'] );
308 }
309
310 $_user['meta'] = self::get_instance()->user_meta();
311 }
312
313 if ( empty( $_user ) ) {
314 $_response['status'] = 'error';
315 }
316
317 $_response['user'] = $_user;
318
319 return $_response;
320 }
321
322 public function user_meta( $meta = [] ): array {
323 $_meta = [
324 'link_account' => self::utils( 'options' )->link_account(),
325 'unlink_account' => self::utils( 'options' )->unlink_account(),
326 'is_globally_signed' => Login::is_globally_signed(),
327 'signed_as_global' => Login::signed_as_global(),
328 'starred' => self::utils( 'options' )->get( 'favourites' ),
329 'reviews' => self::utils( 'options' )->get( 'reviews' ),
330 'cloud_activity' => self::utils( 'options' )->get( 'cloud_activity' ),
331 'has_api' => rest_sanitize_boolean( self::utils( 'options' )->get( 'api_key' ) )
332 ];
333
334 return array_merge( $_meta, $meta );
335 }
336
337 public static function is_globally_signed(): bool {
338 return rest_sanitize_boolean( ( new static )->utils( 'options' )->is_globally_signed() );
339 }
340
341 public static function signed_as_global(): bool {
342 return rest_sanitize_boolean( ( new static )->utils( 'options' )->signed_as_global() );
343 }
344 }
345