Completed
Push — develop ( 4d830b...72e688 )
by Zack
06:12
created

maybe_enqueue_scripts()   B

Complexity

Conditions 8
Paths 10

Size

Total Lines 45

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 72

Importance

Changes 0
Metric Value
cc 8
nc 10
nop 0
dl 0
loc 45
ccs 0
cts 22
cp 0
crap 72
rs 7.9555
c 0
b 0
f 0
1
<?php
2
3
/** If this file is called directly, abort. */
4
if ( ! defined( 'GRAVITYVIEW_DIR' ) ) {
5
	die();
6
}
7
8
/**
9
 * An entry locking class that syncs with GFEntryLocking.
10
 *
11
 * @since 2.5.2
12
 */
13
class GravityView_Edit_Entry_Locking {
14
15
	/**
16
	 * Load extension entry point.
17
	 *
18
	 * DO NOT RENAME this method. Required by the class-edit-entry.php component loader.
19
	 * @see GravityView_Edit_Entry::load_components()
20
	 *
21
	 * @since 2.5.2
22
	 *
23
	 * @return void
24
	 */
25 22
	public function load() {
26 22
		if ( ! has_action( 'wp_enqueue_scripts', array( $this, 'maybe_enqueue_scripts' ) ) ) {
27 22
			add_action( 'wp_enqueue_scripts', array( $this, 'maybe_enqueue_scripts' ) );
28
		}
29
30 22
		add_action( 'wp_ajax_gf_lock_request_entry', array( $this, 'ajax_lock_request' ), 1 );
31 22
		add_action( 'wp_ajax_gf_reject_lock_request_entry', array( $this, 'ajax_reject_lock_request' ), 1 );
32 22
		add_action( 'wp_ajax_nopriv_gf_lock_request_entry', array( $this, 'ajax_lock_request' ) );
33 22
		add_action( 'wp_ajax_nopriv_gf_reject_lock_request_entry', array( $this, 'ajax_reject_lock_request' ) );
34 22
	}
35
36
	// TODO: Convert to extending Gravity Forms
37
	public function ajax_lock_request() {
38
		$object_id = rgget( 'object_id' );
39
		$response  = $this->request_lock( $object_id );
40
		echo json_encode( $response );
41
		die();
42
	}
43
44
	// TODO: Convert to extending Gravity Forms
45
	public function ajax_reject_lock_request() {
46
		$object_id = rgget( 'object_id' );
47
		$response  = $this->delete_lock_request_meta( $object_id );
48
		echo json_encode( $response );
49
		die();
50
	}
51
52
	// TODO: Convert to extending Gravity Forms
53
	protected function delete_lock_request_meta( $object_id ) {
54
		GFCache::delete( 'lock_request_entry_' . $object_id );
55
56
		return true;
57
	}
58
59
	// TODO: Convert to extending Gravity Forms
60
	protected function request_lock( $object_id ) {
61
		if ( 0 == ( $user_id = get_current_user_id() ) ) {
62
			return false;
63
		}
64
65
		$lock_holder_user_id = $this->check_lock( $object_id );
66
67
		$result = array();
68
		if ( ! $lock_holder_user_id ) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $lock_holder_user_id of type false|integer is loosely compared to false; this is ambiguous if the integer can be zero. You might want to explicitly use === null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For integer values, zero is a special case, in particular the following results might be unexpected:

0   == false // true
0   == null  // true
123 == false // false
123 == null  // false

// It is often better to use strict comparison
0 === false // false
0 === null  // false
Loading history...
69
			$this->set_lock( $object_id );
70
			$result['html']   = __( 'You now have control', 'gravityforms' );
71
			$result['status'] = 'lock_obtained';
72
		} else {
73
74
			if( GVCommon::has_cap( 'gravityforms_edit_entries' ) ) {
75
				$user = get_userdata( $lock_holder_user_id );
76
				$result['html']   = sprintf( __( 'Your request has been sent to %s.', 'gravityforms' ), $user->display_name );
77
			} else {
78
				$result['html']   = __( 'Your request has been sent.', 'gravityforms' );
79
			}
80
81
			$this->update_lock_request_meta( $object_id, $user_id );
82
83
			$result['status'] = 'lock_requested';
84
		}
85
86
		return $result;
87
	}
