From 4be553c7983271ede55b68f6d754d086359829ac Mon Sep 17 00:00:00 2001
From: blake hall <blake@blakehall.org>
Date: Thu, 24 Mar 2011 10:08:13 -0500
Subject: [PATCH] Issue #681962 by blakehall: Adding basic cascading for subusers. When a parent user is blocked, unblocked, deleted (configurable), or has their roles changed the same changes are applied to their subusers.

---
 subuser.module    |  102 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 subuser.pages.inc |   12 ++++++
 2 files changed, 114 insertions(+), 0 deletions(-)

diff --git a/subuser.module b/subuser.module
index 23acdb9..4f2fdad 100644
--- a/subuser.module
+++ b/subuser.module
@@ -222,7 +222,51 @@ function subuser_user($op, &$edit, &$account, $category = NULL) {
                   VALUES (%d, %d)', $edit['parent_user'], $account->uid);
       }
       break;
+    case 'update':
+      // Check and see if we even need to bother ourselves with subusers at all.
+      $subusers = subuser_get_subusers($account->uid);
+      if (count($subusers) > 0) {
+        // If we're blocking a user, get the subusers so we can block them too.
+        if ($account->status == 1 && $edit['status'] == 0) {
+          subuser_block_subusers($subusers);
+        }
+        // If we're unblocking a user, get the subusers so we can unblock them too.
+        if ($account->status == 0 && $edit['status'] == 1) {
+          subuser_unblock_subusers($subusers);
+        }
+      }
+      // Allow role changes to cascade down to subusers.
+      $new_roles = $edit['roles'];
+      $old_roles = $account->roles;
+      // Compare the count of old and new roles, > 1 means roles added, < 0 means they've been removed.
+      $role_change = count($new_roles) - count($old_roles);
+      if ($role_change !== 0) {
+        if (is_array($new_roles) && is_array($old_roles)) {
+          $old_keys = array_keys($old_roles);
+          $new_keys = array_keys($new_roles);
+          // We need to do the diff backwards depending on if we have a role addition or subtraction.
+          $diff = ($role_change > 0) ? array_diff($new_keys, $old_keys) : array_diff($old_keys, $new_keys);
+          $op = ($role_change > 0) ? 'add_role' : 'remove_role';
+          subuser_tweak_roles_of_subusers($subusers, $op, $diff);
+        }
+      }
+      break;
     case 'delete':
+      $subusers = subuser_get_subusers($account->uid);
+      // If there are subusers for this account, figure out what to do with them.
+      if (count($subusers) > 0) {
+        $subuser_orphaned_children = variable_get('subuser_orphaned_children', 0);
+        if ($subuser_orphaned_children == 1) {
+          // Block the subuser accounts too.
+          subuser_block_subusers($subusers);
+        }
+        if ($subuser_orphaned_children == 2) {
+          // Delete the subuser accounts too.
+          foreach ($subusers as $uid) {
+            user_delete(NULL, $uid);
+          }
+        }
+      }
       db_query('DELETE FROM {user_relationship} WHERE uid = %d', $account->uid);
       break;
     case 'view':
@@ -274,6 +318,64 @@ function subuser_user($op, &$edit, &$account, $category = NULL) {
 }
 
 /**
+ * Function to block subusers when a parent is blocked.
+ *
+ * @param $uid
+ * [optional] The array of subusers, from subuser_get_subusers(), we're interested in blocking.
+ */
+function subuser_block_subusers($subusers = NULL) {
+  if ($subusers == NULL) {
+    global $user;
+    $subusers = subuser_get_subusers($user->uid);
+  }
+  foreach ($subusers as $uid) {
+    $account = user_load(array('uid' => (int)$uid));
+    // Skip blocking user if they are already blocked.
+    if ($account !== FALSE && $account->status == 1) {
+      user_save($account, array('status' => 0));
+    }
+  }
+}
+
+/**
+ * Function to unblock subusers when a parent is unblocked.
+ *
+ * @param $subusers
+ * [optional] The array of subusers, from subuser_get_subusers(), we're interested in un-blocking.
+ */
+function subuser_unblock_subusers($subusers = NULL) {
+  if ($subusers == NULL) {
+    global $user;
+    $subusers = subuser_get_subusers($user->uid);
+  }
+  foreach ($subusers as $uid) {
+    $account = user_load(array('uid' => (int)$uid));
+    // Skip unblocking user if they are already unblocked.
+    if ($account !== FALSE && $account->status == 0) {
+      user_save($account, array('status' => 1));
+    }
+  }
+}
+
+/**
+ * Function to add roles to subusers based on the parent's account change.
+ *
+ * @param $subusers
+ * An array of user id's (key & value uid) as returned by subuser_get_subusers.
+ * @param $op
+ * Either 'add_role' or 'remove_role' as required by user_multiple_role_edit().
+ * @param $diff
+ * An array of role id's to add or remove from each of the subusers.
+ */
+function subuser_tweak_roles_of_subusers($subusers, $op, $diff) {
+  if (is_array($diff) && is_array($subusers)) {
+    foreach ($diff as $rid) {
+      user_multiple_role_edit($subusers, $op, $rid);
+    }
+  }
+}
+
+/**
  * Implementation of hook_views_api().
  */
 function subuser_views_api() {
diff --git a/subuser.pages.inc b/subuser.pages.inc
index 17c57cd..8347145 100644
--- a/subuser.pages.inc
+++ b/subuser.pages.inc
@@ -98,6 +98,18 @@ function subuser_create_form(&$form_state, $user) {
     '#type' => 'hidden',
     '#value' => 'user/'. $user->uid,
   );
+  $form['advanced']['subuser_orphaned_children'] = array(
+    '#type' => 'select',
+    '#title' => t('How are orphaned child accounts handled?'),
+    '#default_value' => variable_get('subuser_orphaned_children', 0),
+    '#description' => t('Choose how to handle subuser accounts when the parent account is deleted.'),
+    '#options' => array(
+      0 => t('Do Nothing'),
+      1 => t('Block the Subusers'),
+      // TODO It would be nice to allow a role shift here instead too...
+      2 => t('Delete the Subusers'),
+    ),
+  );
 
   $form['account'] = array(
     '#type' => 'fieldset',
-- 
1.7.4.1

