Commit 79916fbe authored by Tim Steiner's avatar Tim Steiner
Browse files

Merge pull request #750 from erasmussen2/issue-677

Closes #677
parents 11bc1112 276dde71
......@@ -13,3 +13,6 @@
[submodule "vendor/Twig"]
path = vendor/Twig
url = https://github.com/fabpot/Twig.git
[submodule "sites/all/themes/unl_og"]
path = sites/all/themes/unl_og
url = git@github.com:unlcms/unl_og.git
......@@ -119,6 +119,10 @@ In this example the web root is /Library/WebServer/Documents and Apache runs as
- Convert FILE_ENTITY_DEFAULT_ALLOWED_EXTENSIONS to the new variable. See http://drupal.org/node/1846674#comment-6760286
* og_menu
- Applied og_menu-jquery_selector.patch. See:http://drupal.org/node/1051542
* redirect
- Merge global redirect functions into Redirect module. See http://drupal.org/node/905914
......
diff --git a/sites/all/modules/og_menu/og_menu.js b/sites/all/modules/og_menu/og_menu.js
index 7802b3f..2d58e79 100755
--- a/sites/all/modules/og_menu/og_menu.js
+++ b/sites/all/modules/og_menu/og_menu.js
@@ -1,7 +1,7 @@
/**
* @file
* Javascript magic. Shows the eligible menu options when switching groups.
- *
+ *
*/
(function ($) {
Drupal.behaviors.og_menu = {
@@ -44,7 +44,7 @@
if (values[0]) {
// Select the menu for the first available group.
for(var i in Drupal.settings.og_menu.menus) {
- if ((enabled === true) && $('.menu-parent-select option[value='+originalParent+']')) {
+ if ((enabled === true) && $('.menu-parent-select option[value="'+originalParent+'"]')) {
$('.menu-parent-select').val(originalParent);
}
else if (Drupal.settings.og_menu.menus[i] == values[0]) {
@@ -73,4 +73,4 @@
}
-}(jQuery));
\ No newline at end of file
+}(jQuery));
......@@ -112,6 +112,15 @@ DEVELOPERS & SITE BUILDERS
http://drupal.org/project/entityreference_prepopulate
and configuring the correct settings in the field UI. Read more about
it in Entity reference prepopulate's README file.
Further more, when Entity reference prepopulate module is enabled the node
"create" permissions will be enabled even for non-members. In order to allow
a non member to create a node to a group they don't belong to, you should
craft the URL in the same way. OG will recognize this situation and add the
group as a valid option under the "My groups" widget.
- When deleting groups, it is possible to delete orphan group-content, or move
it under another group. In order to do it in a scalable way, enable the
"Use queue" option, and process it using for example:
drush queue-run og_membership_orphans
FAQ
----
......
......@@ -9,12 +9,21 @@ function og_user_roles_action_info() {
}
function og_user_roles_action_form($context) {
// Get the group type and group ID from the Views arguments.
list($group_type, $gid) = $context['view']->args;
$gid = '';
$group_type = '';
if(empty($group_type) || empty($gid)) {
if (module_exists('og_context') && $og_context = og_context()) {
// Get the group type and group ID from OG context.
$gid = $og_context['gid'];
$group_type = $og_context['group_type'];
}
elseif (empty($gid) || empty($group_type)) {
// Get the group type and group ID from the Views arguments if they exist.
list($group_type, $gid) = $context['view']->args;
if (empty($group_type) || empty($gid)) {
return;
}
}
if (!entity_get_info($group_type)) {
return;
......
......@@ -5,8 +5,6 @@
* Add OG related fields to group and group-content node-types.
*/
if (db_table_exists('d6_og')) {
class OgMigrateAddFields extends MigrationBase {
public function __construct() {
......@@ -92,5 +90,3 @@ class OgMigrateAddFields extends MigrationBase {
return MigrationBase::RESULT_COMPLETED;
}
}
}
......@@ -6,8 +6,6 @@
* value.
*/
if (db_table_exists('d6_og')) {
class OgMigrateContent extends Migration {
public function __construct() {
......@@ -58,5 +56,3 @@ class OgMigrateContent extends Migration {
$this->addFieldMapping('etid', 'nid');
}
}
}
......@@ -5,8 +5,6 @@
* Upgrade nodes that are groups, by settings the correct field value.
*/
if (db_table_exists('d6_og')) {
class OgMigrateGroup extends DynamicMigration {
/**
......@@ -54,5 +52,3 @@ class OgMigrateGroup extends DynamicMigration {
return drupal_strtolower('OgMigrateGroup' . ucfirst($this->arguments['bundle']));
}
}
}
......@@ -5,8 +5,6 @@
* Create user relation to group.
*/
if (db_table_exists('d6_og')) {
class OgMigrateUser extends Migration {
public function __construct() {
......@@ -64,5 +62,3 @@ class OgMigrateUser extends Migration {
parent::prepareRow($row);
}
}
}
......@@ -8,8 +8,6 @@
* to branch 7.x-2.x
*/
if (db_field_exists('og_membership', 'group_type') && db_table_exists('og') && !db_table_exists('d6_og')) {
class OgMigrateMembership extends OgEntityMigration {
/**
......@@ -50,7 +48,10 @@ class OgMigrateMembership extends OgEntityMigration {
}
}
public function prepare($entity, $row) {
/**
* Reject the source row if the group or group content are missing.
*/
public function prepareRow($row) {
$entity_type = $row->entity_type;
$etid = $row->etid;
$group_type = $row->group_type;
......@@ -59,27 +60,46 @@ class OgMigrateMembership extends OgEntityMigration {
if (!$group_content = entity_load_single($entity_type, $etid)) {
// The OG membership was somehow not deleted when the entity
// was deleted.
return;
return FALSE;
}
if (!$group = entity_load_single($group_type, $gid)) {
return;
return FALSE;
}
return parent::prepareRow($row);
}
public function prepare($entity, $row) {
$entity_type = $row->entity_type;
$etid = $row->etid;
$group_type = $row->group_type;
$gid = $row->gid;
$group_content = entity_load_single($entity_type, $etid);
$group = entity_load_single($group_type, $gid);
list(,, $group_bundle) = entity_extract_ids($group_type, $group);
if (!$field_name = og_get_best_group_audience_field($entity_type, $group_content, $group_type, $group_bundle)) {
// Create a new field. Pick an unused name.
$field_name = substr("og_$group_type", 0, 32);
// Create a new field. Pick an unused name, if the settings don't match.
// To maintain some backwards compatibility, if the group type is a node,
// we try to set its name to OG_AUDIENCE FIELD.
$field_name = $group_type == 'node' ? OG_AUDIENCE_FIELD : substr("og_$group_type", 0, 32);
$i = 1;
while (field_info_field($field_name)) {
$field_name = substr("og_$group_type", 0, 32 - strlen($i)) . $i;
++$i;
}
$og_field = og_fields_info(OG_AUDIENCE_FIELD);
$og_field['field']['settings']['target_type'] = $group_type;
list(,, $bundle) = entity_extract_ids($entity_type, $group_content);
while ($field = field_info_field($field_name)) {
if ($field['settings']['target_type'] == $group_type && empty($field['settings']['handler_settings']['target_bundles']) || in_array($bundle, $field['settings']['handler_settings']['target_bundles'])) {
// An existing field.
$field_name = $field['field_name'];
break;
}
$field_name = substr("og_$group_type", 0, 32 - strlen($i)) . $i;
++$i;
}
og_create_field($field_name, $entity_type, $bundle, $og_field);
}
$entity->field_name = $field_name;
......@@ -88,8 +108,7 @@ class OgMigrateMembership extends OgEntityMigration {
/**
* Override Migration::postImport().
*
* Remove OG-memberships that should hae been deleted.
*
* Remove OG-memberships that should have been deleted.
*/
protected function postImport() {
if (!$this->isComplete()) {
......@@ -100,5 +119,3 @@ class OgMigrateMembership extends OgEntityMigration {
->execute();
}
}
}
......@@ -9,16 +9,12 @@
*/
if (db_field_exists('og_membership', 'group_type') && db_table_exists('og') && !db_table_exists('d6_og')) {
class OgMigrateRoles extends OgEntityMigration {
public $tableName = 'og_role';
public $keyName = 'rid';
protected $dependencies = array('OgMigrateMembership');
/**
* Indicate we are updating existing data.
*/
......@@ -106,5 +102,3 @@ class OgMigrateRoles extends OgEntityMigration {
$entity->group_bundle = $bundle;
}
}
}
\ No newline at end of file
......@@ -8,8 +8,6 @@
* to branch 7.x-2.x
*/
if (db_field_exists('og_membership', 'group_type') && db_table_exists('og') && !db_table_exists('d6_og')) {
class OgMigrateUserRoles extends OgEntityMigration {
public $tableName = 'og_users_roles';
......@@ -108,5 +106,3 @@ class OgMigrateUserRoles extends OgEntityMigration {
}
}
}
}
......@@ -64,10 +64,10 @@ class MigrateDestinationOGMembership extends MigrateDestination {
throw new MigrateException('Missing group ID.');
}
if (empty($entity->entity_type)) {
throw new MigrateException('Missing enity type.');
throw new MigrateException('Missing entity type.');
}
if (empty($entity->etid)) {
throw new MigrateException('Missing enity ID.');
throw new MigrateException('Missing entity ID.');
}
// Set state, make sure legacy states from OG6 are converted to
......@@ -78,13 +78,12 @@ class MigrateDestinationOGMembership extends MigrateDestination {
else {
$state = OG_STATE_ACTIVE;
}
$values = array(
'entity_type' => $entity->entity_type,
'entity' => $entity->etid,
'state' => $state,
'created' => isset($entity->created) ? $entity->created : REQUEST_TIME,
);
$this->prepare($entity, $row);
// Allow passing OG-membership fields via og_group().
$values = (array) $entity;
$values['entity'] = $entity->etid;
$values['state'] = $state;
$values['created'] = isset($entity->created) ? $entity->created : REQUEST_TIME;
$og_membership = og_group($entity->group_type, $entity->gid, $values);
......@@ -109,9 +108,60 @@ class MigrateDestinationOGMembership extends MigrateDestination {
}
}
$this->complete($entity, $row);
return array($og_membership->id);
}
/**
* Give handlers a shot at modifying the object before saving it.
*
* @param $entity
* OGMembership object to build. Prefilled with any fields mapped in
* the Migration.
* @param $source_row
* Raw source data object - passed through to prepare handlers.
*/
public function prepare($entity, stdClass $row) {
// We do nothing here but allow child classes to act.
$migration = Migration::currentMigration();
$entity->migrate = array(
'machineName' => $migration->getMachineName(),
);
// Call any general handlers.
migrate_handler_invoke_all('og_membership', 'prepare', $entity, $row);
// Then call any prepare handler for this specific Migration.
if (method_exists($migration, 'prepare')) {
$migration->prepare($entity, $row);
}
}
/**
* Give handlers a shot at modifying the object (or taking additional action)
* after saving it.
*
* @param $entity
* OGMembership object to build. This is the complete object after
* saving.
* @param $source_row
* Raw source data object - passed through to complete handlers.
*/
public function complete($entity, stdClass $row) {
// We do nothing here but allow child classes to act.
$migration = Migration::currentMigration();
$entity->migrate = array(
'machineName' => $migration->getMachineName(),
);
// Call any general handlers.
migrate_handler_invoke_all('og_membership', 'complete', $entity, $row);
// Then call any complete handler for this specific Migration.
if (method_exists($migration, 'complete')) {
$migration->complete($entity, $row);
}
}
public function fields() {
return array(
'group_type' => 'Group entity type',
......
......@@ -31,7 +31,7 @@ function og_field_widget_form(&$form, &$form_state, $field, $instance, $langcode
return;
}
if ($field['settings']['handler'] != 'og') {
if ($field['settings']['handler'] != 'og' && strpos($field['settings']['handler'], 'og_') !== 0) {
$params = array('%label' => $instance['label']);
form_error($form, t('Field %label is a group-audience but its Entity selection mode is not defined as "Organic groups" in the field settings page.', $params));
return;
......@@ -42,7 +42,7 @@ function og_field_widget_form(&$form, &$form_state, $field, $instance, $langcode
list($id,, $bundle) = entity_extract_ids($entity_type, $entity);
$field_name = $field['field_name'];
$identifier = $field_name . ':' . $entity_type . ':' . $id;
$identifier = $field_name . ':' . $entity_type . ':' . $bundle . ':' . $id;
if (isset($cache[$identifier])) {
return array();
}
......@@ -63,18 +63,19 @@ function og_field_widget_form(&$form, &$form_state, $field, $instance, $langcode
$field_modes[] = 'admin';
}
// Get the "Other group" group IDs.
$target_type = $field['settings']['target_type'];
$other_groups_ids = array();
if ($id) {
$entity_gids = og_get_entity_groups($entity_type, $entity);
$entity_gids = !empty($entity_gids[$target_type]) ? $entity_gids[$target_type] : array();
// Build an array of entity IDs. Field's $items are loaded
// in OgBehaviorHandler::load().
$entity_gids = array();
foreach ($items as $item) {
$entity_gids[] = $item['target_id'];
}
$target_type = $field['settings']['target_type'];
$user_gids = og_get_entity_groups();
$user_gids = !empty($user_gids[$target_type]) ? $user_gids[$target_type] : array();
// Get the "Other group" group IDs.
$other_groups_ids = array_diff($entity_gids, $user_gids);
}
foreach ($field_modes as $field_mode) {
$mocked_instance = og_get_mocked_instance($instance, $field_mode);
......@@ -135,7 +136,6 @@ function og_field_widget_form(&$form, &$form_state, $field, $instance, $langcode
$new_element = ctools_field_invoke_field($mocked_instance, 'form', $entity_type, $dummy_entity, $form, $dummy_form_state, array('default' => TRUE));
$element[$field_mode] = $new_element[$field_name][LANGUAGE_NONE];
if (in_array($mocked_instance['widget']['type'], array('entityreference_autocomplete', 'entityreference_autocomplete_tags'))) {
// Change the "Add more" button name so it adds only the needed
// element.
......@@ -143,36 +143,55 @@ function og_field_widget_form(&$form, &$form_state, $field, $instance, $langcode
$element[$field_mode]['add_more']['#name'] .= '__' . $field_mode;
}
if ($mocked_instance['widget']['type'] == 'entityreference_autocomplete') {
foreach (array_keys($element[$field_mode]) as $delta) {
if (!is_numeric($delta)) {
continue;
}
$sub_element = &$element[$field_mode][$delta]['target_id'];
_og_field_widget_replace_autocomplete_path($sub_element, $field_mode);
}
}
else {
// Tags widget, there's no delta, we can pass the element itself.
_og_field_widget_replace_autocomplete_path($element[$field_mode], $field_mode);
}
}
}
$form['#after_build']['og'] = 'og_complex_widget_after_build';
return $element;
}
/**
* Replace Entity-reference's autocomplete path with our own.
*
* @param $element
* The form element, passed by reference.
* @param $field_mode
* The field mode.
*
*/
function _og_field_widget_replace_autocomplete_path(&$element, $field_mode) {
// Rebuild the autocomplete path.
$path = explode('/', $sub_element['#autocomplete_path']);
$sub_element['#autocomplete_path'] = 'og/autocomplete';
$path = explode('/', $element['#autocomplete_path']);
$element['#autocomplete_path'] = 'og/autocomplete';
// Add autocomplete type
$sub_element['#autocomplete_path'] .= "/$path[2]/$path[3]/$path[4]/$path[5]";
$element['#autocomplete_path'] .= "/$path[2]/$path[3]/$path[4]/$path[5]";
// Add field mode.
$sub_element['#autocomplete_path'] .= "/$field_mode";
$element['#autocomplete_path'] .= "/$field_mode";
// Add the entity ID.
$sub_element['#autocomplete_path'] .= "/$path[6]";
$element['#autocomplete_path'] .= "/$path[6]";
if (!empty($path[7])) {
// Add the text.
$sub_element['#autocomplete_path'] .= "/$path[7]";
}
}
}
$element['#autocomplete_path'] .= "/$path[7]";
}
$form['#after_build']['og'] = 'og_complex_widget_after_build';
return $element;
}
/**
......
......@@ -18,6 +18,11 @@ class OgMembership extends Entity {
public function save() {
$entity_type = $this->entity_type;
$etid = $this->etid;
if ($entity_type == 'user' && !$etid) {
throw new OgException('OG membership can not be created for anonymous user.');
}
$wrapper = entity_metadata_wrapper($entity_type, $etid);
$bundle = $wrapper->getBundle();
......@@ -27,7 +32,6 @@ class OgMembership extends Entity {
list(,,$group_bundle) = entity_extract_ids($group_type, $group);
$field_name = $this->field_name;
$state = !empty($this->state) ? $this->state : OG_STATE_ACTIVE;
// Placeholder for exceptions, in case we need to throw one.
$params = array(
......
......@@ -90,6 +90,9 @@ function og_features_permission_features_export_render($module, $data) {
$permission['roles'] = array();
}
// Ensure consistent ordering of roles on output to avoid extraneious diffs.
asort($permission['roles']);
$perm_identifier = features_var_export($key);
$perm_export = features_var_export($permission, ' ');
$code[] = " // Exported og permission: {$perm_identifier}";
......
<?php
/**
* @file
* Definition of og_handler_field_og_membership_link_edit.
*/
/**
* Field handler to present a link to edit membership.
*
* @ingroup views_field_handlers
*/
class og_handler_field_og_membership_link_edit extends views_handler_field_entity {
function construct() {
parent::construct();
}
function option_definition() {
$options = parent::option_definition();
$options['text'] = array('default' => '', 'translatable' => TRUE);
$options['destination'] = array('default' => FALSE, 'bool' => TRUE);
return $options;
}
function options_form(&$form, &$form_state) {
$form['text'] = array(
'#type' => 'textfield',
'#title' => t('Text to display'),
'#default_value' => $this->options['text'],
);
$form['destination'] = array(
'#type' => 'checkbox',
'#title' => t('Use destination'),
'#description' => t('Add destination to the link'),
'#default_value' => $this->options['destination'],
'#fieldset' => 'more',
);
parent::options_form($form, $form_state);
}
function query() {
$this->ensure_my_table();
$this->add_additional_fields();
}
function render($values) {
$value = $this->get_value($values, 'id');
return $this->render_link($this->sanitize_value($value), $values);
}
function render_link($data, $values) {
$this->options['alter']['make_link'] = TRUE;
$this->options['alter']['html'] = TRUE;
// Ensure user has access to edit this membership.
$og_membership = $this->get_value($values);
$group_type = $og_membership->group_type;
$gid = $og_membership->gid;
if (!og_ui_user_access_group('manage members', $group_type, $gid)) {
return;
}