Projet

Général

Profil

Paste
Télécharger (21,5 ko) Statistiques
| Branche: | Révision:

root / drupal7 / sites / all / modules / content_access / content_access.module @ ae34fb26

1
<?php
2

    
3
/**
4
 * @file Content access module file.
5
 */
6

    
7
/**
8
 * Implements hook_help().
9
 */
10
function content_access_help($path, $arg) {
11
  switch ($path) {
12
    case 'admin/help#content_access':
13
      $output = '<h3>' . t('About') . '</h3>';
14
      $output .= '<p>' . t('The <strong>Content Access</strong> module let you content manage access permission in a flexible and transparant way.') . '</p>';
15
      $output .= '<h3>' . t('Use') . '</h3>';
16
      $output .= '<p>' . t('It provides two new permissions: <em>view all</em> (allows anyone to view the content) and <em>view own</em> (allows  only the content creator to see his/her own content). It also gives access to the existing core permissions <em>edit</em> and <em>delete</em> on the same settings page.') . '</p>';
17
      $output .= '<p>' . t('It provides the following modalities:') . '</p><ul>';
18
      $output .= '<li>' . t('Each <em>!content-type</em> can have its own default content access settings by role.',  array('!content-type' => l('content type', 'admin/structure/types'))) . '</li>';
19
      $output .= '<li>' . t('Optionally you can enable  role based access control settings per <em>content node</em>.') . '</li>';
20
      $output .= '<li>' . t('Access control can be further customized per <em>user</em> if you have the <strong>!acl</strong> module enabled.',
21
        array('!acl' => l('ACL', 'https://www.drupal.org/project/acl/'))) . '</li></ul>';
22
      if (function_exists('advanced_help_hint_docs')) {
23
        $output .= '<p>' . advanced_help_hint_docs('content_access', 'https://drupal.org/node/1194974', TRUE) . '</p>';
24
      }
25
      else {
26
        $output .= '<p>' .t('If you install and enable the module <strong>!url</strong>, you will get more help for <strong>Content Access</strong>.',
27
          array('!url' => l('Advanced Help Hint', 'https://www.drupal.org/project/advanced_help_hint'))) . '</p>';
28
      }
29
      return $output;
30
  }
31
}
32
          
33
/**
34
 * Implements hook_admin_paths().
35
 */
36
function content_access_admin_paths() {
37
  $paths = array(
38
    'node/*/access' => TRUE,
39
  );
40
  return $paths;
41
}
42

    
43
/**
44
 * Implements hook_menu().
45
 */
46
function content_access_menu() {
47
  $items = array();
48

    
49
  $items['node/%node/access'] = array(
50
    'title' => 'Access control',
51
    'page callback' => 'drupal_get_form',
52
    'page arguments' => array('content_access_page', 1),
53
    'access callback' => 'content_access_node_page_access',
54
    'access arguments' => array(1),
55
    'file' => 'content_access.admin.inc',
56
    'theme callback' => '_node_custom_theme',
57
    'type' => MENU_LOCAL_TASK,
58
    'weight' => 3,
59
    'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
60
  );
61

    
62
  $items['admin/structure/types/manage/%node_type/access'] = array(
63
    'title' => 'Access control',
64
    'description' => 'Configure content access control.',
65
    'page callback' => 'drupal_get_form',
66
    'page arguments' => array('content_access_admin_settings', 4),
67
    'access callback' => 'content_access_admin_settings_access',
68
    'access arguments' => array(),
69
    'type' => MENU_LOCAL_TASK,
70
    'file' => 'content_access.admin.inc',
71
    'theme callback' => '_node_custom_theme',
72
    'weight' => 1,
73
  );
74

    
75
  return $items;
76
}
77

    
78
/**
79
 * Implements hook_perm().
80
 */
81
function content_access_permission() {
82
  return array(
83
    'grant content access' => array(
84
      'title' => t('Grant content access'),
85
      'description' => t('View and modify content access for any nodes'),
86
    ),
87
    'grant own content access' => array(
88
      'title' => t('Grant own content access'),
89
      'description' => t('View and modify content access for own nodes'),
90
    ),
91
  );
92
}
93

    
94
/**
95
 * Get access tab page for the viewed node.
96
 */
