Merge pull request #19 from woocommerce/add/cron_job_trigger

Add cron trigger
This commit is contained in:
Fernando 2021-06-21 09:57:14 -03:00 committed by GitHub
commit 85dbb03504
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 298 additions and 62 deletions

View File

@ -29,6 +29,7 @@ function register_woocommerce_admin_test_helper_rest_route( $route, $callback, $
require( 'admin-notes/delete-all-notes.php' ); require( 'admin-notes/delete-all-notes.php' );
require( 'admin-notes/add-note.php' ); require( 'admin-notes/add-note.php' );
require( 'tools/trigger-wca-install.php' ); require( 'tools/trigger-wca-install.php' );
require( 'tools/trigger-cron-job.php' );
require( 'tools/run-wc-admin-daily.php' ); require( 'tools/run-wc-admin-daily.php' );
require( 'options/rest-api.php' ); require( 'options/rest-api.php' );
require( 'tools/delete-all-products.php'); require( 'tools/delete-all-products.php');

View File

@ -0,0 +1,98 @@
<?php
register_woocommerce_admin_test_helper_rest_route(
'/tools/get-cron-list/v1',
'tools_get_cron_list',
array(
'methods' => 'GET',
)
);
register_woocommerce_admin_test_helper_rest_route(
'/tools/trigger-selected-cron/v1',
'trigger_selected_cron',
array(
'methods' => 'POST',
'args' => array(
'hook' => array(
'description' => 'Name of the cron that will be triggered.',
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
'signature' => array(
'description' => 'Signature of the cron to trigger.',
'type' => 'string',
'sanitize_callback' => 'sanitize_text_field',
),
),
)
);
function tools_get_cron_list() {
$crons = _get_cron_array();
$events = array();
if ( empty( $crons ) ) {
return array();
}
foreach ( $crons as $cron ) {
foreach ( $cron as $hook => $data ) {
foreach ( $data as $signature => $element ) {
$events[ $hook ] = (object) array(
'hook' => $hook,
'signature' => $signature,
);
}
}
}
return new WP_REST_Response( $events, 200 );
}
function trigger_selected_cron( $request ) {
$hook = $request->get_param( 'hook' );
$signature = $request->get_param( 'signature' );
if ( ! isset( $hook ) || ! isset( $signature ) ) {
return;
}
$crons = _get_cron_array();
foreach ( $crons as $cron ) {
if ( isset( $cron[ $hook ][ $signature ] ) ) {
$args = $cron[ $hook ][ $signature ]['args'];
delete_transient( 'doing_cron' );
$scheduled = schedule_event( $hook, $args );
if ( false === $scheduled ) {
return $scheduled;
}
add_filter( 'cron_request', function( array $cron_request ) {
$cron_request['url'] = add_query_arg( 'run-cron', 1, $cron_request['url'] );
return $cron_request;
} );
spawn_cron();
sleep( 1 );
return true;
}
}
return false;
}
function schedule_event( $hook, $args = array() ) {
$event = (object) array(
'hook' => $hook,
'timestamp' => 1,
'schedule' => false,
'args' => $args,
);
$crons = (array) _get_cron_array();
$key = md5( serialize( $event->args ) );
$crons[ $event->timestamp ][ $event->hook ][ $key ] = array(
'schedule' => $event->schedule,
'args' => $event->args,
);
uksort( $crons, 'strnatcasecmp' );
return _set_cron_array( $crons );
}

View File

@ -2,9 +2,8 @@
* External dependencies. * External dependencies.
*/ */
import { useState } from '@wordpress/element'; import { useState } from '@wordpress/element';
import { Button } from '@wordpress/components'; import { Button, SelectControl } from '@wordpress/components';
import apiFetch from '@wordpress/api-fetch'; import apiFetch from '@wordpress/api-fetch';
import { SelectControl } from '@wordpress/components';
export const AddNote = () => { export const AddNote = () => {

View File

@ -60,6 +60,13 @@
&.command { &.command {
white-space: nowrap; white-space: nowrap;
} }
.trigger-cron-job {
width: 40%;
padding-top: 4px;
.components-base-control__field {
margin-bottom: 0;
}
}
} }
} }
.components-notice { .components-notice {

View File

@ -1,3 +1,5 @@
import { TriggerCronJob, TRIGGER_CRON_ACTION_NAME } from './trigger-cron';
export default [ export default [
{ {
command: 'Trigger WCA Install', command: 'Trigger WCA Install',
@ -39,4 +41,9 @@ export default [
description: 'Delete all products', description: 'Delete all products',
action: 'deleteAllProducts', action: 'deleteAllProducts',
}, },
{
command: 'Run a cron job',
description: <TriggerCronJob />,
action: TRIGGER_CRON_ACTION_NAME,
},
]; ];

View File

@ -0,0 +1,48 @@
/**
* External dependencies.
*/
import { SelectControl } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
/**
* Internal dependencies
*/
import { STORE_KEY } from '../data/constants';
export const TRIGGER_CRON_ACTION_NAME = 'runSelectedCronJob';
export const TriggerCronJob = () => {
const { cronList } = useSelect((select) => {
const { getCronJobs } = select(STORE_KEY);
return {
cronList: getCronJobs(),
};
});
const { updateCommandParams } = useDispatch(STORE_KEY);
function onCronChange(selectedValue) {
const { hook, signature } = cronList[selectedValue];
updateCommandParams(TRIGGER_CRON_ACTION_NAME, { hook, signature });
}
function getOptions() {
return Object.keys(cronList).map((name) => {
return { label: name, value: name };
});
}
return (
<div className="trigger-cron-job">
{!cronList ? (
<p>Loading ...</p>
) : (
<SelectControl
label="Select cron job to run"
onChange={onCronChange}
labelPosition="side"
options={getOptions()}
/>
)}
</div>
);
};

View File

@ -4,6 +4,8 @@ const TYPES = {
ADD_MESSAGE: 'ADD_MESSAGE', ADD_MESSAGE: 'ADD_MESSAGE',
UPDATE_MESSAGE: 'UPDATE_MESSAGE', UPDATE_MESSAGE: 'UPDATE_MESSAGE',
REMOVE_MESSAGE: 'REMOVE_MESSAGE', REMOVE_MESSAGE: 'REMOVE_MESSAGE',
ADD_COMMAND_PARAMS: 'ADD_COMMAND_PARAMS',
SET_CRON_JOBS: 'SET_CRON_JOBS',
}; };
export default TYPES; export default TYPES;

View File

@ -9,21 +9,21 @@ import { apiFetch } from '@wordpress/data-controls';
import TYPES from './action-types'; import TYPES from './action-types';
import { API_NAMESPACE } from './constants'; import { API_NAMESPACE } from './constants';
export function addCurrentlyRunning( command ) { export function addCurrentlyRunning(command) {
return { return {
type: TYPES.ADD_CURRENTLY_RUNNING, type: TYPES.ADD_CURRENTLY_RUNNING,
command, command,
}; };
} }
export function removeCurrentlyRunning( command ) { export function removeCurrentlyRunning(command) {
return { return {
type: TYPES.REMOVE_CURRENTLY_RUNNING, type: TYPES.REMOVE_CURRENTLY_RUNNING,
command, command,
}; };
} }
export function addMessage( source, message ) { export function addMessage(source, message) {
return { return {
type: TYPES.ADD_MESSAGE, type: TYPES.ADD_MESSAGE,
source, source,
@ -31,7 +31,7 @@ export function addMessage( source, message ) {
}; };
} }
export function updateMessage( source, message, status ) { export function updateMessage(source, message, status) {
return { return {
type: TYPES.ADD_MESSAGE, type: TYPES.ADD_MESSAGE,
source, source,
@ -40,69 +40,84 @@ export function updateMessage( source, message, status ) {
}; };
} }
export function removeMessage( source ) { export function removeMessage(source) {
return { return {
type: TYPES.REMOVE_MESSAGE, type: TYPES.REMOVE_MESSAGE,
source, source,
}; };
} }
function* runCommand( commandName, func ) { export function updateCommandParams(source, params) {
return {
type: TYPES.ADD_COMMAND_PARAMS,
source,
params,
};
}
export function setCronJobs(cronJobs) {
return {
type: TYPES.SET_CRON_JOBS,
cronJobs,
};
}
function* runCommand(commandName, func) {
try { try {
yield addCurrentlyRunning( commandName ); yield addCurrentlyRunning(commandName);
yield addMessage( commandName, 'Executing...' ); yield addMessage(commandName, 'Executing...');
yield func(); yield func();
yield removeCurrentlyRunning( commandName ); yield removeCurrentlyRunning(commandName);
yield updateMessage( commandName, 'Successful!' ); yield updateMessage(commandName, 'Successful!');
} catch ( e ) { } catch (e) {
yield updateMessage( commandName, e.message, 'error' ); yield updateMessage(commandName, e.message, 'error');
yield removeCurrentlyRunning( commandName ); yield removeCurrentlyRunning(commandName);
} }
} }
export function* triggerWcaInstall() { export function* triggerWcaInstall() {
yield runCommand( 'Trigger WCA Install', function* () { yield runCommand('Trigger WCA Install', function* () {
yield apiFetch( { yield apiFetch({
path: API_NAMESPACE + '/tools/trigger-wca-install/v1', path: API_NAMESPACE + '/tools/trigger-wca-install/v1',
method: 'POST', method: 'POST',
} ); });
} ); });
} }
export function* resetOnboardingWizard() { export function* resetOnboardingWizard() {
yield runCommand( 'Reset Onboarding Wizard', function* () { yield runCommand('Reset Onboarding Wizard', function* () {
const optionsToDelete = [ const optionsToDelete = [
'woocommerce_task_list_tracked_completed_tasks', 'woocommerce_task_list_tracked_completed_tasks',
'woocommerce_onboarding_profile', 'woocommerce_onboarding_profile',
'_transient_wc_onboarding_themes', '_transient_wc_onboarding_themes',
]; ];
yield apiFetch( { yield apiFetch({
method: 'DELETE', method: 'DELETE',
path: `${ API_NAMESPACE }/options/${ optionsToDelete.join( ',' ) }`, path: `${API_NAMESPACE}/options/${optionsToDelete.join(',')}`,
} ); });
} ); });
} }
export function* resetJetpackConnection() { export function* resetJetpackConnection() {
yield runCommand( 'Reset Jetpack Connection', function* () { yield runCommand('Reset Jetpack Connection', function* () {
yield apiFetch( { yield apiFetch({
method: 'DELETE', method: 'DELETE',
path: `${ API_NAMESPACE }/options/jetpack_options`, path: `${API_NAMESPACE}/options/jetpack_options`,
} ); });
} ); });
} }
export function* enableTrackingDebug() { export function* enableTrackingDebug() {
yield runCommand( 'Enable WC Admin Tracking Debug Mode', function* () { yield runCommand('Enable WC Admin Tracking Debug Mode', function* () {
window.localStorage.setItem( 'debug', 'wc-admin:*' ); window.localStorage.setItem('debug', 'wc-admin:*');
} ); });
} }
export function* updateStoreAge() { export function* updateStoreAge() {
yield runCommand( 'Update Installation timestamp', function* () { yield runCommand('Update Installation timestamp', function* () {
const today = new Date(); const today = new Date();
const dd = String( today.getDate() ).padStart( 2, '0' ); const dd = String(today.getDate()).padStart(2, '0');
const mm = String( today.getMonth() + 1 ).padStart( 2, '0' ); //January is 0! const mm = String(today.getMonth() + 1).padStart(2, '0'); //January is 0!
const yyyy = today.getFullYear(); const yyyy = today.getFullYear();
// eslint-disable-next-line no-alert // eslint-disable-next-line no-alert
@ -111,43 +126,52 @@ export function* updateStoreAge() {
yyyy + '/' + mm + '/' + dd yyyy + '/' + mm + '/' + dd
); );
if ( numberOfDays !== null ) { if (numberOfDays !== null) {
const dates = numberOfDays.split( '/' ); const dates = numberOfDays.split('/');
const newTimestamp = Math.round( const newTimestamp = Math.round(
new Date( dates[ 0 ], dates[ 1 ] - 1, dates[ 2 ] ).getTime() / new Date(dates[0], dates[1] - 1, dates[2]).getTime() / 1000
1000
); );
const payload = { const payload = {
woocommerce_admin_install_timestamp: JSON.parse( newTimestamp ), woocommerce_admin_install_timestamp: JSON.parse(newTimestamp),
}; };
yield apiFetch( { yield apiFetch({
method: 'POST', method: 'POST',
path: '/wc-admin/options', path: '/wc-admin/options',
headers: { 'content-type': 'application/json' }, headers: { 'content-type': 'application/json' },
body: JSON.stringify( payload ), body: JSON.stringify(payload),
} ); });
} }
} ); });
} }
export function* runWcAdminDailyJob() { export function* runWcAdminDailyJob() {
yield runCommand( 'Run wc_admin_daily job', function* () { yield runCommand('Run wc_admin_daily job', function* () {
yield apiFetch( { yield apiFetch({
path: API_NAMESPACE + '/tools/run-wc-admin-daily/v1', path: API_NAMESPACE + '/tools/run-wc-admin-daily/v1',
method: 'POST', method: 'POST',
} ); });
} ); });
} }
export function* deleteAllProducts() { export function* deleteAllProducts() {
if ( ! confirm( 'Are you sure you want to delete all of the products?' ) ) { if (!confirm('Are you sure you want to delete all of the products?')) {
return; return;
} }
yield runCommand( 'Delete all products', function* () { yield runCommand('Delete all products', function* () {
yield apiFetch( { yield apiFetch({
path: `${ API_NAMESPACE }/tools/delete-all-products/v1`, path: `${API_NAMESPACE}/tools/delete-all-products/v1`,
method: 'POST', method: 'POST',
} ); });
} ); });
}
export function* runSelectedCronJob(params) {
yield runCommand('Run selected cron job', function* () {
yield apiFetch({
path: API_NAMESPACE + '/tools/run-wc-admin-daily/v1',
method: 'POST',
data: params,
});
});
} }

View File

@ -8,6 +8,7 @@ import { controls } from '@wordpress/data-controls';
* Internal dependencies * Internal dependencies
*/ */
import * as actions from './actions'; import * as actions from './actions';
import * as resolvers from './resolvers';
import * as selectors from './selectors'; import * as selectors from './selectors';
import reducer from './reducer'; import reducer from './reducer';
import { STORE_KEY } from './constants'; import { STORE_KEY } from './constants';
@ -15,6 +16,7 @@ import { STORE_KEY } from './constants';
export default registerStore( STORE_KEY, { export default registerStore( STORE_KEY, {
actions, actions,
selectors, selectors,
resolvers,
controls, controls,
reducer, reducer,
} ); } );

View File

@ -6,7 +6,9 @@ import TYPES from './action-types';
const DEFAULT_STATE = { const DEFAULT_STATE = {
currentlyRunning: {}, currentlyRunning: {},
errorMessages: [], errorMessages: [],
cronJobs: false,
messages: {}, messages: {},
params: [],
status: '', status: '',
}; };
@ -54,6 +56,18 @@ const reducer = ( state = DEFAULT_STATE, action ) => {
[ action.command ]: false, [ action.command ]: false,
}, },
}; };
case TYPES.SET_CRON_JOBS:
return {
...state,
cronJobs: action.cronJobs,
};
case TYPES.ADD_COMMAND_PARAMS:
return {
...state,
params: {
[ action.source ]: action.params,
},
};
default: default:
return state; return state;
} }

