You are here

social_group.install in Open Social 8.9

Install, update and uninstall functions for the social_group module.

File

modules/social_features/social_group/social_group.install
View source
<?php

/**
 * @file
 * Install, update and uninstall functions for the social_group module.
 */
use Drupal\menu_link_content\Entity\MenuLinkContent;
use Drupal\field\Entity\FieldConfig;
use Drupal\field\Entity\FieldStorageConfig;
use Drupal\Core\Database\Database;
use Drupal\user\Entity\Role;
use Drupal\social_post\Entity\Post;
use Drupal\node\Entity\Node;
use Symfony\Component\Yaml\Yaml;

/**
 * Implements hook_update_dependencies().
 */
function social_group_update_dependencies() {

  // Necessary because in system_update_8200 all the configuration files are
  // updated and we delete some modules.
  $dependencies['system'][8200] = [
    'social_group' => 8005,
  ];

  // The gnode module is triggering node access rebuild. Lets rebuild it!
  $dependencies['social_group'][8011] = [
    'gnode' => 8005,
  ];

  // Prevent errors when missing VBO module.
  $dependencies['profile'][8002] = [
    'social_group' => 8501,
  ];

  // New config changes should run after the features removal/revert.
  $dependencies['social_group'][8801] = [
    'social_core' => 8805,
  ];
  return $dependencies;
}

/**
 * Implements hook_install().
 *
 * Perform actions related to the installation of social_group.
 */
function social_group_install() {

  // Set some default permissions.
  _social_group_set_permissions();

  // Add menu items.
  _social_group_create_menu_links();

  // Set the view mode to use when shown in activities.
  activity_creator_set_entity_view_mode('group', 'stream');

  // Make sure the admin theme is not used when managing groups.
  $group_settings = \Drupal::configFactory()
    ->getEditable('group.settings');
  $group_settings
    ->set('use_admin_theme', FALSE);
  $group_settings
    ->save();

  // Disable group nodes.
  $view = \Drupal::service('entity.manager')
    ->getStorage('view')
    ->load('group_nodes');
  if (!is_null($view)) {
    $view
      ->setStatus(FALSE);
    $view
      ->save();
  }

  // Set module weight.
  module_set_weight('social_group', 2);
}

/**
 * Function to set permissions.
 */
function _social_group_set_permissions() {
  $roles = Role::loadMultiple();

  /** @var \Drupal\user\Entity\Role $role */
  foreach ($roles as $role) {
    if ($role
      ->id() === 'administrator') {
      continue;
    }
    $permissions = _social_group_get_permissions($role
      ->id());
    user_role_grant_permissions($role
      ->id(), $permissions);
  }
}

/**
 * Build the permissions.
 *
 * @param string $role
 *   The role.
 *
 * @return array
 *   Returns an array containing the permissions.
 */
function _social_group_get_permissions($role) {

  // Anonymous.
  $permissions['anonymous'] = [
    'access group search',
  ];

  // Authenticated.
  $permissions['authenticated'] = array_merge($permissions['anonymous'], [
    'create open_group group',
    'create closed_group group',
    'view group stream page',
    'view groups on my profile',
    'view groups on other profiles',
    'create public_group group',
  ]);
  $config = \Drupal::config('entity_access_by_field.settings');
  $disable_public_visibility = $config
    ->get('disable_public_visibility');
  if ($disable_public_visibility === 0) {
    $permissions['authenticated'][] = 'create public_group group';
  }

  // Content manager.
  $permissions['contentmanager'] = array_merge($permissions['authenticated'], [
    'manage all groups',
    'view node.book.field_content_visibility:group content',
    'view node.event.field_content_visibility:group content',
    'view node.topic.field_content_visibility:group content',
    'view node.page.field_content_visibility:group content',
    'access group overview',
    'edit group types',
  ]);

  // Site manager.
  $permissions['sitemanager'] = array_merge($permissions['contentmanager'], [
    'set social group settings',
  ]);
  if (isset($permissions[$role])) {
    return $permissions[$role];
  }
  return [];
}

/**
 * Function to create some menu items.
 */
