first commit

This commit is contained in:
2023-09-12 21:41:04 +02:00
commit 3361a7f053
13284 changed files with 2116755 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
<?php
namespace WPML\TM\ATE\Log;
class Entry {
/**
* @var int $timestamp The log's creation timestamp.
*/
public $timestamp = 0;
/**
* @see EventsTypes
*
* @var int $eventType The event code that triggered the log.
*/
public $eventType = 0;
/**
* @var string $description The details of the log (e.g. exception message).
*/
public $description = '';
/**
* @var int $wpmlJobId [Optional] The WPML Job ID (when applies).
*/
public $wpmlJobId = 0;
/**
* @var int $ateJobId [Optional] The ATE Job ID (when applies).
*/
public $ateJobId = 0;
/**
* @var array $extraData [Optional] Complementary serialized data (e.g. API request/response data).
*/
public $extraData = [];
/**
* @param array $item
*
* @return Entry
*/
public function __construct( array $item = null ) {
if ( $item ) {
$this->timestamp = (int) $item['timestamp'];
$this->eventType = (int) ( isset( $item['eventType'] ) ? $item['eventType'] : $item['event'] );
$this->description = $item['description'];
$this->wpmlJobId = (int) $item['wpmlJobId'];
$this->ateJobId = (int) $item['ateJobId'];
$this->extraData = (array) $item['extraData'];
}
}
public static function createForType($eventType, $extraData) {
$entry = new self();
$entry->eventType = $eventType;
$entry->extraData = $extraData;
return $entry;
}
public static function retryJob( $wpmlJobId, $extraData ) {
$entry = self::createForType(EventsTypes::JOB_RETRY, $extraData);
$entry->wpmlJobId = $wpmlJobId;
return $entry;
}
/**
* @return string
*/
public function getFormattedDate() {
return date_i18n( 'Y/m/d g:i:s A', $this->timestamp );
}
/**
* @return string
*/
public function getExtraDataToString() {
return json_encode( $this->extraData );
}
}

View File

@@ -0,0 +1,35 @@
<?php
namespace WPML\TM\ATE\Log;
class EventsTypes {
/** Communication errors */
const SERVER_ATE = 1;
const SERVER_AMS = 2;
const SERVER_XLIFF = 3;
/** Internal errors */
const JOB_DOWNLOAD = 10;
/** Retry */
const JOB_RETRY = 20;
const SITE_REGISTRATION_RETRY = 21;
/** Sync */
const JOBS_SYNC = 30;
public static function getLabel( $eventType ) {
return wpml_collect(
[
EventsTypes::SERVER_ATE => 'ATE Server Communication',
EventsTypes::SERVER_AMS => 'AMS Server Communication',
EventsTypes::SERVER_XLIFF => 'XLIFF Server Communication',
EventsTypes::JOB_DOWNLOAD => 'Job Download',
EventsTypes::JOB_RETRY => 'Job resent to ATE',
EventsTypes::SITE_REGISTRATION_RETRY => 'Site registration request resent to ATE',
EventsTypes::JOBS_SYNC => 'Jobs sync request sent to ATE failed',
]
)->get( $eventType, '' );
}
}

View File

@@ -0,0 +1,39 @@
<?php
namespace WPML\TM\ATE\Log;
class Hooks implements \IWPML_Backend_Action, \IWPML_DIC_Action {
const SUBMENU_HANDLE = 'wpml-tm-ate-log';
/** @var ViewFactory $viewFactory */
private $viewFactory;
public function __construct( ViewFactory $viewFactory ) {
$this->viewFactory = $viewFactory;
}
public function add_hooks() {
add_action( 'wpml_support_page_after', [ $this, 'renderSupportSection' ] );
add_action( 'admin_menu', [ $this, 'addLogSubmenuPage' ] );
}
public function renderSupportSection() {
$this->viewFactory->create()->renderSupportSection();
}
public function addLogSubmenuPage() {
add_submenu_page(
WPML_PLUGIN_FOLDER . '/menu/support.php',
__( 'Advanced Translation Editor Error Logs', 'wpml-translation-management' ),
'ATE logs',
'manage_options',
self::SUBMENU_HANDLE,
[ $this, 'renderPage' ]
);
}
public function renderPage() {
$this->viewFactory->create()->renderPage();
}
}

View File

