Commit 195a11a9 authored by Ivan Honcharenko's avatar Ivan Honcharenko Committed by Tim-Erwin
Browse files

Issue #2645172 by BAHbKA: OG workflow access feature support

parent 848f983d
Loading
Loading
Loading
Loading
+211 −0
Original line number Diff line number Diff line
<?php
/**
 * @file
 * Integrates og_workflow_access with features.
 */

/**
 * Implements hook_features_export().
 * Tell workflow and og to export related workflows and roles respectively.
 */
function og_workflow_access_features_export($data, &$export, $module_name = '') {
  $export['dependencies']['features'] = 'features';
  $export['dependencies']['workflow'] = 'workflow';
  $export['dependencies']['og_workflow'] = 'og_workflow';

  $pipe = array();
  foreach ($data as $name) {
    $export['features']['og_workflow_access'][$name] = $name;
    // Depend on the workflow feature of the same name to provide the framework.
    $pipe['workflow'][$name] = $name;
  }

  return $pipe;
}

/**
 * Implements hook_features_export_options().
 * Export all workflows (by name) that are related to og_workflow_access.
 */
function og_workflow_access_features_export_options() {
  $workflows = array();
  foreach (_og_workflow_access_get_workflows() as $wid => $name) {
    $workflows[$name] = $name;
  }
  return $workflows;
}

/**
 * Implements hook_features_export_render().
 * Export all workflows that are related to og_workflow_access by exporting their access configs.
 */
function og_workflow_access_features_export_render($module, $data) {
  $code = array();
  $code[] = '  $og_workflow_access = array();';

  foreach ($data as $name) {
    if ($access = _og_workflow_access_get_access($name)) {
      $og_workflow['name'] = $name;
      $og_workflow['access'] = $access;
      $export = features_var_export($og_workflow, '  ');
      $identifier = features_var_export($name);
      $code[] = '  ';
      $code[] = "  // Exported og_workflow_access: $name";
      $code[] = "  \$og_workflow_access[{$identifier}] = {$export};";
      $code[] = "";
    }
  }
  $code[] = '  return $og_workflow_access;';
  $code = implode("\n", $code);
  return array('og_workflow_access_default_access' => $code);
}

/**
 * Implements hook_features_revert().
 */
function og_workflow_access_features_revert($module) {
  foreach (features_get_default('og_workflow_access', $module) as $key => $workflow) {
    _og_workflow_access_update_access($workflow);
  }
}

/**
 * Implements hook_export_rebuild().
 */
function og_workflow_access_features_export_rebuild($module) {
  og_workflow_access_features_revert($module);
}

/**
 * Return workflows which have associated OG Workflow access.
 *
 * @return array
 *   Associative array of workflow names keyed by wid
 */
function _og_workflow_access_get_workflows() {
  $query = db_select('workflows', 'w');
  $query->join('workflow_states', 'ws', 'ws.wid = w.wid');
  $query->join('og_workflow_access', 'ogwac', 'ws.sid = ogwac.sid');
  $workflows = $query->fields('w', array('wid', 'name'))
    ->execute()
    ->fetchAllKeyed();

  return $workflows;
}

/**
 * Returns an array of workflow access.
 *
 * @param string $name
 *   A workflow name to return access for.
 *
 * @return array
 *   An associative array of access configs to provide a consistent code
 *   output.
 */
