first commit
This commit is contained in:
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\TM\ATE\Hooks;
|
||||
|
||||
use WPML\TM\ATE\ReturnedJobsQueue;
|
||||
|
||||
class ReturnedJobActions implements \IWPML_Action {
|
||||
/** @var callable :: int->string->void */
|
||||
private $addToQueue;
|
||||
|
||||
/**
|
||||
* @param callable $addToQueue
|
||||
*/
|
||||
public function __construct( callable $addToQueue ) {
|
||||
$this->addToQueue = $addToQueue;
|
||||
}
|
||||
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'init', [ $this, 'addToQueue' ] );
|
||||
}
|
||||
|
||||
public function addToQueue() {
|
||||
if ( isset( $_GET['ate_original_id'] ) ) {
|
||||
$ateJobId = (int) $_GET['ate_original_id'];
|
||||
|
||||
if ( isset( $_GET['complete'] ) ) {
|
||||
call_user_func( $this->addToQueue, $ateJobId, ReturnedJobsQueue::STATUS_COMPLETED );
|
||||
} elseif ( isset( $_GET['back'] ) ) {
|
||||
call_user_func( $this->addToQueue, $ateJobId, ReturnedJobsQueue::STATUS_BACK );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace WPML\TM\ATE\Hooks;
|
||||
|
||||
use WPML\TM\ATE\ReturnedJobsQueue;
|
||||
use function WPML\Container\make;
|
||||
use function WPML\FP\partialRight;
|
||||
|
||||
class ReturnedJobActionsFactory implements \IWPML_Backend_Action_Loader, \IWPML_REST_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
$ateJobs = make( \WPML_TM_ATE_Jobs::class );
|
||||
|
||||
$add = partialRight( [ ReturnedJobsQueue::class, 'add' ], [ $ateJobs, 'get_wpml_job_id' ] );
|
||||
|
||||
return new ReturnedJobActions( $add );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
|
||||
class WPML_TM_AMS_Check_Website_ID_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
/**
|
||||
* @return \WPML_TM_AMS_Check_Website_ID|null
|
||||
* @throws \Auryn\InjectionException
|
||||
*/
|
||||
public function create() {
|
||||
$options_manager = \WPML\Container\make( '\WPML\WP\OptionManager' );
|
||||
if (
|
||||
WPML_TM_ATE_Status::is_enabled_and_activated() &&
|
||||
! wpml_is_ajax() &&
|
||||
! $options_manager->get( 'TM-has-run', 'WPML_TM_AMS_Check_Website_ID' )
|
||||
) {
|
||||
return \WPML\Container\make( '\WPML_TM_AMS_Check_Website_ID' );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
use WPML\WP\OptionManager;
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_AMS_Check_Website_ID implements IWPML_Action {
|
||||
|
||||
/** @var \WPML\WP\OptionManager $option_manager */
|
||||
private $option_manager;
|
||||
|
||||
/** @var WPML_TM_ATE_API $ate_api */
|
||||
private $ate_api;
|
||||
|
||||
/** @var WPML_TM_AMS_API $ams_api */
|
||||
private $ams_api;
|
||||
|
||||
public function __construct(
|
||||
OptionManager $option_manager,
|
||||
WPML_TM_ATE_API $ate_api,
|
||||
WPML_TM_AMS_API $ams_api
|
||||
) {
|
||||
$this->option_manager = $option_manager;
|
||||
$this->ate_api = $ate_api;
|
||||
$this->ams_api = $ams_api;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'wpml_after_tm_loaded', array( $this, 'do_check' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the stored site id is different from the one returned by ams api and
|
||||
* then:
|
||||
* 1) test if the ams one works
|
||||
* 2) Update stored id if test is successful
|
||||
*/
|
||||
public function do_check() {
|
||||
$stored_site_id = wpml_get_site_id( WPML_TM_ATE::SITE_ID_SCOPE );
|
||||
$site_id_from_ams = $this->ate_api->get_website_id( get_site_url() );
|
||||
|
||||
if ( $site_id_from_ams && $stored_site_id !== $site_id_from_ams ) {
|
||||
if ( $this->does_site_id_work( $site_id_from_ams ) ) {
|
||||
update_option( WPML_Site_ID::SITE_ID_KEY . ':ate', $site_id_from_ams, false );
|
||||
}
|
||||
}
|
||||
$this->option_manager->set( 'TM-has-run', 'WPML_TM_AMS_Check_Website_ID', true, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $site_id
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function does_site_id_work( $site_id ) {
|
||||
$this->ams_api->override_site_id( $site_id );
|
||||
$response = $this->ams_api->is_subscription_activated( 'any@any.com' );
|
||||
|
||||
$is_site_id_error = false;
|
||||
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$error_data = $response->get_error_data( 400 );
|
||||
$is_site_id_error = isset( $error_data['detail'] ) && $error_data['detail'] === 'Website not found, please validate site identifier';
|
||||
}
|
||||
|
||||
return ! $is_site_id_error;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_AMS_Synchronize_Actions_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
/**
|
||||
* @return IWPML_Action|IWPML_Action[]|null
|
||||
*/
|
||||
public function create() {
|
||||
if ( WPML_TM_ATE_Status::is_enabled_and_activated() ) {
|
||||
$ams_api = WPML\Container\make( WPML_TM_AMS_API::class );
|
||||
|
||||
global $wpdb;
|
||||
$user_query_factory = new WPML_WP_User_Query_Factory();
|
||||
|
||||
$wp_roles = wp_roles();
|
||||
$translator_records = new WPML_Translator_Records( $wpdb, $user_query_factory, $wp_roles );
|
||||
$manager_records = new WPML_Translation_Manager_Records( $wpdb, $user_query_factory, $wp_roles );
|
||||
$admin_translators = new WPML_Translator_Admin_Records( $wpdb, $user_query_factory, $wp_roles );
|
||||
$user_records = new WPML_TM_AMS_Users( $manager_records, $translator_records, $admin_translators );
|
||||
$user_factory = new WPML_WP_User_Factory();
|
||||
$translator_activation_records = new WPML_TM_AMS_Translator_Activation_Records( new WPML_WP_User_Factory() );
|
||||
|
||||
return new WPML_TM_AMS_Synchronize_Actions(
|
||||
$ams_api,
|
||||
$user_records,
|
||||
$user_factory,
|
||||
$translator_activation_records
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_AMS_Synchronize_Actions implements IWPML_Action {
|
||||
|
||||
const ENABLED_FOR_TRANSLATION_VIA_ATE = 'wpml_enabled_for_translation_via_ate';
|
||||
|
||||
/**
|
||||
* @var WPML_TM_AMS_API
|
||||
*/
|
||||
private $ams_api;
|
||||
/**
|
||||
* @var WPML_TM_AMS_Users
|
||||
*/
|
||||
private $ams_user_records;
|
||||
/**
|
||||
* @var WPML_WP_User_Factory $user_factory
|
||||
*/
|
||||
private $user_factory;
|
||||
|
||||
/**
|
||||
* @var WPML_TM_AMS_Translator_Activation_Records
|
||||
*/
|
||||
private $translator_activation_records;
|
||||
|
||||
public function __construct(
|
||||
WPML_TM_AMS_API $ams_api,
|
||||
WPML_TM_AMS_Users $ams_user_records,
|
||||
WPML_WP_User_Factory $user_factory,
|
||||
WPML_TM_AMS_Translator_Activation_Records $translator_activation_records
|
||||
) {
|
||||
$this->ams_api = $ams_api;
|
||||
$this->ams_user_records = $ams_user_records;
|
||||
$this->user_factory = $user_factory;
|
||||
$this->translator_activation_records = $translator_activation_records;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'wpml_tm_ate_synchronize_translators', array( $this, 'synchronize_translators' ) );
|
||||
add_action( 'wpml_tm_ate_synchronize_managers', array( $this, 'synchronize_managers' ) );
|
||||
add_action( 'wpml_tm_ate_enable_subscription', array( $this, 'enable_subscription' ) );
|
||||
add_action( 'deleted_user', array( $this, 'user_changed' ) );
|
||||
add_action( 'profile_update', array( $this, 'user_changed' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function synchronize_translators() {
|
||||
$result = $this->ams_api->synchronize_translators( $this->ams_user_records->get_translators() );
|
||||
if ( ! is_wp_error( $result ) ) {
|
||||
$this->translator_activation_records->update( isset( $result['translators'] ) ? $result['translators'] : array() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function synchronize_managers() {
|
||||
$this->ams_api->synchronize_managers( $this->ams_user_records->get_managers() );
|
||||
}
|
||||
|
||||
public function enable_subscription( $user_id ) {
|
||||
$user = $this->user_factory->create( $user_id );
|
||||
if ( ! $user->get_meta( self::ENABLED_FOR_TRANSLATION_VIA_ATE ) ) {
|
||||
$this->ams_api->enable_subscription( $user->user_email );
|
||||
$user->update_meta( self::ENABLED_FOR_TRANSLATION_VIA_ATE, true );
|
||||
}
|
||||
}
|
||||
|
||||
public function user_changed() {
|
||||
$this->synchronize_managers();
|
||||
$this->synchronize_translators();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
class WPML_TM_AMS_Synchronize_Users_On_Access_Denied_Factory implements IWPML_Backend_Action_Loader {
|
||||
public function create() {
|
||||
return new WPML_TM_AMS_Synchronize_Users_On_Access_Denied();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
class WPML_TM_AMS_Synchronize_Users_On_Access_Denied {
|
||||
|
||||
const ERROR_MESSAGE = 'Authentication error, please contact your translation manager to check your subscription';
|
||||
|
||||
/** @var WPML_TM_AMS_Synchronize_Actions */
|
||||
private $ams_synchronize_actions;
|
||||
|
||||
/** @var WPML_TM_ATE_Jobs */
|
||||
private $ate_jobs;
|
||||
|
||||
public function add_hooks() {
|
||||
if ( WPML_TM_ATE_Status::is_enabled_and_activated() ) {
|
||||
add_action( 'init', array( $this, 'catch_access_error' ) );
|
||||
}
|
||||
}
|
||||
|
||||
public function catch_access_error() {
|
||||
if ( ! $this->ate_redirected_due_to_lack_of_access() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->get_ams_synchronize_actions()->synchronize_translators();
|
||||
|
||||
if ( ! isset( $_GET['ate_job_id'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$wpml_job_id = $this->get_ate_jobs()->get_wpml_job_id( $_GET['ate_job_id'] );
|
||||
if ( ! $wpml_job_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$url = admin_url(
|
||||
'admin.php?page='
|
||||
. WPML_TM_FOLDER
|
||||
. '/menu/translations-queue.php&job_id='
|
||||
. $wpml_job_id
|
||||
);
|
||||
|
||||
wp_safe_redirect( $url, 302, 'WPML' );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function ate_redirected_due_to_lack_of_access() {
|
||||
return isset( $_GET['message'] ) && false !== strpos( $_GET['message'], self::ERROR_MESSAGE );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return IWPML_Action|IWPML_Action[]|WPML_TM_AMS_Synchronize_Actions
|
||||
*/
|
||||
private function get_ams_synchronize_actions() {
|
||||
if ( ! $this->ams_synchronize_actions ) {
|
||||
$factory = new WPML_TM_AMS_Synchronize_Actions_Factory();
|
||||
$this->ams_synchronize_actions = $factory->create();
|
||||
}
|
||||
|
||||
return $this->ams_synchronize_actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return WPML_TM_ATE_Jobs
|
||||
*/
|
||||
private function get_ate_jobs() {
|
||||
if ( ! $this->ate_jobs ) {
|
||||
$ate_jobs_records = wpml_tm_get_ate_job_records();
|
||||
$this->ate_jobs = new WPML_TM_ATE_Jobs( $ate_jobs_records );
|
||||
}
|
||||
|
||||
return $this->ate_jobs;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_TM_AMS_Synchronize_Actions $ams_synchronize_actions
|
||||
*/
|
||||
public function set_ams_synchronize_actions( WPML_TM_AMS_Synchronize_Actions $ams_synchronize_actions ) {
|
||||
$this->ams_synchronize_actions = $ams_synchronize_actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_TM_ATE_Jobs $ate_jobs
|
||||
*/
|
||||
public function set_ate_jobs( WPML_TM_ATE_Jobs $ate_jobs ) {
|
||||
$this->ate_jobs = $ate_jobs;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
class WPML_TM_ATE_API_Error {
|
||||
|
||||
public function log( $message ) {
|
||||
$wpml_admin_notices = wpml_get_admin_notices();
|
||||
|
||||
$notice = new WPML_Notice(
|
||||
WPML_TM_ATE_Jobs_Actions::RESPONSE_ATE_ERROR_NOTICE_ID,
|
||||
sprintf(
|
||||
__( 'There was a problem communicating with ATE: %s ', 'wpml-translation-management' ),
|
||||
'(<i>' . $message . '</i>)'
|
||||
),
|
||||
WPML_TM_ATE_Jobs_Actions::RESPONSE_ATE_ERROR_NOTICE_GROUP
|
||||
);
|
||||
$notice->set_css_class_types( array( 'warning' ) );
|
||||
$notice->add_capability_check( array( 'manage_options', 'wpml_manage_translation_management' ) );
|
||||
$notice->set_flash();
|
||||
$wpml_admin_notices->add_notice( $notice );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
|
||||
class WPML_TM_ATE_Job_Data_Fallback_Factory implements IWPML_Backend_Action_Loader, IWPML_REST_Action_Loader {
|
||||
/**
|
||||
* @return WPML_TM_ATE_Job_Data_Fallback
|
||||
*/
|
||||
public function create() {
|
||||
return \WPML\Container\make( '\WPML_TM_ATE_Job_Data_Fallback' );
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
use WPML\TM\ATE\JobRecords;
|
||||
|
||||
class WPML_TM_ATE_Job_Data_Fallback implements IWPML_Action {
|
||||
/** @var WPML_TM_ATE_API */
|
||||
private $ate_api;
|
||||
|
||||
/**
|
||||
* @param WPML_TM_ATE_API $ate_api
|
||||
*/
|
||||
public function __construct( WPML_TM_ATE_API $ate_api ) {
|
||||
$this->ate_api = $ate_api;
|
||||
}
|
||||
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter( 'wpml_tm_ate_job_data_fallback', array( $this, 'get_data_from_api' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data
|
||||
* @param int $wpml_job_id
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_data_from_api( array $data, $wpml_job_id ) {
|
||||
$response = $this->ate_api->get_jobs_by_wpml_ids( array( $wpml_job_id ) );
|
||||
if ( ! $response || is_wp_error( $response ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
if ( ! isset( $response->{$wpml_job_id}->ate_job_id ) ) {
|
||||
return $data;
|
||||
}
|
||||
|
||||
return array( JobRecords::FIELD_ATE_JOB_ID => $response->{$wpml_job_id}->ate_job_id );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
<?php
|
||||
|
||||
use function WPML\Container\make;
|
||||
use WPML\TM\ATE\ReturnedJobsQueue;
|
||||
|
||||
/**
|
||||
* Factory class for \WPML_TM_ATE_Jobs_Actions.
|
||||
*
|
||||
* @package wpml\tm
|
||||
*
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ATE_Jobs_Actions_Factory implements IWPML_Backend_Action_Loader {
|
||||
/**
|
||||
* The instance of \WPML_Current_Screen.
|
||||
*
|
||||
* @var WPML_Current_Screen
|
||||
*/
|
||||
private $current_screen;
|
||||
|
||||
/**
|
||||
* It returns an instance of \WPML_TM_ATE_Jobs_Actions or null if ATE is not enabled and active.
|
||||
*
|
||||
* @return \WPML_TM_ATE_Jobs_Actions|null
|
||||
* @throws \Auryn\InjectionException
|
||||
*/
|
||||
public function create() {
|
||||
$ams_ate_factories = wpml_tm_ams_ate_factories();
|
||||
|
||||
if ( WPML_TM_ATE_Status::is_enabled() && $ams_ate_factories->is_ate_active() ) {
|
||||
$sitepress = $this->get_sitepress();
|
||||
$current_screen = $this->get_current_screen();
|
||||
|
||||
$ate_api = $ams_ate_factories->get_ate_api();
|
||||
$records = wpml_tm_get_ate_job_records();
|
||||
$ate_jobs = new WPML_TM_ATE_Jobs( $records );
|
||||
|
||||
$translator_activation_records = new WPML_TM_AMS_Translator_Activation_Records( new WPML_WP_User_Factory() );
|
||||
|
||||
return new WPML_TM_ATE_Jobs_Actions(
|
||||
$ate_api,
|
||||
$ate_jobs,
|
||||
$sitepress,
|
||||
$current_screen,
|
||||
$translator_activation_records,
|
||||
make( \WPML_TM_ATE_Jobs_Sync_Script_Loader::class )
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* The global instance of \Sitepress.
|
||||
*
|
||||
* @return SitePress
|
||||
*/
|
||||
private function get_sitepress() {
|
||||
global $sitepress;
|
||||
|
||||
return $sitepress;
|
||||
}
|
||||
|
||||
/**
|
||||
* It gets the instance of \WPML_Current_Screen.
|
||||
*
|
||||
* @return \WPML_Current_Screen
|
||||
*/
|
||||
private function get_current_screen() {
|
||||
if ( ! $this->current_screen ) {
|
||||
$this->current_screen = new WPML_Current_Screen();
|
||||
}
|
||||
|
||||
return $this->current_screen;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,619 @@
|
||||
<?php
|
||||
|
||||
use WPML\TM\ATE\JobRecords;
|
||||
use WPML\FP\Fns;
|
||||
use WPML\FP\Obj;
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ATE_Jobs_Actions implements IWPML_Action {
|
||||
const RESPONSE_ATE_NOT_ACTIVE_ERROR = 403;
|
||||
const RESPONSE_ATE_DUPLICATED_SOURCE_ID = 417;
|
||||
const RESPONSE_ATE_UNEXPECTED_ERROR = 500;
|
||||
|
||||
const RESPONSE_ATE_ERROR_NOTICE_ID = 'ate-update-error';
|
||||
const RESPONSE_ATE_ERROR_NOTICE_GROUP = 'default';
|
||||
|
||||
/**
|
||||
* @var WPML_TM_ATE_API
|
||||
*/
|
||||
private $ate_api;
|
||||
/**
|
||||
* @var WPML_TM_ATE_Jobs
|
||||
*/
|
||||
private $ate_jobs;
|
||||
|
||||
/**
|
||||
* @var WPML_TM_AMS_Translator_Activation_Records
|
||||
*/
|
||||
private $translator_activation_records;
|
||||
|
||||
/** @var bool */
|
||||
private $is_second_attempt_to_get_jobs_data = false;
|
||||
/**
|
||||
* @var SitePress
|
||||
*/
|
||||
private $sitepress;
|
||||
/**
|
||||
* @var WPML_Current_Screen
|
||||
*/
|
||||
private $current_screen;
|
||||
|
||||
/** @var array */
|
||||
private $trid_original_element_map = array();
|
||||
|
||||
/** @var WPML_TM_ATE_Jobs_Sync_Script_Loader */
|
||||
private $job_sync_script_loader;
|
||||
|
||||
/**
|
||||
* WPML_TM_ATE_Jobs_Actions constructor.
|
||||
*
|
||||
* @param \WPML_TM_ATE_API $ate_api
|
||||
* @param \WPML_TM_ATE_Jobs $ate_jobs
|
||||
* @param \SitePress $sitepress
|
||||
* @param \WPML_Current_Screen $current_screen
|
||||
* @param \WPML_TM_AMS_Translator_Activation_Records $translator_activation_records
|
||||
* @param WPML_TM_ATE_Jobs_Sync_Script_Loader $job_sync_script_loader
|
||||
*/
|
||||
public function __construct(
|
||||
WPML_TM_ATE_API $ate_api,
|
||||
WPML_TM_ATE_Jobs $ate_jobs,
|
||||
SitePress $sitepress,
|
||||
WPML_Current_Screen $current_screen,
|
||||
WPML_TM_AMS_Translator_Activation_Records $translator_activation_records,
|
||||
WPML_TM_ATE_Jobs_Sync_Script_Loader $job_sync_script_loader
|
||||
|
||||
) {
|
||||
$this->ate_api = $ate_api;
|
||||
$this->ate_jobs = $ate_jobs;
|
||||
$this->sitepress = $sitepress;
|
||||
$this->current_screen = $current_screen;
|
||||
$this->translator_activation_records = $translator_activation_records;
|
||||
$this->job_sync_script_loader = $job_sync_script_loader;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'wpml_added_translation_job', array( $this, 'added_translation_job' ), 10, 2 );
|
||||
add_action( 'wpml_added_translation_jobs', array( $this, 'added_translation_jobs' ) );
|
||||
add_action( 'admin_notices', array( $this, 'handle_messages' ) );
|
||||
add_action( 'current_screen', array( $this, 'update_jobs_on_current_screen' ) );
|
||||
add_action( 'wp', array( $this, 'update_jobs_on_current_screen' ) );
|
||||
|
||||
add_filter( 'wpml_tm_ate_jobs_data', array( $this, 'get_ate_jobs_data_filter' ), 10, 2 );
|
||||
add_filter( 'wpml_tm_ate_jobs_editor_url', array( $this, 'get_editor_url' ), 10, 3 );
|
||||
}
|
||||
|
||||
public function handle_messages() {
|
||||
if ( $this->current_screen->id_ends_with( WPML_TM_FOLDER . '/menu/translations-queue' ) ) {
|
||||
|
||||
if ( array_key_exists( 'message', $_GET ) ) {
|
||||
if ( array_key_exists( 'ate_job_id', $_GET ) ) {
|
||||
$ate_job_id = filter_var( $_GET['ate_job_id'], FILTER_SANITIZE_NUMBER_INT );
|
||||
|
||||
$this->resign_job_on_error( $ate_job_id );
|
||||
}
|
||||
$message = filter_var( $_GET['message'], FILTER_SANITIZE_STRING );
|
||||
?>
|
||||
|
||||
<div class="error notice-error notice otgs-notice">
|
||||
<p><?php echo $message; ?></p>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $job_id
|
||||
* @param string $translation_service
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function added_translation_job( $job_id, $translation_service ) {
|
||||
$this->added_translation_jobs( array( $translation_service => array( $job_id ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $jobs
|
||||
*
|
||||
* @return bool|void
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function added_translation_jobs( array $jobs ) {
|
||||
$oldEditor = wpml_tm_load_old_jobs_editor();
|
||||
$job_ids = Fns::reject( [ $oldEditor, 'shouldStickToWPMLEditor' ], Obj::propOr( [], 'local', $jobs ) );
|
||||
|
||||
if ( ! $job_ids ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$jobs = [];
|
||||
$rid_to_job_map = [];
|
||||
foreach ( $job_ids as $job_id ) {
|
||||
$rid = wpml_tm_get_records()->icl_translate_job_by_job_id( $job_id )->rid();
|
||||
$rid_to_job_map[ $rid ] = $job_id;
|
||||
$jobs[] = wpml_tm_create_ATE_job_creation_model( $job_id, $rid );
|
||||
}
|
||||
$response = $this->create_jobs( $jobs );
|
||||
|
||||
try {
|
||||
$this->check_response_error( $response );
|
||||
} catch ( RuntimeException $ex ) {
|
||||
do_action( 'wpml_tm_basket_add_message', 'error', $ex->getMessage() );
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$has_valid_response = $response && isset( $response->jobs );
|
||||
$response_jobs = null;
|
||||
if ( $has_valid_response ) {
|
||||
$response_jobs = $response->jobs;
|
||||
}
|
||||
|
||||
if ( $response_jobs ) {
|
||||
if ( is_object( $response_jobs ) ) {
|
||||
$response_jobs = json_decode( wp_json_encode( $response_jobs, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES ), true );
|
||||
}
|
||||
|
||||
$response_jobs = $this->map_response_jobs( $response_jobs, $rid_to_job_map );
|
||||
|
||||
$this->ate_jobs->warm_cache( array_keys( $response_jobs ) );
|
||||
|
||||
foreach ( $response_jobs as $wpml_job_id => $ate_job_id ) {
|
||||
$this->ate_jobs->store( $wpml_job_id, array( JobRecords::FIELD_ATE_JOB_ID => $ate_job_id ) );
|
||||
$oldEditor->set( $wpml_job_id, WPML_TM_Editors::ATE );
|
||||
}
|
||||
|
||||
$message = __( '%1$s jobs added to the Advanced Translation Editor.', 'wpml-translation-management' );
|
||||
$this->add_message( 'updated', sprintf( $message, count( $response_jobs ) ), 'wpml_tm_ate_create_job' );
|
||||
} else {
|
||||
$this->add_message(
|
||||
'error',
|
||||
__(
|
||||
'Jobs could not be created in Advanced Translation Editor. Please try again or contact the WPML support for help.',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
'wpml_tm_ate_create_job'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function map_response_jobs( $responseJobs, $rid_to_job_id_map ) {
|
||||
$result = [];
|
||||
foreach ( $responseJobs as $rid => $ate_job_id ) {
|
||||
if ( isset( $rid_to_job_id_map[ $rid ] ) ) {
|
||||
$result[ $rid_to_job_id_map[ $rid ] ] = $ate_job_id;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $type
|
||||
* @param string $message
|
||||
* @param string|null $id
|
||||
*/
|
||||
private function add_message( $type, $message, $id = null ) {
|
||||
do_action( 'wpml_tm_basket_add_message', $type, $message, $id );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WPML_TM_ATE_Models_Job_Create[] $jobs
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
private function create_jobs( array $jobs ) {
|
||||
$params = json_decode( wp_json_encode( array( 'jobs' => $jobs ) ), true );
|
||||
|
||||
return $this->ate_api->create_jobs( $params );
|
||||
}
|
||||
|
||||
/**
|
||||
* After implementation of wpmltm-3211 and wpmltm-3391, we should not find missing ATE IDs anymore.
|
||||
* Some code below seems dead but we'll keep it for now in case we are missing a specific context.
|
||||
*
|
||||
* @link https://onthegosystems.myjetbrains.com/youtrack/issue/wpmltm-3211
|
||||
* @link https://onthegosystems.myjetbrains.com/youtrack/issue/wpmltm-3391
|
||||
*/
|
||||
private function get_ate_jobs_data( array $translation_jobs ) {
|
||||
$ate_jobs_data = array();
|
||||
$skip_getting_data = false;
|
||||
$ate_jobs_to_create = array();
|
||||
|
||||
$this->ate_jobs->warm_cache( wpml_collect( $translation_jobs )->pluck( 'job_id' )->toArray() );
|
||||
|
||||
foreach ( $translation_jobs as $translation_job ) {
|
||||
if ( $this->is_ate_translation_job( $translation_job ) ) {
|
||||
$ate_job_id = $this->get_ate_job_id( $translation_job->job_id );
|
||||
// Start of possibly dead code.
|
||||
if ( ! $ate_job_id ) {
|
||||
$ate_jobs_to_create[] = $translation_job->job_id;
|
||||
$skip_getting_data = true;
|
||||
}
|
||||
// End of possibly dead code.
|
||||
|
||||
if ( ! $skip_getting_data ) {
|
||||
$ate_jobs_data[ $translation_job->job_id ] = [ 'ate_job_id' => $ate_job_id ];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Start of possibly dead code.
|
||||
if (
|
||||
! $this->is_second_attempt_to_get_jobs_data &&
|
||||
$ate_jobs_to_create &&
|
||||
$this->added_translation_jobs( array( 'local' => $ate_jobs_to_create ) )
|
||||
) {
|
||||
$ate_jobs_data = $this->get_ate_jobs_data( $translation_jobs );
|
||||
$this->is_second_attempt_to_get_jobs_data = true;
|
||||
}
|
||||
// End of possibly dead code.
|
||||
|
||||
return $ate_jobs_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $default_url
|
||||
* @param int $job_id
|
||||
* @param null|string $return_url
|
||||
*
|
||||
* @return string
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function get_editor_url( $default_url, $job_id, $return_url = null ) {
|
||||
if ( $this->translator_activation_records->is_current_user_activated() ) {
|
||||
$ate_job_id = $this->ate_jobs->get_ate_job_id( $job_id );
|
||||
if ( $ate_job_id ) {
|
||||
if ( ! $return_url ) {
|
||||
$return_url = add_query_arg(
|
||||
array(
|
||||
'page' => WPML_TM_FOLDER . '/menu/translations-queue.php',
|
||||
'ate-return-job' => $job_id,
|
||||
),
|
||||
admin_url( '/admin.php' )
|
||||
);
|
||||
}
|
||||
$ate_job_url = $this->ate_api->get_editor_url( $ate_job_id, $return_url );
|
||||
if ( $ate_job_url && ! is_wp_error( $ate_job_url ) ) {
|
||||
return $ate_job_url;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $default_url;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $ignore
|
||||
* @param array $translation_jobs
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_ate_jobs_data_filter( $ignore, array $translation_jobs ) {
|
||||
return $this->get_ate_jobs_data( $translation_jobs );
|
||||
}
|
||||
|
||||
private function get_ate_job_id( $job_id ) {
|
||||
return $this->ate_jobs->get_ate_job_id( $job_id );
|
||||
}
|
||||
|
||||
public function update_jobs_on_current_screen() {
|
||||
$load_ate_jobs_synchronization = $this->is_edit_list_page_of_a_translatable_type() ||
|
||||
$this->is_edit_page_of_a_translatable_type() ||
|
||||
WPML_TM_Page::is_dashboard() ||
|
||||
WPML_TM_Page::is_translation_queue();
|
||||
|
||||
if ( apply_filters( 'wpml_tm_load_ate_jobs_synchronization', $load_ate_jobs_synchronization ) ) {
|
||||
$this->job_sync_script_loader->load();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $message
|
||||
*/
|
||||
private function add_update_error_notice( $message ) {
|
||||
$error_log = new WPML_TM_ATE_API_Error();
|
||||
$error_log->log( $message );
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo: Remove this method in favor of the new SYNC/DOWNLOAD process.
|
||||
*
|
||||
* @param bool $updated
|
||||
* @param array|stdClass $translation_jobs
|
||||
* @param bool $ignore_errors
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @return int[] Returns an array of WPML job IDs that translation was applied (XLIFF updated)
|
||||
*/
|
||||
public function update_jobs( $updated, $translation_jobs, $ignore_errors = false ) {
|
||||
/**
|
||||
* We should only expect an array of objects.
|
||||
* However, this method can be called by an action and a known issue may cause to pass a single object instead
|
||||
*
|
||||
* @see https://developer.wordpress.org/reference/functions/do_action/#comment-2371
|
||||
*/
|
||||
if ( is_object( $translation_jobs ) ) {
|
||||
if ( isset( $translation_jobs->job_id ) ) {
|
||||
$translation_jobs = array( $translation_jobs );
|
||||
} else {
|
||||
$translation_jobs = null;
|
||||
}
|
||||
}
|
||||
|
||||
$jobs_with_translation_applied = array();
|
||||
|
||||
if ( $translation_jobs ) {
|
||||
$ate_jobs_data = $this->get_ate_jobs_data( $translation_jobs );
|
||||
|
||||
if ( ! $ate_jobs_data ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
$job_ids_map = array();
|
||||
foreach ( $translation_jobs as $translation_job ) {
|
||||
if ( $this->is_ate_translation_job( $translation_job ) ) {
|
||||
$ate_job_id = null;
|
||||
if ( isset( $ate_jobs_data[ $translation_job->job_id ]['ate_job_id'] ) ) {
|
||||
$ate_job_id = $ate_jobs_data[ $translation_job->job_id ]['ate_job_id'];
|
||||
$job_ids_map[ $ate_job_id ] = $translation_job->job_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $job_ids_map ) {
|
||||
$ate_job_ids = array_keys( $job_ids_map );
|
||||
$response = $this->ate_api->get_jobs( $ate_job_ids );
|
||||
|
||||
try {
|
||||
$this->check_response_error( $response );
|
||||
} catch ( RuntimeException $e ) {
|
||||
$this->add_update_error_notice( $e->getMessage() );
|
||||
}
|
||||
|
||||
$processed = json_decode( wp_json_encode( $response ), true );
|
||||
|
||||
if ( $processed ) {
|
||||
foreach ( $processed as $ate_job_id => $ate_job_data ) {
|
||||
if ( array_key_exists( $ate_job_id, $job_ids_map ) ) {
|
||||
$wpml_job_id = (int) $job_ids_map[ $ate_job_id ];
|
||||
|
||||
if ( $this->is_delivered_job_being_edited( $wpml_job_id, $ate_job_data ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
$is_translations_applied = $this->maybe_apply_translation( $ate_job_data );
|
||||
} catch ( Exception $e ) {
|
||||
if ( ! $ignore_errors ) {
|
||||
throw new RuntimeException( $e->getMessage(), $e->getCode() );
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( $is_translations_applied ) {
|
||||
$this->ate_jobs->store( $wpml_job_id, $ate_job_data );
|
||||
|
||||
if ( $this->must_acknowledge_ATE( $ate_job_data ) ) {
|
||||
$this->confirm_received_job( $ate_job_id, $ignore_errors );
|
||||
}
|
||||
|
||||
$jobs_with_translation_applied[] = $wpml_job_id;
|
||||
} else {
|
||||
$this->ate_jobs->store( $wpml_job_id, $ate_job_data );
|
||||
|
||||
if ( isset( $ate_job_data['status_id'] ) ) {
|
||||
$this->ate_jobs->set_wpml_status_from_ate( $wpml_job_id, (int) $ate_job_data['status_id'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $jobs_with_translation_applied;
|
||||
}
|
||||
|
||||
/**
|
||||
* This situation happens when a job was delivered
|
||||
* and the translator is editing the job but he did not
|
||||
* click on the "Redeliver" button yet.
|
||||
*
|
||||
* @param int $wpml_job_id
|
||||
* @param array $ate_job_data
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_delivered_job_being_edited( $wpml_job_id, array $ate_job_data ) {
|
||||
return isset( $ate_job_data['status_id'] )
|
||||
&& WPML_TM_ATE_AMS_Endpoints::ATE_JOB_STATUS_DELIVERED === $ate_job_data['status_id']
|
||||
&& $this->ate_jobs->is_editing_job( $wpml_job_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* If we have an XLIFF URL, we will fetch the remote file
|
||||
* and try to apply it.
|
||||
*
|
||||
* @param array $ate_job_data
|
||||
*
|
||||
* @return bool
|
||||
* @throws Requests_Exception
|
||||
*/
|
||||
private function maybe_apply_translation( array $ate_job_data ) {
|
||||
if ( isset( $ate_job_data['translated_xliff'] ) ) {
|
||||
$xliff_content = $this->ate_api->get_remote_xliff_content( $ate_job_data['translated_xliff'] );
|
||||
|
||||
if ( $xliff_content ) {
|
||||
return $this->ate_jobs->apply( $xliff_content );
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $ate_job_id
|
||||
* @param $ignore_errors
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function confirm_received_job( $ate_job_id, $ignore_errors ) {
|
||||
$confirmation_response = $this->ate_api->confirm_received_job( $ate_job_id );
|
||||
try {
|
||||
$this->check_response_error( $confirmation_response );
|
||||
|
||||
return true;
|
||||
} catch ( Exception $ex ) {
|
||||
if ( ! $ignore_errors ) {
|
||||
throw new $ex();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $response
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
protected function check_response_error( $response ) {
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$code = 0;
|
||||
$message = $response->get_error_message();
|
||||
if ( $response->error_data && is_array( $response->error_data ) ) {
|
||||
foreach ( $response->error_data as $http_code => $error_data ) {
|
||||
$code = $error_data[0]['status'];
|
||||
$message = '';
|
||||
|
||||
switch ( (int) $code ) {
|
||||
case self::RESPONSE_ATE_NOT_ACTIVE_ERROR:
|
||||
$wp_admin_url = admin_url( 'admin.php' );
|
||||
$mcsetup_page = add_query_arg(
|
||||
array(
|
||||
'page' => WPML_TM_FOLDER . WPML_Translation_Management::PAGE_SLUG_SETTINGS,
|
||||
'sm' => 'mcsetup',
|
||||
),
|
||||
$wp_admin_url
|
||||
);
|
||||
$mcsetup_page .= '#ml-content-setup-sec-1';
|
||||
|
||||
$resend_link = '<a href="' . $mcsetup_page . '">'
|
||||
. esc_html__( 'Resend that email', 'wpml-translation-management' )
|
||||
. '</a>';
|
||||
$message .= '<p>'
|
||||
. esc_html__( 'WPML cannot send these documents to translation because the Advanced Translation Editor is not fully set-up yet.', 'wpml-translation-management' )
|
||||
. '</p><p>'
|
||||
. esc_html__( 'Please open the confirmation email that you received and click on the link inside it to confirm your email.', 'wpml-translation-management' )
|
||||
. '</p><p>'
|
||||
. $resend_link
|
||||
. '</p>';
|
||||
break;
|
||||
case self::RESPONSE_ATE_DUPLICATED_SOURCE_ID:
|
||||
case self::RESPONSE_ATE_UNEXPECTED_ERROR:
|
||||
default:
|
||||
$message = '<p>'
|
||||
. __( 'Advanced Translation Editor error:', 'wpml-translation-management' )
|
||||
. '</p><p>'
|
||||
. $error_data[0]['message']
|
||||
. '</p>';
|
||||
}
|
||||
|
||||
$message = '<p>' . $message . '</p>';
|
||||
}
|
||||
}
|
||||
/** @var WP_Error $response */
|
||||
throw new RuntimeException( $message, $code );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $ate_job_id
|
||||
*/
|
||||
private function resign_job_on_error( $ate_job_id ) {
|
||||
$job_id = $this->ate_jobs->get_wpml_job_id( $ate_job_id );
|
||||
if ( $job_id ) {
|
||||
wpml_load_core_tm()->resign_translator( $job_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $translation_job
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function is_ate_translation_job( $translation_job ) {
|
||||
return 'local' === $translation_job->translation_service
|
||||
&& WPML_TM_Editors::ATE === $translation_job->editor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $post
|
||||
*
|
||||
* @return array|null|WP_Post
|
||||
*/
|
||||
private function get_wp_post( $post ) {
|
||||
if ( ! $post instanceof WP_Post ) {
|
||||
if ( isset( $post->ID ) ) {
|
||||
$post = get_post( $post->ID );
|
||||
} else {
|
||||
$post = null;
|
||||
}
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function is_edit_list_page_of_a_translatable_type() {
|
||||
return $this->current_screen->is_edit_posts_list()
|
||||
&& $this->sitepress->is_translated_post_type( $this->current_screen->get_post_type() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function is_edit_page_of_a_translatable_type() {
|
||||
return $this->current_screen->is_edit_post()
|
||||
&& $this->sitepress->is_translated_post_type( $this->current_screen->get_post_type() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $trid
|
||||
* @param string $element_type
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function get_original_element( $trid, $element_type ) {
|
||||
if ( ! array_key_exists( $trid, $this->trid_original_element_map ) ) {
|
||||
$element_translation = $this->sitepress->get_original_element_translation( $trid, $element_type );
|
||||
if ( $element_translation ) {
|
||||
$this->trid_original_element_map[ $trid ] = $element_translation;
|
||||
|
||||
return $element_translation;
|
||||
}
|
||||
}
|
||||
|
||||
return $this->trid_original_element_map[ $trid ];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $job_status
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function must_acknowledge_ATE( $job_status ) {
|
||||
return $job_status['status_id'] === WPML_TM_ATE_AMS_Endpoints::ATE_JOB_STATUS_DELIVERING;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @todo Perhaps this class is redundant
|
||||
*
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ATE_Jobs_Store_Actions_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
/**
|
||||
* @return IWPML_Action|IWPML_Action[]|null
|
||||
*/
|
||||
public function create() {
|
||||
if ( WPML_TM_ATE_Status::is_enabled() ) {
|
||||
|
||||
$ate_jobs_records = wpml_tm_get_ate_job_records();
|
||||
$ate_jobs = new WPML_TM_ATE_Jobs( $ate_jobs_records );
|
||||
|
||||
return new WPML_TM_ATE_Jobs_Store_Actions( $ate_jobs );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @todo The hook 'wpml_tm_ate_jobs_store' seems to be never used so this class and its factory may be obsolete
|
||||
*
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ATE_Jobs_Store_Actions implements IWPML_Action {
|
||||
/**
|
||||
* @var WPML_TM_ATE_Jobs
|
||||
*/
|
||||
private $ate_jobs;
|
||||
|
||||
/**
|
||||
* WPML_TM_ATE_Jobs_Actions constructor.
|
||||
*
|
||||
* @param WPML_TM_ATE_Jobs $ate_jobs
|
||||
*/
|
||||
public function __construct( WPML_TM_ATE_Jobs $ate_jobs ) {
|
||||
$this->ate_jobs = $ate_jobs;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'wpml_tm_ate_jobs_store', array( $this, 'store' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $wpml_job_id
|
||||
* @param array $ate_job_data
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function store( $wpml_job_id, $ate_job_data ) {
|
||||
return $this->ate_jobs->store( $wpml_job_id, $ate_job_data );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
use WPML\TM\ATE\Download\Queue;
|
||||
use WPML\TM\ATE\Sync\Trigger;
|
||||
use WPML\TM\ATE\ReturnedJobsQueue;
|
||||
use function WPML\FP\pipe;
|
||||
use WPML\FP\Relation;
|
||||
use WPML\FP\Fns;
|
||||
|
||||
class WPML_TM_ATE_Jobs_Sync_Script_Loader {
|
||||
|
||||
const JS_HANDLER = 'wpml-tm-ate-jobs-sync';
|
||||
const JS_VARIABLE = 'WPML_ATE_JOBS_SYNC';
|
||||
|
||||
/** @var WPML_TM_Scripts_Factory */
|
||||
private $script_factory;
|
||||
|
||||
/** @var WPML_TM_ATE_Job_Repository */
|
||||
private $ate_jobs_repository;
|
||||
|
||||
/** @var Trigger $syncTrigger */
|
||||
private $syncTrigger;
|
||||
|
||||
/** @var Queue $downloadQueue */
|
||||
private $downloadQueue;
|
||||
|
||||
public function __construct(
|
||||
WPML_TM_Scripts_Factory $script_factory,
|
||||
WPML_TM_ATE_Job_Repository $ate_jobs_repository,
|
||||
Trigger $syncTrigger,
|
||||
Queue $downloadQueue
|
||||
) {
|
||||
$this->script_factory = $script_factory;
|
||||
$this->ate_jobs_repository = $ate_jobs_repository;
|
||||
$this->syncTrigger = $syncTrigger;
|
||||
$this->downloadQueue = $downloadQueue;
|
||||
}
|
||||
|
||||
|
||||
public function load() {
|
||||
$jobsToSync = $this->ate_jobs_repository->get_jobs_to_sync();
|
||||
|
||||
if (
|
||||
$jobsToSync->count()
|
||||
|| $this->syncTrigger->isSyncRequired()
|
||||
|| $this->downloadQueue->count()
|
||||
) {
|
||||
wp_register_script(
|
||||
self::JS_HANDLER,
|
||||
WPML_TM_URL . '/dist/js/ate/jobs-sync-app.js',
|
||||
[],
|
||||
WPML_TM_VERSION
|
||||
);
|
||||
|
||||
$jobIds = $jobsToSync->map_to_property( 'translate_job_id' );
|
||||
|
||||
// $isCompletedButNotDownloaded :: int->bool
|
||||
$isCompletedButNotDownloaded = pipe(
|
||||
[ ReturnedJobsQueue::class, 'getStatus' ],
|
||||
Relation::equals( ReturnedJobsQueue::STATUS_COMPLETED )
|
||||
);
|
||||
|
||||
wp_localize_script(
|
||||
self::JS_HANDLER,
|
||||
self::JS_VARIABLE,
|
||||
[
|
||||
'jobIds' => $jobIds,
|
||||
'completedInATE' => Fns::filter( $isCompletedButNotDownloaded, $jobIds ),
|
||||
'strings' => [
|
||||
'tooltip' => __(
|
||||
'Processing translation (could take a few minutes)',
|
||||
'wpml-translation-management'
|
||||
),
|
||||
'status' => __( 'Processing translation', 'wpml-translation-management' ),
|
||||
],
|
||||
]
|
||||
);
|
||||
|
||||
wp_enqueue_script( self::JS_HANDLER );
|
||||
|
||||
$this->script_factory->localize_script( self::JS_HANDLER );
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ATE_Post_Edit_Actions_Factory implements IWPML_Backend_Action_Loader {
|
||||
|
||||
/**
|
||||
* @return IWPML_Action|IWPML_Action[]|null
|
||||
*/
|
||||
public function create() {
|
||||
$tm_ate = new WPML_TM_ATE();
|
||||
$endpoints = WPML\Container\make( 'WPML_TM_ATE_AMS_Endpoints' );
|
||||
|
||||
if ( $tm_ate->is_translation_method_ate_enabled() ) {
|
||||
return new WPML_TM_ATE_Post_Edit_Actions( $endpoints );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
|
||||
class WPML_TM_ATE_Post_Edit_Actions implements IWPML_Action {
|
||||
private $endpoints;
|
||||
|
||||
/**
|
||||
* WPML_TM_ATE_Jobs_Actions constructor.
|
||||
*
|
||||
* @param WPML_TM_ATE_AMS_Endpoints $endpoints
|
||||
*/
|
||||
public function __construct( WPML_TM_ATE_AMS_Endpoints $endpoints ) {
|
||||
$this->endpoints = $endpoints;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_filter( 'allowed_redirect_hosts', array( $this, 'allowed_redirect_hosts' ) );
|
||||
}
|
||||
|
||||
public function allowed_redirect_hosts( $hosts ) {
|
||||
$hosts[] = $this->endpoints->get_AMS_host();
|
||||
$hosts[] = $this->endpoints->get_ATE_host();
|
||||
|
||||
return $hosts;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ATE_Required_Actions_Base {
|
||||
private $ate_enabled;
|
||||
|
||||
protected function is_ate_enabled() {
|
||||
if ( null === $this->ate_enabled ) {
|
||||
$tm_settings = wpml_get_setting_filter( null, 'translation-management' );
|
||||
$doc_translation_method = null;
|
||||
if ( array_key_exists( 'doc_translation_method', $tm_settings ) ) {
|
||||
$doc_translation_method = $tm_settings['doc_translation_method'];
|
||||
}
|
||||
$this->ate_enabled = $doc_translation_method === ICL_TM_TMETHOD_ATE;
|
||||
}
|
||||
|
||||
return $this->ate_enabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* \WPML_TM_ATE_Translator_Login factory.
|
||||
*
|
||||
* @author OnTheGo Systems
|
||||
*
|
||||
* NOTE: This uses the Frontend loader because is_admin() returns false during wp_login
|
||||
*/
|
||||
class WPML_TM_ATE_Translator_Login_Factory implements IWPML_Frontend_Action_Loader {
|
||||
|
||||
/**
|
||||
* It returns an instance of WPML_TM_ATE_Translator_Login is ATE is enabled and active.
|
||||
*
|
||||
* @return \WPML_TM_ATE_Translator_Logine|\IWPML_Frontend_Action_Loader|null
|
||||
*/
|
||||
public function create() {
|
||||
if ( WPML_TM_ATE_Status::is_enabled_and_activated() ) {
|
||||
return WPML\Container\make( WPML_TM_ATE_Translator_Login::class );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* @author OnTheGo Systems
|
||||
*/
|
||||
class WPML_TM_ATE_Translator_Login implements IWPML_Action {
|
||||
|
||||
/** @var WPML_TM_AMS_Translator_Activation_Records */
|
||||
private $translator_activation_records;
|
||||
|
||||
/** @var WPML_Translator_Records */
|
||||
private $translator_records;
|
||||
|
||||
/** @var WPML_TM_AMS_API */
|
||||
private $ams_api;
|
||||
|
||||
public function __construct(
|
||||
WPML_TM_AMS_Translator_Activation_Records $translator_activation_records,
|
||||
WPML_Translator_Records $translator_records,
|
||||
WPML_TM_AMS_API $ams_api
|
||||
) {
|
||||
$this->translator_activation_records = $translator_activation_records;
|
||||
$this->translator_records = $translator_records;
|
||||
$this->ams_api = $ams_api;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'wp_login', array( $this, 'wp_login' ), 10, 2 );
|
||||
}
|
||||
|
||||
public function wp_login( $user_login, $user ) {
|
||||
if ( $this->translator_records->does_user_have_capability( $user->ID ) ) {
|
||||
$result = $this->ams_api->is_subscription_activated( $user->user_email );
|
||||
if ( ! is_wp_error( $result ) ) {
|
||||
$this->translator_activation_records->set_activated(
|
||||
$user->user_email,
|
||||
$result
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
<?php
|
||||
|
||||
class WPML_TM_ATE_Translator_Message_Classic_Editor_Factory implements IWPML_Backend_Action_Loader, IWPML_AJAX_Action_Loader {
|
||||
|
||||
/**
|
||||
* @return \WPML_TM_ATE_Translator_Message_Classic_Editor|\IWPML_Action|null
|
||||
*/
|
||||
public function create() {
|
||||
global $wpdb;
|
||||
|
||||
if ( $this->is_ajax_or_translation_queue() && $this->is_ate_enabled_and_manager_wizard_completed() && ! $this->is_editing_old_translation_and_te_is_used_for_old_translation() ) {
|
||||
|
||||
$email_twig_factory = wpml_tm_get_email_twig_template_factory();
|
||||
|
||||
return new WPML_TM_ATE_Translator_Message_Classic_Editor(
|
||||
new WPML_Translation_Manager_Records(
|
||||
$wpdb,
|
||||
wpml_tm_get_wp_user_query_factory(),
|
||||
wp_roles()
|
||||
),
|
||||
wpml_tm_get_wp_user_factory(),
|
||||
new WPML_TM_ATE_Request_Activation_Email(
|
||||
new WPML_TM_Email_Notification_View( $email_twig_factory->create() )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function is_editing_old_translation_and_te_is_used_for_old_translation() {
|
||||
return array_key_exists( 'job_id', $_GET )
|
||||
&& filter_var( $_GET['job_id'], FILTER_SANITIZE_STRING )
|
||||
&& get_option( WPML_TM_Old_Jobs_Editor::OPTION_NAME ) === WPML_TM_Editors::WPML;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function is_ate_enabled_and_manager_wizard_completed() {
|
||||
return WPML_TM_ATE_Status::is_enabled_and_activated() && (bool) get_option( WPML_TM_Wizard_Options::WIZARD_COMPLETE_FOR_MANAGER, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function is_ajax_or_translation_queue() {
|
||||
return wpml_is_ajax() || WPML_TM_Page::is_translation_queue();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
<?php
|
||||
|
||||
class WPML_TM_ATE_Translator_Message_Classic_Editor implements IWPML_Action {
|
||||
|
||||
const ACTION = 'wpml_ate_translator_classic_editor';
|
||||
const USER_OPTION = 'wpml_ate_translator_classic_editor_minimized';
|
||||
|
||||
/** @var WPML_Translation_Manager_Records */
|
||||
private $translation_manager_records;
|
||||
|
||||
/** @var WPML_WP_User_Factory */
|
||||
private $user_factory;
|
||||
|
||||
/** @var WPML_TM_ATE_Request_Activation_Email */
|
||||
private $activation_email;
|
||||
|
||||
public function __construct(
|
||||
WPML_Translation_Manager_Records $translation_manager_records,
|
||||
WPML_WP_User_Factory $user_factory,
|
||||
WPML_TM_ATE_Request_Activation_Email $activation_email
|
||||
) {
|
||||
$this->translation_manager_records = $translation_manager_records;
|
||||
$this->user_factory = $user_factory;
|
||||
$this->activation_email = $activation_email;
|
||||
}
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( 'wpml_tm_editor_messages', array( $this, 'classic_editor_message' ) );
|
||||
add_action( 'wp_ajax_' . self::ACTION, array( $this, 'handle_ajax' ) );
|
||||
}
|
||||
|
||||
public function classic_editor_message() {
|
||||
$main_message = esc_html__( "This site can use WPML's Advanced Translation Editor, but you did not receive permission to use it. You are still translating with WPML's classic translation editor. Please ask your site's Translation Manager to enable the Advanced Translation Editor for you.", 'wpml-translation-management' );
|
||||
$learn_more = esc_html__( "Learn more about WPML's Advanced Translation Editor", 'wpml-translation-management' );
|
||||
$short_message = esc_html__( 'Advanced Translation Editor is disabled.', 'wpml-translation-management' );
|
||||
$more = esc_html__( 'More', 'wpml-translation-management' );
|
||||
$request_activation = esc_html__( 'Request activation from', 'wpml-translation-management' );
|
||||
|
||||
$show_minimized = (bool) $this->user_factory->create_current()->get_option( self::USER_OPTION );
|
||||
|
||||
?>
|
||||
<div
|
||||
class="notice notice-info otgs-notice js-classic-editor-notice"
|
||||
data-nonce="<?php echo wp_create_nonce( self::ACTION ); ?>"
|
||||
data-action="<?php echo self::ACTION; ?>"
|
||||
<?php
|
||||
if ( $show_minimized ) {
|
||||
?>
|
||||
style="display: none" <?php } ?>
|
||||
>
|
||||
<p><?php echo $main_message; ?></p>
|
||||
<p><a href="#" class="wpml-external-link" target="_blank"><?php echo $learn_more; ?></a></p>
|
||||
<p>
|
||||
<a class="button js-request-activation"><?php echo $request_activation; ?></a> <?php $this->output_translation_manager_list(); ?>
|
||||
</p>
|
||||
<p class="js-email-sent" style="display: none"></p>
|
||||
|
||||
<a class="js-minimize otgs-notice-toggle">
|
||||
<?php esc_html_e( 'Minimize', 'wpml-translation-management' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="notice notice-info otgs-notice js-classic-editor-notice-minimized"
|
||||
<?php
|
||||
if ( ! $show_minimized ) {
|
||||
?>
|
||||
style="display: none" <?php } ?>
|
||||
>
|
||||
<p><?php echo $short_message; ?> <a class="js-maximize"><?php echo $more; ?></a></p>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
private function output_translation_manager_list() {
|
||||
$translation_managers = $this->translation_manager_records->get_users_with_capability();
|
||||
?>
|
||||
|
||||
<select class="js-translation-managers">
|
||||
<?php
|
||||
foreach ( $translation_managers as $translation_manager ) {
|
||||
$display_name = $translation_manager->user_login . ' (' . $translation_manager->user_email . ')';
|
||||
?>
|
||||
<option
|
||||
value="<?php echo $translation_manager->ID; ?> "><?php echo $display_name; ?></option>
|
||||
<?php } ?>
|
||||
</select>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
public function handle_ajax() {
|
||||
if ( wp_verify_nonce( $_POST['nonce'], self::ACTION ) ) {
|
||||
$current_user = $this->user_factory->create_current();
|
||||
|
||||
switch ( $_POST['command'] ) {
|
||||
case 'minimize':
|
||||
$current_user->update_option( self::USER_OPTION, true );
|
||||
wp_send_json_success( array( 'message' => '' ) );
|
||||
|
||||
case 'maximize':
|
||||
$current_user->update_option( self::USER_OPTION, false );
|
||||
wp_send_json_success( array( 'message' => '' ) );
|
||||
|
||||
case 'requestActivation':
|
||||
$manager = $this->user_factory->create( (int) $_POST['manager'] );
|
||||
if ( $this->activation_email->send_email( $manager, $current_user ) ) {
|
||||
$message = sprintf(
|
||||
esc_html__( 'An email has been sent to %s', 'wpml-translation-management' ),
|
||||
$manager->user_login
|
||||
);
|
||||
} else {
|
||||
$message = sprintf(
|
||||
esc_html__( 'Sorry, the email could not be sent to %s for an unknown reason.', 'wpml-translation-management' ),
|
||||
$manager->user_login
|
||||
);
|
||||
}
|
||||
wp_send_json_success( array( 'message' => $message ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<?php
|
||||
|
||||
class WPML_TM_Old_Editor_Factory implements IWPML_Backend_Action_Loader, IWPML_AJAX_Action_Loader {
|
||||
|
||||
public function create() {
|
||||
return new WPML_TM_Old_Editor();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
|
||||
class WPML_TM_Old_Editor implements IWPML_Action {
|
||||
const ACTION = 'icl_ajx_custom_call';
|
||||
|
||||
const CUSTOM_AJAX_CALL = 'icl_doc_translation_method';
|
||||
|
||||
const NOTICE_ID = 'wpml-translation-management-old-editor';
|
||||
|
||||
const NOTICE_GROUP = 'wpml-translation-management';
|
||||
|
||||
public function add_hooks() {
|
||||
add_action( self::ACTION, array( $this, 'handle_custom_ajax_call' ), 10, 2 );
|
||||
}
|
||||
|
||||
public function handle_custom_ajax_call( $call, $data ) {
|
||||
if ( self::CUSTOM_AJAX_CALL === $call ) {
|
||||
if ( ! isset( $data[ WPML_TM_Old_Jobs_Editor::OPTION_NAME ] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$old_editor = $data[ WPML_TM_Old_Jobs_Editor::OPTION_NAME ];
|
||||
|
||||
if ( ! in_array( $old_editor, array( WPML_TM_Editors::WPML, WPML_TM_Editors::ATE ), true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
update_option( WPML_TM_Old_Jobs_Editor::OPTION_NAME, $old_editor );
|
||||
|
||||
if ( WPML_TM_Editors::WPML === $old_editor && $this->is_ate_enabled_and_manager_wizard_completed() ) {
|
||||
$text = __( 'You activated the Advanced Translation Editor for this site, but you are updating an old translation. WPML opened the Standard Translation Editor, so you can update this translation. When you translate new content, you\'ll get the Advanced Translation Editor with all its features. To change your settings, go to WPML Settings.', 'sitepress' );
|
||||
$notice = new WPML_Notice( self::NOTICE_ID, $text, self::NOTICE_GROUP );
|
||||
$notice->set_css_class_types( 'notice-info' );
|
||||
$notice->set_dismissible( true );
|
||||
$notice->add_display_callback( 'WPML_TM_Page::is_translation_editor_page' );
|
||||
wpml_get_admin_notices()->add_notice( $notice, true );
|
||||
} else {
|
||||
wpml_get_admin_notices()->remove_notice( self::NOTICE_GROUP, self::NOTICE_ID );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function is_ate_enabled_and_manager_wizard_completed() {
|
||||
return WPML_TM_ATE_Status::is_enabled_and_activated() && (bool) get_option( WPML_TM_Wizard_Options::WIZARD_COMPLETE_FOR_MANAGER, false );
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user