View File

@ -0,0 +1,24 @@
/**
* External dependencies
*/
import { apiFetch } from '@wordpress/data-controls';
/**
* Internal dependencies
*/
import { API_NAMESPACE } from './constants';
import { setCronJobs } from './actions';
export function* getCronJobs() {
const path = `${ API_NAMESPACE }/tools/get-cron-list/v1`;
try {
const response = yield apiFetch( {
path,
method: 'GET',
} );
yield setCronJobs( response );
} catch ( error ) {
throw new Error( error );
}
}

View File

@ -9,3 +9,11 @@ export function getMessages( state ) {
export function getStatus( state ) { export function getStatus( state ) {
return state.status; return state.status;
} }
export function getCommandParams( state ) {
return state.params;
}
export function getCronJobs( state ) {
return state.cronJobs;
}

View File

@ -12,7 +12,7 @@ import { default as commands } from './commands';
import { STORE_KEY } from './data/constants'; import { STORE_KEY } from './data/constants';
import './data'; import './data';
function Tools( { actions, currentlyRunningCommands, messages } ) { function Tools( { actions, currentlyRunningCommands, messages, comandParams } ) {
actions = actions(); actions = actions();
return ( return (
<div id="wc-admin-test-helper-tools"> <div id="wc-admin-test-helper-tools">
@ -38,17 +38,18 @@ function Tools( { actions, currentlyRunningCommands, messages } ) {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{ commands.map( ( command, index ) => { { commands.map( ( { action, command, description }, index ) => {
const params = comandParams[ action ] ?? false;
return ( return (
<tr key={ index }> <tr key={ index }>
<td className="command">{ command.command }</td> <td className="command">{ command }</td>
<td>{ command.description }</td> <td>{ description }</td>
<td> <td>
<Button <Button
onClick={ actions[ command.action ] } onClick={ () => actions[ action ]( params ) }
disabled={ disabled={
currentlyRunningCommands[ currentlyRunningCommands[
command.command command
] ]
} }
isPrimary isPrimary
@ -67,10 +68,11 @@ function Tools( { actions, currentlyRunningCommands, messages } ) {
export default compose( export default compose(
withSelect( ( select ) => { withSelect( ( select ) => {
const { getCurrentlyRunning, getMessages } = select( STORE_KEY ); const { getCurrentlyRunning, getMessages, getCommandParams } = select( STORE_KEY );
return { return {
currentlyRunningCommands: getCurrentlyRunning(), currentlyRunningCommands: getCurrentlyRunning(),
messages: getMessages(), messages: getMessages(),
comandParams: getCommandParams(),
}; };
} ), } ),
withDispatch( ( dispatch ) => { withDispatch( ( dispatch ) => {