88
89
	protected function update_lock_request_meta( $object_id, $lock_request_value ) {
90
		GFCache::set( 'lock_request_entry_' . $object_id, $lock_request_value, true, 120 );
91
	}
92
93
	/**
94
	 * Checks whether to enqueue scripts based on:
95
	 *
96
	 * - Is it Edit Entry?
97
	 * - Is the entry connected to a View that has `edit_locking` enabled?
98
	 * - Is the entry connected to a form connected to a currently-loaded View?
99
	 *
100
	 * @internal
101
	 * @since 2.6.1
102
	 *
103
	 * @global WP_Post $post
104
	 *
105
	 * @return void
106
	 */
107
	public function maybe_enqueue_scripts() {
108
		global $post;
109
110
		if ( ! $entry = gravityview()->request->is_edit_entry() ) {
111
			return;
112
		}
113
114
		if ( ! $post || ! is_a( $post, 'WP_Post' ) ) {
115
			return;
116
		}
117
118
		$views = \GV\View_Collection::from_post( $post );
119
120
		$entry_array = $entry->as_entry();
121
122
		$continue_enqueuing = false;
123
124
		// If any Views being loaded have entry locking, enqueue the scripts
125
		foreach( $views->all() as $view ) {
126
127
			// Make sure the View has edit locking enabled
128
			if( ! $view->settings->get( 'edit_locking' ) ) {
129
				continue;
130
			}
131
132
			// Make sure that the entry belongs to one of the forms connected to one of the Views in this request
133
			$joined_forms = $view::get_joined_forms( $view->ID );
134
135
			$entry_form_id = $entry_array['form_id'];
136
137
			if( ! isset( $joined_forms[ $entry_form_id ] ) ) {
138
				continue;
139
			}
140
141
			$continue_enqueuing = true;
142
143
			break;
144
		}
145
146
		if( ! $continue_enqueuing ) {
147
			return;
148
		}
149
150
		$this->enqueue_scripts( $entry_array );
151
	}
152
153
	/**
154
	 * Enqueue the required scripts and styles from Gravity Forms.
155
	 *
156
	 * Called via load() and `wp_enqueue_scripts`
157
	 *
158
	 * @since 2.5.2
159
	 *
160
	 * @param array $entry Gravity Forms entry array
161
	 *
162
	 * @return void
163
	 */
164
	protected function enqueue_scripts( $entry ) {
165
166
		$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG || isset( $_GET['gform_debug'] ) ? '' : '.min';
167
		$locking_path = GFCommon::get_base_url() . '/includes/locking/';
168
169
		wp_enqueue_script( 'gforms_locking', $locking_path . "js/locking{$min}.js", array( 'jquery', 'heartbeat' ), GFCommon::$version );
170
		wp_enqueue_style( 'gforms_locking_css', $locking_path . "css/locking{$min}.css", array( 'edit' ), GFCommon::$version );
171
172
		$translations = array_map( 'wp_strip_all_tags', $this->get_strings() );
173
174
		$strings = array(
175
			'noResponse'    => $translations['no_response'],
176
			'requestAgain'  => $translations['request_again'],
177
			'requestError'  => $translations['request_error'],
178
			'gainedControl' => $translations['gained_control'],
179
			'rejected'      => $translations['request_rejected'],
180
			'pending'       => $translations['request_pending'],
181
		);
182
183
		$lock_user_id = $this->check_lock( $entry['id'] );
184
185
		$vars = array(
186
			'hasLock'    => ! $lock_user_id ? 1 : 0,
187
			'lockUI'     => $this->get_lock_ui( $lock_user_id ),
188
			'objectID'   => $entry['id'],
189
			'objectType' => 'entry',
190
			'strings'    => $strings,
191
		);
192
193
		wp_localize_script( 'gforms_locking', 'gflockingVars', $vars );
194
	}
195
196
	/**
197
	 * Returns a string with the Lock UI HTML markup.
198
	 *
199
	 * Called script enqueuing, added to JavaScript gforms_locking global variable.
200
	 *
201
	 * @since 2.5.2
202
	 *
203
	 * @see GravityView_Edit_Entry_Locking::check_lock
204
	 *
205
	 * @param int $user_id The User ID that has the current lock. Will be empty if entry is not locked
206
	 *                     or is locked to the current user.
207
	 *
208
	 * @return string The Lock UI dialog box, etc.
209
	 */