function _social_group_create_menu_links() {
  $menu_links = MenuLinkContent::loadMultiple();
  $parent = NULL;

  /** @var \Drupal\menu_link_content\Entity\MenuLinkContent $menu_link */
  foreach ($menu_links as $menu_link) {
    if ($menu_link
      ->label() === 'Explore' && $menu_link
      ->isExpanded()) {
      $parent = 'menu_link_content:' . $menu_link
        ->uuid();
    }
  }
  if (!is_null($parent)) {
    MenuLinkContent::create([
      'title' => t('All groups'),
      'link' => [
        'uri' => 'internal:/all-groups',
      ],
      'menu_name' => 'main',
      'expanded' => FALSE,
      'weight' => 20,
      'parent' => $parent,
    ])
      ->save();
  }
}

/**
 * Install geolocation, geocoder and grolesync module.
 */
function social_group_update_8001() {
  $modules = [
    'geolocation',
    'geocoder',
    'grolesync',
  ];
  \Drupal::service('module_installer')
    ->install($modules);
}

/**
 * Make sure the group nodes view is disabled.
 */
function social_group_update_8002() {
  $view = \Drupal::service('entity.manager')
    ->getStorage('view')
    ->load('group_nodes');
  if (!is_null($view)) {
    $view
      ->setStatus(FALSE);
    $view
      ->save();
  }
}

/**
 * Converts group description field type from plain text to formatted text.
 */
function social_group_update_8004(&$sandbox) {
  $entity = 'group';
  $bundle = 'open_group';
  $field_name = 'field_group_description';
  $display_mode = 'default';

  // Add a new column 'format' for description field type.
  $spec = [
    'type' => 'varchar',
    'description' => '',
    'length' => 255,
    'not null' => FALSE,
    'default' => NULL,
  ];
  $schema = Database::getConnection()
    ->schema();
  $table = "{$entity}__{$field_name}";
  $col = "{$field_name}_format";
  $schema
    ->addField($table, $col, $spec);

  // Update the field storage settings.
  $field_storage_id = "{$entity}.{$field_name}";
  $field_storage = \Drupal::entityTypeManager()
    ->getStorage('field_storage_config')
    ->load($field_storage_id);

  // Since the usual workflow for field storages do not allow changing the
  // field type, we have to work around it in this case.
  $new_field_storage = $field_storage
    ->toArray();
  $new_field_storage['type'] = 'text_long';
  $new_field_storage['module'] = 'text';
  $new_field_storage['settings'] = [];
  $new_field_storage['dependencies']['module'][] = 'text';
  $new_field_storage = FieldStorageConfig::create($new_field_storage);
  $new_field_storage->original = $new_field_storage;
  $new_field_storage
    ->enforceIsNew(FALSE);
  $new_field_storage
    ->save();

  // Update the field settings.
  $field_id = "{$entity}.{$bundle}.{$field_name}";
  $field = \Drupal::entityTypeManager()
    ->getStorage('field_config')
    ->load($field_id);
  $new_field = $field
    ->toArray();
  $new_field['field_type'] = 'text_long';
  $new_field['dependencies']['module'][] = 'text';
  $new_field = FieldConfig::create($new_field);
  $new_field->original = $field;
  $new_field
    ->enforceIsNew(FALSE);
  $new_field
    ->save();

  // Update entity view display.
  $display_id = "{$entity}.{$bundle}.{$display_mode}";
  $view_display = \Drupal::entityManager()
    ->getStorage('entity_view_display')
    ->load($display_id);
  if ($component = $view_display
    ->getComponent($field_name)) {
    $view_display
      ->setComponent($field_name, [
      'type' => 'basic_string',
      'settings' => [],
    ] + $component)
      ->save();
  }

  // Update entity form display.
  $form_display_name = 'group.open_group.default';
  $form_display = \Drupal::entityTypeManager()
    ->getStorage('entity_form_display')
    ->load($form_display_name);
  if (($component = $form_display
    ->getComponent($field_name)) && $component['type'] == 'string_textarea') {
    $form_display
      ->setComponent($field_name, [
      'type' => 'text_textarea',
      'settings' => [
        'rows' => 5,
        'placeholder' => '',
      ],
    ] + $component)
      ->save();
  }
}