97
function content_access_node_page_access($node) {
98
  global $user;
99
  return content_access_get_settings('per_node', $node->type) && user_access('grant content access') ||
100
    content_access_get_settings('per_node', $node->type) && (user_access('grant own content access') && ($user->uid == $node->uid));
101
}
102

    
103
/**
104
 * Content access settings for content type.
105
 */
106
function content_access_admin_settings_access() {
107
  return user_access('administer nodes') && user_access('administer content types');
108
}
109

    
110
/**
111
 * Implements hook_node_grants().
112
 */
113
function content_access_node_grants($account, $op) {
114
  return array(
115
    'content_access_author' => array($account->uid),
116
    'content_access_rid' => array_keys($account->roles),
117
  );
118
}
119

    
120
/**
121
 * Implements hook_node_access_records().
122
 */
123
function content_access_node_access_records($node) {
124
  if (content_access_disabling() || !$node->status) {
125
    return;
126
  }
127

    
128
  // Apply per node settings if necessary.
129
  if (content_access_get_settings('per_node', $node->type)) {
130
    $grants = array();
131
    foreach (array('view', 'update', 'delete') as $op) {
132
      foreach (content_access_get_rids_per_node_op($op, $node) as $rid) {
133
        $grants[$rid]['grant_' . $op] = 1;
134
      }
135
    }
136
    foreach ($grants as $rid => $grant) {
137
      $grants[$rid] = content_access_proccess_grant($grant, $rid, $node);
138
    }
139

    
140
    // Care for the author grant.
141
    $grant = array();
142
    foreach (array('view', 'update', 'delete') as $op) {
143
      // Get all roles that have access to use $op on this node.
144
      $any_roles = drupal_map_assoc(content_access_per_node_setting($op, $node));
145
      $any_roles = $any_roles ? $any_roles : array();
146
      $any_roles += ($op != 'view') ? content_access_get_settings($op, $node->type) : array();
147
      $grant['grant_' . $op] = content_access_own_op($node, $any_roles, content_access_get_rids_per_node_op($op . '_own', $node));
148
    }
149

    
150
    if (array_filter($grant)) {
151
      $grant['realm'] = 'content_access_author';
152
      $grants[] = content_access_proccess_grant($grant, $node->uid, $node);
153
    }
154
  }
155
  else {
156
    // Apply the content type defaults.
157
    $grants = content_access_get_type_grant($node);
158
  }
159

    
160
  if (empty($grants)) {
161
    // This means we grant no access.
162
    $grants[] = content_access_proccess_grant(array(), 0, $node);
163
  }
164
  else {
165
    content_access_optimize_grants($grants, $node);
166
  }
167

    
168
  return $grants;
169
}
170

    
171
/**
172
 * Implements hook_node_delete().
173
 */
174
function content_access_node_delete($node) {
175
  db_delete('content_access')
176
    ->condition('nid', $node->nid)
177
    ->execute();
178
}
179

    
180
/**
181
 * Used by the ACL module.
182
 */
183
function content_access_enabled() {
184
  return !content_access_disabling();
185
}
186

    
187
/**
188
 * Implements hook_disable().
189
 */
190
function content_access_disable() {
191
  content_access_disabling(TRUE);
192
}
193

    
194
/**
195
 * Remembers if we have disabled access.
196
 */
197
function content_access_disabling($set = NULL) {
198
  static $disabling = FALSE;
199

    
200
  if (isset($set)) {
201
    $disabling = $set;
202
  }
203
  return $disabling;
204
}
205

    
206
/**
207
 * Return content_access' settings.
208
 *
209
 * @param $setting
210
 *   One of the content_access_available_settings(), e.g. 'view' or 'per_node'.
211
 *   If 'all' is passed, all available settings are returned.
212
 * @param $type_name
213
 *   The name of the content type to return settings for.
214
 *
215
 * @return
216
 *   The value of the given setting or an array of all settings.
217
 */
218
function content_access_get_settings($setting, $type_name) {
219
  $settings = variable_get('content_access_' . $type_name, array());
220
  $settings += content_access_get_setting_defaults($type_name);
221
  if ($setting == 'all') {
222
    return $settings;
223
  }
224
  return isset($settings[$setting]) ? $settings[$setting] : NULL;
225
}
226

    
227
/**
228
 * Save content_access settings of a content type.
229
 */