210
	public function get_lock_ui( $user_id ) {
211
		$user = get_userdata( $user_id );
212
213
		$locked = $user_id && $user;
214
215
		$hidden = $locked ? '' : ' hidden';
216
		if ( $locked ) {
217
218
			if( GVCommon::has_cap( 'gravityforms_edit_entries' ) ) {
219
				$avatar = get_avatar( $user->ID, 64 );
220
				$person_editing_text = $user->display_name;
221
			} else {
222
				$current_user = wp_get_current_user();
223
				$avatar = get_avatar( $current_user->ID, 64 );
224
				$person_editing_text = _x( 'the person who is editing the entry', 'Referring to the user who is currently editing a locked entry', 'gravityview' );
225
			}
226
227
			$message = '<div class="gform-locked-message">
228
                            <div class="gform-locked-avatar">' . $avatar . '</div>
229
                            <p class="currently-editing" tabindex="0">' . esc_html( sprintf( $this->get_string( 'currently_locked' ), $person_editing_text ) ) . '</p>
230
                            <p>
231
232
                                <a id="gform-take-over-button" style="display:none" class="button button-primary wp-tab-first" href="' . esc_url( add_query_arg( 'get-edit-lock', '1' ) ) . '">' . esc_html__( 'Take Over', 'gravityforms' ) . '</a>
233
                                <button id="gform-lock-request-button" class="button button-primary wp-tab-last">' . esc_html__( 'Request Control', 'gravityforms' ) . '</button>
234
                                <a class="button" onclick="history.back(-1); return false;">' . esc_html( $this->get_string( 'cancel' ) ) . '</a>
235
                            </p>
236
                            <div id="gform-lock-request-status">
237
                                <!-- placeholder -->
238
                            </div>
239
                        </div>';
240
241
		} else {
242
243
			$message = '<div class="gform-taken-over">
244
                            <div class="gform-locked-avatar"></div>
245
                            <p class="wp-tab-first" tabindex="0">
246
                                <span class="currently-editing"></span><br>
247
                            </p>
248
                            <p>
249
                                <a id="gform-release-lock-button" class="button button-primary wp-tab-last"  href="' . esc_url( add_query_arg( 'release-edit-lock', '1' ) ) . '">' . esc_html( $this->get_string( 'accept' ) ) . '</a>
250
                                <button id="gform-reject-lock-request-button" style="display:none"  class="button button-primary wp-tab-last">' . esc_html__( 'Reject Request', 'gravityforms' ) . '</button>
251
                            </p>
252
                        </div>';
253
254
		}
255
		$html = '<div id="gform-lock-dialog" class="notification-dialog-wrap' . $hidden . '">
256
                    <div class="notification-dialog-background"></div>
257
                    <div class="notification-dialog">';
258
		$html .= $message;
259
260
		$html .= '   </div>
261
                 </div>';
262
263
		return $html;
264
	}
265
266
	/**
267
	 * Localized string for the UI.
268
	 *
269
	 * Uses gravityforms textdomain unchanged.
270
	 *
271
	 * @since 2.5.2
272
	 *
273
	 * @return array An array of translations.
274
	 */
275
	public function get_strings() {
276
		$translations = array(
277
			'currently_locked'  => __( 'This entry is currently locked. Click on the "Request Control" button to let %s know you\'d like to take over.', 'gravityforms' ),
278
			'currently_editing' => __( '%s is currently editing this entry', 'gravityforms' ),
279
			'taken_over'        => __( '%s has taken over and is currently editing this entry.', 'gravityforms' ),
280
			'lock_requested'    => __( '%s has requested permission to take over control of this entry.', 'gravityforms' ),
281
			'accept'            => __( 'Accept', 'gravityforms' ),
282
			'cancel'            => __( 'Cancel', 'gravityforms' ),
283
			'gained_control'    => __( 'You now have control', 'gravityforms' ),
284
			'request_pending'   => __( 'Pending', 'gravityforms' ),
285
			'no_response'       => __( 'No response', 'gravityforms' ),
286
			'request_again'     => __( 'Request again', 'gravityforms' ),
287
			'request_error'     => __( 'Error', 'gravityforms' ),
288
			'request_rejected'  => __( 'Your request was rejected', 'gravityforms' ),
289
		);
290
291
		$translations = array_map( 'wp_strip_all_tags', $translations );
292
293
		return $translations;
294
	}
