PluginProbe
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses / 4.4.8
LearnPress – WordPress LMS Plugin for Create and Sell Online Courses v4.4.8
4.4.8 4.4.7 4.4.6 4.4.5 4.4.4 4.4.3 4.4.2 4.4.1 4.4.0 4.3.9.1 4.3.9 4.3.8 4.3.7 4.1.6.9 4.1.6.9.1 4.1.6.9.2 4.1.6.9.3 4.1.6.9.4 4.1.7 4.1.7.1 4.1.7.2 4.1.7.3 4.1.7.3.1 4.1.7.3.2 4.2.0 All 139 releases
learnpress / inc / Ajax / Webhook / WebhooksAjax.php

WebhooksAjax.php in LearnPress – WordPress LMS Plugin for Create and Sell Online Courses 4.4.8, at inc/Ajax/Webhook/WebhooksAjax.php

231 lines 6.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace LearnPress\Ajax\Webhook;
4
5 use Exception;
6 use LearnPress\Ajax\AbstractAjax;
7 use LearnPress\Models\Webhook\WebhookModel;
8 use LearnPress\Webhook\WebhookEvents;
9 use LP_Helper;
10 use LP_Settings;
11 use LP_REST_Response;
12 use Throwable;
13
14 defined( 'ABSPATH' ) || exit;
15
16 /**
17 * Handle webhook CRUD requests through lp-load-ajax transport.
18 */
19 class WebhooksAjax extends AbstractAjax {
20 /**
21 * @var string
22 */
23 protected static $required_capability = 'manage_options';
24
25 /**
26 * Validate current request and decode JSON payload.
27 *
28 * @return array<string, mixed>
29 * @throws Exception
30 */
31 public static function check_valid(): array {
32 if ( ! current_user_can( self::$required_capability ) ) {
33 throw new Exception( __( 'You are not allowed to manage webhooks.', 'learnpress' ) );
34 }
35
36 if ( 'yes' !== LP_Settings::get_option( 'enable_webhook_integration', 'no' ) ) {
37 throw new Exception( __( 'Webhook integration is disabled.', 'learnpress' ) );
38 }
39
40 $params = wp_unslash( $_REQUEST['data'] ?? '' );
41 if ( empty( $params ) ) {
42 throw new Exception( __( 'Error: params invalid!', 'learnpress' ) );
43 }
44
45 $params = LP_Helper::json_decode( $params, true );
46 if ( ! is_array( $params ) ) {
47 throw new Exception( __( 'Error: params invalid!', 'learnpress' ) );
48 }
49
50 return $params;
51 }
52
53 /**
54 * Create a webhook.
55 *
56 * @return void
57 */
58 public static function create_webhook() {
59 $response = new LP_REST_Response();
60
61 try {
62 $data = self::normalize_webhook_payload( self::check_valid() );
63 $webhook = new WebhookModel();
64 $webhook->user_id = get_current_user_id();
65 $webhook->name = $data['name'];
66 $webhook->delivery_url = $data['delivery_url'];
67 $webhook->status = $data['status'];
68 $webhook->events = $data['events'];
69 $webhook->secret = '' !== $data['secret'] ? $data['secret'] : WebhookModel::generate_secret();
70 $webhook->save();
71
72 $response->status = 'success';
73 $response->message = __( 'Webhook created.', 'learnpress' );
74 $response->data = array(
75 'webhook' => $webhook->to_array( true ),
76 );
77 } catch ( Throwable $e ) {
78 $response->status = 'error';
79 $response->message = $e->getMessage();
80 }
81
82 wp_send_json( $response );
83 }
84
85 /**
86 * Update a webhook.
87 *
88 * @return void
89 */
90 public static function update_webhook() {
91 $response = new LP_REST_Response();
92
93 try {
94 $payload = self::check_valid();
95 $webhook_id = absint( $payload['webhook_id'] ?? 0 );
96 $webhook = WebhookModel::find( $webhook_id );
97 if ( ! $webhook ) {
98 throw new Exception( __( 'Webhook not found.', 'learnpress' ) );
99 }
100
101 $data = self::normalize_webhook_payload( $payload );
102 $webhook->name = $data['name'];
103 $webhook->delivery_url = $data['delivery_url'];
104 $webhook->status = $data['status'];
105 $webhook->events = $data['events'];
106 if ( '' !== $data['secret'] ) {
107 $webhook->secret = $data['secret'];
108 }
109 $webhook->save();
110
111 $response->status = 'success';
112 $response->message = __( 'Webhook updated.', 'learnpress' );
113 $response->data = array(
114 'webhook' => $webhook->to_array(),
115 );
116 } catch ( Throwable $e ) {
117 $response->status = 'error';
118 $response->message = $e->getMessage();
119 }
120
121 wp_send_json( $response );
122 }
123
124 /**
125 * Delete a webhook.
126 *
127 * @return void
128 */
129 public static function delete_webhook() {
130 $response = new LP_REST_Response();
131
132 try {
133 $payload = self::check_valid();
134 $webhook_id = absint( $payload['webhook_id'] ?? 0 );
135 $webhook = WebhookModel::find( $webhook_id );
136 if ( ! $webhook || ! $webhook->delete() ) {
137 throw new Exception( __( 'Could not delete webhook.', 'learnpress' ) );
138 }
139
140 $response->status = 'success';
141 $response->message = __( 'Webhook deleted.', 'learnpress' );
142 } catch ( Throwable $e ) {
143 $response->status = 'error';
144 $response->message = $e->getMessage();
145 }
146
147 wp_send_json( $response );
148 }
149
150 /**
151 * Regenerate a webhook secret and return it once.
152 *
153 * @return void
154 */
155 public static function regenerate_webhook_secret() {
156 $response = new LP_REST_Response();
157
158 try {
159 $payload = self::check_valid();
160 $webhook_id = absint( $payload['webhook_id'] ?? 0 );
161 $webhook = WebhookModel::find( $webhook_id );
162 if ( ! $webhook ) {
163 throw new Exception( __( 'Webhook not found.', 'learnpress' ) );
164 }
165
166 $secret = $webhook->regenerate_secret();
167
168 $response->status = 'success';
169 $response->message = __( 'Webhook secret regenerated.', 'learnpress' );
170 $response->data = array(
171 'secret' => $secret,
172 );
173 } catch ( Throwable $e ) {
174 $response->status = 'error';
175 $response->message = $e->getMessage();
176 }
177
178 wp_send_json( $response );
179 }
180
181 /**
182 * Normalize and validate mutable webhook fields.
183 *
184 * @param array<string, mixed> $payload Raw request payload.
185 *
186 * @return array<string, mixed>
187 * @throws Exception
188 */
189 protected static function normalize_webhook_payload( array $payload ): array {
190 $name = sanitize_text_field( (string) ( $payload['name'] ?? '' ) );
191 $delivery_url = esc_url_raw( (string) ( $payload['delivery_url'] ?? '' ) );
192 $status = sanitize_key( (string) ( $payload['status'] ?? '' ) );
193 $events = is_array( $payload['events'] ?? null ) ? WebhookEvents::sanitize( $payload['events'] ) : array();
194 $secret = (string) ( $payload['secret'] ?? '' );
195 $name_length = function_exists( 'mb_strlen' ) ? mb_strlen( $name ) : strlen( $name );
196 $scheme = wp_parse_url( $delivery_url, PHP_URL_SCHEME );
197
198 if ( '' === $name ) {
199 throw new Exception( __( 'Webhook name is required.', 'learnpress' ) );
200 }
201
202 if ( $name_length > 200 ) {
203 throw new Exception( __( 'Webhook name must not exceed 200 characters.', 'learnpress' ) );
204 }
205
206 if ( ! in_array( $scheme, array( 'http', 'https' ), true ) || ! wp_http_validate_url( $delivery_url ) ) {
207 throw new Exception( __( 'Webhook callback URL is invalid.', 'learnpress' ) );
208 }
209
210 if ( ! in_array( $status, array( WebhookModel::STATUS_ACTIVE, WebhookModel::STATUS_PAUSED ), true ) ) {
211 throw new Exception( __( 'Webhook status is invalid.', 'learnpress' ) );
212 }
213
214 if ( empty( $events ) ) {
215 throw new Exception( __( 'Select at least one webhook event.', 'learnpress' ) );
216 }
217
218 if ( '' !== $secret && ( '' === trim( $secret ) || preg_match( '/[\r\n]/', $secret ) || strlen( $secret ) > 255 ) ) {
219 throw new Exception( __( 'Webhook secret is invalid.', 'learnpress' ) );
220 }
221
222 return array(
223 'name' => $name,
224 'delivery_url' => $delivery_url,
225 'status' => $status,
226 'events' => $events,
227 'secret' => $secret,
228 );
229 }
230 }
231