230
function content_access_set_settings($settings, $type_name) {
231
  // Do not store default values so we do not have to care about syncing our
232
  // settings with the permissions.
233
  foreach (content_access_get_setting_defaults($type_name) as $setting => $default_value) {
234
    if (isset($settings[$setting]) && $settings[$setting] == $default_value) {
235
      unset($settings[$setting]);
236
    }
237
  }
238
  variable_set('content_access_' . $type_name, $settings);
239
}
240

    
241
/**
242
 * Return an array containing all available content_access settings.
243
 */
244
function content_access_available_settings() {
245
  return array('view', 'update', 'delete', 'view_own', 'update_own', 'delete_own', 'per_node', 'priority');
246
}
247

    
248
/**
249
 * Defines default values for settings.
250
 */
251
function content_access_get_setting_defaults($type) {
252
  $defaults = array();
253
  $defaults['view'] = $defaults['view_own'] = array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID);
254
  foreach (array('update', 'delete') as $op) {
255
    $defaults[$op] = content_access_get_permission_access(content_access_get_permission_by_op($op, $type));
256
    $defaults[$op . '_own'] = content_access_get_permission_access(content_access_get_permission_by_op($op . '_own', $type));
257
  }
258
  $defaults['priority'] = 0;
259
  $defaults['per_node'] = FALSE;
260
  return $defaults;
261
}
262

    
263
/**
264
 * Returns an array of role ids that contain the given permission.
265
 */
266
function content_access_get_permission_access($perm, $reset = FALSE) {
267
  $roles = &drupal_static(__FUNCTION__, array());
268

    
269
  if ($reset) {
270
    $roles = array();
271
  }
272
  if (!isset($roles[$perm]) && $perm) {
273
    $roles[$perm] = array_keys(user_roles(0, $perm));
274
  }
275
  return isset($roles[$perm]) ? $roles[$perm] : array();
276
}
277

    
278
/**
279
 * Gets the name of a permission for the given operation, if there is a suiting one.
280
 */
281
function content_access_get_permission_by_op($op, $type) {
282
  switch ($op) {
283
    default:
284
      return FALSE;
285
    case 'update':
286
      return 'edit any ' . $type . ' content';
287
    case 'update_own':
288
      return 'edit own ' . $type . ' content';
289
    case 'delete':
290
      return 'delete any ' . $type . ' content';
291
    case 'delete_own':
292
      return 'delete own ' . $type . ' content';
293
  }
294
}
295

    
296
/**
297
 * Returns the default grants for a given node type.
298
 */
299
function content_access_get_type_grant($node) {
300
  // Cache per type default grants in a static array
301
  static $defaults = array();
302

    
303
  if (!isset($defaults[$node->type])) {
304
    $grants = array();
305

    
306
    // Only process the 'view' op as node_access() will take care of edit and delete
307
    foreach (content_access_get_settings('view', $node->type) as $rid) {
308
      $grants[$rid]['grant_view'] = 1;
309
      $grants[$rid] = content_access_proccess_grant($grants[$rid], $rid, $node);
310
    }
311
    $defaults[$node->type] = $grants;
312
  }
313

    
314
  // Care for the author grant.
315
  $grant = $grants = array();
316
  $grant['grant_view'] = content_access_own_op($node, content_access_get_settings('view', $node->type), content_access_get_settings('view_own', $node->type));
317
  if ($grant['grant_view']) {
318
    $grant['realm'] = 'content_access_author';
319
    $grants = array('author' => content_access_proccess_grant($grant, $node->uid, $node));
320
  }
321

    
322
  return $defaults[$node->type] + $grants;
323
}
324

    
325
/**
326
 * Process a grant, which means add priority, realm and other properties.
327
 */
328
function content_access_proccess_grant($grant, $gid, $node) {
329
  $grant += array('grant_view' => 0, 'grant_update' => 0, 'grant_delete' => 0, 'realm' => 'content_access_rid');
330
  $grant['gid'] = $gid;
331
  $grant['priority'] = content_access_get_settings('priority', $node->type);
332
  return $grant;
333
}
334

    
335
/**
336
 * Determines the grant for the node author and the given allowed roles of a operation.
337
 *
338
 * @param $any_roles
339
 *   The roles with which anybody has access (not optimized!)
340
 * @param $own_roles
341
 *   The roles with which only the author has access (optimized!)
342
 */
