? .kdev4
? profile_permission.kdev4
? profile_permission_testcase.patch
Index: profile_permission.module
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/profile_permission/profile_permission.module,v
retrieving revision 1.4
diff -u -p -r1.4 profile_permission.module
--- profile_permission.module	9 Feb 2009 18:55:21 -0000	1.4
+++ profile_permission.module	3 Nov 2010 08:13:16 -0000
@@ -111,13 +111,13 @@ function profile_permission_user_view_fi
         unset($element[$key]);
       }
     }
-
-    // Search the array recursively for restricted fields.
-    $children = element_children($element[$key]);
-    if ($children) {
-      if (profile_permission_user_view_field($account, $element[$key])) {
-        // No children, remove empty element.
-        unset($element[$key]);
+    else {
+      // Search the array recursively for restricted fields.
+      if ($children = element_children($element[$key])) {
+        if (profile_permission_user_view_field($account, $element[$key])) {
+          // No children, remove empty element.
+          unset($element[$key]);
+        }
       }
     }
   }
Index: profile_permission.test
===================================================================
RCS file: /cvs/drupal-contrib/contributions/modules/profile_permission/profile_permission.test,v
retrieving revision 1.3
diff -u -p -r1.3 profile_permission.test
--- profile_permission.test	20 Jan 2009 05:52:04 -0000	1.3
+++ profile_permission.test	3 Nov 2010 08:13:16 -0000
@@ -11,7 +11,7 @@ class ProfilePermissionTestCase extends 
   /**
    * Implementation of getInfo().
    */
-  function getInfo() {
+  public static function getInfo() {
     return array(
       'name' => t('Profile permission'),
       'description' => t('Test the visibility/editablity of a field based on its role settings.'),
@@ -22,84 +22,267 @@ class ProfilePermissionTestCase extends 
   /**
    * Implementation of setUp().
    */
-  function setUp() {
+  protected function setUp() {
     parent::setUp('profile', 'profile_permission');
   }
 
   /**
-   * Test the visibility of a field based on its role settings.
+   * Verify that a protected, required field is considered by permissions, and
+   * that submitting the form passes validation and does not reset the current
+   * value.
+   *
+   * @TODO: how to handle when user has view permission, not edit permission
+   *        in the user/%/edit/category form.. show a non editable value?
+   * @TODO: how to handle when a category is empty, show a message?
    */
-  function testFieldVisibility() {
-    // Create and login user.
+  protected function testPublicFieldProtectedRequired() {
+
+    // Create admin and standard user.
     $admin_user = $this->drupalCreateUser(array('administer users', 'administer permissions'));
+    $other_user = $this->drupalCreateUser();
+
+    // Login as admin user to allow for profile field creation.
     $this->drupalLogin($admin_user);
 
-    // Create profile field.
-    $this->drupalget('admin/user/profile');
-    $this->clickLink(t('single-line textfield'));
+    // Create a public profile field.
+    $field1 = $this->createProfileField(array('required' => TRUE));
 
-    $field = array();
-    $field['category'] = $this->randomName();
-    $field['title'] = $this->randomName();
-    $field['name'] = $this->randomName();
-    $this->drupalPost(NULL, $field, t('Save field'));
-    $this->assertText(t('The field has been created.'));
+    // Attempt to view field when editting profile.
+    $this->drupalGet('user/' . $admin_user->uid . '/edit/' . $field1['category']);
+    $this->assertFieldByName($field1['name'], '', t('Field editable.'));
+
+    // Set a value for the field so it will display for both users.
+    $edit = array();
+    $field1_value = $this->randomName();
+    $edit[$field1['name']] = $field1_value;
+    $this->drupalPost('user/' . $admin_user->uid . '/edit/' . $field1['category'], $edit, t('Save'));
+    $this->drupalPost('user/' . $other_user->uid . '/edit/' . $field1['category'], $edit, t('Save'));
 
-    // Attempt to field when editting profile.
-    $this->drupalGet('user/' . $admin_user->uid . '/edit/' . $field['category']);
-    $this->assertFieldByName($field['name'], '', t('Field editable.'));
+    // Attempt to view field on view page.
+    $this->drupalGet('user/' . $admin_user->uid);
+    $this->assertTrue($this->xpath('.//dt[@class="profile-' . $field1['name'] . '"]'), t('Field visible.'));
+
+    // Create a second field in the same category as the previous one. This
+    // required second field will be protected later.
+    $settings = array(
+      'category' => $field1['category'],
+      'required' => TRUE,
+    );
+    $field2 = $this->createProfileField($settings);
+
+    // Attempt to view field when editting profile.
+    $this->drupalGet('user/' . $admin_user->uid . '/edit/' . $field2['category']);
+    $this->assertFieldByName($field2['name'], '', t('Field editable.'));
 
     // Set a value for the field so it will display.
     $edit = array();
-    $edit[$field['name']] = $this->randomName();
-    $this->drupalPost(NULL, $edit, t('Save'));
+    $field2_value = $this->randomName();
+    $edit[$field2['name']] = $field2_value;
+    $this->drupalPost('user/' . $admin_user->uid . '/edit/' . $field2['category'], $edit, t('Save'));
+    $this->drupalPost('user/' . $other_user->uid . '/edit/' . $field2['category'], $edit, t('Save'));
 
     // Attempt to view field on view page.
     $this->drupalGet('user/' . $admin_user->uid);
-    $this->assertTrue($this->xpath('.//dt[@class="profile-' . $field['name'] . '"]'), t('Field visible.'));
+    $this->assertTrue($this->xpath('.//dt[@class="profile-' . $field2['name'] . '"]'), t('Field visible.'));
 
-    // Create profile field.
-    $this->drupalget('admin/user/profile');
-    $this->clickLink(t('single-line textfield'));
+    // Edit this field and set as protected field.
+    $this->drupalPost('admin/user/profile/edit/' . $field2['fid'], array('profile_permission' => TRUE), t('Save field'));
+    $this->assertText(t('The field has been updated.'));
 
-    // Restrict field: require permission to view.
-    $field = array();
-    $field['category'] = $this->randomName();
-    $field['title'] = $this->randomName();
-    $field['name'] = $this->randomName();
-    $field['profile_permission'] = TRUE;
-    $this->drupalPost(NULL, $field, t('Save field'));
-    $this->assertText(t('The field has been created.'));
+    // A protected field will not be shown by default.
+
+    // Attempt to view field on view page.
+    $this->drupalGet('user/' . $admin_user->uid);
+    $this->assertFalse($this->xpath('.//dt[@class="profile-' . $field2['name'] . '"]'), t('Field not visible.'));
 
-    // Attempt to field when editting profile.
-    $this->drupalGet('user/' . $admin_user->uid . '/edit/' . $field['category']);
-    $this->assertNoFieldByName($field['name'], '', t('Field not editable.'));
+    // Attempt to view field when editting profile.
+    $this->drupalGet('user/' . $admin_user->uid . '/edit/' . $field2['category']);
+    $this->assertNoFieldByName($field2['name'], '', t('Field not editable.'));
 
-    // Give user access to field.
+    // Verify EDIT OWN NAME FIELD.
+    // Grant this user edit own field permission and verify.
     $edit = array();
-    $edit[DRUPAL_AUTHENTICATED_RID . '[edit ' . $field['name'] . ' field]'] = TRUE;
+    $edit[DRUPAL_AUTHENTICATED_RID . '[edit own ' . $field2['name'] . ' field]'] = TRUE;
     $this->drupalPost('admin/user/permissions', $edit, t('Save permissions'));
 
-    // Attempt to field when editting profile.
-    $this->drupalGet('user/' . $admin_user->uid . '/edit/' . $field['category']);
-    $this->assertFieldByName($field['name'], '', t('Field editable.'));
+    // Attempt to view the field when editting its own profile.
+    $this->drupalGet('user/' . $admin_user->uid . '/edit/' . $field2['category']);
+    $this->assertFieldByName($field2['name'], '', t('Field editable.'));
 
-    // Set a value for the field so it will display.
+    // Attempt to view field when editting profile of other user.
+    $this->drupalGet('user/' . $other_user->uid . '/edit/' . $field2['category']);
+    $this->assertNoFieldByName($field2['name'], '', t('Field not editable.'));
+
+
+    // Verify EDIT NAME FIELD
+    // Grant this user edit ANY field permissions and verify.
     $edit = array();
-    $edit[$field['name']] = $this->randomName();
-    $this->drupalPost(NULL, $edit, t('Save'));
+    $edit[DRUPAL_AUTHENTICATED_RID . '[edit own ' . $field2['name'] . ' field]'] = TRUE;
+    $edit[DRUPAL_AUTHENTICATED_RID . '[edit ' . $field2['name'] . ' field]'] = FALSE;
+    $this->drupalPost('admin/user/permissions', $edit, t('Save permissions'));
 
-    // Attempt to view field on view page.
+    // Attempt to view the field when editting its own profile.
+    $this->drupalGet('user/' . $admin_user->uid . '/edit/' . $field2['category']);
+    $this->assertFieldByName($field2['name'], '', t('Field editable.'));
+
+    // Attempt to view field when editting profile of other user.
+    $this->drupalGet('user/' . $other_user->uid . '/edit/' . $field2['category']);
+    $this->assertFieldByName($field2['name'], '', t('Field editable.'));
+
+
+    // Verify VIEW OWN NAME FIELD.
+    // Grant this user view own field permission and verify.
+    $edit = array();
+    $edit[DRUPAL_AUTHENTICATED_RID . '[view own ' . $field2['name'] . ' field]'] = TRUE;
+    $this->drupalPost('admin/user/permissions', $edit, t('Save permissions'));
+
+    // Attempt to view the field when editting its own profile.
     $this->drupalGet('user/' . $admin_user->uid);
-    $this->assertFalse($this->xpath('.//dt[@class="profile-' . $field['name'] . '"]'), t('Field not visible.'));
+    $this->assertTrue($this->xpath('.//dt[@class="profile-' . $field2['name'] . '"]'), t('Field visible.'));
 
-    // Give user access to view field.
+    // Attempt to view field when editting profile of other user.
+    $this->drupalGet('user/' . $other_user->uid);
+    $this->assertFalse($this->xpath('.//dt[@class="profile-' . $field2['name'] . '"]'), t('Field not visible.'));
+
+    // Verify VIEW NAME FIELD
+    // Grant this user edit ANY field permissions and verify.
     $edit = array();
-    $edit[DRUPAL_AUTHENTICATED_RID . '[view ' . $field['name'] . ' field]'] = TRUE;
+    $edit[DRUPAL_AUTHENTICATED_RID . '[view own ' . $field2['name'] . ' field]'] = TRUE;
+    $edit[DRUPAL_AUTHENTICATED_RID . '[view ' . $field2['name'] . ' field]'] = FALSE;
     $this->drupalPost('admin/user/permissions', $edit, t('Save permissions'));
 
-    // Attempt to view field on view page.
+    // Attempt to view the field when editting its own profile.
     $this->drupalGet('user/' . $admin_user->uid);
-    $this->assertTrue($this->xpath('.//dt[@class="profile-' . $field['name'] . '"]'), t('Field visible.'));
+    $this->assertTrue($this->xpath('.//dt[@class="profile-' . $field2['name'] . '"]'), t('Field visible.'));
+
+    // Attempt to view field when editting profile of other user.
+    $this->drupalGet('user/' . $other_user->uid);
+    $this->assertTrue($this->xpath('.//dt[@class="profile-' . $field2['name'] . '"]'), t('Field visible.'));
+
+    // Verify that editing protected fields pass validation and does not reset
+    // the current value.
+
+    // Grant this user edit and view ANY field permissions and verify.
+    $edit = array();
+    $edit[DRUPAL_AUTHENTICATED_RID . '[edit ' . $field2['name'] . ' field]'] = TRUE;
+    $edit[DRUPAL_AUTHENTICATED_RID . '[edit own ' . $field2['name'] . ' field]'] = TRUE;
+    $edit[DRUPAL_AUTHENTICATED_RID . '[view ' . $field2['name'] . ' field]'] = TRUE;
+    $edit[DRUPAL_AUTHENTICATED_RID . '[view own ' . $field2['name'] . ' field]'] = TRUE;
+    $this->drupalPost('admin/user/permissions', $edit, t('Save permissions'));
+
+    // Create fake user objects.
+    $fake_user1 = new stdClass();
+    $fake_user1->uid = $admin_user->uid;
+    $fake_user2 = new stdClass();
+    $fake_user2->uid = $other_user->uid;
+
+    // Submit default values on both users.
+    $values = array();
+    $this->drupalPost('user/' . $admin_user->uid . '/edit/' . $field2['category'], $values, t('Save'));
+    $this->assertRaw(t('The changes have been saved.'), t('Required field pass validation'));
+    profile_load_profile($fake_user1);
+    $this->assertEqual($fake_user1->{$field1['name']}, $field1_value, t('Field 1 was saved successfully.'));
+    $this->assertEqual($fake_user1->{$field2['name']}, $field2_value, t('Field 2 was saved successfully.'));
+
+    $this->drupalPost('user/' . $other_user->uid . '/edit/' . $field2['category'], $values, t('Save'));
+    $this->assertRaw(t('The changes have been saved.'), t('Required field pass validation'));
+    profile_load_profile($fake_user2);
+    $this->assertEqual($fake_user1->{$field1['name']}, $field1_value, t('Field 1 was saved successfully.'));
+    $this->assertEqual($fake_user2->{$field2['name']}, $field2_value, t('Field 2 was saved successfully.'));
+
+
+    // Grant this user only edit permissions and verify.
+    $edit = array();
+    $edit[DRUPAL_AUTHENTICATED_RID . '[edit ' . $field2['name'] . ' field]'] = TRUE;
+    $edit[DRUPAL_AUTHENTICATED_RID . '[edit own ' . $field2['name'] . ' field]'] = TRUE;
+    $edit[DRUPAL_AUTHENTICATED_RID . '[view ' . $field2['name'] . ' field]'] = FALSE;
+    $edit[DRUPAL_AUTHENTICATED_RID . '[view own ' . $field2['name'] . ' field]'] = FALSE;
+    $this->drupalPost('admin/user/permissions', $edit, t('Save permissions'));
+
+    // Create fake user objects.
+    $fake_user1 = new stdClass();
+    $fake_user1->uid = $admin_user->uid;
+    $fake_user2 = new stdClass();
+    $fake_user2->uid = $other_user->uid;
+
+    // Submit default values on both users.
+    $values = array();
+    $this->drupalPost('user/' . $admin_user->uid . '/edit/' . $field2['category'], $values, t('Save'));
+    $this->assertRaw(t('The changes have been saved.'), t('Required field pass validation'));
+    profile_load_profile($fake_user1);
+    $this->assertEqual($fake_user1->{$field1['name']}, $field1_value, t('Field 1 was saved successfully.'));
+    $this->assertEqual($fake_user1->{$field2['name']}, $field2_value, t('Field 2 was saved successfully.'));
+
+    $this->drupalPost('user/' . $other_user->uid . '/edit/' . $field2['category'], $values, t('Save'));
+    $this->assertRaw(t('The changes have been saved.'), t('Required field pass validation'));
+    profile_load_profile($fake_user2);
+    $this->assertEqual($fake_user2->{$field1['name']}, $field1_value, t('Field 1 was saved successfully.'));
+    $this->assertEqual($fake_user2->{$field2['name']}, $field2_value, t('Field 2 was saved successfully.'));
+
+    
+    // Remove all permissions and verify.
+    $edit = array();
+    $edit[DRUPAL_AUTHENTICATED_RID . '[edit ' . $field2['name'] . ' field]'] = FALSE;
+    $edit[DRUPAL_AUTHENTICATED_RID . '[edit own ' . $field2['name'] . ' field]'] = FALSE;
+    $edit[DRUPAL_AUTHENTICATED_RID . '[view ' . $field2['name'] . ' field]'] = FALSE;
+    $edit[DRUPAL_AUTHENTICATED_RID . '[view own ' . $field2['name'] . ' field]'] = FALSE;
+    $this->drupalPost('admin/user/permissions', $edit, t('Save permissions'));
+
+    // Create fake user objects.
+    $fake_user1 = new stdClass();
+    $fake_user1->uid = $admin_user->uid;
+    $fake_user2 = new stdClass();
+    $fake_user2->uid = $other_user->uid;
+
+    // Submit default values on both users.
+    $values = array();
+    $this->drupalPost('user/' . $admin_user->uid . '/edit/' . $field2['category'], $values, t('Save'));
+    $this->assertRaw(t('The changes have been saved.'), t('Required field pass validation'));
+    profile_load_profile($fake_user1);
+    $this->assertEqual($fake_user1->{$field1['name']}, $field1_value, t('Field 1 was saved successfully.'));
+    $this->assertEqual($fake_user1->{$field2['name']}, $field2_value, t('Field 2 was saved successfully.'));
+
+    $this->drupalPost('user/' . $other_user->uid . '/edit/' . $field2['category'], $values, t('Save'));
+    $this->assertRaw(t('The changes have been saved.'), t('Required field pass validation'));
+    profile_load_profile($fake_user2);
+    $this->assertEqual($fake_user2->{$field1['name']}, $field1_value, t('Field 1 was saved successfully.'));
+    $this->assertEqual($fake_user2->{$field2['name']}, $field2_value, t('Field 2 was saved successfully.'));
+
   }
+
+  /**
+   * Creates a profile field.
+   *
+   * @param array $settings
+   * @return field settings.
+   */
+  protected function createProfileField($settings = array()) {
+    // Set default attributes.
+    $settings += array(
+      'category'   => $this->randomName(),
+      'title'      => $this->randomName(),
+      'name'       => $this->randomName(),
+      'visibility' => 2,
+    );
+
+    // Create profile field.
+    $this->drupalget('admin/user/profile');
+    $this->clickLink(t('single-line textfield'));
+
+    $this->drupalPost(NULL, $settings, t('Save field'));
+    $this->assertText(t('The field has been created.'));
+
+    $result = _profile_get_fields($settings['category'], FALSE);
+    while ($field = db_fetch_object($result)) {
+      if (_profile_field_serialize($field->type)) {
+        $fields[$field->name] = serialize($edit[$field->name]);
+      }
+      else {
+        $fields[$field->name] = (array) $field;
+      }
+    }
+    $this->assertTrue(isset($fields[$settings['name']]), t('Field saved.'));
+    return isset($fields[$settings['name']]) ? $fields[$settings['name']] : NULL;
+  }
+
 }