function _og_workflow_access_get_access($name) {
  $cached = &drupal_static(__FUNCTION__, array());

  if (empty($cached[$name])) {
    $workflow = workflow_load_by_name($name);
    $roles = array();
    // Add a table for every workflow state.
    foreach ($workflow->getStates($all = TRUE) as $state) {
      if ($state->isCreationState()) {
        // No need to set perms on creation.
        continue;
      }
      $view = $update = $delete = array();
      foreach (og_workflow_access_get_workflow_access_by_sid($state->sid) as $access) {
        // Export author rid in a different way.
        if ($access->rid == WORKFLOW_ROLE_AUTHOR_RID && empty($roles[$access->rid])) {
          $roles[$access->rid] = OG_WORKFLOW_FEATURES_AUTHOR;
        }

        if (empty($roles[$access->rid])) {
          $role = og_role_load($access->rid);
          $roles[$access->rid] = $role->group_type . ':' . $role->group_bundle . ':' . $role->name;
        }

        $view[$roles[$access->rid]] = !empty($access->grant_view);
        $update[$roles[$access->rid]] = !empty($access->grant_update);
        $delete[$roles[$access->rid]] = !empty($access->grant_delete);
      }

      $cached[$name][$state->getName()] = array(
        'view' => $view,
        'update' => $update,
        'delete' => $delete,
      );
    }
  }
  return $cached[$name];
}

/**
 * Store new workflow settings.
 *
 * @param array $workflow
 *   An associative array containing the workflow name and code definition.
 */
function _og_workflow_access_update_access($workflow) {
  $cached = &drupal_static(__FUNCTION__, array());
  if ($dbworkflow = workflow_load_by_name($workflow['name'])) {
    foreach ($workflow['access'] as $state_name => $config) {
      // Lookup state ids from name.
      if (empty($cached[$workflow['name']]['sidmap'][$state_name])) {
        $squery = db_select('workflow_states', 'ws')
          ->condition('ws.wid', $dbworkflow->wid)
          ->condition('ws.name', $state_name)
          ->fields('ws', array('sid'));
        $result = $squery->execute()->fetchField();
        if (empty($result)) {
          drupal_set_message(t('Could not fully restore workflow "@name" because there is invalid or missing data in the workflow table.'), array('@name' => $workflow['name']));
          continue; // Try to restore remaining data.
        }
        $cached[$workflow['name']]['sidmap'][$state_name] = $result;
      }

      // Lookup role ids from name.
      foreach ($config as $op => $roles) {
        foreach($roles as $role_name => $checked) {
          if ($role_name == OG_WORKFLOW_FEATURES_AUTHOR && empty($cached['ridmap'][$role_name])) {
            $cached[$workflow['name']]['ridmap'][$role_name] = WORKFLOW_ROLE_AUTHOR_RID;
          }

          if (empty($cached[$workflow['name']]['ridmap'][$role_name])) {
            list($entity, $bundle, $role) = explode(':', $role_name);
            $query = db_select('og_role', 'ogr');
            $query->condition('ogr.gid', 0)
              ->condition('group_type', $entity)
              ->condition('group_bundle', $bundle)
              ->condition('name', $role)
              ->fields('ogr', array('rid'));
            $result = $query->execute()->fetchField();
            if (empty($result)) {
              drupal_set_message(t('Could not fully restore workflow "@name" because there is invalid or missing data in the workflow table.'), array('@name' => $workflow['name']));
              continue; // Try to restore remaining data.
            }
            $cached[$workflow['name']]['ridmap'][$role_name] = $result;
          }
        }
      }

      foreach ($config['view'] as $role_name => $checked) {
        $data = array(
          'sid' => $cached[$workflow['name']]['sidmap'][$state_name],
          'rid' => $cached[$workflow['name']]['ridmap'][$role_name],
          'grant_view' => (!empty($checked)) ? (bool) $checked : 0,
          'grant_update' => (!empty($config['update'][$role_name])) ? (bool) $config['update'][$role_name] : 0,
          'grant_delete' => (!empty($config['delete'][$role_name])) ? (bool) $config['delete'][$role_name] : 0,
        );
        og_workflow_access_insert_workflow_access_by_sid($data);
      }

      foreach (workflow_get_workflow_node_by_sid($cached[$workflow['name']]['sidmap'][$state_name]) as $data) {
        $node = node_load($data->nid);
        node_access_acquire_grants($node);
      }
    }
  }
}