343
function content_access_own_op($node, $any_roles, $own_roles) {
344
  static $roles = array();
345

    
346
  if (!isset($roles[$node->uid])) {
347
    $roles[$node->uid] = $node->uid ? array(DRUPAL_AUTHENTICATED_RID) : array(DRUPAL_ANONYMOUS_RID);
348
    $result = db_query('SELECT rid FROM {users_roles} WHERE uid = :uid', array(':uid' => $node->uid));
349

    
350
    foreach ($result as $role) {
351
      $roles[$node->uid][] = $role->rid;
352
    }
353
  }
354
  if (array_intersect($roles[$node->uid], $any_roles)) {
355
    // If there is access due to "any permissions" there is no need to at an author grant.
356
    return 0;
357
  }
358
  return array_intersect($roles[$node->uid], $own_roles) ? 1 : 0;
359
}
360

    
361
/**
362
 * Returns optimized role ids for the given operation and node to
363
 * grant access for.
364
 *
365
 * If to a role access is granted by permissions, it's not necessary
366
 * to write a grant for it. So it won't be returned.
367
 *
368
 * @param $op
369
 *   One of the supported operations.
370
 * @param $node
371
 *   The node object.
372
 */
373
function content_access_get_rids_per_node_op($op, $node) {
374
  $rids = content_access_per_node_setting($op, $node);
375

    
376
  if ($permission = content_access_get_permission_by_op($op, $node->type)) {
377
    $perm_roles = content_access_get_permission_access($permission);
378
    $rids = array_diff($rids, $perm_roles);
379

    
380
    if (in_array(DRUPAL_AUTHENTICATED_RID, $perm_roles)) {
381
      return in_array(DRUPAL_ANONYMOUS_RID, $rids) ? array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID) : array(DRUPAL_AUTHENTICATED_RID);
382
    }
383
  }
384
  return $rids;
385
}
386

    
387

    
388
/**
389
 * Returns the per node role settings. If no per node settings are available,
390
 * it will return the content type settings.
391
 *
392
 * @param $op
393
 *   One of the supported operations.
394
 * @param $node
395
 *   The node object.
396
 * @param $settings
397
 *   Optional array used to update the settings cache with the given settings.
398
 * @return
399
 *   An array of role ids which have access.
400
 */
401
function content_access_per_node_setting($op, $node, $settings = NULL) {
402
  static $grants = array();
403

    
404
  if (isset($settings)) {
405
    // Update settings cache
406
    $grants[$node->nid] = $settings;
407
    return;
408
  }
409

    
410
  if (!isset($grants[$node->nid]) || $grants[$node->nid] === FALSE) {
411
    $grants[$node->nid] = content_access_get_per_node_settings($node);
412
  }
413

    
414
  // Return the content type defaults if no per node settings are available
415
  return isset($grants[$node->nid][$op]) ? $grants[$node->nid][$op] : content_access_get_settings($op, $node->type);
416
}
417

    
418
/**
419
 * Gets the per node settings of a node.
420
 *
421
 * @note
422
 *   This function won't apply defaults, so if there are no other settings
423
 *   it will return an empty array.
424
 */
425
function content_access_get_per_node_settings($node) {
426
  foreach (db_query("SELECT settings FROM {content_access} WHERE nid = :nid", array(':nid' => $node->nid)) as $record) {
427
    $settings = $record->settings;
428
    if (!$settings) {
429
      return array();
430
    }
431
    return unserialize($settings);
432
  }
433
}
434

    
435
/**
436
 * Saves custom per node settings in the own content_access table.
437
 */
438
function content_access_save_per_node_settings($node, $settings) {
439
  $count = db_select('content_access')
440
            ->condition('nid', $node->nid)
441
            ->countQuery()->execute()->fetchField();
442

    
443
  if ($count > 0) {
444
    db_update('content_access')
445
      ->condition('nid', $node->nid)
446
      ->fields(array('settings' => serialize($settings)))
447
      ->execute();
448
  }
449
  else {
450
    db_insert('content_access')
451
      ->fields(array('nid' => $node->nid, 'settings' => serialize($settings)))
452
      ->execute();
453
  }
454

    
455
  // Make content_access_per_node_setting() use the new settings
456
  content_access_per_node_setting(NULL, $node, $settings);
457
}
458

    
459
/**
460
 * Deletes all custom per node settings, so that content type defaults are used again.
461
 */
