Completed
Push — develop ( 8ca23c...429df8 )
by Zack
06:51
created

GravityView_Edit_Entry_Locking::request_lock()   A

Complexity

Conditions 4
Paths 4

Size

Total Lines 28

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 20

Importance

Changes 0
Metric Value
cc 4
nc 4
nop 1
dl 0
loc 28
ccs 0
cts 16
cp 0
crap 20
rs 9.472
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, 'enqueue_scripts' ) ) ) {
27 22
			add_action( 'wp_enqueue_scripts', array( $this, '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
	 * Enqueue the required scripts and styles from Gravity Forms.
95
	 *
96
	 * Called via load() and `wp_enqueue_scripts`
97
	 *
98
	 * @since 2.5.2
99
	 *
100
	 * @return void
101
	 */
102
	public function enqueue_scripts() {
103
104
		if ( ! $entry = gravityview()->request->is_edit_entry() ) {
105
			return;
106
		}
107
108
		$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG || isset( $_GET['gform_debug'] ) ? '' : '.min';
109
		$locking_path = GFCommon::get_base_url() . '/includes/locking/';
110
111
		wp_enqueue_script( 'gforms_locking', $locking_path . "js/locking{$min}.js", array( 'jquery', 'heartbeat' ), GFCommon::$version );
112
		wp_enqueue_style( 'gforms_locking_css', $locking_path . "css/locking{$min}.css", array( 'edit' ), GFCommon::$version );
113
114
		$translations = array_map( 'wp_strip_all_tags', $this->get_strings() );
115
116
		$strings = array(
117
			'noResponse'    => $translations['no_response'],
118
			'requestAgain'  => $translations['request_again'],
119
			'requestError'  => $translations['request_error'],
120
			'gainedControl' => $translations['gained_control'],
121
			'rejected'      => $translations['request_rejected'],
122
			'pending'       => $translations['request_pending'],
123
		);
124
125
		$lock_user_id = $this->check_lock( $entry['id'] );
126
127
		$vars = array(
128
			'hasLock'    => ! $lock_user_id ? 1 : 0,
129
			'lockUI'     => $this->get_lock_ui( $lock_user_id ),
130
			'objectID'   => $entry['id'],
131
			'objectType' => 'entry',
132
			'strings'    => $strings,
133
		);
134
135
		wp_localize_script( 'gforms_locking', 'gflockingVars', $vars );
136
	}
137
138
	/**
139
	 * Returns a string with the Lock UI HTML markup.
140
	 *
141
	 * Called script enqueuing, added to JavaScript gforms_locking global variable.
142
	 *
143
	 * @since 2.5.2
144
	 *
145
	 * @see GravityView_Edit_Entry_Locking::check_lock
146
	 *
147
	 * @param int $user_id The User ID that has the current lock. Will be empty if entry is not locked
148
	 *                     or is locked to the current user.
149
	 *
150
	 * @return string The Lock UI dialog box, etc.
151
	 */
152
	public function get_lock_ui( $user_id ) {
153
		$user = get_userdata( $user_id );
154
155
		$locked = $user_id && $user;
156
157
		$hidden = $locked ? '' : ' hidden';
158
		if ( $locked ) {
159
160
			if( GVCommon::has_cap( 'gravityforms_edit_entries' ) ) {
161
				$avatar = get_avatar( $user->ID, 64 );
162
				$person_editing_text = $user->display_name;
163
			} else {
164
				$current_user = wp_get_current_user();
165
				$avatar = get_avatar( $current_user->ID, 64 );
166
				$person_editing_text = _x( 'the person who is editing the entry', 'Referring to the user who is currently editing a locked entry', 'gravityview' );
167
			}
168
169
			$message = '<div class="gform-locked-message">
170
                            <div class="gform-locked-avatar">' . $avatar . '</div>
171
                            <p class="currently-editing" tabindex="0">' . esc_html( sprintf( $this->get_string( 'currently_locked' ), $person_editing_text ) ) . '</p>
172
                            <p>
173
174
                                <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>
175
                                <button id="gform-lock-request-button" class="button button-primary wp-tab-last">' . esc_html__( 'Request Control', 'gravityforms' ) . '</button>
176
                                <a class="button" onclick="history.back(-1); return false;">' . esc_html( $this->get_string( 'cancel' ) ) . '</a>
177
                            </p>
178
                            <div id="gform-lock-request-status">
179
                                <!-- placeholder -->
180
                            </div>
181
                        </div>';
182
183
		} else {
184
185
			$message = '<div class="gform-taken-over">
186
                            <div class="gform-locked-avatar"></div>
187
                            <p class="wp-tab-first" tabindex="0">
188
                                <span class="currently-editing"></span><br>
189
                            </p>
190
                            <p>
191
                                <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>
192
                                <button id="gform-reject-lock-request-button" style="display:none"  class="button button-primary wp-tab-last">' . esc_html__( 'Reject Request', 'gravityforms' ) . '</button>
193
                            </p>
194
                        </div>';
195
196
		}
197
		$html = '<div id="gform-lock-dialog" class="notification-dialog-wrap' . $hidden . '">
198
                    <div class="notification-dialog-background"></div>
199
                    <div class="notification-dialog">';
200
		$html .= $message;
201
202
		$html .= '   </div>
203
                 </div>';
204
205
		return $html;
206
	}
207
208
	/**
209
	 * Localized string for the UI.
210
	 *
211
	 * Uses gravityforms textdomain unchanged.
212
	 *
213
	 * @since 2.5.2
214
	 *
215
	 * @return array An array of translations.
216
	 */
217
	public function get_strings() {
218
		$translations = array(
219
			'currently_locked'  => __( 'This entry is currently locked. Click on the "Request Control" button to let %s know you\'d like to take over.', 'gravityforms' ),
220
			'currently_editing' => __( '%s is currently editing this entry', 'gravityforms' ),
221
			'taken_over'        => __( '%s has taken over and is currently editing this entry.', 'gravityforms' ),
222
			'lock_requested'    => __( '%s has requested permission to take over control of this entry.', 'gravityforms' ),
223
			'accept'            => __( 'Accept', 'gravityforms' ),
224
			'cancel'            => __( 'Cancel', 'gravityforms' ),
225
			'gained_control'    => __( 'You now have control', 'gravityforms' ),
226
			'request_pending'   => __( 'Pending', 'gravityforms' ),
227
			'no_response'       => __( 'No response', 'gravityforms' ),
228
			'request_again'     => __( 'Request again', 'gravityforms' ),
229
			'request_error'     => __( 'Error', 'gravityforms' ),
230
			'request_rejected'  => __( 'Your request was rejected', 'gravityforms' ),
231
		);
232
233
		$translations = array_map( 'wp_strip_all_tags', $translations );
234
235
		return $translations;
236
	}
237
238
	/**
239
	 * Get a localized string.
240
	 *
241
	 * @param string $string The string to get.
242
	 *
243
	 * @return string A localized string. See self::get_strings()
244
	 */
245
	public function get_string( $string ) {
246
		return \GV\Utils::get( $this->get_strings(), $string, '' );
247
	}
248
249
	/**
250
	 * Lock the entry... maybe.
251
	 *
252
	 * Has 3 modes of locking:
253
	 *
254
	 *  - acquire (get), which reloads the page after locking the entry
255
	 *  - release, which reloads the page after unlocking the entry
256
	 *  - default action to lock on load if not locked
257
	 *
258
	 * @param int $entry_id The entry ID.
259
	 *
260
	 * @return void
261
	 */
262 22
	public function maybe_lock_object( $entry_id ) {
263 22
		global $wp;
264
265 22
		$current_url = add_query_arg( $wp->query_string, '', home_url( $wp->request ) );
266
267 22
		if ( isset( $_GET['get-edit-lock'] ) ) {
268
			$this->set_lock( $entry_id );
269
			echo '<script>window.location = ' . json_encode( remove_query_arg( 'get-edit-lock', $current_url ) ) . ';</script>';
270
			exit();
271 22
		} else if ( isset( $_GET['release-edit-lock'] ) ) {
272
			$this->delete_lock_meta( $entry_id );
273
			$current_url = remove_query_arg( 'edit', $current_url );
274
			echo '<script>window.location = ' . json_encode( remove_query_arg( 'release-edit-lock', $current_url ) ) . ';</script>';
275
			exit();
276
		} else {
277 22
			if ( ! $user_id = $this->check_lock( $entry_id ) ) {
278 22
				$this->set_lock( $entry_id );
279
			}
280
		}
281 22
	}
282
283
	/**
284
	 * Is this entry locked to some other user?
285
	 *
286
	 * @param int $entry_id The entry ID.
287
	 *
288
	 * @return boolean Yes or no.
289
	 */
290 22
	public function check_lock( $entry_id ) {
291 22
		if ( ! $user_id = $this->get_lock_meta( $entry_id ) ) {
292 22
			return false;
293
		}
294
295 9
		if ( $user_id != get_current_user_id() ) {
296
			return $user_id;
297
		}
298
299 9
		return false;
300
	}
301
302
	/**
303
	 * The lock for an entry.
304
	 *
305
	 * Leverages Gravity Forms' persistent caching mechanisms.
306
	 *
307
	 * @param int $entry_id The entry ID.
308
	 *
309
	 * @return int|null The User ID or null.
310
	 */
311 22
	public function get_lock_meta( $entry_id ) {
312 22
		return GFCache::get( 'lock_entry_' . $entry_id );
313
	}
314
315
	/**
316
	 * Set the lock for an entry.
317
	 *
318
	 * @param int $entry_id The entry ID.
319
	 * @param int $user_id The user ID to lock the entry to.
320
	 *
321
	 * @return void
322
	 */
323 22
	public function update_lock_meta( $entry_id, $user_id ) {
324 22
		GFCache::set( 'lock_entry_' . $entry_id, $user_id, true, 1500 );
325 22
	}
326
327
	/**
328
	 * Release the lock for an entry.
329
	 *
330
	 * @param int $entry_id The entry ID.
331
	 *
332
	 * @return void
333
	 */
334
	public function delete_lock_meta( $entry_id ) {
335
		GFCache::delete( 'lock_entry_' . $entry_id );
336
	}
337
338
	/**
339
	 * Lock the entry to the current user.
340
	 *
341
	 * @since 2.5.2
342
	 *
343
	 * @param int $entry_id The entry ID.
344
	 *
345
	 * @return int|false Locked or not.
346
	 */
347 22
	public function set_lock( $entry_id ) {
348
349 22
		$entry = GFAPI::get_entry( $entry_id );
350
351 22
		if ( ! GravityView_Edit_Entry::check_user_cap_edit_entry( $entry ) ) {
352
			return false;
353
		}
354
355 22
		if ( 0 === ( $user_id = get_current_user_id() ) ) {
356
			return false;
357
		}
358
359 22
		$this->update_lock_meta( $entry_id, $user_id );
360
361 22
		return $user_id;
362
	}
363
}
364