
Apply the security fixes including: - Drupal Core - Moderately Critical - Multiple Vulnerabilities - SA-CORE-2015-001 - SA-CONTRIB-2015-079 - Chaos tool suite (ctools) - Multiple vulnerabilities The following patches were applied to 7.x-3.23 commons modules: - patches/0001-utility-links-block-install-theme.patch - patches/0002-events-page-refactor-to-pages-module.patch Installation profile got a refactor of module installation, as groups_ modules and l10n_updates deployed from an installation task to avoid memory exhausted errors of the installation process. Change-Id: I48481657124fdbbee84e1cbfec3a3a2b5f475c2c
506 lines
15 KiB
Plaintext
506 lines
15 KiB
Plaintext
<?php
|
|
/**
|
|
* @file
|
|
* Code for the Commons Browsing Widget feature.
|
|
*/
|
|
|
|
include_once 'commons_bw.features.inc';
|
|
|
|
/**
|
|
* Implements hook_hook_info().
|
|
*/
|
|
function commons_bw_hook_info() {
|
|
$hooks = array(
|
|
'commons_bw_group_widget',
|
|
'commons_bw_create_all_widget',
|
|
);
|
|
|
|
return array_fill_keys($hooks, array('group' => 'commons'));
|
|
}
|
|
|
|
/**
|
|
* Implements hook_system_info_alter().
|
|
*/
|
|
function commons_bw_system_info_alter(&$info, $file, $type) {
|
|
// Commons BW dynamically adds the title_field field to content types that
|
|
// request it.
|
|
// We must add a corresponding line for each field instance to commons_bw.info
|
|
// so that Features is aware of the instance and can successfully revert the
|
|
// field_instance component back to its default state.
|
|
if ($file->name == 'commons_bw') {
|
|
foreach (node_type_get_types() as $node_type_object) {
|
|
$node_type = $node_type_object->type;
|
|
|
|
if (commons_bw_node_auto_title_instance($node_type)) {
|
|
$info['features']['field_instance'][] = "node-$node_type-title_field";
|
|
}
|
|
}
|
|
}
|
|
|
|
// Dynamically adding a field to a content type results in features
|
|
// automatically detecting Commons BW as a dependency.
|
|
// We manually exclude the dependency in order to prevent the content type
|
|
// modules from appearing overridden and to allow them to be used
|
|
// independently of Commons BW.
|
|
$node_types = &drupal_static(__FUNCTION__);
|
|
|
|
if (!isset($node_types)) {
|
|
foreach (module_implements('node_info') as $module) {
|
|
$node_types[$module] = call_user_func($module . '_node_info');
|
|
}
|
|
}
|
|
|
|
if (isset($node_types[$file->name])) {
|
|
foreach ($node_types[$file->name] as $node_type => $node_info) {
|
|
if (commons_bw_node_auto_title_instance($node_type)) {
|
|
$info['features_exclude']['dependencies']['commons_bw'] = 'commons_bw';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_modules_enabled().
|
|
*/
|
|
function commons_bw_modules_enabled($modules) {
|
|
// Ensure that dynamically added title_field fields are in the default state
|
|
// when modules that provide content types are enabled.
|
|
foreach ($modules as $module) {
|
|
if (module_hook($module, 'node_info')) {
|
|
features_revert(array('commons_bw' => array('field_instance')));
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_forms().
|
|
*
|
|
* The bundle is added to the partial node form ID, to prevent duplicate IDs on
|
|
* the same page, but all of the partial forms are built with the same function.
|
|
*/
|
|
function commons_bw_forms($form_id, $args) {
|
|
$forms = array();
|
|
|
|
if (strpos($form_id, 'commons_bw_partial_node_form__') === 0) {
|
|
$forms[$form_id] = array(
|
|
'callback' => 'commons_bw_partial_node_form',
|
|
);
|
|
}
|
|
|
|
return $forms;
|
|
}
|
|
|
|
/**
|
|
* Implements hook_form_FORM_ID_alter().
|
|
*/
|
|
function commons_bw_form_views_exposed_form_alter(&$form, &$form_state, $form_id) {
|
|
// Implements tweaks to exposed filters and sorts per the Commons designs.
|
|
if (strpos($form['#id'],'views-exposed-form-commons-bw') === 0) {
|
|
// Remove the sort order (eg, descending vs ascending).
|
|
$form['sort_order']['#access'] = FALSE;
|
|
$form['sort_by']['#title'] = t('Sorted by');
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Implements hook_form_FORM_ID_alter().
|
|
*
|
|
* Add a setting to group content fields, to determine whether they will be
|
|
* displayed on the mini node form of the browsing widget.
|
|
*/
|
|
function commons_bw_form_field_ui_field_edit_form_alter(&$form, &$form_state, $form_id) {
|
|
if (!og_is_group_content_type($form['instance']['entity_type']['#value'], $form['instance']['bundle']['#value'])) {
|
|
return;
|
|
}
|
|
|
|
// See if we're building for the first time, or getting pre-saved values.
|
|
$field_name = $form['#field']['field_name'];
|
|
|
|
if(!empty($form_state['field'][$field_name][LANGUAGE_NONE]['instance']['display_in_partial_form'])) {
|
|
$display_default = $form_state['field'][$field_name][LANGUAGE_NONE]['instance']['display_in_partial_form'];
|
|
}
|
|
else if (isset($form_state['build_info']['args'][0]['display_in_partial_form'])) {
|
|
$display_default = $form_state['build_info']['args'][0]['display_in_partial_form'];
|
|
}
|
|
else {
|
|
$display_default = FALSE;
|
|
}
|
|
|
|
$form['instance']['display_in_partial_form'] = array(
|
|
'#type' => 'checkbox',
|
|
'#title' => t('Display in the browsing widget mini-form'),
|
|
'#default_value' => $display_default,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Partial node form for the browsing widget.
|
|
*/
|
|
function commons_bw_partial_node_form($form, &$form_state, $bundle, $group_id = NULL) {
|
|
global $user;
|
|
global $language;
|
|
|
|
if (!$group_id) {
|
|
// Reset the og_field_widget_form cache because otherwise it ignores
|
|
// multiple tries to render the same group audience widget (We have the
|
|
// same group audience widget on the All and Posts tabs, when displaying
|
|
// this form without group context).
|
|
drupal_static_reset('og_field_widget_form');
|
|
}
|
|
|
|
if ($group_id) {
|
|
$form_state['group_id'] = $group_id;
|
|
}
|
|
|
|
$instances = field_info_instances('node', $bundle);
|
|
|
|
// Remove all fields except those marked as "display_in_partial_form".
|
|
foreach($instances as $field_name => $instance) {
|
|
if (empty($instance['display_in_partial_form'])) {
|
|
unset($instances[$field_name]);
|
|
}
|
|
}
|
|
|
|
// Make sure there's a field left to display.
|
|
if (empty($instances)) {
|
|
return $form;
|
|
}
|
|
|
|
// Create a dummy node for field_attach_form().
|
|
$node = new stdClass();
|
|
$node->type = $bundle;
|
|
node_object_prepare($node);
|
|
|
|
if (module_exists('locale')) {
|
|
if (locale_multilingual_node_type($node->type)) {
|
|
$node->language = $language->language;
|
|
}
|
|
else {
|
|
$default = language_default();
|
|
$node->language = $default->language;
|
|
}
|
|
}
|
|
else {
|
|
$node->language = LANGUAGE_NONE;
|
|
}
|
|
|
|
field_attach_form('node', $node, $form, $form_state, entity_language('node', $node));
|
|
|
|
foreach(element_children($form) as $field_name) {
|
|
if (empty($instances[$field_name])) {
|
|
$form[$field_name]['#access'] = FALSE;
|
|
}
|
|
}
|
|
|
|
if (!empty($form['#metatags'])) {
|
|
unset($form['#metatags']);
|
|
}
|
|
|
|
// When not in a group context, enable the group audience widget.
|
|
$form[OG_AUDIENCE_FIELD]['#weight'] = 100;
|
|
$form[OG_AUDIENCE_FIELD]['#access'] = !$group_id;
|
|
|
|
// Add a default form title.
|
|
$form['title'] = array(
|
|
'#markup' => t('Create content'),
|
|
'#weight' => -100,
|
|
);
|
|
|
|
// Display the user's picture.
|
|
$wrapper = entity_metadata_wrapper('user', $user);
|
|
$path = empty($user->picture) ? variable_get('user_picture_default') : $wrapper->value()->picture->uri;
|
|
$form['user_picture'] = array(
|
|
'#theme' => 'image_style',
|
|
'#style_name' => '50x50_avatar',
|
|
'#path' => $path,
|
|
'#prefix' => '<div class="user-picture">',
|
|
'#suffix' => '</div>',
|
|
'#weight' => -20,
|
|
);
|
|
|
|
$form['actions'] = array(
|
|
'#type' => 'actions',
|
|
'#weight' => 200,
|
|
);
|
|
$form['actions']['submit'] = array(
|
|
'#type' => 'submit',
|
|
'#value' => t('Save'),
|
|
);
|
|
|
|
// Attach the browsing widget JS and give it a higher weight than
|
|
// quicktabs.js.
|
|
$form['#attached']['js'][] = array(
|
|
'data' => drupal_get_path('module', 'commons_bw') . '/js/partial_node_form.js',
|
|
'type' => 'file',
|
|
'weight' => 100,
|
|
);
|
|
|
|
// Add in some descriptive classes for css down the line.
|
|
$form['#attributes']['class'][] = 'node';
|
|
$form['#attributes']['class'][] = 'commons-bw-partial-node-form';
|
|
$form['#attributes']['class'][] = 'commons-bw-partial-node-form-' . $bundle;
|
|
|
|
// Add a link to the full node form.
|
|
$form['full_form'] = array(
|
|
'#theme' => 'link',
|
|
'#text' => t('Go to full form'),
|
|
'#path' => 'node/add/' . str_replace('_', '-', $bundle),
|
|
'#options' => array(
|
|
'attributes' => array('class' => array('full-form')),
|
|
'html' => FALSE,
|
|
),
|
|
'#weight' => 100,
|
|
);
|
|
|
|
if ($group_id) {
|
|
$form['full_form']['#options']['query'] = array(OG_AUDIENCE_FIELD => $group_id);
|
|
}
|
|
|
|
// Add the commons_bw after build first, in case other pre-renders needs need
|
|
// to address fields by there CSS ID.
|
|
array_unshift($form['#pre_render'], 'commons_bw_partial_node_form_after_build');
|
|
$form['#validate'][] = 'commons_bw_partial_node_form_validate';
|
|
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* After-build call-back. See commons_bw_partial_node_form().
|
|
*/
|
|
function commons_bw_partial_node_form_after_build($form) {
|
|
$bundle = $form['#bundle'];
|
|
|
|
// Add the node's bundle to the IDs of inputs, to avoid having duplicate IDs.
|
|
$id_suffix = '-' . str_replace('_', '-', $bundle);
|
|
|
|
foreach(element_children($form) as $field_name) {
|
|
if (!empty($form[$field_name]['#language'])) {
|
|
$language = $form[$field_name]['#language'];
|
|
|
|
if (!empty($form[$field_name][$language][0]['value']['#id'])) {
|
|
$form[$field_name][$language][0]['value']['#id'] .= $id_suffix;
|
|
}
|
|
|
|
if (!empty($form[$field_name][$language][0]['default']['#id'])) {
|
|
$form[$field_name][$language][0]['default']['#id'] .= $id_suffix;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Set the form action to the form's tab.
|
|
$tabs = commons_bw_get_tab_definitions();
|
|
|
|
// Search for the tab displaying the current bundle.
|
|
foreach ($tabs as $tab_id => $settings) {
|
|
if ($settings['bundle'] == $bundle) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
$form['#action'] = url(current_path(), array('query' => array('qt-commons_bw' => $tab_id)));
|
|
|
|
return $form;
|
|
}
|
|
|
|
/**
|
|
* Validation handler; Attach the node validation to the partial node form.
|
|
*/
|
|
function commons_bw_partial_node_form_validate($form, $form_state) {
|
|
$node = $form['#entity'];
|
|
|
|
field_attach_validate('node', $node);
|
|
node_validate($node, $form, $form_state);
|
|
|
|
if ((!module_exists('commons_trusted_contacts') || (module_exists('commons_trusted_contacts') && !module_exists('og_access'))) && empty($form_state['group_id']) && empty($form_state['values'][OG_AUDIENCE_FIELD][LANGUAGE_NONE][0])) {
|
|
form_set_error(OG_AUDIENCE_FIELD, t('Please enter one or more groups where this content will be posted.'));
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Submit handler; Create a node from the partial node form.
|
|
*/
|
|
function commons_bw_partial_node_form_submit($form, $form_state) {
|
|
$node = $form['#entity'];
|
|
|
|
node_submit($node);
|
|
|
|
// Mark the node as created with the partial form
|
|
$node->partial_node_form = TRUE;
|
|
field_attach_submit('node', $node, $form, $form_state);
|
|
|
|
$wrapper = entity_metadata_wrapper('node', $node);
|
|
|
|
// If the node has a body and doesn't has a title, create a title from the
|
|
// body.
|
|
if ((empty($wrapper->title_field) || !$wrapper->title_field->value()) && empty($node->title)) {
|
|
if (!empty($wrapper->body) && $wrapper->body->value()) {
|
|
$title = htmlspecialchars_decode($wrapper->body->value->value());
|
|
|
|
// Strip tags and whitespaces.
|
|
$title = preg_replace('/[\t\n\r\0\x0B]/', '', strip_tags($title));
|
|
|
|
// Shorten the title.
|
|
$node->title = truncate_utf8($title, 30, TRUE, TRUE);
|
|
}
|
|
}
|
|
|
|
// Set the group audience.
|
|
if (!empty($form_state['group_id'])) {
|
|
$wrapper->{OG_AUDIENCE_FIELD}->set(array($form_state['group_id']));
|
|
}
|
|
|
|
$node->form_state = $form_state;
|
|
|
|
$wrapper->save();
|
|
|
|
// Notify about the node creation.
|
|
$arguments = array('@type' => node_type_get_name($node), '%title' => $node->title);
|
|
|
|
drupal_set_message(t('@type %title has been created.', $arguments));
|
|
}
|
|
|
|
/**
|
|
* Get a list of modules that add content to a particular type of widget.
|
|
*
|
|
* The only currently supported widget type is 'group', but this
|
|
* could be extended to support other entities.
|
|
*
|
|
* @param $widget_type
|
|
* An optional type of widget to restrict results to, defaults to 'group'.
|
|
*
|
|
* @return array
|
|
* An array of return values of the hook implementations.
|
|
*/
|
|
function commons_bw_get_tab_definitions($widget_type = 'group') {
|
|
$hook_name = 'commons_bw_' . $widget_type . '_widget';
|
|
|
|
$tabs = module_invoke_all($hook_name);
|
|
|
|
drupal_alter($hook_name, $tabs);
|
|
|
|
return $tabs;
|
|
}
|
|
|
|
/**
|
|
* Helper function to determine whether Commons_BW should define a title field
|
|
* instance on behalf of a content type.
|
|
*
|
|
* @param $node_type
|
|
* The type of the node to check auto title settings for.
|
|
*
|
|
* @return boolean
|
|
* The value of the auto title setting if available, TRUE otherwise.
|
|
*/
|
|
function commons_bw_node_auto_title_instance($node_type) {
|
|
$commons_groups_entity_types = commons_groups_get_group_content_entity_types();
|
|
|
|
return isset($commons_groups_entity_types['node'][$node_type]['auto_title_instance']) ? $commons_groups_entity_types['node'][$node_type]['auto_title_instance'] : TRUE;
|
|
}
|
|
|
|
/**
|
|
* Provides a styled content creation dropdown widget for the 'all' tab of the
|
|
* group homepage browsing widget.
|
|
*
|
|
* @param $group
|
|
* The group node associated with the group homepage.
|
|
*
|
|
* @return string
|
|
* The content creation dropdown widget HTML.
|
|
*/
|
|
function commons_bw_create_all_widget($group) {
|
|
$links = array();
|
|
|
|
// Collect definitions from implementing modules.
|
|
$items = module_invoke_all('commons_bw_create_all_widget', $group);
|
|
uasort($items, 'element_sort');
|
|
|
|
foreach ($items as $module => $item) {
|
|
$links[] = $item['link'] . ' ' . $item['text'];
|
|
|
|
// Populate the default content creation link.
|
|
if (isset($item['default']) && $item['default']) {
|
|
$default = $item;
|
|
}
|
|
}
|
|
|
|
$output = '';
|
|
|
|
if (!empty($default)) {
|
|
$output .= $default['link'] . '<a class="commons-bw-create-choose"><span></span></a>';
|
|
}
|
|
|
|
$output .= '<div class="commons-bw-create-choose-bg"></div><div class="commons-bw-create-choose-holder">' . theme('item_list', array('items' => $links, 'type' => 'ul', 'attributes' => array('class' => 'commons-bw-create-all-widget-types'))) . '</div>';
|
|
|
|
return $output;
|
|
}
|
|
|
|
/**
|
|
* Generate a renderable group widget.
|
|
*
|
|
* @param $group
|
|
* An optional group node to be used as a tab and views argument.
|
|
*
|
|
* @return array
|
|
* An array in the format expected by drupal_render().
|
|
*/
|
|
function commons_bw_generate_group_widget($group = NULL) {
|
|
// Prepare an array of default quicktabs settings.
|
|
$settings = array(
|
|
'style' => 'Commons Pills',
|
|
'ajax' => FALSE,
|
|
'html' => TRUE,
|
|
);
|
|
|
|
// Load the browsing widget tab definitions.
|
|
$tabs = commons_bw_get_tab_definitions('group');
|
|
|
|
foreach ($tabs as $machine_name => $tab_settings) {
|
|
// Populate the group argument.
|
|
$tabs[$machine_name]['args'] = $group ? $group->nid : 0;
|
|
|
|
// Add the result count to the title for 'view' tabs.
|
|
if ($tab_settings['type'] == 'view') {
|
|
// Get the view specified by the tab settings.
|
|
$view = views_get_view($tab_settings['vid']);
|
|
|
|
// If the tab specified a view display use it, otherwise the view will be
|
|
// rendered using the default display.
|
|
if (isset($tab_settings['display'])) {
|
|
$view->set_display($tab_settings['display']);
|
|
}
|
|
|
|
// If the tab references a group, set it as a tab argument.
|
|
if ($group) {
|
|
$view->set_arguments(array($group->nid));
|
|
}
|
|
|
|
$view->display_handler->options['filters']['flagged']['value'] = 'All';
|
|
$view->get_total_rows = TRUE;
|
|
$view->execute();
|
|
|
|
// Append the result count to the tab title.
|
|
$tabs[$machine_name]['title'] = $tabs[$machine_name]['title'] . ' <span class="commons-bw-result-count">'. $view->total_rows . '</span>';
|
|
}
|
|
|
|
// Use the current tab as the quicktabs default if the tab settings specify.
|
|
if (!empty($tabs[$machine_name]['default'])) {
|
|
$settings['default_tab'] = $machine_name;
|
|
}
|
|
}
|
|
|
|
return quicktabs_build_quicktabs('commons_bw', $settings, $tabs);
|
|
}
|
|
|
|
/**
|
|
* Implements hook_quicktabs_tabstyles().
|
|
*/
|
|
function commons_bw_quicktabs_tabstyles() {
|
|
$path = drupal_get_path('module', 'commons_bw');
|
|
|
|
return array(
|
|
$path . '/plugins/quicktabs_styles/commons_pills/commons_pills.css' => t('Commons Pills'),
|
|
$path . '/plugins/quicktabs_styles/commons_tabs/commons_tabs.css' => t('Commons Tabs'),
|
|
);
|
|
}
|