462
function content_access_delete_per_node_settings($node) {
463
  db_delete('content_access')
464
    ->condition('nid', $node->nid)
465
    ->execute();
466

    
467
  // Clear the cache.
468
  content_access_per_node_setting(NULL, $node, FALSE);
469

    
470
  // Delete possible acl settings
471
  if (module_exists('acl')) {
472
    // @todo why content_access.admin.inc is not loaded before?
473
    module_load_include('inc', 'content_access', 'content_access.admin');
474
    foreach (array('view', 'update', 'delete') as $op) {
475
      $acl_id = content_access_get_acl_id($node, $op);
476
      acl_delete_acl($acl_id);
477
    }
478
  }
479
}
480

    
481
/**
482
 * Removes grants that doesn't change anything.
483
 *
484
 * @note
485
 *   The grants are compared with the normal access control settings.
486
 */
487
function content_access_optimize_grants(&$grants, $node) {
488
  $rids = array('view' => array(), 'update' => array(), 'delete' => array());
489

    
490
  foreach ($grants as $key => $grant) {
491
    foreach (array('view', 'update', 'delete') as $op) {
492
      if (is_numeric($key) && !empty($grant['grant_' . $op])) {
493
        $rids[$op][] = $key;
494
      }
495
    }
496
  }
497

    
498
  // Detect if all are allowed to view
499
  $all = array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID);
500
  if (count(array_diff($all, $rids['view'])) == 0) {
501
    //grant view access to all instead of single roles
502
    $rids['view'] = array('all');
503
    $grants['all'] = array('realm' => 'all', 'gid' => 0, 'grant_view' => 1, 'grant_update' => 0, 'grant_delete' => 0, 'priority' => content_access_get_settings('priority', $node->type));
504
  }
505

    
506
  // If authenticated users are involved, remove unnecessary other roles.
507
  foreach (array('view', 'update', 'delete') as $op) {
508
    if (in_array(DRUPAL_AUTHENTICATED_RID, $rids[$op])) {
509
      $rids[$op] = in_array(DRUPAL_ANONYMOUS_RID, $rids[$op]) ? array(DRUPAL_ANONYMOUS_RID, DRUPAL_AUTHENTICATED_RID) : array(DRUPAL_AUTHENTICATED_RID);
510
    }
511
  }
512

    
513
  // Now let's remove unnecessary grants, if any.
514
  foreach ($grants as $key => $grant) {
515
    if (!is_numeric($key)) {
516
      continue;
517
    }
518
    foreach (array('view', 'update', 'delete') as $op) {
519
      if ($grant['grant_' . $op] && in_array($key, $rids[$op])) {
520
        //it's still here, so we can't remove this grant
521
        continue 2;
522
      }
523
    }
524
    //ok, remove it
525
    unset($grants[$key]);
526
  }
527
}
528

    
529
/**
530
 * Implements hook_node_type_delete().
531
 */
532
function content_access_node_type_delete($info) {
533
  variable_del('content_access_' . $info->type);
534
}
535

    
536
/**
537
 * Implements hook_node_type_update().
538
 *
539
 * Updates settings on node type name change.
540
 */
541
function content_access_node_type_update($info) {
542
  if (!empty($info->old_type) && $info->old_type != $info->type) {
543
    $settings = content_access_get_settings('all', $info->old_type);
544
    content_access_set_settings($settings, $info->type);
545
    variable_del('content_access_' . $info->old_type);
546
  }
547
}
548

    
549
/**
550
 * Implements hook_node_access_explain().
551
 */
552
function content_access_node_access_explain($row) {
553
  static $roles;
554

    
555
  if (!isset($roles)) {
556
    $roles = user_roles();
557
  }
558
  if (!$row->gid && $row->realm == 'content_access_rid') {
559
    return t('Content access: No access is granted.');
560
  }
561
  switch ($row->realm) {
562
    case 'content_access_author':
563
      return t('Content access: author of the content can access');
564
    case 'content_access_rid':
565
      return t('Content access: %role can access', array('%role' => $roles[$row->gid]));
566
  }
567
}
568

    
569
/**
570
 * Implements hook_form_alter().
571
 */
