Plugin Directory

Changeset 2146523


Ignore:
Timestamp:
08/27/2019 06:28:54 PM (7 years ago)
Author:
labs64
Message:

Preparing for 0.9.3 release

Location:
pluginpass-pro-plugintheme-licensing/trunk
Files:
5 added
14 edited

Legend:

Unmodified
Added
Removed
  • pluginpass-pro-plugintheme-licensing/trunk/README.txt

    r2137441 r2146523  
    88Tested up to: 5.2.2
    99Requires PHP: 5.6
    10 Stable tag: 0.9.2
     10Stable tag: 0.9.3
    1111License: GPLv2 or later
    1212License URI: https://www.gnu.org/licenses/gpl-2.0.html
     
    135135== Changelog ==
    136136
     137= 0.9.3 =
     138* New: User consent before validation #13
     139* New: Add deregister plugin function #15
     140* Fix: Column "Expiration Date" used wrongly #18
     141* Update: Verify / implement / fix licensee / license deactivation roundtrip #17
     142* Update: How To: Describe plugin usage #4
     143* New: Install & activate PluginPass as dependency #2
     144* Update: Force validate #3
     145* Update: Bulk validate plugins error #11
     146* Fix: HTTP 4xx/5xx handling #7
     147* Update: Optimize DB table structure #10
     148* Update: Validation response output variables #9
     149
    137150= 0.9.2 =
    138151* Update: Plugin documentation
  • pluginpass-pro-plugintheme-licensing/trunk/composer.json

    r2137166 r2146523  
    2323        "monetize"
    2424    ],
    25     "homepage": "https://wordpress.org/plugins/pluginpass/",
     25    "homepage": "https://wordpress.org/plugins/pluginpass-pro-plugintheme-licensing/",
    2626    "license": "GPL-2.0",
    2727    "authors": [
     
    3636        "issues": "https://github.com/Labs64/PluginPass/issues",
    3737        "source": "https://github.com/Labs64/PluginPass",
    38         "docs": "https://wordpress.org/plugins/pluginpass/faq/"
     38        "docs": "https://github.com/Labs64/PluginPass/wiki"
    3939    },
    4040    "require": {
  • pluginpass-pro-plugintheme-licensing/trunk/composer.lock

    r2137166 r2146523  
    55        "This file is @generated automatically"
    66    ],
    7     "hash": "a890e6ee8bf1b1036a0af6d786b2e26f",
     7    "hash": "f22cc9d3d1c567a5e1ad00f10d5b0453",
    88    "content-hash": "7236f443f9d2d77b9b6f186c5f89be9c",
    99    "packages": [
  • pluginpass-pro-plugintheme-licensing/trunk/constants.php

    r2137441 r2146523  
    88define( __NAMESPACE__ . '\NS', __NAMESPACE__ . '\\' );
    99
    10 define( NS . 'PLUGIN_VERSION', '0.9.2' );
     10define( NS . 'PLUGIN_VERSION', '0.9.3' );
    1111
    1212define( NS . 'PLUGIN_NAME', 'pluginpass' );
  • pluginpass-pro-plugintheme-licensing/trunk/docker-compose.yml

    r2137166 r2146523  
    2828     volumes:
    2929       - ".:/var/www/html/wp-content/plugins/pluginpass"
    30        - "./data/testplugin:/var/www/html/wp-content/plugins/testplugin"
     30       - "./data/pluginpass-demo:/var/www/html/wp-content/plugins/pluginpass-demo"
    3131   phpmyadmin:
    3232     image: phpmyadmin/phpmyadmin
  • pluginpass-pro-plugintheme-licensing/trunk/inc/admin/class-pluginpass-admin.php

    r2137166 r2146523  
    8383    public function enqueue_scripts() {
    8484        $params = array( 'ajaxurl' => admin_url( 'admin-ajax.php' ) );
     85        wp_enqueue_script( 'sweetalert2', plugin_dir_url( __FILE__ ) . 'js/sweetalert2.all.min.js', array( 'jquery' ), $this->version, false );
    8586        wp_enqueue_script( 'pluginpass_ajax_handle', plugin_dir_url( __FILE__ ) . 'js/pluginpass-admin.js', array( 'jquery' ), $this->version, false );
    8687        wp_localize_script( 'pluginpass_ajax_handle', 'params', $params );
  • pluginpass-pro-plugintheme-licensing/trunk/inc/admin/class-pluginpass-table.php

    r2137441 r2146523  
    44
    55use NetLicensing\Constants;
     6use NetLicensing\NetLicensingService;
     7use NetLicensing\RestException;
    68use PluginPass\Inc\Common\Traits\PluginPass_Plugable;
    79use PluginPass\Inc\Common\Traits\PluginPass_Validatable;
     
    7577        $page     = $this->get_pagenum() - 1;
    7678        $per_page = $this->get_items_per_page( 'plugins_per_page' );
    77         $order_by = ( isset( $_GET['orderby'] ) ) ? esc_sql( $_GET['orderby'] ) : 'name';
     79        $order_by = ( isset( $_GET['orderby'] ) ) ? esc_sql( $_GET['orderby'] ) : 'expires_ttl_at';
    7880        $order    = ( isset( $_GET['order'] ) ) ? esc_sql( $_GET['order'] ) : 'ASC';
    7981
     
    106108        $table_columns = array(
    107109            'cb'           => '<input type="checkbox" />', // to display the checkbox.
    108             'name'         => __( 'Plugin Name', $this->plugin_text_domain ),
     110            'plugin_name'  => __( 'Plugin Name', $this->plugin_text_domain ),
    109111            'expires_at'   => _x( 'Expiration Date', 'column name', $this->plugin_text_domain ),
    110112            'validated_at' => __( 'Last Validated', $this->plugin_text_domain ),
     
    136138         */
    137139        $sortable_columns = array(
    138             'name'         => 'name',
    139             'expires_at'   => 'expires_at',
    140             'validated_at' => 'last_validated',
     140            'validated_at' => 'validated_at',
    141141        );
    142142
     
    163163     */
    164164
    165     public function fetch_table_data( $page, $per_page, $order_by = 'name', $order = 'ASC', $search_key = null ) {
     165    public function fetch_table_data( $page, $per_page, $order_by = 'plugin_name', $order = 'ASC', $search_key = null ) {
    166166        global $wpdb;
    167167
     
    172172
    173173        if ( $search_key ) {
    174             $query      .= " WHERE name LIKE '$search_key'";
    175             $countQuery .= " WHERE name LIKE '$search_key'";
     174            $query      .= " WHERE plugin_name LIKE '$search_key'";
     175            $countQuery .= " WHERE plugin_name LIKE '$search_key'";
    176176        }
    177177
     
    179179
    180180        // query output_type will be an associative array with ARRAY_A.
    181         $items       = $wpdb->get_results( $query, ARRAY_A );
     181        $plugins     = $wpdb->get_results( $query, ARRAY_A );
    182182        $total_items = $wpdb->get_row( $countQuery )->total_items;
    183183
    184         foreach ( $items as &$item ) {
    185             $item['validation'] = json_decode( $item['validation'], true );
     184        $items = [];
     185
     186        foreach ( $plugins as $plugin ) {
     187            if ( array_key_exists( $plugin['plugin_folder'], get_plugins() ) ) {
     188                $plugin['validation_result'] = json_decode( $plugin['validation_result'], true );
     189
     190                $items[] = $plugin;
     191            }
    186192        }
    187193
     
    213219    protected function column_cb( $item ) {
    214220        return sprintf(
    215             '<label class="screen-reader-text" for="plugins_' . $item['ID'] . '">' . sprintf( __( 'Select %s' ), $item['name'] ) . '</label>'
     221            '<label class="screen-reader-text" for="plugins_' . $item['ID'] . '">' . sprintf( __( 'Select %s', $this->plugin_text_domain ), $this->get_plugin_name( $item['plugin_folder'] ) ) . '</label>'
    216222            . "<input type='checkbox' name='plugins[]' id='plugins_{$item['ID']}' value='{$item['ID']}' />"
    217223        );
     
    233239     * @return string
    234240     */
    235     protected function column_name( $item ) {
     241    protected function column_plugin_name( $item ) {
    236242        /*
    237243         *  Build table row actions.
     
    250256        );
    251257
     258        $class = empty( $item['consented_at'] ) ? 'need-consent-before-validation' : '';
     259
    252260        $validate_plugin_link       = esc_url( add_query_arg( $query_args_validate_plugin, $admin_page_url ) );
    253         $actions['validate_plugin'] = '<a href="' . $validate_plugin_link . '">' . __( 'Validate', $this->plugin_text_domain ) . '</a>';
    254 
    255         // row actions to show validation details
    256         $query_args_validation_details = array(
     261        $actions['validate_plugin'] = '<a class="' . $class . '" href="' . $validate_plugin_link . '">' . __( 'Validate', $this->plugin_text_domain ) . '</a>';
     262
     263        if ( ! empty( $item['validated_at'] ) ) {
     264            // row actions to show validation details
     265            $query_args_validation_details = array(
     266                'page'      => wp_unslash( $_REQUEST['page'] ),
     267                'action'    => 'validation_details',
     268                'plugin_id' => absint( $item['ID'] ),
     269                '_wpnonce'  => wp_create_nonce( 'validation_details_nonce' ),
     270            );
     271            $validation_details_link       = esc_url( add_query_arg( $query_args_validation_details, $admin_page_url ) );
     272            $actions['validation_details'] = '<a href="' . $validation_details_link . '">' . __( 'Details', $this->plugin_text_domain ) . '</a>';
     273        }
     274
     275        // row actions to deregister plugin
     276        $query_args_deregister_plugin = array(
    257277            'page'      => wp_unslash( $_REQUEST['page'] ),
    258             'action'    => 'validation_details',
     278            'action'    => 'deregister_plugin',
    259279            'plugin_id' => absint( $item['ID'] ),
    260             '_wpnonce'  => wp_create_nonce( 'validation_details_nonce' ),
     280            '_wpnonce'  => wp_create_nonce( 'deregister_plugin_nonce' ),
    261281        );
    262         $validation_details_link       = esc_url( add_query_arg( $query_args_validation_details, $admin_page_url ) );
    263         $actions['validation_details'] = '<a href="' . $validation_details_link . '">' . __( 'Details', $this->plugin_text_domain ) . '</a>';
    264 
    265         // row actions to deregister plugin
    266 //        $query_args_deregister_plugin = array(
    267 //            'page' => wp_unslash($_REQUEST['page']),
    268 //            'action' => 'deregister_plugin',
    269 //            'plugin_id' => absint($item['ID']),
    270 //            '_wpnonce' => wp_create_nonce('deregister_plugin_nonce'),
    271 //        );
    272 //        $deregister_plugin_link = esc_url(add_query_arg($query_args_deregister_plugin, $admin_page_url));
    273 //        $actions['deregister_plugin'] = '<a href="' . $deregister_plugin_link . '">' . __('Deregister', $this->plugin_text_domain) . '</a>';
    274 
    275 
    276         $row_value = '<strong>' . $item['name'] . '</strong>';
     282        $deregister_plugin_link       = esc_url( add_query_arg( $query_args_deregister_plugin, $admin_page_url ) );
     283        $actions['deregister_plugin'] = '<a class="need-deregister-confirmation" href="' . $deregister_plugin_link . '">' . __( 'Deregister', $this->plugin_text_domain ) . '</a>';
     284        $row_value                    = '<strong>' . $this->get_plugin_name( $item['plugin_folder'] ) . '</strong>';
    277285
    278286        return $row_value . $this->row_actions( $actions );
     287    }
     288
     289    protected function column_expires_at( $item ) {
     290        $expires_at = '';
     291
     292        if ( ! empty( $item['validation_result'] ) ) {
     293            foreach ( $item['validation_result'] as $result ) {
     294                if ( ! empty( $result['expires'] ) ) {
     295                    if ( ! $expires_at || strtotime( $result['expires'] ) < strtotime( $expires_at ) ) {
     296                        $expires_at = $result['expires'];
     297                    }
     298                }
     299            }
     300        }
     301
     302        return ( $expires_at ) ? date( 'Y-m-d H:i:s', strtotime( $expires_at ) ) : '';
    279303    }
    280304
     
    295319        $invalid = 0;
    296320
    297         foreach ( $item['validation'] as $product_module => $results ) {
    298             $licensing_model = $results['licensingModel'];
    299 
    300             if ( $licensing_model === Constants::LICENSING_MODEL_MULTI_FEATURE ) {
    301                 foreach ( $results as $key => $result ) {
    302                     if ( is_array( $result ) ) {
    303                         if ( PluginPass_Dot::get( $result, '0.valid' ) === 'true' ) {
    304                             $valid ++;
    305                         } else {
    306                             $invalid ++;
     321        if ( ! empty( $item['validation_result'] ) ) {
     322            foreach ( $item['validation_result'] as $product_module => $results ) {
     323                $licensing_model = $results['licensingModel'];
     324
     325                if ( $licensing_model === Constants::LICENSING_MODEL_MULTI_FEATURE ) {
     326                    foreach ( $results as $key => $result ) {
     327                        if ( is_array( $result ) ) {
     328                            if ( PluginPass_Dot::get( $result, '0.valid' ) === 'true' ) {
     329                                $valid ++;
     330                            } else {
     331                                $invalid ++;
     332                            }
    307333                        }
    308334                    }
    309                 }
    310             } else {
    311                 if ( $results['valid'] === 'true' ) {
    312                     $valid ++;
    313335                } else {
    314                     $invalid ++;
    315                 }
    316             }
    317         }
    318 
     336                    if ( $results['valid'] === 'true' ) {
     337                        $valid ++;
     338                    } else {
     339                        $invalid ++;
     340                    }
     341                }
     342            }
     343        }
     344
     345        if ( ! $item['validated_at'] ) {
     346            return '<span class="label label-danger">' . __( 'run validation first', $this->plugin_text_domain ) . '</span>';
     347        }
    319348
    320349        if ( $valid > 0 && $invalid === 0 ) {
    321             return '<span class="label label-primary">' . __( 'valid' ) . '</span>';
     350            return '<span class="label label-primary">' . __( 'valid', $this->plugin_text_domain ) . '</span>';
    322351        }
    323352
    324353        if ( $invalid > 0 && $valid === 0 ) {
    325             return '<span class="label label-danger">' . __( 'invalid' ) . '</span>';
    326         }
    327 
    328         return '<span class="label label-warning">' . $valid . '/' . $invalid . ' ' . __( 'valid' ) . '</span>';
     354            return '<span class="label label-danger">' . __( 'invalid', $this->plugin_text_domain ) . '</span>';
     355        }
     356
     357        return '<span class="label label-warning">' . sprintf( __( '%s valid', $this->plugin_text_domain ), $valid . '/' . $invalid ) . '</span>';
    329358    }
    330359
     
    347376         */
    348377        $actions = array(
    349             'bulk-validate' => 'Validate Plugins',
    350 //            'bulk-deregister' => 'Deregister Plugins'
     378            'bulk-validate'   => 'Validate Plugins',
     379            'bulk-deregister' => 'Deregister Plugins'
    351380        );
    352381
     
    399428                $this->invalid_nonce_redirect();
    400429            } else {
    401                 $this->deregister_plugin( absint( $_REQUEST['user_id'] ) );
    402                 $this->graceful_exit();
     430                $this->deregister_plugin( absint( $_REQUEST['plugin_id'] ) );
    403431            }
    404432        }
     
    418446            } else {
    419447                $this->bulk_validate( $_REQUEST['plugins'] );
    420                 $this->graceful_exit();
    421448            }
    422449        }
     
    435462            } else {
    436463                $this->bulk_deregister( $_REQUEST['plugins'] );
    437                 $this->graceful_exit();
    438464            }
    439465        }
     
    449475     */
    450476    public function validate_plugin( $plugin_id ) {
    451         try {
    452             // get plugin
    453             $plugin = $this->get_plugin( [ 'ID' => $plugin_id ] );
    454 
    455             if ( ! $plugin ) {
    456                 throw new Exception( __( 'Plugin not found' ) );
    457             }
    458 
    459             $result = self::validate( $plugin->api_key, $plugin->number );
    460 
    461             /** @var  $ttl DateTime */
    462             $ttl        = $result->getTtl();
    463             $expires_at = $ttl->format( DATE_ATOM );
    464             $validation = json_encode( $result->getValidations() );
    465 
    466             $this->update_plugin( [
    467                 'expires_at' => $expires_at,
    468                 'validation' => $validation
    469             ], [ 'ID' => $plugin_id ] );
    470 
    471             $this->show_notice( __( 'Plugin(-s) have been validated', $this->plugin_text_domain ), 'success', true );
    472         } catch ( Exception $exception ) {
    473             $this->show_notice( $exception->getMessage(), 'error', true );
    474         }
     477        $this->bulk_validate( [ $plugin_id ] );
    475478    }
    476479
     
    489492
    490493            if ( ! $plugin ) {
    491                 throw new Exception( __( 'Plugin not found' ) );
    492             }
     494                throw new Exception( __( 'Plugin not found', $this->plugin_text_domain ) );
     495            }
     496
     497            $plugin_name = $this->get_plugin_name( $plugin->plugin_folder );
    493498
    494499            $validation_details = [];
    495500
    496             foreach ($plugin->validation as $data ) {
    497                 if ( $data['licensingModel'] === Constants::LICENSING_MODEL_MULTI_FEATURE ) {
    498                     foreach ( $data as $features ) {
    499                         if ( is_array( $features ) ) {
    500                             $feature                                       = reset( $features );
    501                             $validation_details[ $feature['featureName'] ] = $feature['valid'] === 'true';
     501            if ( ! empty( $plugin->validation_result ) ) {
     502                foreach ( $plugin->validation_result as $data ) {
     503                    if ( $data['licensingModel'] === Constants::LICENSING_MODEL_MULTI_FEATURE ) {
     504                        foreach ( $data as $features ) {
     505                            if ( is_array( $features ) ) {
     506                                $feature                                       = reset( $features );
     507                                $validation_details[ $feature['featureName'] ] = $feature['valid'] === 'true';
     508                            }
    502509                        }
     510
     511                        continue;
    503512                    }
    504513
    505                     continue;
    506                 }
    507 
    508                 $validation_details[ $data['productModuleName'] ] = $data['valid'] === 'true';
     514                    $validation_details[ $data['productModuleName'] ] = $data['valid'] === 'true';
     515                }
    509516            }
    510517
     
    525532     */
    526533    public function deregister_plugin( $plugin_id ) {
    527         // TODO: degeregister plugin
     534        $this->bulk_deregister( [ $plugin_id ] );
    528535    }
    529536
     
    531538     * Bulk validate plugins.
    532539     *
    533      * @param array $bulk_plugin_ids
    534      *
    535      * @since 1.0.0
    536      *
     540     * @param $plugin_ids
     541     *
     542     * @throws \ErrorException
     543     * @since 1.0.0
    537544     */
    538545    public function bulk_validate( $plugin_ids ) {
    539         // TODO: bulk plugin validate
     546        $errors = [];
     547
     548        $count = 0;
     549
     550        $has_consent = ! empty( $_GET['has_consent'] ) ? true : false;
     551
     552        $plugins = $this->get_plugins( [ 'ID' => $plugin_ids ] );
     553
     554        foreach ( $plugin_ids as $plugin_id ) {
     555            // get plugin
     556            $plugin = isset( $plugins[ $plugin_id ] ) ? $plugins[ $plugin_id ] : null;
     557
     558            try {
     559                if ( ! $plugin ) {
     560                    throw new Exception( sprintf( __( 'Plugin not found', $this->plugin_text_domain ) ) );
     561                }
     562
     563                if ( empty( $plugin->consented_at ) && ! $has_consent ) {
     564                    continue;
     565                }
     566
     567                $result = self::validate( $plugin->api_key, $plugin->product_number );
     568
     569                /** @var  $ttl DateTime */
     570                $ttl            = $result->getTtl();
     571                $expires_ttl_at = $ttl->format( DATE_ATOM );
     572                $validation     = json_encode( $result->getValidations() );
     573
     574                $data = [
     575                    'expires_ttl_at'    => $expires_ttl_at,
     576                    'validated_at'      => date( DATE_ATOM ),
     577                    'validation_result' => $validation,
     578                ];
     579
     580                if ( empty( $plugin->consented_at ) ) {
     581                    $data['consented_at'] = date( DATE_ATOM );
     582                }
     583
     584                $this->update_plugin( $data, [ 'ID' => $plugin_id ] );
     585
     586                $count ++;
     587            } catch ( RestException $rest_exception ) {
     588                $request = NetLicensingService::getInstance()->lastCurlInfo();
     589
     590                if ( $request->httpStatusCode === 401 ) {
     591                    $errors[] = sprintf( __( 'Failed to validate the plugin %s, please contact the plugin developer.', $this->plugin_text_domain ), $this->get_plugin_name( $plugin->plugin_folder ) );
     592                } else {
     593                    $errors[] = $rest_exception->getMessage();
     594                }
     595            } catch ( Exception $exception ) {
     596                $errors[] = $exception->getMessage();
     597            }
     598        }
     599
     600        if ( ! empty( $errors ) ) {
     601            foreach ( $errors as $error ) {
     602                $this->show_notice( $error, 'error', true );
     603            }
     604        }
     605
     606        if ( $count > 0 ) {
     607            $this->show_notice( $count . __( ' plugin(s) have been validated', $this->plugin_text_domain ), 'success', true );
     608        }
    540609    }
    541610
     
    543612     * Bulk deregister plugins.
    544613     *
    545      * @param array $bulk_plugin_ids
    546      *
    547      * @since 1.0.0
    548      *
     614     * @param $plugin_ids
    549615     */
    550616    public function bulk_deregister( $plugin_ids ) {
    551         // TODO: bulk deregister plugin
     617        $errors = [];
     618
     619        $count = 0;
     620
     621        $plugins = $this->get_plugins( [ 'ID' => $plugin_ids ] );
     622
     623        foreach ( $plugin_ids as $plugin_id ) {
     624            // get plugin
     625            $plugin = isset( $plugins[ $plugin_id ] ) ? $plugins[ $plugin_id ] : null;
     626
     627            try {
     628                if ( ! $plugin ) {
     629                    throw new Exception( sprintf( __( 'Plugin not found', $this->plugin_text_domain ) ) );
     630                }
     631
     632                $this->delete_plugin( [ 'ID' => $plugin_id ] );
     633
     634                $count ++;
     635            } catch ( Exception $exception ) {
     636                $errors[] = $exception->getMessage();
     637            }
     638        }
     639
     640        if ( ! empty( $errors ) ) {
     641            foreach ( $errors as $error ) {
     642                $this->show_notice( $error, 'error', true );
     643            }
     644        }
     645
     646        if ( $count > 0 ) {
     647            $this->show_notice( $count . __( ' plugin(s) have been deregistered', $this->plugin_text_domain ), 'success', true );
     648        }
    552649    }
    553650
     
    588685             </div>";
    589686    }
     687
     688    protected function get_plugin_name( $plugin_folder, $default = '' ) {
     689        return isset( get_plugins()[ $plugin_folder ]['Name'] ) ? get_plugins()[ $plugin_folder ]['Name'] : $default;
     690    }
    590691}
  • pluginpass-pro-plugintheme-licensing/trunk/inc/admin/js/pluginpass-admin.js

    r2137166 r2146523  
    1 (function( $ ) {
    2     'use strict';
     1(function ($) {
     2    'use strict';
    33
    4     /**
    5     * All of the code for your admin-facing JavaScript source
    6     * should reside in this file.
    7     *
    8     * Note: It has been assumed you will write jQuery code here, so the
    9     * $ function reference has been prepared for usage within the scope
    10     * of this function.
    11     *
    12     * This enables you to define handlers, for when the DOM is ready:
    13     *
    14     * $(function() {
    15     *
    16     * });
    17     *
    18     * When the window is loaded:
    19     *
    20     * $( window ).load(function() {
    21     *
    22     * });
    23     *
    24     * ...and/or other possibilities.
    25     *
    26     * Ideally, it is not considered best practise to attach more than a
    27     * single DOM-ready or window-load handler for a particular page.
    28     * Although scripts in the WordPress core, Plugins and Themes may be
    29     * practising this, we should strive to set a better example in our own work.
    30          *
    31          * The file is enqueued from inc/admin/class-admin.php.
    32     */
     4    /**
     5    * All of the code for your admin-facing JavaScript source
     6    * should reside in this file.
     7    *
     8    * Note: It has been assumed you will write jQuery code here, so the
     9    * $ function reference has been prepared for usage within the scope
     10    * of this function.
     11    *
     12    * This enables you to define handlers, for when the DOM is ready:
     13    *
     14    * $(function() {
     15    *
     16    * });
     17    *
     18    * When the window is loaded:
     19    *
     20    * $( window ).load(function() {
     21    *
     22    * });
     23    *
     24    * ...and/or other possibilities.
     25    *
     26    * Ideally, it is not considered best practise to attach more than a
     27    * single DOM-ready or window-load handler for a particular page.
     28    * Although scripts in the WordPress core, Plugins and Themes may be
     29    * practising this, we should strive to set a better example in our own work.
     30     *
     31     * The file is enqueued from inc/admin/class-admin.php.
     32    */
    3333
    34 })( jQuery );
     34    $(function () {
     35        $('.need-consent-before-validation').on('click', function (e) {
     36            e.preventDefault();
     37
     38            var href = $(e.target).attr('href');
     39
     40            var text = 'By choosing "Agree" validation request will be sent to the Labs64 NetLicensing ' +
     41                'to verify valid use of the plugin or theme.<br/>' +
     42                'Personal data transferred with this request such as Unique Identifiers, Plugin and Theme Details, ' +
     43                'WordPress Instance Name, Domain Name, System Details of the data subject.<br/><br/>' +
     44                'For more details on Labs64 NetLicensing data protection provisions visit ' +
     45                '<a target="_blank" href="https://www.labs64.com/legal/privacy-policy">Privacy Policy</a>' +
     46                ' and <a target="_blank" href="https://www.labs64.de/confluence/x/vQEKAQ">Privacy Center</a>';
     47
     48            Swal.fire({
     49                html: text,
     50                type: 'warning',
     51                showCancelButton: true,
     52                confirmButtonText: 'Agree',
     53                cancelButtonText: 'Cancel'
     54            }).then((result) => {
     55                if (result.value) {
     56                    window.location.href = href + '&has_consent=true';
     57                }
     58            })
     59        });
     60
     61        $('.need-deregister-confirmation').on('click', function (e) {
     62            e.preventDefault();
     63
     64            var href = $(e.target).attr('href');
     65
     66            Swal.fire({
     67                title:'Are you sure?',
     68                html: 'You won\'t be able to revert this!',
     69                type: 'warning',
     70                showCancelButton: true,
     71                confirmButtonText: 'Deregister',
     72                cancelButtonText: 'Cancel'
     73            }).then((result) => {
     74                if (result.value) {
     75                    window.location.href = href;
     76                }
     77            })
     78        });
     79
     80    });
     81})(jQuery);
  • pluginpass-pro-plugintheme-licensing/trunk/inc/admin/views/partials-pluginpass-validation-details.php

    r2137166 r2146523  
    77
    88<div class="wrap">
    9     <h2> <?php echo __('Plugin validation details for "' . $plugin->name . '"', $this->plugin_text_domain ); ?> </h2>
     9    <h2> <?php echo __( 'Plugin validation details for "' . $plugin_name . '"', $this->plugin_text_domain ); ?> </h2>
    1010
    1111    <div class="pluginpass-card">
    12         <ul class="list-group clear-list">
    13             <?php foreach ( $validation_details as $name => $valid ): ?>
    14                 <li class="list-group-item">
    15                     <span><?php echo $name; ?></span>
     12        <?php if ( ! $plugin->validated_at ): ?>
     13            <?php _e( 'Please go back and run validation first', $this->plugin_text_domain ) ?>
     14        <?php else: ?>
     15            <?php if ( ! empty( $validation_details ) ): ?>
     16                <ul class="list-group clear-list">
     17                    <?php foreach ( $validation_details as $name => $valid ): ?>
     18                        <li class="list-group-item">
     19                            <span><?php echo $name; ?></span>
    1620
    17                     <span class="float-right">
     21                            <span class="float-right">
    1822
    1923                        <?php if ( $valid ): ?>
     
    2327                        <?php endif; ?>
    2428                  </span>
    25                 </li>
    26             <?php endforeach; ?>
    27         </ul>
     29                        </li>
     30                    <?php endforeach; ?>
     31                </ul>
     32            <?php else: ?>
     33                <?php _e( 'No results', $this->plugin_text_domain ) ?>
     34            <?php endif; ?>
     35        <?php endif; ?>
    2836    </div>
    2937
    30     <a href="<?php echo esc_url( add_query_arg( array( 'page' => wp_unslash( $_REQUEST['page'] ) ) , admin_url( 'options-general.php' ) ) ); ?>">
    31         <?php _e( 'Back', $this->plugin_text_domain ) ?>
     38    <a href="<?php echo esc_url( add_query_arg( array( 'page' => wp_unslash( $_REQUEST['page'] ) ), admin_url( 'options-general.php' ) ) ); ?>">
     39        <?php _e( 'Back', $this->plugin_text_domain ) ?>
    3240    </a
    3341</div>
  • pluginpass-pro-plugintheme-licensing/trunk/inc/common/class-pluginpass-guard.php

    r2137441 r2146523  
    1212class PluginPass_Guard {
    1313    use PluginPass_Validatable {
    14         validate as restValidate;
     14        validate as protected restValidate;
    1515    }
    1616    use PluginPass_Plugable;
     
    1818    protected $plugin;
    1919
     20    protected $has_consent = false;
     21
    2022    /**
    2123     * Initialize and register plugin.
    2224     *
     25     * @param string $api_key NetLicensing APIKey.
     26     * @param string $product_number NetLicensing product number.
     27     * @param string $plugin_folder Relative path to single plugin folder.
     28     * @param boolean $has_consent Indicate whether the author of the plugin has the user's consent to the use his personal data.
     29     *
     30     * @throws \Exception
    2331     * @since 1.0.0
    2432     * @access   public
    25      * @param    string               $api_key             NetLicensing APIKey.
    26      * @param    string               $product_number      NetLicensing product number.
    27      * @param    string               $plugin_name         The plugin name.
    28      *
    29      * @throws \Exception
    3033     */
    31     public function __construct( $api_key, $product_number, $plugin_name ) {
    32         $this->plugin = $this->get_plugin( [ 'number' => $product_number ] );
     34    public function __construct( $api_key, $product_number, $plugin_folder, $has_consent = false ) {
     35        if ( ! array_key_exists( $plugin_folder, get_plugins() ) ) {
     36            throw new \Exception( 'Plugin on path "' . $plugin_folder . '" not found' );
     37        }
    3338
    34         if ( $this->is_plugin_not_exits_or_validation_expired() ) {
    35             /** @var  $result ValidationResults*/
    36             $result = self::restValidate( $api_key, $product_number );
     39        $this->plugin      = $this->get_plugin( [ 'product_number' => $product_number ] );
     40        $this->has_consent = $has_consent;
    3741
    38             /** @var  $ttl \DateTime */
    39             $ttl        = $result->getTtl();
    40             $expires_at = $ttl->format( \DateTime::ATOM );
    41             $validation_result = json_encode( $result->getValidations() );
     42        $data = [
     43            'product_number' => $product_number,
     44            'plugin_folder'  => $plugin_folder,
     45            'api_key'        => $api_key,
     46        ];
    4247
    43             $data = [
    44                 'number'     => $product_number,
    45                 'name'       => $plugin_name,
    46                 'api_key'    => $api_key,
    47                 'expires_at' => $expires_at,
    48                 'validation' => $validation_result,
    49             ];
     48        $this->plugin = ( ! $this->plugin )
     49            ? $this->create_plugin( $data )
     50            : $this->update_plugin( $data, [ 'product_number' => $product_number ] );
     51    }
    5052
    51             $this->plugin = ( ! $this->plugin )
    52                 ? $this->create_plugin( $data )
    53                 : $this->update_plugin( $data, [ 'number' => $product_number ] );
    54         }
     53    /**
     54     * Indicate whether the author of the plugin has the user's consent to the use his personal data.
     55     * @return bool
     56     */
     57    public function has_consent() {
     58        return ( ! empty( $this->plugin->consented_at ) || $this->has_consent );
    5559    }
    5660
     
    5862     * Validate plugin feature for the current wordpress instance.
    5963     *
     64     * @param string $feature The plugin feature to be checked.
     65     *
     66     * @return   boolean The status, whether this feature is available.
     67     * @throws \Exception
    6068     * @since 1.0.0
    6169     * @access   public
    62      * @param    string               $feature         The plugin feature to be checked.
    63      * @return   boolean                               The status, whether this feature is available.
    6470     */
    6571    public function validate( $feature ) {
    6672
    67         if ( ! PluginPass_Dot::has( $this->plugin->validation, $feature ) ) {
     73        if ( ! $this->has_consent() ) {
    6874            return false;
    6975        }
    7076
    71     $feature_parsed = explode( '.', $feature );
    72         $product_module = reset( $feature_parsed);
    73         $licensingModel = PluginPass_Dot::get( $this->plugin->validation, "$product_module.licensingModel" );
     77        if ( $this->is_validation_expired() ) {
     78            /** @var  $result ValidationResults */
     79            $result = self::restValidate( $this->plugin->api_key, $this->plugin->product_number );
     80
     81            /** @var  $ttl \DateTime */
     82            $ttl               = $result->getTtl();
     83            $expires_ttl_at    = $ttl->format( \DateTime::ATOM );
     84            $validation_result = json_encode( $result->getValidations() );
     85
     86            $data = [
     87                'expires_ttl_at'    => $expires_ttl_at,
     88                'validated_at'      => date( DATE_ATOM ),
     89                'validation_result' => $validation_result,
     90            ];
     91
     92            if ( empty( $this->plugin->consented_at ) ) {
     93                $data['consented_at'] = date( DATE_ATOM );
     94            }
     95
     96            $this->plugin = $this->update_plugin( $data, [ 'product_number' => $this->plugin->product_number ] );
     97        }
     98
     99        if ( ! $this->plugin->validation_result || ! PluginPass_Dot::has( $this->plugin->validation_result, $feature ) ) {
     100            return false;
     101        }
     102
     103        $feature_parsed = explode( '.', $feature );
     104        $product_module = reset( $feature_parsed );
     105        $licensingModel = PluginPass_Dot::get( $this->plugin->validation_result, "$product_module.licensingModel" );
    74106
    75107        if ( is_null( $licensingModel ) ) {
     
    80112            ? '.0.valid' : '.valid';
    81113
    82         return PluginPass_Dot::get( $this->plugin->validation, $feature ) === 'true';
     114        return PluginPass_Dot::get( $this->plugin->validation_result, $feature ) === 'true';
     115    }
     116
     117    /**
     118     * Get validation result for feature
     119     *
     120     * @param null $feature
     121     *
     122     * @return mixed
     123     */
     124    public function validation_result( $feature = null ) {
     125        if ( ! $feature ) {
     126            return $this->plugin->validation_result;
     127        }
     128
     129        return PluginPass_Dot::get( $this->plugin->validation_result, $feature );
    83130    }
    84131
     
    86133     * Redirect user to the Shop URL for license acquisition.
    87134     *
    88      * @since 1.0.0
    89      * @access   public
    90135     * @param string $successUrl
    91136     * @param string $successUrlTitle
    92137     * @param string $cancelUrl
    93138     * @param string $cancelUrlTitle
     139     *
     140     * @since 1.0.0
     141     * @access   public
    94142     */
    95143    public function open_shop( $successUrl = '', $successUrlTitle = '', $cancelUrl = '', $cancelUrlTitle = '' ) {
     
    104152     * Generate shop URL for license acquisition.
    105153     *
     154     * @param string $successUrl
     155     * @param string $successUrlTitle
     156     * @param string $cancelUrl
     157     * @param string $cancelUrlTitle
     158     *
     159     * @return string
    106160     * @since 1.0.0
    107161     * @access   public
    108162     */
    109     public function get_shop_url( $title, array $attrs = [], $successUrl = '', $successUrlTitle = '', $cancelUrl = '', $cancelUrlTitle = '' ) {
    110         $shopToken = $this->get_shop_token( $successUrl, $successUrlTitle, $cancelUrl, $cancelUrlTitle );
    111 
    112         $shopUrl = $shopToken->getShopURL();
    113 
    114         $attrsMap = array_map( function ( $key, $value ) {
    115             return "$key=\"$value\"";
    116         }, array_keys( $attrs ), $attrs );
    117 
    118         $attrsString = implode( " ", $attrsMap );
    119 
    120         echo "<a href='$shopUrl' $attrsString target='_blank'>$title</a>";
     163    public function get_shop_url( $successUrl = '', $successUrlTitle = '', $cancelUrl = '', $cancelUrlTitle = '' ) {
     164        return $this->get_shop_token( $successUrl, $successUrlTitle, $cancelUrl, $cancelUrlTitle )->getShopURL();
    121165    }
    122166
     
    147191    }
    148192
    149     protected function is_plugin_not_exits_or_validation_expired() {
    150         return ( ! $this->plugin || strtotime( $this->plugin->expires_at ) <= time() );
     193    protected function is_validation_expired() {
     194        return ( ! $this->plugin->expires_ttl_at || strtotime( $this->plugin->expires_ttl_at ) <= time() );
    151195    }
    152196}
  • pluginpass-pro-plugintheme-licensing/trunk/inc/common/traits/class-pluginpass-plugable.php

    r2137166 r2146523  
    1212
    1313    protected function get_plugin( array $where ) {
    14         global $wpdb;
     14        $results = $this->get_plugins( $where );
    1515
    16         $plugins_table = Activator::get_plugins_table_name();
    17 
    18         $queryWhere = implode( ' AND ', array_map( function ( $key, $value ) {
    19             return "$key='$value'";
    20         }, array_keys( $where ), $where ) );
    21 
    22         $plugin = $wpdb->get_row( "SELECT * FROM $plugins_table WHERE $queryWhere" );
    23 
    24         if ( $plugin ) {
    25             $plugin->validation = json_decode( $plugin->validation, true );
    26         }
    27 
    28         return $plugin;
     16        return is_array( $results ) ? reset( $results ) : $results;
    2917    }
    3018
     
    4230        $plugins_table = Activator::get_plugins_table_name();
    4331
    44         $result = $wpdb->insert( $plugins_table, array_merge( $data, [ 'validated_at' => date( DATE_ATOM ) ] ) );
     32        $result = $wpdb->insert( $plugins_table, $data );
    4533
    46         if ( ! $result ) {
     34        if ( $result === false ) {
    4735            throw new \Exception( 'Failed to save plugin validation data.' );
    4836        }
     
    6553        $plugins_table = Activator::get_plugins_table_name();
    6654
    67         $result = $wpdb->update( $plugins_table, array_merge( $data, [ 'validated_at' => date( DATE_ATOM ) ] ), $where );
     55        $result = $wpdb->update( $plugins_table, $data, $where );
    6856
    69         if ( ! $result ) {
     57        if ( $result === false ) {
    7058            throw new \Exception( 'Failed to update plugin validation data.' );
    7159        }
     
    7361        return $this->get_plugin( $where );
    7462    }
     63
     64    /**
     65     * Delete plugin data
     66     *
     67     * @param array $where
     68     *
     69     * @return false|int
     70     */
     71    protected function delete_plugin( array $where ) {
     72        global $wpdb;
     73
     74        $plugins_table = Activator::get_plugins_table_name();
     75
     76        return $wpdb->delete( $plugins_table, $where );
     77    }
     78
     79
     80    protected function get_plugins( array $where = [] ) {
     81        global $wpdb;
     82
     83        $plugins_table = Activator::get_plugins_table_name();
     84
     85        $query = "SELECT * FROM $plugins_table";
     86
     87        if ( ! empty( $where ) ) {
     88            $queryWhere = implode( ' AND ', array_map( function ( $key, $value ) {
     89                if ( is_array( $value ) ) {
     90                    $in = implode( '\',', $value );
     91
     92                    return "$key IN ('$in')";
     93                }
     94
     95                return "$key='$value'";
     96            }, array_keys( $where ), $where ) );
     97
     98            $query .= " WHERE $queryWhere";
     99        }
     100
     101        $results = $wpdb->get_results( $query );
     102
     103        $plugins = [];
     104
     105        if ( ! empty( $results ) ) {
     106            foreach ( $results as &$plugin ) {
     107                $plugin->validation_result = json_decode( $plugin->validation_result, true );
     108                $plugins[ $plugin->ID ]    = $plugin;
     109            }
     110
     111            return $plugins;
     112        }
     113
     114        return $results;
     115    }
    75116}
  • pluginpass-pro-plugintheme-licensing/trunk/inc/common/traits/class-pluginpass-validatable.php

    r2137166 r2146523  
    66use NetLicensing\Context;
    77use NetLicensing\LicenseeService;
     8use NetLicensing\NetLicensingService;
    89use NetLicensing\ValidationParameters;
     10use PluginPass as NS;
    911
    1012trait PluginPass_Validatable {
     
    2527        $validation_parameters->setLicenseeName( get_bloginfo( 'name' ) );
    2628
     29
     30        NetLicensingService::getInstance()->curl()->setUserAgent( 'NetLicensing/PHP/' . NS\PLUGIN_NAME . ' ' . PHP_VERSION . '/' . NS\PLUGIN_VERSION . ' (https://netlicensing.io)' . '; ' . $_SERVER['HTTP_USER_AGENT'] );
     31
    2732        return LicenseeService::validate( $context, self::get_licensee_number(), $validation_parameters );
    2833    }
  • pluginpass-pro-plugintheme-licensing/trunk/inc/core/class-activator.php

    r2137166 r2146523  
    4444        $sql = "CREATE TABLE $plugins_table (
    4545            ID bigint(20) NOT NULL AUTO_INCREMENT,
    46             number varchar(255) NOT NULL,
    47             name tinytext NOT NULL,
     46            plugin_folder varchar(255) NOT NULL,
     47            product_number varchar(255) NOT NULL,
    4848            api_key varchar(255) NOT NULL,
    49             validated_at timestamp,
    50             expires_at timestamp ,
    51             validation json NOT NULL,
     49            consented_at timestamp NULL DEFAULT NULL,
     50            validated_at timestamp NULL DEFAULT NULL,
     51            expires_ttl_at timestamp NULL DEFAULT NULL,
     52            validation_result json DEFAULT NULL,
    5253            PRIMARY KEY (ID)
    5354        ) $charset_collate;";
     
    5758        dbDelta( $sql );
    5859
    59         $indexes                 = $wpdb->get_results( "SHOW INDEX FROM $plugins_table" );
     60        $indexes           = $wpdb->get_results( "SHOW INDEX FROM $plugins_table" );
    6061        $number_index_name = 'pluginpass_pl_number';
    6162
     
    6970
    7071        if ( ! $is_unique_number_exists ) {
    71             $wpdb->query("CREATE UNIQUE INDEX $number_index_name ON $plugins_table (number)");
     72            $wpdb->query("CREATE UNIQUE INDEX $number_index_name ON $plugins_table (product_number)");
    7273        }
    7374
  • pluginpass-pro-plugintheme-licensing/trunk/pluginpass.php

    r2137441 r2146523  
    1616 * Plugin URI:        https://github.com/Labs64/PluginPass
    1717 * Description:       WordPress Plugin/Theme Licensing powered by Labs64 NetLicensing
    18  * Version:           0.9.2
     18 * Version:           0.9.3
    1919 * Author:            Labs64
    2020 * Author URI:        https://netlicensing.io
Note: See TracChangeset for help on using the changeset viewer.