/**
 * Uninstall geocoder and geolocation modules. Remove group geolocation field.
 */
function social_group_update_8005() {
  $modules = [
    'geolocation',
    'geocoder',
  ];
  $config_factory = \Drupal::service('config.factory');
  foreach ($modules as $module) {

    // Remove config.
    $config_factory
      ->getEditable("{$module}.settings")
      ->delete();

    // Remove cache tables.
    if (db_table_exists("cache_{$module}")) {
      db_drop_table("cache_{$module}");
    }

    // Remove data from system.schema.
    $query = \Drupal::database()
      ->delete('key_value');
    $query
      ->condition('name', $module);
    $query
      ->execute();
  }

  // Remove group geolocation field.
  $config_factory
    ->getEditable('field.field.group.closed_group.field_group_geolocation')
    ->delete();
  $config_factory
    ->getEditable('field.field.group.open_group.field_group_geolocation')
    ->delete();
  $config_factory
    ->getEditable('field.storage.group.field_group_geolocation')
    ->delete();

  // Uninstall geocoder and geolocation modules.
  \Drupal::service('module_installer')
    ->uninstall($modules);
}

/**
 * Add 'closed_group' group type and enable the permission for Authenticated.
 */
function social_group_update_8006() {
  $permissions = _social_group_get_permissions('authenticated');
  user_role_grant_permissions('authenticated', $permissions);
}

/**
 * Uninstall grolesync module (for now, more info: drupal.org/node/2850417).
 */
function social_group_update_8007() {
  $modules = [
    'grolesync',
  ];
  \Drupal::service('module_installer')
    ->uninstall($modules);
}

/**
 * Update the permissions for social_group.
 */
function social_group_update_8008() {
  _social_group_set_permissions();
}

/**
 * Set the default group configuration and permission for sitemanager.
 */
function social_group_update_8009() {
  $config = \Drupal::configFactory()
    ->getEditable('social_group.settings');
  $config
    ->set('allow_group_selection_in_node', FALSE);
  $config
    ->save();

  // Site manager should have permission to set social group settings.
  $roles = Role::loadMultiple();

  /** @var \Drupal\user\Entity\Role $role */
  foreach ($roles as $role) {
    if ($role
      ->id() !== 'sitemanager') {
      continue;
    }
    $permissions = [
      'set social group settings',
    ];
    user_role_grant_permissions($role
      ->id(), $permissions);
  }
}

/**
 * Add permissions for public groups.
 */
function social_group_update_8010() {

  /** @var \Drupal\user\Entity\Role $role */
  foreach (Role::loadMultiple() as $role) {
    if ($role
      ->id() === 'anonymous') {
      user_role_grant_permissions($role
        ->id(), [
        'access group search',
      ]);
    }
    else {
      user_role_grant_permissions($role
        ->id(), [
        'create public_group group',
      ]);
    }
  }
}

/**
 * Rebuild node access.
 */
function social_group_update_8011() {
  node_access_rebuild(TRUE);
}

/**
 * Set module weight.
 */
function social_group_update_8012() {
  module_set_weight('social_group', 2);
}

/**
 * Set my groups permissions.
 */
function social_group_update_8013() {

  // Make it so that everyone who has the 'access user profiles' permission,
  // now also get these two new permissions.
  $permissions = [
    'view groups on my profile',
    'view groups on other profiles',
  ];

  /** @var \Drupal\user\Entity\Role $role */
  foreach (Role::loadMultiple() as $role) {
    if ($role
      ->hasPermission('access user profiles')) {
      user_role_grant_permissions($role
        ->id(), $permissions);
    }
  }
}

/**
 * Grant permission to access group overview to contentmanager and sitemanager.
 */
function social_group_update_8014() {
  user_role_grant_permissions('contentmanager', [
    'access group overview',
  ]);
  user_role_grant_permissions('sitemanager', [
    'access group overview',
  ]);
}