572
function content_access_form_alter(&$form, $form_state, $form_id) {
573
  if ($form_id == 'user_admin_perm') {
574
    module_load_include('inc', 'content_access', 'content_access.admin');
575
    $form['#submit'][] = 'content_access_user_admin_perm_submit';
576
  }
577
}
578

    
579
/**
580
 * Returns an array of possible operations on content and their labels.
581
 */
582
function _content_access_get_operations($type = NULL) {
583
  $operations = array(
584
    'view' => t('View any @type content', array('@type' => $type)),
585
    'view_own' => t('View own @type content', array('@type' => $type)),
586
    'update' => t('Edit any @type content', array('@type' => $type)),
587
    'update_own' => t('Edit own @type content', array('@type' => $type)),
588
    'delete' => t('Delete any @type content', array('@type' => $type)),
589
    'delete_own' => t('Delete own @type content', array('@type' => $type)),
590
  );
591
  return $operations;
592
}
593

    
594
/**
595
 * Formapi #process callback, that disables checkboxes for roles without access to content
596
 */
597
function content_access_disable_checkboxes($element) {
598
  $access_roles = content_access_get_permission_access('access content');
599
  $admin_roles = content_access_get_permission_access('bypass node access');
600

    
601
  foreach (element_children($element) as $key) {
602
    if (!in_array($key, $access_roles) &&
603
        $key == DRUPAL_ANONYMOUS_RID &&
604
        !in_array(DRUPAL_AUTHENTICATED_RID, $access_roles)) {
605
      $element[$key]['#disabled'] = TRUE;
606
      $element[$key]['#default_value'] = FALSE;
607
      $element[$key]['#prefix'] = '<span' . drupal_attributes(array('title' => t("This role is lacking the permission '@perm', so it has no access.", array('@perm' => t('access content'))))) . '>';
608
      $element[$key]['#suffix'] = "</span>";
609
    }
610
    elseif (in_array($key, $admin_roles) ||
611
            ($key != DRUPAL_ANONYMOUS_RID && in_array(DRUPAL_AUTHENTICATED_RID, $admin_roles))) {
612
      // Fix the checkbox to be enabled for users with bypass node access privileges
613
      $element[$key]['#disabled'] = TRUE;
614
      $element[$key]['#default_value'] = TRUE;
615
      $element[$key]['#prefix'] = '<span' . drupal_attributes(array('title' => t("This role has '@perm' permission, so access is granted.", array('@perm' => t('bypass node access'))))) . '>';
616
      $element[$key]['#suffix'] = "</span>";
617
    }
618
  }
619

    
620
  return $element;
621
}
622

    
623
/**
624
 * Gets node's access permissions.
625
 */
626
function _content_access_get_node_permissions($type) {
627
  return array_filter(array_map('content_access_get_permission_by_op', array_flip(_content_access_get_operations()), array_fill(0, 6, $type)));
628
}
629

    
630
/**
631
 * Gets the content access acl id of the node.
632
 */
633
function content_access_get_acl_id($node, $op) {
634
  $acl_id = acl_get_id_by_name('content_access', $op . '_' . $node->nid);
635
  if (!$acl_id) {
636
    $acl_id = acl_create_new_acl('content_access', $op . '_' . $node->nid);
637
  }
638
  return $acl_id;
639
}
640

    
641
/**
642
 * Detaches all our ACLs for the nodes of the given type.
643
 */
644
function _content_access_remove_acls($type) {
645
  $result = db_query("SELECT n.nid FROM {node} n WHERE type = :type", array('type' => $type));
646
  foreach ($result as $node) {
647
    acl_node_clear_acls($node->nid, 'content_access');
648
  }
649
}
650

    
651
/**
652
 * Implements hook_node_export_alter().
653
 */
654
function content_access_node_export_alter(array $nodes) {
655
  foreach ($nodes as $node) {
656
    $node->content_access = content_access_get_per_node_settings($node);
657
  }
658
}
659

    
660
/**
661
 * Implements hook_node_export_after_import_alter().
662
 */
663
function content_access_node_export_after_import_alter(array $nodes) {
664
  foreach ($nodes as $node) {
665
    if(empty($node->nid))
666
      continue;
667
    content_access_save_per_node_settings($node, $node->content_access);
668
  }
669
  // Rebuild content access permissions
670
  node_access_rebuild();
671
}