diff --git a/assets/css/rop_core.css b/assets/css/rop_core.css index fe69e5ce6..c72175e33 100644 --- a/assets/css/rop_core.css +++ b/assets/css/rop_core.css @@ -4777,8 +4777,10 @@ a.active { } @media (max-width: 1280px) { - #rop_core .sidebar { - display: none; + #rop_core .sidebar .rop-container-start { + display: flex; + flex-direction: row; + gap: 15px; } #rop_core .sidebar-top { @@ -4787,6 +4789,10 @@ a.active { display: -ms-flexbox; display: flex; } + + #rop_core .container-column { + min-width: 350px; + } } @media (max-width: 840px) { diff --git a/includes/admin/class-rop-admin.php b/includes/admin/class-rop-admin.php index 1b1097926..79ebd0090 100644 --- a/includes/admin/class-rop-admin.php +++ b/includes/admin/class-rop-admin.php @@ -337,6 +337,7 @@ public function enqueue_scripts() { $global_settings = new Rop_Global_Settings(); $settings = new Rop_Settings_Model(); + $rop_api_settings['license_data_view'] = $global_settings->get_license_data_view(); $rop_api_settings['license_type'] = $global_settings->license_type(); $rop_api_settings['fb_domain_toast_display'] = $this->facebook_exception_toast_display(); $rop_api_settings['labels'] = Rop_I18n::get_labels(); diff --git a/includes/admin/class-rop-global-settings.php b/includes/admin/class-rop-global-settings.php index 8f633e951..1688ea46a 100644 --- a/includes/admin/class-rop-global-settings.php +++ b/includes/admin/class-rop-global-settings.php @@ -448,6 +448,74 @@ public static function instance() { return self::$instance; } + /** + * Get the license data. + * + * @since 9.1.0 + * @access public + * + * @return object + */ + public function get_license_data() { + if ( ! defined( 'ROP_PRO_VERSION' ) ) { + return -1; + } + + $license_data = get_option( 'tweet_old_post_pro_license_data', '' ); + + if ( empty( $license_data ) ) { + return -1; + } + + if ( ! isset( $license_data->license ) ) { + return -1; + } + + return $license_data; + } + + /** + * Get the license data for the public view (display). + * + * @since 9.1.0 + * @access public + * + * @return array With data for display. + */ + public function get_license_data_view() { + $license_data = $this->get_license_data(); + $view_license_data = array( + 'installed' => defined( 'ROP_PRO_VERSION' ), + 'license' => 'invalid', + 'expires' => '', + 'passwordMask' => '', + ); + + if ( -1 === $license_data ) { + return $view_license_data; + } + + // Pick only the necessary data. + if ( isset( $license_data->license ) ) { + $view_license_data['license'] = $license_data->license; + } + + if ( isset( $license_data->expires ) ) { + $view_license_data['expires'] = date( 'F j, Y', strtotime( $license_data->expires ) ); + if ( 'valid' === $view_license_data['license'] ) { + $view_license_data['expires'] = sprintf( Rop_I18n::get_labels( 'general.expires' ), $view_license_data['expires'] ); + } else { + $view_license_data['expires'] = sprintf( Rop_I18n::get_labels( 'general.expired' ), $view_license_data['expires'] ); + } + } + + if ( isset( $license_data->key ) ) { + $view_license_data['passwordMask'] = str_repeat( '*', strlen( $license_data->key ) - 4 ) . substr( $license_data->key, -4 ); + } + + return $view_license_data; + } + /** * Get license plan. * -1 - Pro is not present nor installed. @@ -460,20 +528,9 @@ public static function instance() { */ public function license_type() { - $pro_check = defined( 'ROP_PRO_VERSION' ); + $license_data = $this->get_license_data(); - if ( ! $pro_check ) { - return - 1; - } - - $product_key = 'tweet_old_post_pro'; - $license_data = get_option( $product_key . '_license_data', '' ); - - if ( empty( $license_data ) ) { - return - 1; - } - - if ( ! isset( $license_data->license ) ) { + if ( - 1 === $license_data ) { return - 1; } @@ -481,7 +538,7 @@ public function license_type() { * If we have an invalid license but the pro is installed. */ if ( $license_data->license !== 'valid' ) { - if ( $pro_check ) { + if ( defined( 'ROP_PRO_VERSION' ) ) { return 0; } @@ -492,15 +549,13 @@ public function license_type() { return intval( $license_data->price_id ); } - $plan = get_option( $product_key . '_license_plan', - 1 ); - - $plan = intval( $plan ); + $plan = intval( get_option( 'tweet_old_post_pro_license_data', - 1 ) ); /** * If the plan is not fetched but we have pro. */ if ( $plan < 1 ) { - if ( $pro_check ) { + if ( defined( 'ROP_PRO_VERSION' ) ) { return 0; } @@ -508,7 +563,6 @@ public function license_type() { } return $plan; - } /** diff --git a/includes/admin/class-rop-rest-api.php b/includes/admin/class-rop-rest-api.php index 714194fff..bfee37623 100644 --- a/includes/admin/class-rop-rest-api.php +++ b/includes/admin/class-rop-rest-api.php @@ -1339,6 +1339,51 @@ private function add_account_vk( $data ) { return $this->response->to_array(); } + /** + * API method to call the license processor. + * + * @SuppressWarnings(PHPMD.UnusedPrivateMethod) As it is called dynamically. + * + * @since 9.1.0 + * + * @param array $data Data passed from the AJAX call. + * + * @return array + */ + private function set_license( $data ) { + + if ( ! current_user_can( 'manage_options' ) ) { + $this->response + ->set_code( '403' ) + ->set_message( 'Forbidden' ) + ->set_data( array( 'success' => false, 'message' => Rop_I18n::get_labels( 'general.no_permission' ) ) ); + + return $this->response->to_array(); + } + + // NOTE: The license processor requires the license key, even if we want to deactivate the license. + if ( empty( $data['license_key'] ) ) { + $general_settings = new Rop_Global_Settings; + $license_data = $general_settings->get_license_data(); + if ( ! empty( $license_data ) && isset( $license_data->key ) ) { + $data['license_key'] = $license_data->key; + } + } + + $response = apply_filters( 'themeisle_sdk_license_process_rop', $data['license_key'], $data['action'] ); + + if ( is_wp_error( $response ) ) { + return $this->response + ->set_data( array( 'success' => false, 'message' => 'activate' === $data['action'] ? Rop_I18n::get_labels( 'general.validation_failed' ) : Rop_I18n::get_labels( 'general.could_not_change_license' ) ) ) + ->to_array(); + } + + return $this->response + ->set_code( '200' ) + ->set_data( array( 'success' => true ) ) + ->to_array(); + } + /** * API method called to add Webhook account. * diff --git a/includes/class-rop-i18n.php b/includes/class-rop-i18n.php index 3beaecf1d..5c85eb3b3 100644 --- a/includes/class-rop-i18n.php +++ b/includes/class-rop-i18n.php @@ -385,6 +385,18 @@ public static function get_labels( $key = '' ) { 'rop_docs' => __( 'Documentation', 'tweet-old-post' ), 'rop_roadmap' => __( 'Roadmap & Voting', 'tweet-old-post' ), 'rop_linkedin_refresh_token' => __( 'Your Linkedin access token is about to expire. You need to refresh your LinkedIn token to continue sharing without issue. Paste this link in your browser to find out why and how: https://is.gd/refresh_linkedin_token', 'tweet-old-post' ), + 'license_product' => __( '%1$s license', 'tweet-old-post' ), + 'license_help' => __( 'Enter your revive.social license from purchase history in order to get plugin updates.', 'tweet-old-post' ), + 'purchase_history' => __( 'Go to Purchase History.', 'tweet-old-post' ), + 'activate' => __( 'Activate', 'tweet-old-post' ), + 'deactivate' => __( 'Deactivate', 'tweet-old-post' ), + 'valid' => __( 'Valid', 'tweet-old-post' ), + 'expires' => __( 'Expires on %1$s.', 'tweet-old-post' ), + 'expired' => __( 'Expired on %1$s.', 'tweet-old-post' ), + 'could_not_change_license' => __( 'Could not change the license.', 'tweet-old-post' ), + 'validation_failed' => __( 'Validation failed.', 'tweet-old-post' ), + 'could_not_send' => __( 'Could not send the request to the server.', 'tweet-old-post' ), + 'no_permission' => __( 'You do not have permission to change the license.', 'tweet-old-post' ), ), 'post_editor' => array( 'remove_variation' => __( 'Delete', 'tweet-old-post' ), diff --git a/includes/class-rop.php b/includes/class-rop.php index 2a8500b7e..4e7606a01 100644 --- a/includes/class-rop.php +++ b/includes/class-rop.php @@ -128,6 +128,14 @@ private function define_admin_hooks() { $plugin_admin_notices_helpers = new Rop_Admin_Notices_Helpers(); $tutorial_pointers = new Rop_Pointers(); + add_filter( 'tweet_old_post_pro_hide_license_field', '__return_true' ); + add_filter( + 'tweet_old_post_pro_lc_no_valid_string', + function ( $message ) { + return str_replace( '', '', $message ); + } + ); + $this->loader->add_action( 'wp_ajax_rop_notice_dismissed', $plugin_admin_notices_helpers, 'rop_notice_dismissed' ); $this->loader->add_action( 'admin_init', $plugin_admin, 'legacy_auth', 2 ); diff --git a/vue/src/models/rop_store.js b/vue/src/models/rop_store.js index c3e4ae13f..7e4e4a63c 100644 --- a/vue/src/models/rop_store.js +++ b/vue/src/models/rop_store.js @@ -91,6 +91,7 @@ export default new Vuex.Store({ isActive: false } ], + licenseDataView: ropApiSettings.license_data_view, licence: parseInt(ropApiSettings.license_type), labels: ropApiSettings.labels, availableServices: [], diff --git a/vue/src/vue-elements/main-page-panel.vue b/vue/src/vue-elements/main-page-panel.vue index 5c732549c..7b22f539d 100644 --- a/vue/src/vue-elements/main-page-panel.vue +++ b/vue/src/vue-elements/main-page-panel.vue @@ -95,67 +95,118 @@ :class="'rop-license-plan-'+license" >
- +
+ - + - + +
- - {{ labels.click }} {{ labels.to }} {{ ( start_status ? labels.stop : labels.start ) }} {{ labels.sharing }} - - - -
-
- + v-if="license_data_view.installed" + class="container-column license-container" + > +
+ {{ license_field_title }} +
+

+ {{ labels.license_help }} + {{ labels.purchase_history }} +

+ + + {{ license_data_view.expires }} + + + +

+ {{ license_error }} +

- {{ labels.rop_support }} - {{ labels.rop_docs }} - {{ labels.review_it }}
@@ -199,9 +250,16 @@ is_loading: false, is_loading_logs: false, status_is_error_display: false, + license_data_view: this.$store.state.licenseDataView, + license_field_title: window.wp.i18n.sprintf(this.$store.state.labels.general.license_product, 'Revive Old Posts Pro Add-on'), + license_error: false, + password_mask: this.$store.state.licenseDataView?.passwordMask } }, computed: { + is_license_valid() { + return this.$store.state.licenseDataView.license === 'valid'; + }, is_preloading_over: function () { return this.$store.state.hide_preloading; }, @@ -425,6 +483,32 @@ Vue.$log.error('Got nothing from server. Prompt user to check internet connection and try again', error) this.is_loading_logs = false; }) + }, + activateLicense() { + this.uploadLicense( 'activate' ); + }, + disableLicense() { + this.generalSettings.license_key = ''; + this.uploadLicense( 'deactivate' ); + }, + uploadLicense( action ) { + this.$store.dispatch( 'fetchAJAXPromise', { + req: 'set_license', + updateState: false, + data: { + license_key: this.generalSettings.license_key, + action + } + }).then( response => { + if ( response?.success ) { + window.location.reload(); + } else { + this.license_error = response?.message; + } + }, error => { + this.license_error = this.labels.could_not_send; + Vue.$log.error('Got nothing from server. Prompt user to check internet connection and try again', error) + }) } } } @@ -449,4 +533,32 @@ #rop_core .badge.badge-logs { padding-right: 10px; } + + #rop_core .container-column { + display: flex; + flex-direction: column; + } + + #rop_core .license-container { + margin-top: 20px; + gap: 15px; + } + + #rop_core .license-title { + font-size: 14px; + font-weight: bold; + line-height: 0; + color: black; + } + + #rop_core .license-description { + font-size: 13px; + line-height: 1.2em; + margin: 0; + } + + .expires-on { + font-size: 13px; + line-height: 1.2em; + }