@@ -0,0 +1,73 @@
<?php
namespace WPML\TM\ATE\Log;
use WPML\Collect\Support\Collection;
use WPML\WP\OptionManager;
class Storage {
const OPTION_GROUP = 'TM\ATE\Log';
const OPTION_NAME = 'logs';
const MAX_ENTRIES = 50;
public static function add( Entry $entry, $avoidDuplication = false ) {
$entry->timestamp = $entry->timestamp ?: time();
$entries = self::getAll();
if ( $avoidDuplication ) {
$entries = $entries->reject(
function( $iteratedEntry ) use ( $entry ) {
return (
$iteratedEntry->wpmlJobId === $entry->wpmlJobId
&& $entry->ateJobId === $iteratedEntry->ateJobId
&& $entry->description === $iteratedEntry->description
&& $entry->eventType === $iteratedEntry->eventType
);
}
);
}
$entries->prepend( $entry );
$newOptionValue = $entries->forPage( 1, self::MAX_ENTRIES )
->map(
function( Entry $entry ) {
return (array) $entry; }
)
->toArray();
OptionManager::updateWithoutAutoLoad( self::OPTION_NAME, self::OPTION_GROUP, $newOptionValue );
}
/**
* @param Entry $entry
*/
public static function remove( Entry $entry ) {
$entries = self::getAll();
$entries = $entries->reject(
function( $iteratedEntry ) use ( $entry ) {
return $iteratedEntry->timestamp === $entry->timestamp && $entry->ateJobId === $iteratedEntry->ateJobId;
}
);
$newOptionValue = $entries->forPage( 1, self::MAX_ENTRIES )
->map(
function( Entry $entry ) {
return (array) $entry; }
)
->toArray();
OptionManager::updateWithoutAutoLoad( self::OPTION_NAME, self::OPTION_GROUP, $newOptionValue );
}
/**
* @return Collection Collection of Entry objects.
*/
public static function getAll() {
return wpml_collect( OptionManager::getOr( [], self::OPTION_NAME, self::OPTION_GROUP ) )
->map(
function( array $item ) {
return new Entry( $item );
}
);
}
}

View File

@@ -0,0 +1,113 @@
<?php
namespace WPML\TM\ATE\Log;
use WPML\Collect\Support\Collection;
class View {
/** @var Collection $logs */
private $logs;
public function __construct( Collection $logs ) {
$this->logs = $logs;
}
public function renderSupportSection() {
?>
<div class="wrap">
<h2 id="ate-log">
<?php esc_html_e( 'Advanced Translation Editor', 'wpml-translation-management' ); ?>
</h2>
<p>
<a href="<?php echo admin_url( 'admin.php?page=' . Hooks::SUBMENU_HANDLE ); ?>">
<?php echo sprintf( esc_html__( 'Error Logs (%d)', 'wpml-translation-management' ), $this->logs->count() ); ?>
</a>
</p>
</div>
<?php
}
public function renderPage() {
?>
<div class="wrap">
<h1><?php esc_html_e( 'Advanced Translation Editor Error Logs', 'wpml-translation-management' ); ?></h1>
<br>
<table class="wp-list-table widefat fixed striped posts">
<thead><?php $this->renderTableHeader(); ?></thead>
<tbody id="the-list">
<?php
if ( $this->logs->isEmpty() ) {
$this->renderEmptyTable();
} else {
$this->logs->each( [ $this, 'renderTableRow' ] );
}
?>
</tbody>
<tfoot><?php $this->renderTableHeader(); ?></tfoot>
</table>
</div>
<?php
}
private function renderTableHeader() {
?>
<tr>
<th class="date">
<span><?php esc_html_e( 'Date', 'wpml-translation-management' ); ?></span>
</th>
<th class="event">
<span><?php esc_html_e( 'Event', 'wpml-translation-management' ); ?></span>
</th>
<th class="description">
<span><?php esc_html_e( 'Description', 'wpml-translation-management' ); ?></span>
</th>
<th class="wpml-job-id">
<span><?php esc_html_e( 'WPML Job ID', 'wpml-translation-management' ); ?></span>
</th>
<th class="ate-job-id">
<span><?php esc_html_e( 'ATE Job ID', 'wpml-translation-management' ); ?></span>
</th>
<th class="extra-data">
<span><?php esc_html_e( 'Extra data', 'wpml-translation-management' ); ?></span>
</th>
</tr>
<?php
}
public function renderTableRow( Entry $entry ) {
?>
<tr>
<td class="date">
<?php echo esc_html( $entry->getFormattedDate() ); ?>
</td>
<td class="event">
<?php echo esc_html( EventsTypes::getLabel( $entry->eventType ) ); ?>
</td>
<td class="description">
<?php echo esc_html( $entry->description ); ?>
</td>
<td class="wpml-job-id">
<?php echo esc_html( $entry->wpmlJobId ); ?>
</td>
<td class="ate-job-id">
<?php echo esc_html( $entry->ateJobId ); ?>
</td>
<td class="extra-data">
<?php echo esc_html( $entry->getExtraDataToString() ); ?>
</td>
</tr>
<?php
}
private function renderEmptyTable() {
?>
<tr>
<td colspan="6" class="title column-title has-row-actions column-primary">
<?php esc_html_e( 'No entries', 'wpml-translation-management' ); ?>
</td>
</tr>
<?php
}
}

View File

@@ -0,0 +1,14 @@
<?php
namespace WPML\TM\ATE\Log;
use function WPML\Container\make;
class ViewFactory {
public function create() {
$logs = make( Storage::class )->getAll();
return new View( $logs );
}
}