diff --git a/app/Captures.php b/app/Captures.php new file mode 100644 index 0000000..3fa80b8 --- /dev/null +++ b/app/Captures.php @@ -0,0 +1,9 @@ += $required_version ) { + if ( $version >= $required_version and $force != true ) { echo "Not needed `captaincore_db_version` is v{$version} and required v{$required_version}."; } @@ -181,6 +181,18 @@ class DB { PRIMARY KEY (log_id) ) $charset_collate;"; + dbDelta($sql); + + $sql = "CREATE TABLE `{$wpdb->base_prefix}captaincore_captures` ( + capture_id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, + site_id bigint(20) UNSIGNED NOT NULL, + environment_id bigint(20) UNSIGNED NOT NULL, + created_at datetime NOT NULL DEFAULT '0000-00-00 00:00:00', + git_commit varchar(100), + pages longtext, + PRIMARY KEY (capture_id) + ) $charset_collate;"; + dbDelta($sql); $sql = "CREATE TABLE `{$wpdb->base_prefix}captaincore_quicksaves` ( @@ -241,6 +253,7 @@ class DB { core varchar(10), subsite_count varchar(10), home_url varchar(255), + capture_pages longtext, themes longtext, plugins longtext, users longtext, @@ -291,7 +304,7 @@ class DB { dbDelta($sql); - // Permission/relationships data stucture for CaptainCore: https://dbdiagram.io/d/5d7d409283427516dc0ba8b3 + // Permission/relationships data structure for CaptainCore: https://dbdiagram.io/d/5d7d409283427516dc0ba8b3 $sql = "CREATE TABLE `{$wpdb->base_prefix}captaincore_accounts` ( account_id bigint(20) UNSIGNED NOT NULL AUTO_INCREMENT, name varchar(255), diff --git a/app/Site.php b/app/Site.php index fccb3d9..0fff70f 100644 --- a/app/Site.php +++ b/app/Site.php @@ -162,6 +162,7 @@ class Site { 'update_logs' => 'Loading', 'quicksave_panel' => [], 'quicksave_search' => '', + 'capture_pages' => json_decode ( $environments[0]->capture_pages ), 'core' => $environments[0]->core, 'home_url' => $environments[0]->home_url, 'updates_enabled' => intval( $environments[0]->updates_enabled ), @@ -255,6 +256,7 @@ class Site { 'update_logs' => 'Loading', 'quicksave_panel' => [], 'quicksave_search' => '', + 'capture_pages' => json_decode ( $environments[1]->capture_pages ), 'core' => $environments[1]->core, 'home_url' => $environments[1]->home_url, 'updates_enabled' => intval( $environments[1]->updates_enabled ), @@ -618,4 +620,28 @@ class Site { } + public function captures( $environment = "production" ) { + + if ( $environment == "production" ) { + $environment_id = get_field( 'environment_production_id', $this->site_id ); + } + if ( $environment == "staging" ) { + $environment_id = get_field( 'environment_staging_id', $this->site_id ); + } + + $captures = new Captures(); + $results = $captures->where( [ "site_id" => $this->site_id, "environment_id" => $environment_id ] ); + + foreach ( $results as $result ) { + $created_at_friendly = new \DateTime( $result->created_at ); + $created_at_friendly->setTimezone( new \DateTimeZone( get_option( 'gmt_offset' ) ) ); + $created_at_friendly = date_format( $created_at_friendly, 'D, M jS Y g:i a'); + $result->created_at_friendly = $created_at_friendly; + $result->pages = json_decode( $result->pages ); + } + + return $results; + + } + } \ No newline at end of file diff --git a/captaincore.php b/captaincore.php index 29049a1..e5d8bde 100755 --- a/captaincore.php +++ b/captaincore.php @@ -1591,6 +1591,74 @@ function captaincore_api_func( WP_REST_Request $request ) { } } + // Add capture + if ( $command == 'new-capture' ) { + + print_r( $data ); + + if ( $environment == "production" ) { + $environment_id = get_field( 'environment_production_id', $site_id ); + } + if ( $environment == "staging" ) { + $environment_id = get_field( 'environment_staging_id', $site_id ); + } + + $captures = new CaptainCore\Captures(); + $capture_lookup = $captures->where( [ "site_id" => $site_id, "environment_id" => $environment_id ] ); + if ( count( $capture_lookup ) > 0 ) { + $current_capture_pages = json_decode( $capture_lookup[0]->pages ); + } + + $git_commit_short = substr( $data->git_commit, 0, 7 ); + $image_ending = "_{$data->created_at}_{$git_commit_short}.jpg"; + $capture_pages = explode( ",", $data->capture_pages ); + $captured_pages = explode( ",", $data->captured_pages ); + $pages = []; + foreach( $capture_pages as $page ) { + $page_name = str_replace( "/", "#", $page ); + + // Add page with new screenshot + if ( in_array( $page, $captured_pages ) ) { + $pages[] = [ + "name" => $page, + "image" => "{$page_name}{$image_ending}", + ]; + continue; + } + + // Lookup current image from DB + $current_image = ""; + foreach($current_capture_pages as $current_capture_page) { + if ($page == $current_capture_page->name) { + $current_image = $current_capture_page->image; + break; + } + } + + // Otherwise add image to current screenshot + $pages[] = [ + "name" => $page, + "image" => $current_image, + ]; + } + + // Format for mysql timestamp format. Changes "1530817828" to "2018-06-20 09:15:20" + $epoch = $data->created_at; + $created_at = new DateTime("@$epoch"); // convert UNIX timestamp to PHP DateTime + $created_at = $created_at->format('Y-m-d H:i:s'); // output = 2017-01-01 00:00:00 + + $new_capture = array( + 'site_id' => $site_id, + 'environment_id' => $environment_id, + 'created_at' => $created_at, + 'git_commit' => $data->git_commit, + 'pages' => json_encode( $pages ), + ); + + $capture = new CaptainCore\Captures(); + $capture->insert( $new_capture ); + } + // Imports update log if ( $command == 'import-quicksaves' ) { @@ -1825,6 +1893,13 @@ function captaincore_site_snapshot_download_func( $request ) { exit; } +function captaincore_site_captures_func( $request ) { + $site_id = $request['id']; + $environment = $request['environment']; + $site = new CaptainCore\Site( $site_id ); + return $site->captures( $environment ); +} + function captaincore_site_quicksaves_func( $request ) { $site_id = $request['id']; @@ -2102,7 +2177,7 @@ function captaincore_register_rest_endpoints() { ) ); - // Custom endpoint for CaptainCore site + // Custom endpoint for CaptainCore site//quicksaves register_rest_route( 'captaincore/v1', '/site/(?P[\d]+)/quicksaves', array( 'methods' => 'GET', @@ -2111,7 +2186,16 @@ function captaincore_register_rest_endpoints() { ) ); - // Custom endpoint for CaptainCore site + // Custom endpoint for CaptainCore site//captures + register_rest_route( + 'captaincore/v1', '/site/(?P[\d]+)/(?P[a-zA-Z0-9-]+)/captures', array( + 'methods' => 'GET', + 'callback' => 'captaincore_site_captures_func', + 'show_in_index' => false + ) + ); + + // Custom endpoint for CaptainCore site//snapshots register_rest_route( 'captaincore/v1', '/site/(?P[\d]+)/snapshots', array( 'methods' => 'GET', @@ -4043,6 +4127,32 @@ function captaincore_ajax_action_callback() { } + if ( $cmd == 'updateCapturePages' ) { + + $db_environments = new CaptainCore\Environments(); + $value_json = json_encode($value); + + // Saves update settings for a site + $environment_update = array( + 'capture_pages' => $value_json, + ); + $environment_update['updated_at'] = date("Y-m-d H:i:s"); + + if ($environment == "Production") { + $environment_id = get_field( 'environment_production_id', $post_id ); + $db_environments->update( $environment_update, [ "environment_id" => $environment_id ] ); + } + if ($environment == "Staging") { + $environment_id = get_field( 'environment_staging_id', $post_id ); + $db_environments->update( $environment_update, [ "environment_id" => $environment_id ] ); + } + + // Remote Sync + $remote_command = true; + $command = "site update-field $site capture_pages $value_json"; + + } + if ( $cmd == 'fetchLink' ) { // Fetch snapshot details $db = new CaptainCore\Snapshots; diff --git a/templates/core.php b/templates/core.php index ac4d077..1158f69 100644 --- a/templates/core.php +++ b/templates/core.php @@ -1614,17 +1614,89 @@ if ( $role_check ) { - Will turn off search privacy and update development urls to the following live urls.

- - - Launch Site - + Will turn off search privacy and update development urls to the following live urls.

+ + + Launch Site +
+ + + + + close + + Historical Captures of {{ dialog_captures.site.name }} + + + + + + + + + +
+ +
+
+ +
+ + + + Configure pages to capture + + +
+ + + + + close + + Configured pages to capture. + + + Should start with a /. Example use / for the homepage and /contact for the the contact page. + +

mdi-plus-box

+

Save Pages

+
+
+ + + + + There are no historical captures, yet. + + + + +
+
+
- +
@@ -3807,12 +3879,14 @@ new Vue({ drawer: null, billing_link: "", home_link: "", + remote_upload_uri: "", loading_page: true, expanded: [], accounts: [], account_tab: null, modules: { dns: }, dialog_bulk: { show: false, tabs_management: "tab-Sites", environment_selected: "Production" }, + dialog_captures: { site: {}, pages: [{ page: ""}], capture: { pages: [] }, image_path:"", selected_page: "", captures: [], mode: "screenshot", loading: true, show: false, show_configure: false }, dialog_delete_user: { show: false, site: {}, users: [], username: "", reassign: {} }, dialog_apply_https_urls: { show: false, site_id: "", site_name: "", sites: [] }, dialog_copy_site: { show: false, site: {}, options: [], destination: "" }, @@ -4071,6 +4145,9 @@ new Vue({ } }, filters: { + safeUrl: function( url ) { + return url.replace('#', '%23' ) + }, timeago: function( timestamp ){ return moment.utc( timestamp, "YYYY-MM-DD hh:mm:ss").fromNow(); }, @@ -4180,6 +4257,16 @@ new Vue({ return this.dialog_configure_defaults.record.default_recipes; } }, + dialogCapturesPagesText() { + if ( typeof this.dialog_captures.capture.pages == 'undefined' ) { + return "" + } + if ( this.dialog_captures.capture.pages.length == 1 ) { + return "Page" + } else { + return "Pages" + } + }, runningJobs() { return this.jobs.filter(job => job.status != 'done' && job.status != 'error' ).length; }, @@ -6047,6 +6134,53 @@ new Vue({ .catch( error => console.log( error ) ); }, + showCaptures( site_id ) { + site = this.sites.filter( site => site.id == site_id )[0]; + this.dialog_captures.site = site; + environment = site.environments.filter( e => e.environment == site.environment_selected )[0]; + this.dialog_captures.pages = environment.capture_pages + if ( environment.capture_pages == "" || environment.capture_pages == null ) { + this.dialog_captures.pages = [{ page: "/" }] + } + this.dialog_captures.loading = true + this.dialog_captures.show = true; + this.dialog_captures.selected_page + axios.get( + `/wp-json/captaincore/v1/site/${site_id}/${site.environment_selected.toLowerCase()}/captures`, { + headers: {'X-WP-Nonce':this.wp_nonce} + }) + .then(response => { + this.dialog_captures.image_path = this.remote_upload_uri + site.site + "_" + site.id + "/" + site.environment_selected.toLowerCase() + "/captures/" + this.dialog_captures.captures = response.data + if ( this.dialog_captures.captures.length > 0 ) { + this.dialog_captures.capture = this.dialog_captures.captures[0] + this.dialog_captures.selected_page = this.dialog_captures.capture.pages[0] + } + this.dialog_captures.loading = false + }); + }, + closeCaptures() { + this.dialog_captures = { site: {}, pages: [{ page: ""}], capture: { pages: [] }, image_path:"", selected_page: "", captures: [], mode: "screenshot", loading: true, show: false, show_configure: false }; + }, + addAdditionalCapturePage() { + this.dialog_captures.pages.push({ page: "/" }); + }, + updateCapturePages() { + var data = { + action: 'captaincore_ajax', + post_id: this.dialog_captures.site.id, + command: 'updateCapturePages', + environment: this.dialog_captures.site.environment_selected, + value: this.dialog_captures.pages, + }; + + axios.post( ajaxurl, Qs.stringify( data ) ) + .then( response => { + this.dialog_captures.show = false; + this.dialog_captures.pages = []; + }) + .catch( error => console.log( error ) ); + }, toggleSite( site_id ) { site = this.sites.filter( site => site.id == site_id )[0]; this.dialog_toggle.show = true;