/home/fdhrevqn/public_html/wp-content/plugins.disabled/lingotek-translation/include/api.php
<?php
if ( ! defined( 'ABSPATH' ) ) exit();
require_once 'http.php';
/**
* manages communication with Lingotek TMS
* uses Lingotek API V5
*
* @since 0.1
*/
class Lingotek_API extends Lingotek_HTTP {
protected $base_url;
protected $api_url;
protected $client_id;
private $auth_temp;
const PRODUCTION_URL = 'https://myaccount.lingotek.com';
// Lingotek App ID.
const CLIENT_ID = '780966c9-f9c8-4691-96e2-c0aaf47f62ff';
private $bridge_url = '';
/**
* constructor
*
* @since 0.1
*/
public function __construct() {
$base_url = get_option( 'lingotek_base_url' );
$this->base_url = $base_url ? $base_url : self::PRODUCTION_URL;
$this->api_url = $this->base_url . '/api';
$this->client_id = self::CLIENT_ID;
$token_details = get_option( 'lingotek_token', array() );
if ( isset( $token_details['access_token'] ) ) {
$this->headers['Authorization'] = 'bearer ' . $token_details['access_token'];
}
$this->defaults = get_option( 'lingotek_defaults', array() );
$this->bridge_url = LINGOTEK_BRIDGE_URL . '/api/v2/transaction/translation/';
}
public function get_token_details( $access_token ) {
$url = "{$this->base_url}/auth/oauth2/access_token_info";
Lingotek_Logger::debug(
'GET',
array(
'url' => $url,
'method' => __METHOD__,
)
);
$args = array(
'headers' => array(
'Authorization' => "Bearer $access_token",
),
);
$response = wp_remote_get( $url, $args );
$response_code = wp_remote_retrieve_response_code( $response );
if ( $response_code == 200 ) {
$response_body = json_decode( wp_remote_retrieve_body( $response ) );
$token_details = $response_body;
} else {
$token_details = false;
}
$this->log_error_on_response_failure( $response, 'GetTokenDetails: Error occured' );
return $token_details;
}
public function get_api_url() {
return $this->api_url;
}
/**
* updates the projet callback
*
* @since 0.2
*
* @param string $project_id
*/
public function update_callback_url( $project_id ) {
$args = array( 'callback_url' => add_query_arg( 'lingotek', 1, site_url() ) );
$response = $this->patch( $this->api_url . '/project/' . $project_id, $args );
Lingotek_Logger::info( 'Request to update callback url', array( 'project_id' => $project_id ) );
$this->log_error_on_response_failure( $response, 'UpdateCallbackUrl: Error occured', array( 'project_id' => $project_id ) );
return ! is_wp_error( $response ) && 204 == wp_remote_retrieve_response_code( $response );
}
/**
* creates a new project
*
* @since 0.2
*
* @param string $title
*/
public function create_project( $title, $community_id ) {
$args = array(
'title' => $title,
'community_id' => $community_id,
'workflow_id' => $this->get_workflow_id(),
'callback_url' => add_query_arg( 'lingotek', 1, site_url() ),
);
$response = $this->post( $this->api_url . '/project', $args );
if ( ! is_wp_error( $response ) && 201 == wp_remote_retrieve_response_code( $response ) ) {
$new_id = json_decode( wp_remote_retrieve_body( $response ) );
Lingotek_Logger::info(
'Project created',
array(
'id' => $new_id->properties->id,
'title' => $title,
)
);
return $new_id->properties->id;
}
$this->log_error_on_response_failure(
$response,
'CreateProject: Error occured',
array(
'title' => $title,
'community_id' => $community_id,
)
);
return false;
}
/**
* uploads a document
*
* @since 0.1
*
* @param array $args expects array with title, content and locale_code
* @returns bool|string document_id, false if something got wrong
*/
public function upload_document( $args, $wp_id = null ) {
$args = wp_parse_args(
$args,
array(
'format' => 'JSON',
'project_id' => $this->defaults['project_id'],
'workflow_id' => $this->get_workflow_id(),
)
);
$this->format_as_multipart( $args );
$response = $this->post( $this->api_url . '/document', $args );
$this->update_lingotek_error_option( $response, $wp_id, 'upload_document', sprintf( __( 'There was an error uploading WordPress item %1$s', 'lingotek-translation' ), $wp_id ) );
$code = wp_remote_retrieve_response_code( $response );
if ( ! is_wp_error( $response ) && 202 == $code ) {
$b = json_decode( wp_remote_retrieve_body( $response ) );
Lingotek_Logger::info(
'Document uploaded',
array(
'document_id' => $b->properties->id,
'wp_id' => $wp_id,
)
);
return $b->properties->id;
} elseif ( $code == 402 ) {
$lingotek_log_errors = get_option( 'lingotek_log_errors' );
$error_message = $this->get_error_message_from_response( $response ) !== false ?
$this->get_error_message_from_response( $response ) : 'No error message set by Lingotek';
$lingotek_log_errors['patch_document_error'] = sprintf(
__("Payment required. Message: %s", 'lingotek-translation'),
esc_html($error_message)
);
update_option( 'lingotek_log_errors', $lingotek_log_errors, false );
} elseif ( $code == 429 ) {
$lingotek_log_errors = get_option( 'lingotek_log_errors', array() );
$lingotek_log_errors['word_limit_error'] = true;
update_option( 'lingotek_log_errors', $lingotek_log_errors, false );
}//end if
return false;
}
/**
* modifies a document
*
* @since 0.1
*
* @param string $id document id
* @param array $args expects array with content
* @return bool|string false if something got wrong
*/
public function patch_document( $id, $args, $wp_id = null ) {
$lgtm = $GLOBALS['wp_lingotek']->model;
$document = $lgtm->get_group_by_id( $id );
$args = $unformatted_args = wp_parse_args( $args, array( 'format' => 'JSON' ) );
$title = isset( $args['title'] ) ? $args['title'] : $id;
$this->format_as_multipart( $args );
$response = $this->patch( $this->api_url . '/document/' . $id, $args );
$status_code = wp_remote_retrieve_response_code( $response );
$body = json_decode( wp_remote_retrieve_body( $response ) );
if ( $status_code == 400 && strpos( $body->messages[0], 'has previously been cancelled' ) ) {
// Document has been cancelled, re-upload the post
// Slug can't be empty or duplicated, so we prefix `disassociated` to show the document id is no longer associated with this post
$document->document_id = 'disassociated_' . $document->document_id;
unset( $document->desc_array['lingotek'] );
$document->save();
return $lgtm->upload_post( $wp_id );
}
if ( $status_code == 423 ) {
$document->document_id = $body->next_document_id;
$document->save();
return $this->patch_document( $body->next_document_id, $unformatted_args, $wp_id );
}
if ( $status_code == 429 ) {
$lingotek_log_errors = get_option( 'lingotek_log_errors', array() );
$lingotek_log_errors['word_limit_error'] = true;
update_option( 'lingotek_log_errors', $lingotek_log_errors, false );
return false;
}
// We will handle patch errors separately. All we want to do is return the result of the current patch request to the user if payment is required
// (although in theory this will never happen, because the WP model is document count based, and it will not allow them to upload documents until
// they choose to buy more documents)
$this->update_patch_error_message( $response, $status_code, $title );
// The current behavior sends no body, so we will just check to see if the body is empty for now in order to maintain current behavior
if ( empty( $body ) ) {
$success = ! is_wp_error( $response ) && 202 == wp_remote_retrieve_response_code( $response );
if ( $success ) {
Lingotek_Logger::info(
'Document updated',
array(
'document_id' => $id,
'wp_id' => $wp_id,
)
);
} else {
Lingotek_Logger::error(
'Document failed to update',
array(
'document_id' => $id,
'wp_id' => $wp_id,
)
);
}
return $success;
}//end if
if ( $status_code == 410 || $status_code == 404 ) {
$document_status_string = $status_code == 410 ? 'archived' : 'not found';
Lingotek_Logger::info(
'Document ID was ' . $document_status_string . ', reuploading document',
array(
'old_document_id' => $id,
'wp_id' => $wp_id,
'args' => $args,
)
);
$targets = array_keys( $document->translations );
$lingotek_locales = array();
foreach ( $targets as $target ) {
// Targets stored in the document translations property are the polylang targets, so we need to get the lingotek locales instead
$document->translations[ $target ] = 'pending';
$lingotek_locales[] = Lingotek::map_to_lingotek_locale( $target );
}
$unformatted_args['translation_locale_code'] = $lingotek_locales;
$this->format_args_for_upload( $unformatted_args, $wp_id );
$document->document_id = 'disassociated_' . $document->document_id;
unset( $document->desc_array['lingotek'] );
$document->save();
return $this->upload_document( $unformatted_args, $wp_id );
}//end if
if ( $status_code == 402 ) {
Lingotek_Logger::error( 'There was an error updating WordPress item', array( 'error' => $this->get_error_message_from_response( $response ) ) );
$document->source_failed();
return false;
}
if ( $status_code == 202 && ! is_wp_error( $response ) ) {
Lingotek_Logger::info(
'Document updated',
array(
'old_document_id' => $id,
'new_document_id' => $body->next_document_id,
'wp_id' => $wp_id,
)
);
$document->document_id = $body->next_document_id;
$document->save();
return $body->next_document_id;
}
return false;
}
private function format_args_for_upload( &$args, $wp_id ) {
$lgtm = $GLOBALS['wp_lingotek']->model;
$post = get_post( $wp_id );
$language = PLL()->model->post->get_language( $wp_id );
$project_id = $lgtm->get_profile_option( 'project_id', $post->post_type, $language, false, $wp_id );
$workflow_id = $lgtm->get_profile_option( 'workflow_id', $post->post_type, $language, false, $wp_id );
$locale_code = $language->lingotek_locale;
unset( $args['format'] );
$args['locale_code'] = $locale_code;
$args['project_id'] = $project_id;
$args['workflow_id'] = $workflow_id;
}
private function update_patch_error_message( $response, $status_code, $title ) {
// Do not inform user if call was successful.
if ( $status_code == 202 || $status_code == 410 || $status_code == 404 || $status_code == 429 ) {
return;
}
$lingotek_log_errors = get_option( 'lingotek_log_errors', array() );
if ( ! is_array( $lingotek_log_errors ) ) {
$lingotek_log_errors = array();
}
$error_message = $this->get_error_message_from_response( $response ) !== false ?
$this->get_error_message_from_response( $response ) : 'No error message set by Lingotek.';
if ( $status_code == 402 ) {
$lingotek_log_errors['patch_document_error'] = sprintf(
__("Payment required. Message: %s", 'lingotek-translation'),
esc_html($error_message)
);
} else {
$lingotek_log_errors['patch_document_error'] = sprintf(
__("Error occurred while updating document %s. Message: %s", 'lingotek-translation'),
$title,
$error_message
);
}
update_option( 'lingotek_log_errors', $lingotek_log_errors );
}
/**
* cancels a document
*
* @since 1.4.2
*
* @param string $id document id
*/
public function cancel_document( &$id, $wp_id = null ) {
$args = wp_parse_args( array( 'cancelled_reason' => 'CANCELLED_BY_AUTHOR' ) );
$response = $this->post( "$this->api_url/document/$id/cancel", $args );
if ( $wp_id ) {
$arr = get_option( 'lingotek_log_errors' );
if ( isset( $arr[ $wp_id ] ) ) {
unset( $arr[ $wp_id ] );
update_option( 'lingotek_log_errors', $arr, false );
}
}
$this->log_error_on_response_failure(
$response,
'CancelDocument: Error occurred',
array(
'id' => $id,
'wordpress_id' => $wp_id,
)
);
$is_success = ! is_wp_error( $response ) && ( 204 == wp_remote_retrieve_response_code( $response ) || 202 == wp_remote_retrieve_response_code( $response ) );
$lgtm = $GLOBALS['wp_lingotek']->model;
$document = $lgtm->get_group_by_id( $id );
$current_status = $document->status;
$document->status = 'cancelled';
if ( $is_success ) {
wp_remove_object_terms( $wp_id, "lingotek_hash_{$wp_id}", 'lingotek_hash' );
Lingotek_Logger::info(
'Document cancelled',
array(
'document_id' => $id,
'wp_id' => $wp_id,
)
);
$document->save();
return $is_success;
} elseif ( 403 != wp_remote_retrieve_response_code( $response ) ) {
wp_remove_object_terms( $wp_id, "lingotek_hash_{$wp_id}", 'lingotek_hash' );
Lingotek_Logger::warning(
'Document was not cancelled in TMS',
array(
'document' => $id,
'wp_id' => $wp_id,
)
);
// Slug can't be empty or duplicated, so we prefix `disassociated` to show the document id is no longer associated with this post
$document->document_id = $id = 'disassociated_' . $document->document_id;
$document->save();
return true;
}//end if
$document->status = $current_status;
$lingotek_log_errors = get_option( 'lingotek_log_errors', array() );
if ( ! is_array( $lingotek_log_errors ) ) {
$lingotek_log_errors = array();
}
$error_message = $this->get_error_message_from_response( $response ) !== false ?
$this->get_error_message_from_response( $response ) : 'No error message set by Lingotek.';
$lingotek_log_errors['disassociate_document_error'] = $error_message;
update_option( 'lingotek_log_errors', $lingotek_log_errors, false );
return $is_success;
}
/**
* get all documents ids
*
* @since 0.1
*/
public function get_document_ids( $args = array() ) {
$response = $this->get( add_query_arg( $args, $this->api_url . '/document' ) );
$ids = array();
if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
$documents = json_decode( wp_remote_retrieve_body( $response ) );
foreach ( $documents->entities as $doc ) {
$ids[] = $doc->properties->id;
}
}
$this->log_error_on_response_failure( $response, 'GetDocumentIds: Error occured' );
return $ids;
}
public function get_document_count( $args = array() ) {
$response = $this->get( add_query_arg( $args, $this->api_url . '/document' ) );
$docs = array();
if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
$response = json_decode( wp_remote_retrieve_body( $response ) );
return $response->properties->total;
}
$this->log_error_on_response_failure( $response, 'GetDocumentCount: Error occured' );
return null;
}
/**
* get all documents
*
* @since 0.1
*/
public function get_documents( $args = array() ) {
$response = $this->get( add_query_arg( $args, $this->api_url . '/document' ) );
$docs = array();
if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
$documents = json_decode( wp_remote_retrieve_body( $response ) );
foreach ( $documents->entities as $doc ) {
$docs[] = $doc;
}
}
$this->log_error_on_response_failure( $response, 'GetDocuments: Error occured' );
return $docs;
}
/**
* get document by id
*
* @since 0.1
*/
public function get_document( $doc_id ) {
$response = $this->get( $this->api_url . '/document/' . $doc_id );
if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
$document = json_decode( wp_remote_retrieve_body( $response ) );
}
$this->log_error_on_response_failure( $response, 'GetDocument: Error occured' );
return $document;
}
public function get_document_status( $doc_id ) {
$imported = false;
$response = $this->get( $this->api_url . '/document/' . $doc_id . '/status' );
if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
$body = json_decode( wp_remote_retrieve_body( $response ) );
// Cancelled docs return with a 200 status code,
$imported = 'cancelled' !== strtolower( $body->properties->status ) ? 'current' : 'cancelled';
} elseif ( 410 == wp_remote_retrieve_response_code( $response ) ) {
$imported = 'archived';
} elseif ( 404 == wp_remote_retrieve_response_code( $response ) ) {
$imported = 'deleted';
}
$this->log_error_on_response_failure( $response, 'GetDocumentStatus: Error occured', array( 'document_id' => $doc_id ) );
return $imported;
}
/**
* get specific document content
*
* @since 0.1
*
* @param string $id document id
* @return string
*/
public function get_document_content( $doc_id ) {
$response = $this->get( $this->api_url . "/document/$doc_id/content" );
if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
$content = wp_remote_retrieve_body( $response );
}
$this->log_error_on_response_failure( $response, 'GetDocumentContent: Error occured', array( 'document_id' => $doc_id ) );
return $content;
}
/**
* check translations status of a specific locale for a document
*
* @since 0.1
*
* @param string $doc_id document id
* @param string $locale locale
* @return bool
*/
public function get_translation_status( $doc_id, $locale ) {
$locale = Lingotek::map_to_lingotek_locale( $locale );
$status = false;
$response = $this->get( $this->api_url . "/document/$doc_id/translation/$locale" );
if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
$b = json_decode( wp_remote_retrieve_body( $response ) );
$ready_to_download = $b->properties->ready_to_download;
$status = is_string( $ready_to_download ) ? filter_var( $ready_to_download, FILTER_VALIDATE_BOOLEAN ) : (bool) $ready_to_download;
}
$this->log_error_on_response_failure(
$response,
'GetTranslationStatus: Error occurred',
array(
'document_id' => $doc_id,
'locale' => $locale,
)
);
return $status;
}
/**
* check translations status of a document
*
* @since 0.1
*
* @param string $id document id
* @return array with locale as key and status as value
*/
public function get_translations_status( $doc_id, $wp_id = null ) {
$response = $this->get( $this->api_url . '/document/' . $doc_id . '/translation' );
if ( ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ) {
$b = json_decode( wp_remote_retrieve_body( $response ) );
foreach ( $b->entities as $e ) {
if ( $e->properties->status != 'CANCELLED' ) {
// cancelled is in a completed state, but it does not mean the translation is 100% complete
$ready_to_download = $e->properties->ready_to_download;
$ready_to_download = is_string( $ready_to_download ) ? filter_var( $ready_to_download, FILTER_VALIDATE_BOOLEAN ) : (bool) $ready_to_download;
$translations[ $e->properties->locale_code ] = array(
'progress' => $e->properties->status,
'percent_complete' => $e->properties->percent_complete,
'ready_to_download' => $ready_to_download,
);
}
}
}
Lingotek_Logger::info(
'Translation status requested',
array(
'document_id' => $doc_id,
'wp_id' => $wp_id,
'translations' => isset( $translations ) ? $translations : '',
)
);
$this->update_lingotek_error_option(
$response,
$wp_id,
'get_translations_status',
sprintf( __( 'There was an error updating the translations status for WordPress item %1$s', 'lingotek-translation' ), $wp_id ),
array( 'document_id' => $doc_id )
);
return empty( $translations ) ? array() : $translations;
}
public function get_language_mappings() {
$url = 'https://gmc.lingotek.com/v1/locales';
$response = $this->get( $url );
return json_decode( wp_remote_retrieve_body( $response ), true );
}
/**
* Makes an API call to bridge to get the estimated cost for translating a particular document professionally.
*
* @param string $lingotek_auth the auth token to make an API call to bridge.
* @param string $document_id the id of the specific document.
* @param string $locale the locale of the document being requested.
*/
public function get_cost_estimate( $lingotek_auth, $document_id, $locale ) {
$this->start_bridge_call();
$args = array(
'document_id' => $document_id,
'locale' => $locale,
);
$response = $this->get( $this->bridge_url . 'estimate', $args );
$success = 200 === wp_remote_retrieve_response_code( $response );
$this->end_bridge_call();
$this->log_error_on_response_failure(
$response,
'GetCostEstimate: Error occured',
array(
'document_id' => $document_id,
'locale' => $locale,
)
);
return array(
'success' => $success,
'data' => $this->get_response_body_from_bridge( $response ),
);
}
/**
* Makes an API call to bridge request translation for a document using the professional workflow.
*
* @param string $document_id the id of the specific document.
* @param string $locale the locale of the document being requested.
* @param string $workflow_id the id used to process the document.
*/
public function request_professional_translation( $document_id, $locale, $workflow_id ) {
$this->start_bridge_call();
$args = array(
'document_id' => $document_id,
'locale' => $locale,
'workflow_id' => $workflow_id,
);
$response = $this->post( $this->bridge_url . 'request', $args );
$success = 200 === wp_remote_retrieve_response_code( $response );
$this->end_bridge_call();
if ( $success ) {
Lingotek_Logger::info(
'Professional translation requested',
array(
'document_id' => $document_id,
'locale' => $locale,
'wordflow_id' => $workflow_id,
)
); }
$this->log_error_on_response_failure(
$response,
'RequestProfessionalTranslation: Error occured',
array(
'document_id' => $document_id,
'locale' => $locale,
'workflow_id' => $workflow_id,
)
);
return array(
'success' => $success,
'data' => $this->get_response_body_from_bridge( $response ),
);
}
/**
* Makes an API call to bridge request bulk translations for a document using the professional workflow.
*
* @param string $document_id the id of the specific document.
* @param string $locale the locale of the document being requested.
* @param string $workflow_id the id used to process the document.
*/
public function request_professional_translation_bulk( $workflow_id, $translations, $total_estimate, $summary ) {
$this->start_bridge_call();
$args = array(
'workflow_id' => $workflow_id,
'translations' => $translations,
'total_estimate' => $total_estimate,
'summary' => $summary,
);
$response = $this->post( $this->bridge_url . 'request/bulk', $args, 60 );
$success = 200 === wp_remote_retrieve_response_code( $response );
$this->end_bridge_call();
if ( $success ) {
Lingotek_Logger::info(
'Professional translation (bulk) requested',
array(
'translations' => $translations,
'wordflow_id' => $workflow_id,
)
); }
$this->log_error_on_response_failure(
$response,
'RequestProfessionalTranslationBulk: Error occured',
array(
'translations' => $translations,
'total_estimate' => $total_estimate,
'workflow_id' => $workflow_id,
)
);
return array( 'data' => $this->get_response_body_from_bridge( $response ) );
}
public function get_lingotek_terms_and_conditions() {
$this->start_bridge_call();
$response = $this->get( LINGOTEK_BRIDGE_URL . '/api/v2/transaction/terms/' );
$success = 200 === wp_remote_retrieve_response_code( $response );
$this->end_bridge_call();
$this->log_error_on_response_failure( $response, 'GetLingotekTermsAndConditions: Error occured' );
return array(
'success' => $success,
'data' => $this->get_response_body_from_bridge( $response ),
);
}
/**
* Makes an API call to bridge to get the payment information about the user.
*/
public function get_user_payment_information() {
$this->start_bridge_call();
$response = $this->get( LINGOTEK_BRIDGE_URL . '/api/v2/transaction/payment' );
$success = 200 === wp_remote_retrieve_response_code( $response );
$this->end_bridge_call();
$this->log_error_on_response_failure( $response, 'GetUserPaymentInformation: Error occured' );
return array(
'success' => $success,
'payment_info' => $this->get_response_body_from_bridge( $response ),
);
}
/**
* Helper function to retrieve the response body from bridge.
*
* @param array $response the response from bridge.
*/
private function get_response_body_from_bridge( $response ) {
$body = json_decode( wp_remote_retrieve_body( $response ), true );
return isset( $body ) ? $body : wp_remote_retrieve_body( $response );
}
/**
* requests a new translation of a document
*
* @since 0.1
*
* @param string &$document_id document id.
* @param string $locale Lingotek locale.
* @param array $args optional arguments (only workflow_id at the moment).
* @param object $document the translation term for the post.
* @return bool true if the request succeeded.
*/
public function request_translation( &$document_id, $locale, $args = array(), $wp_id = null, $document = null ) {
$lgtm = $GLOBALS['wp_lingotek']->model;
$document = isset( $document ) ? $document : $lgtm->get_group_by_id( $document_id );
$lingotek_locale = Lingotek::map_to_lingotek_locale( $locale );
$args = $unformatted_args = wp_parse_args( $args, array() );
$args = array_merge( array( 'locale_code' => $lingotek_locale ), $args );
Lingotek_Logger::info(
'Request Translation',
array(
'document id' => $document_id,
'wp_id' => $wp_id,
'locale' => $locale,
'args' => $args,
)
);
$response = $this->post( $this->api_url . '/document/' . $document_id . '/translation', $args );
$title = isset( $args['title'] ) ? $args['title'] : $document_id;
if ( $wp_id ) {
$arr = get_option( 'lingotek_log_errors', array() );
$status_code = wp_remote_retrieve_response_code( $response );
$body = json_decode( wp_remote_retrieve_body( $response ) );
$this->update_patch_error_message( $response, $status_code, $title );
if ( 423 === $status_code ) {
$document->document_id = $body->next_document_id;
$document->save();
return $this->request_translation( $body->next_document_id, $lingotek_locale, $unformatted_args, $wp_id );
}
if ( 402 === $status_code ) {
Lingotek_Logger::error( 'There was an error updating WordPress item', array( 'error' => $this->get_error_message_from_response( $response ) ) );
$document->source_failed();
return false;
}
if ( 429 === $status_code ) {
$lingotek_log_errors = get_option( 'lingotek_log_errors', array() );
$lingotek_log_errors['word_limit_error'] = true;
update_option( 'lingotek_log_errors', $lingotek_log_errors, false );
return false;
}
if ( 410 === $status_code || 404 === $status_code ) {
// WP hooks automatically check source status so this might not get called
$polylang_targets = array_keys( $document->translations );
if ( ! in_array( $locale, $polylang_targets ) ) {
$polylang_targets[] = $locale;
}
$params = $lgtm->reupload_build_params( $wp_id );
$unformatted_args = array_merge( $unformatted_args, $params );
unset( $document->desc_array['lingotek'] );
$document->save();
$lingotek_locales = array();
foreach ( $polylang_targets as $target ) {
$document->translations[ $target ] = 'pending';
// Targets stored in the document translations property are the polylang targets, so we need to get the lingotek locales instead
$lingotek_locales[] = Lingotek::map_to_lingotek_locale( $target );
}
$unformatted_args['translation_locale_code'] = $lingotek_locales;
$this->format_args_for_upload( $unformatted_args, $wp_id );
$upload_response = $this->upload_document( $unformatted_args, $wp_id );
if ( $upload_response ) {
$document_id = $upload_response;
}
return $upload_response;
}//end if
if ( 400 === $status_code &&
! empty( $body->messages ) &&
strpos( $body->messages[0], 'already exists' ) ) {
// Translation has already been requested, treat it as a 201 response
$status_code = 201;
}
if ( 201 === $status_code ) {
if ( isset( $arr[ $wp_id ] ) ) {
unset( $arr[ $wp_id ]['wp_error'] );
unset( $arr[ $wp_id ]['request_translation'][ $lingotek_locale ] );
if ( empty( $arr[ $wp_id ] ) ) {
unset( $arr[ $wp_id ] );
}
}
} elseif ( is_wp_error( $response ) ) {
$arr[ $wp_id ]['wp_error'] = __( 'Make sure you have internet connectivity', 'lingotek-translation' );
} elseif ( 400 == $status_code ) {
$arr[ $wp_id ]['request_translation'][ $lingotek_locale ] = sprintf(
__( 'There was an error requesting translation %1$s for WordPress item %2$s', 'lingotek-translation' ),
$lingotek_locale,
$wp_id
);
}
update_option( 'lingotek_log_errors', $arr, false );
}//end if
if ( 201 !== $status_code ) {
$this->log_error_on_response_failure(
$response,
'RequestTranslation: Error Occurred',
array(
'document_id' => $document_id,
'locale' => $lingotek_locale,
'args' => $args,
)
);
}
return ! is_wp_error( $response ) && 201 === $status_code;
}
/**
* get a translation
*
* @since 0.1
*
* @param string $id document id
* @param string $locale Lingotek locale
* @return string|bool the translation, false if there is none
*/
public function get_translation( $doc_id, $locale, $wp_id = null ) {
$locale = Lingotek::map_to_lingotek_locale( $locale );
$response = $this->get(
add_query_arg(
array(
'locale_code' => $locale,
'auto_format' => 'true',
),
$this->api_url . '/document/' . $doc_id . '/content'
)
);
if ( $wp_id ) {
$arr = get_option( 'lingotek_log_errors' );
$status_code = wp_remote_retrieve_response_code( $response );
if ( 410 == $status_code ) {
$lgtm = $GLOBALS['wp_lingotek']->model;
$document = $lgtm->get_group_by_id( $doc_id );
$document->source_failed();
//TODO IS THIS SETTING ERROR PROPERLY?
$arr[ $wp_id ]['wp_error'] = sprintf(
__( 'Document %s has been archived. Please re-upload source', 'lingotek-translation' ),
esc_html( $doc_id )
);
return false;
} elseif ( 200 == $status_code ) {
if ( isset( $arr[ $wp_id ] ) ) {
unset( $arr[ $wp_id ]['wp_error'] );
unset( $arr[ $wp_id ]['get_translation'][ $locale ] );
if ( empty( $arr[ $wp_id ] ) ) {
unset( $arr[ $wp_id ] );
}
}
} elseif ( is_wp_error( $response ) ) {
$arr[ $wp_id ]['wp_error'] = __( 'Make sure you have internet connectivity', 'lingotek-translation' );
} elseif ( 400 == $status_code || 404 == $status_code ) {
$arr[ $wp_id ]['get_translation'][ $locale ] = sprintf(
__( 'There was an error downloading translation %1$s for WordPress item %2$s', 'lingotek-translation' ),
$locale,
$wp_id
);
}//end if
update_option( 'lingotek_log_errors', $arr, false );
}//end if
$this->log_error_on_response_failure(
$response,
'GetTranslation: Error Occurred',
array(
'document_id' => $doc_id,
'locale' => $locale,
)
);
return ! is_wp_error( $response ) && 200 == $status_code ? wp_remote_retrieve_body( $response ) : false;
}
/**
* cancels a translation
*
* @since 1.4.2
* @since 1.5.0 Changed signature, breaking change.
*
* @param string $document_id document id
* @param string $locale Lingotek locale
*/
public function cancel_translation( $document_id, $locale, $wp_id = null ) {
$args = wp_parse_args(
array(
'cancelled_reason' => 'CANCELLED_BY_AUTHOR',
'mark_invoiceable' => true,
)
);
$lingotek_locale = Lingotek::map_to_lingotek_locale( $locale );
$response = $this->post( "$this->api_url/document/$document_id/translation/$lingotek_locale/cancel", $args );
if ( $wp_id ) {
$arr = get_option( 'lingotek_log_errors' );
if ( isset( $arr[ $wp_id ] ) ) {
unset( $arr[ $wp_id ] );
update_option( 'lingotek_log_errors', $arr, false );
}
}
$this->log_error_on_response_failure(
$response,
'CancelTranslation: Error occurred',
array(
'id' => $document_id,
'wordpress_id' => $wp_id,
)
);
$is_success = ! is_wp_error( $response ) && ( 204 == wp_remote_retrieve_response_code( $response ) || 202 == wp_remote_retrieve_response_code( $response ) );
if ( $is_success ) {
Lingotek_Logger::info(
'Target cancelled',
array(
'document_id' => $document_id,
'wp_id' => $wp_id,
)
);
return $is_success;
}
$lingotek_log_errors = get_option( 'lingotek_log_errors', array() );
if ( ! is_array( $lingotek_log_errors ) ) {
$lingotek_log_errors = array();
}
// Use the response message if it's an authorization error
$response_error_message = 403 == wp_remote_retrieve_response_code( $response ) && $this->get_error_message_from_response( $response ) !== false ?
$this->get_error_message_from_response( $response ) : false;
if ( $response_error_message ) {
$error_message = $response_error_message;
$lingotek_log_errors['disassociate_document_error'] = $error_message;
}
update_option( 'lingotek_log_errors', $lingotek_log_errors, false );
return $is_success;
}
/**
* get connect account url
*
* @param string $redirect_uri the location where to redirect to after account has been connected
* @return string the complete url for the connect account link
*/
public function get_connect_url( $redirect_uri, $env = null ) {
$base_url = $this->base_url;
$client_id = $this->client_id;
if ( ! is_null( $env ) ) {
$base_url = self::PRODUCTION_URL;
}
return "$base_url/auth/authorize.html?client_id=$client_id&redirect_uri=" . urlencode( $redirect_uri ?? '') . '&response_type=token';
}
public function get_new_url( $redirect_uri ) {
$base_url = self::PRODUCTION_URL;
$client_id = $this->client_id;
return "$base_url/lingopoint/portal/requestAccount.action?client_id=$client_id&app=" . urlencode( $redirect_uri ?? '') . '&response_type=token';
}
public function get_communities() {
$response = $this->get( add_query_arg( array( 'limit' => 1000 ), $this->api_url . '/community' ) );
return ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ? json_decode( wp_remote_retrieve_body( $response ) ) : false;
}
public function get_projects( $community_id ) {
$response = $this->get(
add_query_arg(
array(
'community_id' => $community_id,
'limit' => 1000,
),
$this->api_url . '/project'
)
);
if ( wp_remote_retrieve_response_code( $response ) == 204 ) {
// There are currently no projects.
return array();
}
return ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ? json_decode( wp_remote_retrieve_body( $response ) ) : false;
}
public function get_vaults( $community_id ) {
$response = $this->get(
add_query_arg(
array(
'community_id' => $community_id,
'limit' => 1000,
),
$this->api_url . '/vault'
)
);
return ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ? json_decode( wp_remote_retrieve_body( $response ) ) : false;
}
public function get_workflows( $community_id ) {
$response = $this->get(
add_query_arg(
array(
'community_id' => $community_id,
'limit' => 1000,
),
$this->api_url . '/workflow'
)
);
return ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ? json_decode( wp_remote_retrieve_body( $response ) ) : false;
}
public function get_filters() {
$response = $this->get( add_query_arg( array( 'limit' => 1000 ), $this->api_url . '/filter' ) );
return ! is_wp_error( $response ) && 200 == wp_remote_retrieve_response_code( $response ) ? json_decode( wp_remote_retrieve_body( $response ) ) : false;
}
public function upload_filter( $name, $type, $content ) {
$args = array(
'name' => $name,
'type' => $type,
'content' => $content,
);
$response = $this->post( "$this->api_url/filter", $args );
}
private function start_bridge_call() {
$this->auth_temp = $this->headers['Authorization'];
unset( $this->headers['Authorization'] );
$option = get_option( 'lingotek_token' );
$this->headers['Authorization-Lingotek'] = $option['access_token'];
}
private function end_bridge_call() {
unset( $this->headers['Authorization-Lingotek'] );
$this->headers['Authorization'] = $this->auth_temp;
}
private function get_workflow_id() {
return 'project-default' === $this->defaults['workflow_id'] ? null : $this->defaults['workflow_id'];
}
/**
* Helper function to update lingotek errors as 'lingotek_log_errors' option in case of translation actions (get / request).
*
* @param $response the response from the action (wp_remote_*).
* @param $wp_id id that represents the object in the WP world (post_id / term_id / etc)
* @param $action the name of the action performed (for ex 'reqeust_translation')
* @param $error_message the message to write in case the response indicates failure
* @param $locale the locale the translation action was performed on
* @param $extra_data (optional) array of key/value pairs that will be sent as part of the error
*/
private function update_lingotek_error_option_for_translation( $response, $wp_id, $action, $error_message, $locale, $extra_data = array() ) {
if ( $wp_id ) {
$arr = get_option( 'lingotek_log_errors' );
$response_message_code = wp_remote_retrieve_response_code( $response );
if ( 200 == $response_message_code || 201 == $response_message_code ) {
if ( isset( $arr[ $wp_id ] ) ) {
unset( $arr[ $wp_id ]['wp_error'] );
unset( $arr[ $wp_id ][ $action ][ $locale ] );
if ( empty( $arr[ $wp_id ] ) ) {
unset( $arr[ $wp_id ] );
}
}
} elseif ( is_wp_error( $response ) ) {
$arr[ $wp_id ]['wp_error'] = __( 'Make sure you have internet connectivity', 'lingotek-translation' );
Lingotek_Logger::error(
$action . ': WordPress error occured, please make sure you have internet connectivity',
array_merge(
array(
'http_status' => $response_message_code,
'wordpress_id' => $wp_id,
),
$extra_data
)
);
} elseif ( 400 == $response_message_code || 404 == $response_message_code ) {
$arr[ $wp_id ][ $action ][ $locale ] = $error_message;
Lingotek_Logger::error(
$action . ': Error occured',
array_merge(
array(
'response_message_code' => $response_message_code,
'wordpress_id' => $wp_id,
'response_message' => $this->get_error_message_from_response( $response ),
),
$extra_data
)
);
}//end if
update_option( 'lingotek_log_errors', $arr, false );
}//end if
}
/**
* Helper function to update lingotek errors as 'lingotek_log_errors' option.
*
* @param $response the response from the action (wp_remote_*).
* @param $wp_id id that represents the object in the WP world (post_id / term_id / etc)
* @param $action the name of the action performed (for ex 'reqeust_translation')
* @param $error_message the message to write in case the response indicates failure
* @param $extra_data (optional) array of key/value pairs that will be sent as part of the error
*/
private function update_lingotek_error_option( $response, $wp_id, $action, $error_message, $extra_data = array() ) {
if ( $wp_id ) {
$arr = get_option( 'lingotek_log_errors' );
$response_message_code = wp_remote_retrieve_response_code( $response );
if ( empty( $arr ) ) {
return;
}
if ( 200 == $response_message_code || 202 == $response_message_code ) {
if ( isset( $arr[ $wp_id ] ) ) {
unset( $arr[ $wp_id ] );
}
} elseif ( is_wp_error( $response ) ) {
$arr[ $wp_id ]['wp_error'] = __( 'Make sure you have internet connectivity', 'lingotek-translation' );
Lingotek_Logger::error(
"$action: WordPress error occured, please make sure you have internet connectivity",
array_merge(
array(
'http_status' => $response_message_code,
'wordpress_id' => $wp_id,
),
$extra_data
)
);
} elseif ( 400 == $response_message_code || 404 == $response_message_code ) {
$arr[ $wp_id ][ $action ] = $error_message;
Lingotek_Logger::error(
"$action: Error occured",
array_merge(
array(
'http_status' => $response_message_code,
'wordpress_id' => $wp_id,
'response_message' => $this->get_error_message_from_response( $response ),
),
$extra_data
)
);
}//end if
update_option( 'lingotek_log_errors', $arr, false );
}//end if
}
/**
* Helper function to send error log entry to Lingotek_Logger in case the response indicates failure.
* Failure response has http status different than 200/201/202/204 and is not wp_error response
*
* @param $response the response from the action (wp_remote_*).
* @param $error_message the message to write in case the response indicates failure
* @param $extra_data (optional) array of key/value pairs that will be sent as part of the error
*/
private function log_error_on_response_failure( $response, $error_message, $extra_data = array() ) {
$http_code = wp_remote_retrieve_response_code( $response );
$success = 200 === $http_code || 201 === $http_code || 202 === $http_code || 204 === $http_code;
if ( ! $success || is_wp_error( $response ) ) {
Lingotek_Logger::error(
$error_message,
array_merge(
array(
'http_status' => $http_code,
$extra_data,
)
)
);
}
}
private function get_error_message_from_response( $response ) {
$responseBody = json_decode( wp_remote_retrieve_body( $response ) );
if ( empty( $responseBody ) ) {
return false;
}
return property_exists( $responseBody, 'messages' ) && is_array( $responseBody->messages ) ? implode( ' ', $responseBody->messages ) : false;
}
}