/**
 * NOTE: Contains possible data alteration!
 *
 * Change the visibility of all posts placed in an open group, which have
 * visibility public, to community.
 * See: https://www.drupal.org/project/social/issues/2992332#comment-12790905.
 */
function social_group_update_8301(&$sandbox) {
  if (!isset($sandbox['progress'])) {
    $sandbox['progress'] = 0;
    $sandbox['items'] = [];
    $sandbox['max'] = 0;

    // First grab all the post IDs that need to change.
    $connection = Database::getConnection();
    $sth = $connection
      ->select('post__field_visibility', 'pv');
    $sth
      ->fields('pv', [
      'entity_id',
    ]);
    $sth
      ->join('post_field_data', 'pd', 'pd.id = pv.entity_id');
    $sth
      ->join('post__field_recipient_group', 'pg', 'pv.entity_id = pg.entity_id');
    $sth
      ->join('groups', 'g', 'pg.field_recipient_group_target_id = g.id');
    $sth
      ->condition('pv.field_visibility_value', '1', '=');
    $sth
      ->condition('g.type', 'open_group', '=');

    // Timestamp is from the moment the commit landed in 8.x-3.x see:
    // https://cgit.drupalcode.org/social/commit/?id=3e465bb1ad927712e22469c193b6e9547ba1c081
    $sth
      ->condition('pd.created', '1534118400', '>');
    $data = $sth
      ->execute();
    $sandbox['items']['post_ids'] = $data
      ->fetchCol();
    $sandbox['max'] = count($sandbox['items']['post_ids']);
  }
  if ($sandbox['items']['post_ids']) {
    $pid = array_shift($sandbox['items']['post_ids']);

    // Load all the entities and re-save them with the correct visibility.
    $post = Post::load($pid);

    /** @var \Drupal\social_post\Entity\Post $post */
    $post
      ->set('field_visibility', '0');
    $post
      ->save();
  }
  $sandbox['progress']++;
  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : $sandbox['progress'] / $sandbox['max'];
}

/**
 * NOTE: Contains possible data alteration!
 *
 * Change the visibility of all nodes placed in an open group, which have
 * visibility public, to community.
 * See: https://www.drupal.org/project/social/issues/2992332#comment-12790905.
 */
function social_group_update_8302(&$sandbox) {
  if (!isset($sandbox['progress'])) {
    $sandbox['progress'] = 0;
    $sandbox['items'] = [];
    $sandbox['max'] = 0;

    // First grab all the node IDs that need to change.
    $connection = Database::getConnection();
    $sth = $connection
      ->select('group_content_field_data', 'gc');
    $sth
      ->fields('gc', [
      'entity_id',
    ]);
    $sth
      ->join('node__field_content_visibility', 'nv', 'gc.entity_id = nv.entity_id');
    $sth
      ->join('node_field_data', 'nd', 'gc.entity_id = nd.nid');
    $sth
      ->condition('gc.type', 'open_group-group_node-%', 'LIKE');
    $sth
      ->condition('nv.field_content_visibility_value', 'public', '=');

    // Timestamp is from the moment the commit landed in 8.x-3.x see:
    // https://cgit.drupalcode.org/social/commit/?id=3e465bb1ad927712e22469c193b6e9547ba1c081
    $sth
      ->condition('nd.created', '1534118400', '>');
    $data = $sth
      ->execute();
    $sandbox['items']['node_ids'] = $data
      ->fetchCol();
    $sandbox['max'] = count($sandbox['items']['node_ids']);
  }
  if ($sandbox['items']['node_ids']) {
    $pid = array_shift($sandbox['items']['node_ids']);

    // Load all the entities and re-save them with the correct visibility.
    $node = Node::load($pid);

    /** @var \Drupal\node\Entity\Node $node */
    $node
      ->set('field_content_visibility', 'community');
    $node
      ->save();
  }
  $sandbox['progress']++;
  $sandbox['#finished'] = empty($sandbox['max']) ? 1 : $sandbox['progress'] / $sandbox['max'];
}

