initial
This commit is contained in:
@@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
namespace Vrts\Services;
|
||||
|
||||
use Vrts\Tables\Alerts_Table;
|
||||
|
||||
class Alert_Service {
|
||||
|
||||
/**
|
||||
* Create alert from comparison.
|
||||
*
|
||||
* @param int $post_id Post ID.
|
||||
* @param int $test_id Test ID.
|
||||
* @param array $comparison Comparison.
|
||||
* @param object $test_run Test run.
|
||||
*/
|
||||
public function create_alert_from_comparison( $post_id, $test_id, $comparison, $test_run = null ) {
|
||||
global $wpdb;
|
||||
$table_alert = Alerts_Table::get_table_name();
|
||||
|
||||
$prepare_alert = [];
|
||||
$prepare_alert['post_id'] = $post_id;
|
||||
$prepare_alert['screenshot_test_id'] = $test_id;
|
||||
$prepare_alert['target_screenshot_url'] = $comparison['screenshot']['image_url'];
|
||||
$prepare_alert['target_screenshot_finish_date'] = $comparison['screenshot']['updated_at'];
|
||||
$prepare_alert['base_screenshot_url'] = $comparison['base_screenshot']['image_url'];
|
||||
$prepare_alert['base_screenshot_finish_date'] = $comparison['base_screenshot']['updated_at'];
|
||||
$prepare_alert['comparison_screenshot_url'] = $comparison['image_url'];
|
||||
$prepare_alert['comparison_id'] = $comparison['id'];
|
||||
$prepare_alert['differences'] = $comparison['pixels_diff'];
|
||||
$prepare_alert['test_run_id'] = $test_run ? $test_run->id : null;
|
||||
$prepare_alert['meta'] = maybe_serialize( $comparison['meta'] ?? [] );
|
||||
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- It's ok.
|
||||
if ( $wpdb->insert( $table_alert, $prepare_alert ) ) {
|
||||
$alert_id = $wpdb->insert_id;
|
||||
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- It's ok.
|
||||
$wpdb->update(
|
||||
$table_alert,
|
||||
[ 'title' => '#' . $alert_id ],
|
||||
[ 'id' => $alert_id ]
|
||||
);
|
||||
}
|
||||
|
||||
return $alert_id;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
namespace Vrts\Services;
|
||||
|
||||
use Vrts\Models\Alert;
|
||||
use Vrts\Models\Test;
|
||||
use Vrts\Models\Test_Run;
|
||||
|
||||
class Email_Service {
|
||||
|
||||
/**
|
||||
* Send Test Run email.
|
||||
*
|
||||
* @param int $test_run_id the id of the test run.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function send_test_run_email( $test_run_id ) {
|
||||
$subject = sprintf(
|
||||
/* translators: %1$s: the id of the test run, %2$s: home url */
|
||||
esc_html_x( 'VRTs: Run #%1$s (%2$s)', 'test run notification email subject', 'visual-regression-tests' ),
|
||||
$test_run_id,
|
||||
esc_url( home_url() )
|
||||
);
|
||||
|
||||
$data = $this->get_test_run_email_data( $test_run_id );
|
||||
$message = vrts()->get_component( 'emails/test-run', $data );
|
||||
|
||||
$headers = [
|
||||
'Content-Type: text/html; charset=UTF-8',
|
||||
];
|
||||
|
||||
$emails = $this->get_test_run_emails( $data['run'] );
|
||||
|
||||
if ( $emails ) {
|
||||
remove_filter( 'wp_mail', 'wp_staticize_emoji_for_email' );
|
||||
return wp_mail( $emails, wp_specialchars_decode( $subject ), $message, $headers );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the emails for the test run.
|
||||
*
|
||||
* @param object $run the test run.
|
||||
*
|
||||
* @return array Email addresses.
|
||||
*/
|
||||
private function get_test_run_emails( $run ) {
|
||||
$emails = [];
|
||||
$trigger = $run->trigger;
|
||||
|
||||
switch ( $trigger ) {
|
||||
case 'manual':
|
||||
$meta = maybe_unserialize( $run->trigger_meta );
|
||||
$user = get_user_by( 'ID', $meta['user_id'] ?? 0 );
|
||||
if ( $user ) {
|
||||
$emails = [ $user->user_email ];
|
||||
}
|
||||
break;
|
||||
case 'api':
|
||||
$emails = vrts()->settings()->get_option( 'vrts_email_api_notification_address' );
|
||||
break;
|
||||
case 'update':
|
||||
$emails = vrts()->settings()->get_option( 'vrts_email_update_notification_address' );
|
||||
break;
|
||||
default:
|
||||
$emails = vrts()->settings()->get_option( 'vrts_email_notification_address' );
|
||||
break;
|
||||
}
|
||||
|
||||
return $emails;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data for the test run email.
|
||||
*
|
||||
* @param int $run_id the id of the test run.
|
||||
*/
|
||||
private function get_test_run_email_data( $run_id ) {
|
||||
$run = Test_Run::get_item( $run_id );
|
||||
$tests = maybe_unserialize( $run->tests );
|
||||
$alerts = Alert::get_items_by_test_run( $run_id );
|
||||
|
||||
if ( is_array( $tests ) && count( $tests ) > 0 && ! is_array( $tests[0] ) ) {
|
||||
$tests = array_map( function ( $test ) {
|
||||
$test = (int) $test;
|
||||
$post_id = Test::get_post_id( $test );
|
||||
return [
|
||||
'id' => $test,
|
||||
'post_id' => $post_id,
|
||||
'post_title' => get_the_title( $post_id ),
|
||||
'permalink' => get_permalink( $post_id ),
|
||||
];
|
||||
}, $tests );
|
||||
}
|
||||
usort( $tests, function ( $a, $b ) {
|
||||
return $a['post_id'] > $b['post_id'] ? -1 : 1;
|
||||
} );
|
||||
|
||||
$data = [
|
||||
'run' => $run,
|
||||
'tests' => $tests,
|
||||
'alerts' => $alerts,
|
||||
];
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Preview test run email.
|
||||
*
|
||||
* @param int $run_id the id of the test run.
|
||||
*/
|
||||
public function preview_test_run_email( $run_id ) {
|
||||
$data = $this->get_test_run_email_data( $run_id );
|
||||
vrts()->component( 'emails/test-run', $data );
|
||||
}
|
||||
}
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
namespace Vrts\Services;
|
||||
|
||||
use Vrts\Features\Cron_Jobs;
|
||||
use Vrts\Features\Service;
|
||||
use Vrts\Features\Subscription;
|
||||
use Vrts\Models\Test;
|
||||
|
||||
class Manual_Test_Service {
|
||||
const OPTION_NAME_STATUS = 'vrts_run_manual_test_is_active';
|
||||
|
||||
/**
|
||||
* Check whether the option is set to true.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function get_option() {
|
||||
return get_option( self::OPTION_NAME_STATUS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the option.
|
||||
*
|
||||
* @param int $status Status 1 for success, 2 for failure.
|
||||
*/
|
||||
public function set_option( $status = 1 ) {
|
||||
update_option( self::OPTION_NAME_STATUS, $status );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the option.
|
||||
*/
|
||||
public function delete_option() {
|
||||
delete_option( self::OPTION_NAME_STATUS );
|
||||
}
|
||||
|
||||
/**
|
||||
* Run manual tests.
|
||||
*
|
||||
* @param array|null $test_ids Array of test ids.
|
||||
*/
|
||||
public function run_tests( $test_ids = null ) {
|
||||
$has_subscription = Subscription::get_subscription_status();
|
||||
if ( ! $has_subscription ) {
|
||||
return false;
|
||||
}
|
||||
if ( empty( $test_ids ) ) {
|
||||
$tests = Test::get_all_running();
|
||||
} else {
|
||||
$tests = Test::get_items_by_ids( $test_ids );
|
||||
}
|
||||
$service_test_ids = array_map( function ( $test ) {
|
||||
return $test->service_test_id;
|
||||
}, $tests );
|
||||
self::set_option();
|
||||
$request = Service::run_manual_tests( $service_test_ids, [
|
||||
'trigger_meta' => [ 'user_id' => get_current_user_id() ],
|
||||
] );
|
||||
|
||||
$test_ids = array_map( function ( $test ) {
|
||||
return $test->id;
|
||||
}, $tests );
|
||||
|
||||
if ( 201 === $request['status_code'] ) {
|
||||
self::set_option( 1 );
|
||||
$response = $request['response'];
|
||||
$service = new Test_Run_Service();
|
||||
$id = $service->create_test_run( $response['id'], [
|
||||
'tests' => maybe_serialize( $test_ids ),
|
||||
'trigger' => 'manual',
|
||||
'started_at' => current_time( 'mysql' ),
|
||||
] );
|
||||
Cron_Jobs::schedule_initial_fetch_test_run_updates( $id );
|
||||
} else {
|
||||
self::set_option( 2 );
|
||||
}
|
||||
}
|
||||
}
|
||||
+169
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
|
||||
namespace Vrts\Services;
|
||||
|
||||
use Vrts\Features\Service;
|
||||
use Vrts\Features\Subscription;
|
||||
use Vrts\Models\Test;
|
||||
use Vrts\Models\Test_Run;
|
||||
use Vrts\Services\Email_Service;
|
||||
|
||||
class Test_Run_Service {
|
||||
|
||||
/**
|
||||
* Create test from API data.
|
||||
*
|
||||
* @param array $data Data.
|
||||
* @param bool $with_cleanup With cleanup.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function update_run_from_api_data( $data, $with_cleanup = true ) {
|
||||
$run_id = $data['run_id'];
|
||||
|
||||
if ( empty( $run_id ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$test_run = Test_Run::get_by_service_test_run_id( $run_id );
|
||||
|
||||
$test_run_just_finished = false;
|
||||
|
||||
if ( $test_run && empty( $test_run->finished_at ) && ! empty( $data['finished_at'] ) ) {
|
||||
$test_run_just_finished = true;
|
||||
$alert_ids = $this->update_tests_and_create_alerts( $data['comparisons'], $test_run );
|
||||
}
|
||||
|
||||
$test_ids = empty( $data['comparison_schedule_ids'] ) ? [] : array_map(function ( $test ) {
|
||||
return [
|
||||
'id' => $test->id,
|
||||
'post_id' => $test->post_id,
|
||||
'post_title' => get_the_title( $test->post_id ),
|
||||
'permalink' => get_permalink( $test->post_id ),
|
||||
];
|
||||
}, Test::get_by_service_test_ids( $data['comparison_schedule_ids'] ));
|
||||
|
||||
$test_run_id = $this->create_test_run( $data['run_id'], [
|
||||
'tests' => maybe_serialize( $test_ids ),
|
||||
'started_at' => $data['started_at'],
|
||||
'finished_at' => $data['finished_at'],
|
||||
'scheduled_at' => $data['scheduled_at'],
|
||||
'trigger' => $data['trigger'],
|
||||
'trigger_notes' => $data['trigger_notes'],
|
||||
'trigger_meta' => maybe_serialize( $data['trigger_meta'] ),
|
||||
], true, $with_cleanup );
|
||||
|
||||
if ( $test_run_just_finished && ! empty( $alert_ids ) ) {
|
||||
$email_service = new Email_Service();
|
||||
$email_service->send_test_run_email( $test_run_id );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update tests and create alerts.
|
||||
*
|
||||
* @param array $comparisons Comparisons.
|
||||
* @param object $test_run Test run.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function update_tests_and_create_alerts( $comparisons, $test_run ) {
|
||||
$alert_ids = [];
|
||||
|
||||
foreach ( $comparisons as $comparison ) {
|
||||
$test_id = $comparison['comparison_schedule_id'];
|
||||
$alert_id = null;
|
||||
|
||||
if ( $comparison['pixels_diff'] > 1 && ! $comparison['matches_false_positive'] ) {
|
||||
$post_id = Test::get_post_id_by_service_test_id( $test_id );
|
||||
$alert_service = new Alert_Service();
|
||||
$alert_id = $alert_service->create_alert_from_comparison( $post_id, $test_id, $comparison, $test_run );
|
||||
$alert_ids[] = $alert_id;
|
||||
}//end if
|
||||
|
||||
$test_service = new Test_Service();
|
||||
$test_service->update_test_from_comparison( $alert_id, $test_id, [
|
||||
'comparison' => $comparison,
|
||||
] );
|
||||
}
|
||||
return $alert_ids;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create test run.
|
||||
*
|
||||
* @param string $service_test_run_id Service test run id.
|
||||
* @param array $data Data.
|
||||
* @param bool $update Update.
|
||||
* @param bool $with_cleanup With cleanup.
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function create_test_run( $service_test_run_id, $data, $update = false, $with_cleanup = true ) {
|
||||
$test_run = Test_Run::get_by_service_test_run_id( $service_test_run_id );
|
||||
|
||||
if ( $test_run && ! $update ) {
|
||||
return false;
|
||||
}
|
||||
$test_run_id = Test_Run::save(array_merge( $data, [
|
||||
'service_test_run_id' => $service_test_run_id,
|
||||
]), $test_run->id ?? null);
|
||||
if ( $with_cleanup ) {
|
||||
Test_Run::delete_duplicates();
|
||||
Test_Run::delete_empty();
|
||||
$this->check_stalled_test_runs();
|
||||
}
|
||||
return $test_run_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check stalled test runs.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function check_stalled_test_runs() {
|
||||
$test_run_ids = array_column( Test_Run::get_stalled_test_run_ids(), 'service_test_run_id' );
|
||||
if ( empty( $test_run_ids ) ) {
|
||||
return;
|
||||
}
|
||||
$response = Service::fetch_test_runs( $test_run_ids );
|
||||
if ( 200 === $response['status_code'] ) {
|
||||
$test_runs = $response['response']['data'] ?? [];
|
||||
foreach ( $test_runs as $test_run ) {
|
||||
$this->update_run_from_api_data( $test_run, false );
|
||||
}
|
||||
$missing_test_run_ids = array_diff( $test_run_ids, array_column( $test_runs, 'run_id' ) );
|
||||
foreach ( $missing_test_run_ids as $missing_test_run_id ) {
|
||||
Test_Run::delete_by_service_test_run_id( $missing_test_run_id );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and update tests.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function fetch_and_update_test_runs() {
|
||||
$service_request = Service::fetch_updates();
|
||||
if ( 200 === $service_request['status_code'] ) {
|
||||
$response = $service_request['response'];
|
||||
if ( array_key_exists( 'run_updates', $response ) ) {
|
||||
$updates = $response['run_updates'];
|
||||
foreach ( $updates as $update ) {
|
||||
$this->update_run_from_api_data( $update, false );
|
||||
}
|
||||
}
|
||||
if (
|
||||
array_key_exists( 'remaining_credits', $response )
|
||||
&& array_key_exists( 'total_credits', $response )
|
||||
&& array_key_exists( 'has_subscription', $response )
|
||||
&& array_key_exists( 'tier_id', $response )
|
||||
) {
|
||||
Subscription::update_available_tests( $response['remaining_credits'], $response['total_credits'], $response['has_subscription'], $response['tier_id'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,471 @@
|
||||
<?php
|
||||
|
||||
namespace Vrts\Services;
|
||||
|
||||
use Vrts\Features\Cron_Jobs;
|
||||
use Vrts\Features\Service;
|
||||
use Vrts\Features\Subscription;
|
||||
use Vrts\Models\Alert;
|
||||
use Vrts\Models\Test;
|
||||
use Vrts\Tables\Alerts_Table;
|
||||
use Vrts\Tables\Tests_Table;
|
||||
use WP_Error;
|
||||
|
||||
class Test_Service {
|
||||
|
||||
/**
|
||||
* Update tests from comparison.
|
||||
*
|
||||
* @param int $alert_id Alert id.
|
||||
* @param int $test_id Test id.
|
||||
* @param array $data Comparison data.
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public function update_test_from_comparison( $alert_id, $test_id, $data ) {
|
||||
global $wpdb;
|
||||
$table_test = Tests_Table::get_table_name();
|
||||
$comparison = $data['comparison'];
|
||||
if ( $comparison['screenshot']['image_url'] ?? null ) {
|
||||
// Update test row with new id foreign key and add latest screenshot.
|
||||
$update_data = [
|
||||
'next_run_date' => $data['next_run_at'] ?? '',
|
||||
'last_comparison_date' => $comparison['updated_at'],
|
||||
'base_screenshot_url' => $comparison['screenshot']['image_url'],
|
||||
'base_screenshot_date' => $comparison['screenshot']['updated_at'],
|
||||
'is_running' => false,
|
||||
];
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- It's ok.
|
||||
return $wpdb->update(
|
||||
$table_test,
|
||||
$update_data,
|
||||
[ 'service_test_id' => $test_id ]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update test from schedule.
|
||||
*
|
||||
* @param int $test_id Test id.
|
||||
* @param array $data Screenshot data.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function update_test_from_schedule( $test_id, $data ) {
|
||||
global $wpdb;
|
||||
$table_test = Tests_Table::get_table_name();
|
||||
$screenshot = $data['schedule']['base_screenshot'];
|
||||
if ( $screenshot['image_url'] ?? null ) {
|
||||
// Update test row with new id foreign key and add latest screenshot.
|
||||
// phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- It's ok.
|
||||
$wpdb->update(
|
||||
$table_test,
|
||||
[
|
||||
'base_screenshot_url' => $screenshot['image_url'],
|
||||
'base_screenshot_date' => $screenshot['updated_at'],
|
||||
'next_run_date' => $data['next_run_at'] ?? '',
|
||||
],
|
||||
[ 'service_test_id' => $test_id ]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create test from API data.
|
||||
*
|
||||
* @param array $data Data.
|
||||
*
|
||||
* @return int|false
|
||||
*/
|
||||
public function update_test_from_api_data( $data ) {
|
||||
$test_id = $data['test_id'];
|
||||
$post_id = Test::get_post_id_by_service_test_id( $test_id );
|
||||
|
||||
if ( $post_id ) {
|
||||
if ( $data['schedule']['base_screenshot'] ?? null ) {
|
||||
$this->update_test_from_schedule( $test_id, $data );
|
||||
} elseif ( $data['comparison'] ?? null ) {
|
||||
$alert_id = null;
|
||||
if ( $data['comparison']['pixels_diff'] > 1 && ! $data['matches_false_positive'] ) {
|
||||
$comparison = $data['comparison'];
|
||||
$alert_service = new Alert_Service();
|
||||
$alert_id = $alert_service->create_alert_from_comparison( $post_id, $test_id, $comparison );
|
||||
}//end if
|
||||
$test_service = new Test_Service();
|
||||
$test_service->update_test_from_comparison( $alert_id, $test_id, $data );
|
||||
}//end if
|
||||
return true;
|
||||
}//end if
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch and update tests.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function fetch_and_update_tests() {
|
||||
$service_request = Service::fetch_updates();
|
||||
if ( 200 === $service_request['status_code'] ) {
|
||||
$response = $service_request['response'];
|
||||
if ( array_key_exists( 'updates', $response ) ) {
|
||||
$updates = $response['updates'];
|
||||
foreach ( $updates as $update ) {
|
||||
$this->update_test_from_api_data( $update );
|
||||
}
|
||||
}
|
||||
if (
|
||||
array_key_exists( 'remaining_credits', $response )
|
||||
&& array_key_exists( 'total_credits', $response )
|
||||
&& array_key_exists( 'has_subscription', $response )
|
||||
&& array_key_exists( 'tier_id', $response )
|
||||
) {
|
||||
Subscription::update_available_tests( $response['remaining_credits'], $response['total_credits'], $response['has_subscription'], $response['tier_id'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create test.
|
||||
*
|
||||
* @param int $post_id Post id.
|
||||
*
|
||||
* @return int|WP_Error
|
||||
*/
|
||||
public function create_test( $post_id ) {
|
||||
if ( Service::is_connected() ) {
|
||||
$post = get_post( $post_id );
|
||||
if ( ! $post ) {
|
||||
return new WP_Error( 'vrts_post_error', __( 'Post not found.', 'visual-regression-tests' ) );
|
||||
}
|
||||
$test = Test::get_item_by_post_id( $post_id );
|
||||
if ( $test ) {
|
||||
return $test;
|
||||
}
|
||||
if ( 'publish' === $post->post_status ) {
|
||||
return $this->create_remote_test( $post );
|
||||
} elseif ( 'revision' !== $post->post_type && 'auto-draft' !== $post->post_status ) {
|
||||
$args = [
|
||||
'post_id' => $post_id,
|
||||
'status' => 0,
|
||||
];
|
||||
$new_row_id = Test::save( $args );
|
||||
return Test::get_item( $new_row_id );
|
||||
}
|
||||
} else {
|
||||
return new WP_Error( 'vrts_service_error', __( 'Service is not connected.', 'visual-regression-tests' ) );
|
||||
}//end if
|
||||
return new WP_Error( 'vrts_service_error', __( 'Error creating test.', 'visual-regression-tests' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create tests.
|
||||
*
|
||||
* @param array $post_ids Post ids.
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public function create_tests( $post_ids ) {
|
||||
if ( Service::is_connected() ) {
|
||||
$created_tests = [];
|
||||
$post_types = vrts()->get_public_post_types();
|
||||
$posts = get_posts( [
|
||||
'post__in' => $post_ids,
|
||||
'post_type' => $post_types,
|
||||
'post_status' => 'any',
|
||||
'posts_per_page' => -1,
|
||||
'update_post_meta_cache' => false,
|
||||
'update_post_term_cache' => false,
|
||||
] );
|
||||
|
||||
if ( ! $posts ) {
|
||||
return new WP_Error( 'vrts_posts_error', __( 'Posts not found.', 'visual-regression-tests' ) );
|
||||
}
|
||||
|
||||
$post_ids = wp_list_pluck( $posts, 'ID' );
|
||||
$remaining_tests = get_option( 'vrts_remaining_tests' );
|
||||
$existing_tests = Test::get_items_by_post_ids( $post_ids );
|
||||
$existing_tests_posts_ids = array_map( 'intval', wp_list_pluck( $existing_tests, 'post_id' ) );
|
||||
|
||||
// Remove posts that already have tests.
|
||||
$posts = array_filter( $posts, function ( $post ) use ( $existing_tests_posts_ids ) {
|
||||
return ! in_array( $post->ID, $existing_tests_posts_ids, true );
|
||||
} );
|
||||
|
||||
if ( ! $posts ) {
|
||||
return $existing_tests;
|
||||
}
|
||||
|
||||
// Only try to create as many remote tests as we have remaining.
|
||||
$published_posts = array_slice( array_filter( $posts, function ( $post ) {
|
||||
return 'publish' === $post->post_status;
|
||||
} ), 0, $remaining_tests );
|
||||
|
||||
$not_published_posts = array_filter( $posts, function ( $post ) {
|
||||
return 'publish' !== $post->post_status && 'revision' !== $post->post_type && 'auto-draft' !== $post->post_status;
|
||||
} );
|
||||
|
||||
if ( $published_posts ) {
|
||||
$published_posts_ids = wp_list_pluck( $published_posts, 'ID' );
|
||||
$remote_tests = $this->create_remote_tests( $published_posts_ids );
|
||||
if ( ! is_wp_error( $remote_tests ) ) {
|
||||
$created_tests = $remote_tests;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $not_published_posts ) {
|
||||
$args = array_values( array_map(function ( $post ) {
|
||||
return [
|
||||
'post_id' => $post->ID,
|
||||
'status' => 0,
|
||||
];
|
||||
}, $not_published_posts) );
|
||||
|
||||
$is_saved = Test::save_multiple( $args );
|
||||
|
||||
if ( $is_saved ) {
|
||||
$not_published_posts_ids = wp_list_pluck( $not_published_posts, 'ID' );
|
||||
$created_tests = array_merge( $created_tests, Test::get_items_by_post_ids( $not_published_posts_ids ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $created_tests;
|
||||
} else {
|
||||
return new WP_Error( 'vrts_service_error', __( 'Service is not connected.', 'visual-regression-tests' ) );
|
||||
}//end if
|
||||
return new WP_Error( 'vrts_service_error', __( 'Error creating test.', 'visual-regression-tests' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Create test remotely via service.
|
||||
*
|
||||
* @param WP_Post $post Post.
|
||||
* @param array $test Test.
|
||||
*
|
||||
* @return object|WP_Error
|
||||
*/
|
||||
public function create_remote_test( $post, $test = [] ) {
|
||||
if ( Service::is_connected() ) {
|
||||
$existing_test = Test::get_item_by_post_id( $post->ID );
|
||||
if ( $existing_test && $existing_test->service_test_id ) {
|
||||
return $existing_test;
|
||||
}
|
||||
$service_project_id = get_option( 'vrts_project_id' );
|
||||
$request_url = 'tests';
|
||||
$parameters = [
|
||||
'project_id' => $service_project_id,
|
||||
'url' => get_permalink( $post ),
|
||||
'frequency' => 'daily',
|
||||
];
|
||||
$service_request = Service::rest_service_request( $request_url, $parameters, 'post' );
|
||||
if ( 201 === $service_request['status_code'] ) {
|
||||
$test_id = $service_request['response']['id'];
|
||||
$args = array_merge($test, [
|
||||
'post_id' => $post->ID,
|
||||
'service_test_id' => $test_id,
|
||||
'status' => 1,
|
||||
]);
|
||||
unset( $args['id'] );
|
||||
// TODO: Add some validation.
|
||||
|
||||
$new_row_id = Test::save( $args, $test['id'] ?? null );
|
||||
if ( $new_row_id ) {
|
||||
Subscription::decrease_tests_count();
|
||||
Cron_Jobs::schedule_initial_fetch_test_updates( $new_row_id );
|
||||
return Test::get_item( $new_row_id );
|
||||
}
|
||||
} else {
|
||||
return new WP_Error( 'vrts_service_error', __( 'Service could not create test.', 'visual-regression-tests' ) );
|
||||
}
|
||||
} else {
|
||||
return new WP_Error( 'vrts_service_error', __( 'Service is not connected.', 'visual-regression-tests' ) );
|
||||
}//end if
|
||||
}
|
||||
|
||||
/**
|
||||
* Create tests remotely via service.
|
||||
*
|
||||
* @param array $post_ids Post IDs.
|
||||
*
|
||||
* @return array|WP_Error
|
||||
*/
|
||||
public function create_remote_tests( $post_ids ) {
|
||||
if ( Service::is_connected() ) {
|
||||
$service_project_id = get_option( 'vrts_project_id' );
|
||||
$request_url = 'tests';
|
||||
|
||||
$urls = array_combine( $post_ids, array_map( function ( $post_id ) {
|
||||
return get_permalink( $post_id );
|
||||
}, $post_ids ) );
|
||||
|
||||
$parameters = [
|
||||
'project_id' => $service_project_id,
|
||||
'urls' => array_values( $urls ),
|
||||
'frequency' => 'daily',
|
||||
];
|
||||
|
||||
$service_request = Service::rest_service_request( $request_url, $parameters, 'post' );
|
||||
|
||||
if ( 201 === $service_request['status_code'] ) {
|
||||
$args = [];
|
||||
|
||||
foreach ( $service_request['response'] as $test ) {
|
||||
$args[] = [
|
||||
'post_id' => array_search( $test['url'], $urls, true ),
|
||||
'service_test_id' => $test['id'],
|
||||
'status' => 1,
|
||||
];
|
||||
}
|
||||
|
||||
$saved_tests_number = Test::save_multiple( $args );
|
||||
|
||||
if ( $saved_tests_number ) {
|
||||
Subscription::decrease_tests_count( $saved_tests_number );
|
||||
|
||||
$post_ids = wp_list_pluck( $args, 'post_id' );
|
||||
$created_tests = Test::get_items_by_post_ids( $post_ids );
|
||||
|
||||
foreach ( $created_tests as $test ) {
|
||||
Cron_Jobs::schedule_initial_fetch_test_updates( $test->id );
|
||||
}
|
||||
|
||||
return $created_tests;
|
||||
} else {
|
||||
return new WP_Error( 'vrts_test_error', __( 'Plugin could not save tests.', 'visual-regression-tests' ) );
|
||||
}
|
||||
} else {
|
||||
return new WP_Error( 'vrts_service_error', __( 'Service could not create tests.', 'visual-regression-tests' ) );
|
||||
}//end if
|
||||
} else {
|
||||
return new WP_Error( 'vrts_service_error', __( 'Service is not connected.', 'visual-regression-tests' ) );
|
||||
}//end if
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete test.
|
||||
*
|
||||
* @param int|object $test_id Test id or test object.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_test( $test_id ) {
|
||||
$delete_locally = true;
|
||||
$test = ( is_string( $test_id ) || is_int( $test_id ) )
|
||||
? Test::get_item( (int) $test_id )
|
||||
: $test_id;
|
||||
if ( ! empty( $test->service_test_id ) ) {
|
||||
$delete_locally = (bool) $this->delete_remote_test( $test_id );
|
||||
}
|
||||
if ( ! $delete_locally ) {
|
||||
Subscription::get_latest_status();
|
||||
}
|
||||
return $delete_locally && Test::delete( $test->id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete test remotely via service.
|
||||
*
|
||||
* @param int|object $test_id Test id or test object.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_remote_test( $test_id ) {
|
||||
if ( Service::is_connected() ) {
|
||||
$test = ( is_string( $test_id ) || is_int( $test_id ) )
|
||||
? Test::get_item( (int) $test_id )
|
||||
: $test_id;
|
||||
if (
|
||||
Service::delete_test( $test->service_test_id )
|
||||
&& Subscription::increase_tests_count()
|
||||
) {
|
||||
$args = (array) $test;
|
||||
$args['status'] = 0;
|
||||
$args['service_test_id'] = null;
|
||||
unset( $args['id'] );
|
||||
unset( $args['current_alert_id'] );
|
||||
Test::save( $args, $test->id );
|
||||
return $test;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume stale tests.
|
||||
*/
|
||||
public function resume_stale_tests() {
|
||||
$stale_tests = Test::get_all_inactive();
|
||||
foreach ( $stale_tests as $stale_test ) {
|
||||
if ( Subscription::get_remaining_tests() > 0 ) {
|
||||
$this->resume_stale_test( $stale_test );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume stale test.
|
||||
*
|
||||
* @param object $test Test.
|
||||
*/
|
||||
private function resume_stale_test( $test ) {
|
||||
if ( empty( $test->service_test_id ) ) {
|
||||
$post = get_post( $test->post_id );
|
||||
if ( 'publish' === $post->post_status ) {
|
||||
$this->create_remote_test( $post, (array) $test );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update test.
|
||||
*
|
||||
* @param int $test_id Test id.
|
||||
* @param string $css_hide_selector CSS selector to hide.
|
||||
*
|
||||
* @return int|WP_Error
|
||||
*/
|
||||
public function update_css_hide_selectors( $test_id, $css_hide_selector ) {
|
||||
if ( Service::is_connected() ) {
|
||||
$test = Test::get_item( $test_id );
|
||||
if ( ! $test ) {
|
||||
return new WP_Error( 'vrts_test_error', __( 'Test not found.', 'visual-regression-tests' ) );
|
||||
}
|
||||
|
||||
$updated = Service::update_test(
|
||||
$test->service_test_id,
|
||||
[ 'options' => [ 'hideSelectors' => $css_hide_selector ] ]
|
||||
);
|
||||
if ( $updated ) {
|
||||
return Test::save_hide_css_selectors( $test_id, $css_hide_selector );
|
||||
} else {
|
||||
return new WP_Error( 'vrts_service_error', __( 'Service could not update test.', 'visual-regression-tests' ) );
|
||||
}
|
||||
} else {
|
||||
return new WP_Error( 'vrts_service_error', __( 'Service is not connected.', 'visual-regression-tests' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume test.
|
||||
*
|
||||
* @param int $post_id Post id.
|
||||
*/
|
||||
public function resume_test( $post_id ) {
|
||||
$test = Test::get_item_by_post_id( $post_id );
|
||||
if ( ! $test ) {
|
||||
return false;
|
||||
} else {
|
||||
Test::reset_base_screenshot( $test->id );
|
||||
Service::resume_test( $post_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Resume tests.
|
||||
*/
|
||||
public function resume_tests() {
|
||||
Test::reset_base_screenshots();
|
||||
Service::resume_tests();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user