295
296
	/**
297
	 * Get a localized string.
298
	 *
299
	 * @param string $string The string to get.
300
	 *
301
	 * @return string A localized string. See self::get_strings()
302
	 */
303
	public function get_string( $string ) {
304
		return \GV\Utils::get( $this->get_strings(), $string, '' );
305
	}
306
307
	/**
308
	 * Lock the entry... maybe.
309
	 *
310
	 * Has 3 modes of locking:
311
	 *
312
	 *  - acquire (get), which reloads the page after locking the entry
313
	 *  - release, which reloads the page after unlocking the entry
314
	 *  - default action to lock on load if not locked
315
	 *
316
	 * @param int $entry_id The entry ID.
317
	 *
318
	 * @return void
319
	 */
320 22
	public function maybe_lock_object( $entry_id ) {
321 22
		global $wp;
322
323 22
		$current_url = add_query_arg( $wp->query_string, '', home_url( $wp->request ) );
324
325 22
		if ( isset( $_GET['get-edit-lock'] ) ) {
326
			$this->set_lock( $entry_id );
327
			echo '<script>window.location = ' . json_encode( remove_query_arg( 'get-edit-lock', $current_url ) ) . ';</script>';
328
			exit();
329 22
		} else if ( isset( $_GET['release-edit-lock'] ) ) {
330
			$this->delete_lock_meta( $entry_id );
331
			$current_url = remove_query_arg( 'edit', $current_url );
332
			echo '<script>window.location = ' . json_encode( remove_query_arg( 'release-edit-lock', $current_url ) ) . ';</script>';
333
			exit();
334
		} else {
335 22
			if ( ! $user_id = $this->check_lock( $entry_id ) ) {
336 22
				$this->set_lock( $entry_id );
337
			}
338
		}
339 22
	}
340
341
	/**
342
	 * Is this entry locked to some other user?
343
	 *
344
	 * @param int $entry_id The entry ID.
345
	 *
346
	 * @return boolean Yes or no.
347
	 */
348 22
	public function check_lock( $entry_id ) {
349 22
		if ( ! $user_id = $this->get_lock_meta( $entry_id ) ) {
350 22
			return false;
351
		}
352
353 9
		if ( $user_id != get_current_user_id() ) {
354
			return $user_id;
355
		}
356
357 9
		return false;
358
	}
359
360
	/**
361
	 * The lock for an entry.
362
	 *
363
	 * Leverages Gravity Forms' persistent caching mechanisms.
364
	 *
365
	 * @param int $entry_id The entry ID.
366
	 *
367
	 * @return int|null The User ID or null.
368
	 */
369 22
	public function get_lock_meta( $entry_id ) {
370 22
		return GFCache::get( 'lock_entry_' . $entry_id );
371
	}
372
373
	/**
374
	 * Set the lock for an entry.
375
	 *
376
	 * @param int $entry_id The entry ID.
377
	 * @param int $user_id The user ID to lock the entry to.
378
	 *
379
	 * @return void
380
	 */
381 22
	public function update_lock_meta( $entry_id, $user_id ) {
382 22
		GFCache::set( 'lock_entry_' . $entry_id, $user_id, true, 1500 );
383 22
	}
384
385
	/**
386
	 * Release the lock for an entry.
387
	 *
388
	 * @param int $entry_id The entry ID.
389
	 *
390
	 * @return void
391
	 */
392
	public function delete_lock_meta( $entry_id ) {
393
		GFCache::delete( 'lock_entry_' . $entry_id );
394
	}
395
396
	/**
397
	 * Lock the entry to the current user.
398
	 *
399
	 * @since 2.5.2
400
	 *
401
	 * @param int $entry_id The entry ID.
402
	 *
403
	 * @return int|false Locked or not.
404
	 */
405 22
	public function set_lock( $entry_id ) {
406
407 22
		$entry = GFAPI::get_entry( $entry_id );
408
409 22
		if ( ! GravityView_Edit_Entry::check_user_cap_edit_entry( $entry ) ) {
410
			return false;
411
		}
412
413 22
		if ( 0 === ( $user_id = get_current_user_id() ) ) {
414
			return false;
415
		}
416
417 22
		$this->update_lock_meta( $entry_id, $user_id );
418
419 22
		return $user_id;
420
	}
421
}
422