/**
 * Grant permission to edit group types to contentmanager and sitemanager.
 */
function social_group_update_8303() {
  user_role_grant_permissions('contentmanager', [
    'edit group types',
  ]);
  user_role_grant_permissions('sitemanager', [
    'edit group types',
  ]);
}

/**
 * Install gvbo module.
 */
function social_group_update_8501() {
  $modules = [
    'gvbo',
    'social_group_gvbo',
  ];
  \Drupal::service('module_installer')
    ->install($modules);
}

/**
 * Set some extra configuration.
 */
function social_group_update_8502() {
  $config = \Drupal::configFactory()
    ->getEditable('social_group.settings');
  $config
    ->set('allow_hero_selection', FALSE);
  $config
    ->set('default_hero', 'hero');
  $config
    ->save();
}

/**
 * Update view mode for new small teaser style.
 */
function social_group_update_8801() {

  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

  // Execute configuration update definitions with logging of success.
  $updateHelper
    ->executeUpdate('social_group', 'social_group_update_8801');

  // Output logged messages to related channel of update execution.
  return $updateHelper
    ->logger()
    ->output();
}

/**
 * Add new field for rendered profile entity so we can sort it.
 *
 * Load in a config file from an specific update hook that will never change.
 * Update helper did not update all fields correctly.
 */
function social_group_update_8802() {
  $config_file = drupal_get_path('module', 'social_group') . '/config/update/social_group_update_8802.yml';
  if (is_file($config_file)) {
    $settings = Yaml::parse(file_get_contents($config_file));
    if (is_array($settings)) {
      $config = \Drupal::configFactory()
        ->getEditable('views.view.group_manage_members');
      $config
        ->setData($settings)
        ->save(TRUE);
    }
  }
}

/**
 * Install Group Invite & Request modules by default.
 */
function social_group_update_8901() {
  $modules = [
    'social_group_invite',
    'social_group_request',
  ];
  \Drupal::service('module_installer')
    ->install($modules);
}

/**
 * Update group's event views.
 */
function social_group_update_8902() {

  /** @var \Drupal\update_helper\Updater $updateHelper */
  $updateHelper = \Drupal::service('update_helper.updater');

  // Execute configuration update definitions with logging of success.
  $updateHelper
    ->executeUpdate('social_group', 'social_group_update_8803');

  // Update views configuration.
  _social_event_views_update('views.view.group_events', 'default');
}

Functions

Namesort descending Description
social_group_install Implements hook_install().
social_group_update_8001 Install geolocation, geocoder and grolesync module.
social_group_update_8002 Make sure the group nodes view is disabled.
social_group_update_8004 Converts group description field type from plain text to formatted text.
social_group_update_8005 Uninstall geocoder and geolocation modules. Remove group geolocation field.
social_group_update_8006 Add 'closed_group' group type and enable the permission for Authenticated.
social_group_update_8007 Uninstall grolesync module (for now, more info: drupal.org/node/2850417).
social_group_update_8008 Update the permissions for social_group.
social_group_update_8009 Set the default group configuration and permission for sitemanager.
social_group_update_8010 Add permissions for public groups.
social_group_update_8011 Rebuild node access.
social_group_update_8012 Set module weight.
social_group_update_8013 Set my groups permissions.
social_group_update_8014 Grant permission to access group overview to contentmanager and sitemanager.
social_group_update_8301 NOTE: Contains possible data alteration!
social_group_update_8302 NOTE: Contains possible data alteration!
social_group_update_8303 Grant permission to edit group types to contentmanager and sitemanager.
social_group_update_8501 Install gvbo module.
social_group_update_8502 Set some extra configuration.
social_group_update_8801 Update view mode for new small teaser style.
social_group_update_8802 Add new field for rendered profile entity so we can sort it.
social_group_update_8901 Install Group Invite & Request modules by default.
social_group_update_8902 Update group's event views.
social_group_update_dependencies Implements hook_update_dependencies().
_social_group_create_menu_links Function to create some menu items.
_social_group_get_permissions Build the permissions.
_social_group_set_permissions Function to set permissions.