PluginProbe
Booktics – Appointment Booking Calendar for Service Businesses / 1.0.27
Booktics – Appointment Booking Calendar for Service Businesses v1.0.27
1.0.29 1.0.28 1.0.27 1.0.26 1.0.25 1.0.24 1.0.23 1.0.22 1.0.21 1.0.20 1.0.19 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.13 1.0.14 1.0.15 1.0.16 1.0.17 1.0.18 1.0.2 1.0.3 All 31 releases
← All changes | core/extensions/controllers/extension-controller.php +107 -1 1.0.21 → 1.0.27 View file →
@@ -142,8 +142,23 @@
142 142 if ( ! isset( $extensions[ $name ] ) ) {
143 143 return $this->error( __( 'Invalid extension', 'booktics' ) );
144 144 }
145 145 $extension = $extensions[ $name ];
146 +
147 + // Strict, so a "1" or "true" string never counts as agreement.
148 + $aisentic_consent = 'aisentic' === $name && true === ( $input_data['consent'] ?? null );
149 + $aisentic_email = '';
150 +
151 + // The Ask AI setup dialog sends an edited email. Reject a bad one before
152 + // anything is installed.
153 + if ( $aisentic_consent && isset( $input_data['email'] ) ) {
154 + $aisentic_email = sanitize_email( (string) $input_data['email'] );
155 +
156 + if ( ! is_email( $aisentic_email ) ) {
157 + return $this->error( __( 'Enter a valid email address.', 'booktics' ), 400 );
158 + }
159 + }
160 +
146 161 if ( 'addon' === $extension['type'] ) {
147 162 $result = null;
148 163
149 164 if ( in_array( $status, array( 'install', 'activate' ) ) ) {
@@ -169,10 +184,23 @@
169 184
170 185 if ( 'plugin' === $extension['type'] ) {
171 186 $result = null;
172 187
188 + // Only people who could do this by hand from the Plugins screen.
189 + if ( 'install' === $status && ! current_user_can( 'install_plugins' ) ) {
190 + return $this->error( __( 'You are not allowed to install plugins.', 'booktics' ), 403 );
191 + }
192 +
193 + if ( 'install' !== $status && ! current_user_can( 'activate_plugins' ) ) {
194 + return $this->error( __( 'You are not allowed to manage plugins.', 'booktics' ), 403 );
195 + }
196 +
173 197 if ( 'install' === $status ) {
174 - $result = SdkPluginManager::install_plugin( $extension['slug'] );
198 + // Prefer the extension's own download_link (e.g. GitHub release) so a
199 + // non-wordpress.org URL is not shadowed by the SDK's hardcoded wp.org zip.
200 + $result = ! empty( $extension['download_link'] )
201 + ? Plugin_Manager::install_plugin( $extension['slug'] )
202 + : SdkPluginManager::install_plugin( $extension['slug'] );
175 203 if ( $result ) {
176 204 $result = SdkPluginManager::activate_plugin( $extension['slug'] );
177 205 }
178 206 } elseif ( 'activate' === $status ) {
@@ -191,8 +219,34 @@
191 219 }
192 220 }
193 221
194 222 $response = Plugin_Manager::extensions()[ $name ];
223 +
224 + // Nothing reaches Aisentic's provider on activation alone. The handshake only
225 + // runs when the caller ticked the consent box and the plugin really is active.
226 + if ( 'aisentic' === $name
227 + && in_array( $status, array( 'install', 'activate' ), true )
228 + && $aisentic_consent
229 + && SdkPluginManager::is_activated( $extension['slug'] ) ) {
230 + // Snapshot before the handshake so the caller can tell a fresh
231 + // registration (tokens just granted) from re-activating a site that
232 + // was already connected (no new tokens).
233 + $was_registered = booktics_aisentic_is_registered();
234 +
235 + $this->register_aisentic_site(
236 + $aisentic_email,
237 + sanitize_text_field( (string) ( $input_data['account_name'] ?? '' ) )
238 + );
239 +
240 + $is_registered = booktics_aisentic_is_registered();
241 +
242 + $response['aisentic_registered'] = $is_registered;
243 +
244 + // True only when this request is what connected the site, so the
245 + // "150K tokens added" message never fires on a plain re-activation.
246 + $response['aisentic_newly_registered'] = $is_registered && ! $was_registered;
247 + }
248 +
195 249 $response['status'] = 'install';
196 250 if ( SdkPluginManager::is_installed( $response['slug'] ) ) {
197 251 $response['status'] = 'activate';
198 252 }
@@ -200,6 +254,58 @@
200 254 $response['status'] = 'deactivate';
201 255 }
202 256
203 257 return $this->response( $response, __( 'Successfully updated', 'booktics' ) );
258 + }
259 +
260 + /**
261 + * Record consent and hand the site identity to Aisentic.
262 + *
263 + * Only ever called from behind the consent gate in update_item(). The action is
264 + * fire and forget: Aisentic owns the provider call, so a provider outage cannot
265 + * fail the activation the user actually asked for.
266 + *
267 + * @param string $email Email the user confirmed in the Ask AI dialog. Empty uses the business email.
268 + * @param string $name Account name sent by the Ask AI dialog. Empty uses the business name.
269 + *
270 + * @return void
271 + */
272 + private function register_aisentic_site( string $email = '', string $name = '' ): void {
273 + // Older Aisentic builds ship no listener, so the handshake would go nowhere.
274 + if ( ! class_exists( 'Aisentic\Api\Services\Registration_Service' ) ) {
275 + return;
276 + }
277 +
278 + $identity = booktics_aisentic_identity();
279 +
280 + if ( $email ) {
281 + $identity['email'] = $email;
282 + }
283 +
284 + if ( $name ) {
285 + $identity['name'] = $name;
286 + }
287 +
288 + // Fail closed. An account cannot be minted without a real address.
289 + if ( empty( $identity['email'] ) ) {
290 + return;
291 + }
292 +
293 + update_option(
294 + 'booktics_aisentic_consent', array(
295 + 'agreed' => true,
296 + 'time' => gmdate( 'c' ),
297 + 'user_id' => get_current_user_id(),
298 + 'email' => $identity['email'],
299 + )
300 + );
301 +
302 + /**
303 + * Fires once the admin has opted in to sharing site details with Aisentic.
304 + *
305 + * @param string $name Business name, falling back to the site title.
306 + * @param string $email Business email, falling back to the admin email.
307 + * @param string $site_url Site URL.
308 + */
309 + do_action( 'booktics/aisentic/register_site', $identity['name'], $identity['email'], $identity['site_url'] );
204 310 }
205 311 }