-
Notifications
You must be signed in to change notification settings - Fork 1
/
enforce_revlog.module
305 lines (275 loc) · 11.1 KB
/
enforce_revlog.module
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
<?php
/**
* @file
* Allows enforcing unpriviledged users to enter a log message every time
* a node revision is created or reverted
*/
/**
* Implements hook_permission().
*/
function enforce_revlog_permission() {
return array(
'skip revision log message' => array(
'title' => t('Skip revision log message'),
'description' => t('Skip entering a log message at each new node revision.'),
),
'override force revision' => array(
'title' => t('Override create new revision'),
'description' => t('Override "Create new revision" on node form when new revisions are the default for the content type.'),
),
);
}
/**
* Implements hook_menu().
*/
function enforce_revlog_menu() {
$items = array();
$items['admin/config/content/enforce-revlog'] = array(
'title' => 'Enforce Revision Logs',
'description' => 'Enforce the requirement for users to enter a log message for every revision.',
'page callback' => 'backdrop_get_form',
'page arguments' => array('enforce_revlog_settings'),
'access callback' => 'user_access',
'access arguments' => array('administer site configuration'),
);
return $items;
}
/**
* Implements hook_config_info().
*/
function enforce_revlog_config_info() {
$prefixes['enforce_revlog.settings'] = array(
'label' => t('Enforce revlog settings'),
'group' => t('Configuration'),
);
return $prefixes;
}
/**
* Settings page.
*/
function enforce_revlog_settings() {
// Get the config for the module.
$config = config('enforce_revlog.settings');
$form['#config'] = 'enforce_revlog.settings';
// Define the permission reminder url depending on whether Filter Permissions
// module is enabled or not.
if (module_exists('filter_perms')) {
$reminder_url = url('admin/config/people/permissions/module-enforce_revlog');
}
else {
$reminder_url = url('admin/config/people/permissions', array(
'query' => array('search' => 'enforce revision logs'),
));
}
// Global settings.
$form['global'] = array(
'#type' => 'fieldset',
'#title' => t('Global settings'),
'#description' => t("Don't forget to <a href='@setperms'>set permissions</a> for roles that will be able to skip entering a log message or override creating a new revision.", array(
'@setperms' => $reminder_url,
)),
);
$form['global']['enforce_revlog_revision_revert'] = array(
'#type' => 'checkbox',
'#title' => t('Enforce log message when reverting a revision'),
'#description' => t('Enforce the requirement for users to enter a log message when reverting a revision'),
'#default_value' => $config->get('enforce_revlog_revision_revert'),
);
$form['global']['enforce_create_new_revision'] = array(
'#type' => 'checkbox',
'#title' => t('Enforce "Create new revision"'),
'#description' => t('Enforce "Create new revision" if this is the default for the content type.'),
'#default_value' => $config->get('enforce_create_new_revision'),
);
$form['global']['enforce_revlog_user1'] = array(
'#type' => 'checkbox',
'#title' => t('Enforce permissions for User 1'),
'#description' => t("Disable 'Skip revision log message' and/or 'Override create new revision' permissions for User 1 if administrators do not have the permission(s)."),
'#default_value' => $config->get('enforce_revlog_user1'),
);
// Generate per content-type settings.
$form['types'] = array(
'#type' => 'fieldset',
'#title' => t('Content Types'),
'#description' => t('Select each content type to enforce. Each selected type must have revisions enabled for this module to work.'),
);
foreach (node_type_get_names() as $type => $name) {
$form['types']['enforce_revlog_node_type_' . $type] = array(
'#type' => 'checkbox',
'#title' => $name,
'#default_value' => $config->get('enforce_revlog_node_type_' . $type),
);
}
return system_settings_form($form);
}
/**
* Implements hook_node_prepare().
*/
function enforce_revlog_node_prepare($node) {
$node->enforce_revlog = FALSE;
// Get config for content type.
$enforce_for_content_type = config_get('enforce_revlog.settings', 'enforce_revlog_node_type_' . $node->type);
// Check if the node exists and whether the content type is set to enforce
// the revision log.
if (isset($node->nid) && $enforce_for_content_type) {
// Check permission for enforcing a log.
$node->enforce_revlog = !enforce_revlog_check_permission('skip revision log message');
}
}
/**
* Checks if user has permission to skip revision log.
*
* @todo if https://github.com/backdrop/backdrop-issues/issues/6186 is approved
* then replace check for admin role permission with user_role_has_permission.
*
* @param string $permission_name
* The machine name of the permission to check for.
*
* @return boolean
* TRUE if the role has the permission, FALSE if it does not have the
* permission.
*/
function enforce_revlog_check_permission($permission_name) {
// Get the defined admin role.
$role = user_role_load(config_get('system.core', 'user_admin_role'));
// Check the admin role for the permission.
if (in_array($permission_name, $role->permissions)) {
// If the admin role DOES have the permission, then the check is simply
// for whether the user has access.
$check_permission = user_access($permission_name);
}
else {
// If the admin role DOES NOT have permission, then we should also check
// whether we should enforce for user 1.
global $user;
$enforce_revlog_user1 = config_get('enforce_revlog.settings', 'enforce_revlog_user1');
if ($user->uid == 1 && $enforce_revlog_user1) {
$check_permission = FALSE;
}
else {
// It is possible, but unlikely, that another role would have the
// permission even though admin does not, so if the user is not User 1,
// or the revision log is not enforced for User 1, then we will apply
// the generic check.
$check_permission = user_access($permission_name);
}
}
return $check_permission;
}
/**
* Implements hook_node_presave().
*/
function enforce_revlog_node_presave($node) {
// Trigger only if we're reverting a revision.
// Determined thanks to a custom property in the node object.
if (!empty($node->enforce_revlog_revision_revert)) {
// Adding the custom log message to the standard one.
$node->log = $node->enforce_revlog_log_message . ' (' . $node->log . ')';
// Deleting custom object properties, there aren't needed anymore.
unset($node->enforce_revlog_log_message, $node->enforce_revlog_revision_revert);
}
}
/**
* Implements hook_form_alter().
*
* Trying to identify all node forms to enable log message textarea as required
*/
function enforce_revlog_form_alter(&$form, &$form_state, $form_id) {
$config = config('enforce_revlog.settings');
if (strpos($form_id, 'node_form')) {
// Get required state for revision message.
$required = isset($form_state['values']['revision']) ? (bool) $form_state['values']['revision'] : (bool) $form['revision_information']['revision']['#default_value'];
// Only alter form if enforce_revlog is enabled.
if (!empty($form['#node']->enforce_revlog)) {
if (!empty($form['#node']->revision)) {
// Mark the log message as required if creation of a new revision is
// enabled.
$form['revision_information']['log']['#prefix'] = '<div id="enforce-revlog-wrapper">';
$form['revision_information']['log']['#suffix'] = '</div>';
$form['revision_information']['log']['#required'] = $required;
$form['revision_information']['revision']['#ajax'] = array(
'callback' => 'enforce_revlog_js',
'wrapper' => 'enforce-revlog-wrapper',
);
// If "Create new revision" is enabled by default for the content type,
// then we check whether we should disable that checkbox.
if ($required && config_get('enforce_revlog.settings', 'enforce_create_new_revision')) {
$permission = !enforce_revlog_check_permission('override force revision');
$form['revision_information']['revision']['#disabled'] = $permission;
}
}
// Handle buttons before validation.
$form['#after_build'][] = 'enforce_revlog_after_build';
}
}
elseif ($form_id == 'node_revision_revert_confirm') {
// Add a log message textarea to the revision revert form - adapt the one
// from node.module.
$form['log'] = array(
'#type' => 'textarea',
'#title' => t('Log message'),
'#default_value' => '',
'#rows' => 2,
'#description' => t('An explanation of your reasons for reverting the revision to help other authors understand your motivations.'),
'#required' => $config->get('enforce_revlog_revision_revert') && !enforce_revlog_check_permission('skip revision log message'),
);
// Adding our own properties to the node object for future use.
$form['#node_revision']->enforce_revlog_revision_revert = 1;
$form['#node_revision']->enforce_revlog_log_message = '';
// Custom validation function.
$form['#validate'][] = 'enforce_revlog_revision_revert_validate';
}
elseif ($form_id === 'node_type_form') {
// Adding enforce_revlog setting on the content type editing form.
// Value will be automatically saved in the variable table.
// Content type name changes are handled automatically too.
$form['revision']['revision']['enforce_revlog_node_type'] = array(
'#type' => 'checkbox',
'#title' => t('Enforce users to enter a log message for every revision'),
'#description' => t('Revisions must be enabled for this module to work'),
'#default_value' => $config->get('enforce_revlog_node_type_' . $form['#node_type']->type, 0),
// '#options' => array(t('Disabled'), t('Enabled')),
);
}
}
/**
* After build callback
*/
function enforce_revlog_after_build($form, $form_state) {
// Do not require a log message when previewing or deleting the node.
$excluded = array(
$form['actions']['preview']['#value'],
);
if (isset($form['actions']['delete']['#value'])) {
$excluded[] = $form['actions']['delete']['#value'];
}
if (!empty($form_state['input']['op']) && in_array($form_state['input']['op'], $excluded)) {
$form['revision_information']['log']['#validated'] = TRUE;
}
return $form;
}
/**
* Validation function for the revision revert form
* Passing $form by reference to store changes to the object
*/
function enforce_revlog_revision_revert_validate(&$form, &$form_state) {
// Storing the custom log message in the node object.
$form['#node_revision']->enforce_revlog_log_message = check_plain($form_state['values']['log']);
}
/**
* AJAX callback to change the required state of the log message textarea.
* Allows visual feedback by the user.
* This function is only triggered when the right conditions are met.
*/
function enforce_revlog_js($form, $form_state) {
$form['revision_information']['log']['#required'] = (bool) $form_state['values']['revision'];
return $form['revision_information']['log'];
}
/**
* Implements hook_node_type_delete().
*
* Delete associated config when content type is deleted.
*/
function enforce_revlog_node_type_delete($info) {
config_clear('enforce_revlog.settings', 'enforce_revlog_node_type_' . $info->type);
}