diff --git a/includes/project_maintainers.inc b/includes/project_maintainers.inc
index 88f3727..6c433d8 100644
--- a/includes/project_maintainers.inc
+++ b/includes/project_maintainers.inc
@@ -34,7 +34,7 @@
  * @see hook_project_permission_info()
  * @see drupal_get_form()
  */
-function project_maintainers_form($form_state, $project) {
+function project_maintainers_form($form, &$form_state, $project) {
   // Load all the info about per-project permissions on this site.
   $project_perms = project_permission_load($project);
 
@@ -68,12 +68,12 @@ function project_maintainers_form($form_state, $project) {
           $form['maintainers'][$uid]['permissions'][$perm_name]['#disabled'] = TRUE;
         }
         $form['maintainers'][$uid]['operations']['delete'] = array(
-          '#value' => t('locked'),
+          '#markup' => t('locked'),
         );
       }
       else {
         $form['maintainers'][$uid]['operations']['delete'] = array(
-          '#value' => l(t('delete'), "node/$project->nid/maintainers/delete/$uid"),
+          '#markup' => l(t('delete'), "node/$project->nid/maintainers/delete/$uid"),
         );
       }
     }
@@ -114,7 +114,8 @@ function project_maintainers_form($form_state, $project) {
  * @see theme()
  * @see project_maintainers_form()
  */
-function theme_project_maintainers_form($form) {
+function theme_project_maintainers_form(&$variables) {
+  $form = $variables['element'];
   $output = '';
 
   $header = $form['#header'];
@@ -127,7 +128,7 @@ function theme_project_maintainers_form($form) {
       $account = new stdClass;
       $account->uid = $uid;
       $account->name = $form['maintainers'][$uid]['name']['#value'];
-      $row[] = theme('username', $account);
+      $row[] = theme('username', array('account' => $account));
       foreach (element_children($form['maintainers'][$uid]['permissions']) as $perm) {
         $row[] = drupal_render($form['maintainers'][$uid]['permissions'][$perm]);
       }
@@ -156,7 +157,7 @@ function theme_project_maintainers_form($form) {
   // Although using named keys in the $header array makes this form easier to
   // alter, theme_table() freaks out if the $header array has non-numeric
   // keys. So we ditch the keys at this point to avoid notices.
-  $output .= theme('table', array_values($header), $rows);
+  $output .= theme('table', array('header' => array_values($header), 'rows' => $rows));
 
   $project_perms = project_permission_load($form['#project']);
   $output .= '<dl class="description">';
@@ -166,7 +167,7 @@ function theme_project_maintainers_form($form) {
   }
   $output .= "</dl>\n";
 
-  $output .= drupal_render($form);
+  $output .= drupal_render_children($form);
   return $output;
 }
 
@@ -176,13 +177,13 @@ function theme_project_maintainers_form($form) {
 function project_maintainers_form_validate($form, &$form_state) {
   $new_maintainer = $form_state['values']['new_maintainer'];
   if (!empty($new_maintainer['user'])) {
-    $user_result = db_fetch_object(db_query("SELECT name, uid FROM {users} WHERE name = '%s'", $new_maintainer['user']));
+    $user_result = db_query("SELECT name, uid FROM {users} WHERE name = :user_name", array(':user_name' => $new_maintainer['user']))->fetch();
     if (empty($user_result->uid)) {
-      form_set_error('new_maintainer][user', t('%user is not a valid user on this site.', array('%user' => $new_maintainer['user'])), 'error');
+      form_set_error('new_maintainer][user', t('%user is not a valid user on this site.', array('%user' => $new_maintainer['user'])));
       return;
     }
     if (!empty($form['#project']->project['maintainers'][$user_result->uid])) {
-      form_set_error('new_maintainer][user', t('%user is already a maintainer of this project.', array('%user' => $new_maintainer['user'])), 'error');
+      form_set_error('new_maintainer][user', t('%user is already a maintainer of this project.', array('%user' => $new_maintainer['user'])));
       return;
     }
     // Save the uid in the form so we don't have to look it up again at submit.
@@ -227,9 +228,9 @@ function project_maintainers_form_submit($form, &$form_state) {
 /**
  * Confirm form for removing a uid as a cvs maintainer from a given project.
  */
-function project_maintainer_delete_confirm($form_state, $project, $user) {
+function project_maintainer_delete_confirm($form, &$form_state, $project, $user) {
   if ($user->uid == $project->uid) {
-    drupal_set_message(t('You can not delete the project owner (!user) as a maintainer.', array('!user' => theme('username', $user))), 'error');
+    drupal_set_message(t('You can not delete the project owner (!user) as a maintainer.', array('!user' => theme('username', array('account' => $user)))), 'error');
     return drupal_goto("node/$project->nid/maintainers/");
   }
 
@@ -239,7 +240,7 @@ function project_maintainer_delete_confirm($form_state, $project, $user) {
   return confirm_form($form,
            t('Are you sure you want to delete !user as a maintainer of !project?',
              array(
-               '!user' => theme('username', $user),
+               '!user' => theme('username', array('account' => $user)),
                '!project' => l($project->title, "node/$project->nid"),
              )),
            "node/$project->nid/maintainers",
@@ -256,10 +257,11 @@ function project_maintainer_delete_confirm($form_state, $project, $user) {
 function project_maintainer_delete_confirm_submit($form, &$form_state) {
   $nid = $form_state['values']['nid'];
   $uid = $form_state['values']['uid'];
-  $user = user_load(array('uid' => $uid));
+  $user = user_load($uid);
 
   project_maintainer_remove($nid, $uid);
 
-  drupal_set_message(t('Removed !user as a maintainer.', array('!user' => theme('username', $user))));
+  drupal_set_message(t('Removed !user as a maintainer.', array('!user' => theme('username', array('account' => $user)))));
   $form_state['redirect'] = "node/$nid/maintainers";
 }
+
diff --git a/project.install b/project.install
index 11db2d1..c8ff163 100644
--- a/project.install
+++ b/project.install
@@ -42,3 +42,44 @@ function project_uninstall() {
   watchdog('project', 'Deleted the :field_name field from all content type instances.', array(':field_name' => 'field_project_type'));
 }
 
+/**
+ * Implements hook_schema().
+ */
+function project_schema() {
+  return array(
+    'project_maintainer' => array(
+      'description' => t('Users who have various per-project maintainer permissions.'),
+      'fields' => array(
+        'nid' => array(
+          'description' => t('Foreign key: node.nid of the project.'),
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+          'default' => 0,
+        ),
+        'uid' => array(
+          'description' => t('Foreign key: {users}.uid of a user with any project maintainer permissions.'),
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+          'default' => 0,
+        ),
+        'edit_project' => array(
+          'description' => t('Can this user edit the given project and modify its settings.'),
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+          'default' => 0,
+        ),
+        'administer_maintainers' => array(
+          'description' => t('Can this user manipulate the maintainers for the given project.'),
+          'type' => 'int',
+          'unsigned' => TRUE,
+          'not null' => TRUE,
+          'default' => 0,
+        ),
+      ),
+      'primary key' => array('nid', 'uid'),
+    ),
+  );
+}
diff --git a/project.module b/project.module
index 6b57fa7..19781af 100644
--- a/project.module
+++ b/project.module
@@ -98,3 +98,254 @@ else {
   }
   return $node;
 }
+
+/**
+ * Implementats hook_menu().
+ */
+function project_menu() {
+  $items = array();
+
+  $items['node/%project/maintainers'] = array(
+    'title' => 'Maintainers',
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('project_maintainers_form', 1),
+    'access callback' => 'project_user_access',
+    'access arguments' => array(1, 'administer maintainers'),
+    'file' => 'includes/project_maintainers.inc',
+    'type' => MENU_LOCAL_TASK,
+    'weight' => 4,
+  );
+
+  $items['node/%project/maintainers/delete/%user'] = array(
+    'page callback' => 'drupal_get_form',
+    'page arguments' => array('project_maintainer_delete_confirm', 1, 4),
+    'access callback' => 'project_user_access',
+    'access arguments' => array(1, 'administer maintainers'),
+    'file' => 'includes/project_maintainers.inc',
+    'type' => MENU_CALLBACK,
+  );
+
+  return $items;
+}
+
+/**
+ * Implements hook_permission().
+ */
+function project_permission() {
+  return array(
+    'administer projects' => array(
+      'title' => t('Administer projects'),
+      'description' => t('Administer all projects.'),
+      'restrict access' => TRUE,
+    ),
+  );
+}
+
+/**
+ * See if the current user has the given permission on a given project.
+ *
+ * @param $project
+ *   The project to check access against. Can be either a numeric node ID
+ *   (nid) or a fully-loaded $node object.
+ * @param $permission
+ *   The string representing the permission to check access for.
+ */
+function project_user_access($project, $permission) {
+  global $user;
+  if (empty($user->uid)) {
+    return FALSE;
+  }
+
+  $project_obj = is_numeric($project) ? node_load($project) : $project;
+  if (!isset($project_obj) || (isset($project_obj->type) && !project_node_is_project($project_obj))) {
+    return FALSE;
+  }
+
+  // If the user has the site-wide admin permission, always grant access.
+  if (user_access('administer projects')) {
+     return TRUE;
+  }
+
+  // Project owners are treated as super users and can always access.
+  if ($user->uid == $project_obj->uid) {
+    return TRUE;
+  }
+
+  // Otherwise, see if the user has the right permission for this project.
+  return !empty($project_obj->project['maintainers'][$user->uid]['permissions'][$permission]);
+
+  // If we haven't granted access yet, deny it.
+  return FALSE;
+}
+
+/**
+ * Load all per-project permission information and return it.
+ *
+ * This invokes hook_project_permission_info() and
+ * hook_project_permission_alter(), and caches the results in RAM.
+ *
+ * @param $project
+ *   A project object to pass to hook_project_permission_info().
+ *
+ * @see hook_project_permission_info()
+ * @see hook_project_permission_alter()
+ * @see drupal_alter()
+ */
+function project_permission_load($project) {
+  static $project_permissions = array();
+  if (empty($project_permissions[$project->nid])) {
+    $permissions = module_invoke_all('project_permission_info', $project);
+    drupal_alter('project_permission', $permissions, $project);
+    $project_permissions[$project->nid] = $permissions;
+  }
+  return $project_permissions[$project->nid];
+}
+
+/**
+ * Implement hook_project_permission_info()
+ */
+function project_project_permission_info($project = NULL) {
+  return array(
+    'edit project' => array(
+      'title' => t('Edit project'),
+      'description' => t('Allows a user to edit a project and modify its settings.'),
+    ),
+    'administer maintainers' => array(
+      'title' => t('Administer maintainers'),
+      'description' => t('Allows a user to add and remove other project maintainers and to modify their permissions.'),
+    ),
+  );
+}
+
+/**
+ * Save the permissions associated with a maintainer for a given project.
+ *
+ * This creates a new maintainer record if none currently exists. Furthermore,
+ * it invokes hook_project_maintainer_save() to give other modules a chance to
+ * act on the fact that a maintainer is being saved.
+ *
+ * @param $nid
+ *   The Project NID to update the maintainer for.
+ * @param $uid
+ *   The user ID of the maintainer to update.
+ * @param array $permissions
+ *   Associative array of which project-level permissions the maintainer
+ *   should have. The keys are permission names, and the values are if the
+ *   permission should be granted or not.
+ *
+ * @see hook_project_maintainer_save()
+ * @see hook_project_permission_info()
+ */
+function project_maintainer_save($nid, $uid, $permissions = array()) {
+  // Try to update an existing record, if any.
+  db_merge('project_maintainer')
+    ->key(array('nid' => $nid, 'uid' => $uid))
+    ->fields(array(
+      'edit_project' => $permissions['edit project'],
+      'administer_maintainers' => $permissions['administer maintainers']
+    ))
+    ->execute();
+
+  // Invoke hook_project_maintainer_save() to let other modules know this
+  // maintainer is being saved so they can take any actions or record any
+  // data they need to.
+  module_invoke_all('project_maintainer_save', $nid, $uid, $permissions);
+}
+
+/**
+ * Remove a maintainer from a given project.
+ *
+ * @param $nid
+ *   The Project NID to remove the maintainer from.
+ * @param $uid
+ *   The user ID of the maintainer to remove.
+ */
+function project_maintainer_remove($nid, $uid) {
+  db_query("DELETE FROM {project_maintainer} WHERE nid = :nid and uid = :uid", array(':nid' => $nid, ':uid' => $uid));
+
+  // Invoke hook_project_maintainer_remove() to let other modules know this
+  // maintainer is being removed so they can take any actions or record any
+  // data they need to.
+  module_invoke_all('project_maintainer_remove', $nid, $uid);
+}
+
+/**
+ * Load all the per-project maintainer info for a given project.
+ *
+ * @param $nid
+ *   Node ID of the project to load maintainer info about.
+ *
+ * @return
+ *   Array of maintainer info for the given project.
+ *
+ * @see hook_project_maintainer_project_load().
+ */
+function project_maintainer_project_load($nid) {
+  $maintainers = array();
+
+  // We don't want to load all the permissions here, just the ones that
+  // Project itself is responsible for, so we use our implementation of the
+  // hook, instead of the global load function.
+  $project_perms = project_project_permission_info();
+  $result = db_query('SELECT u.name, pm.* FROM {project_maintainer} pm INNER JOIN {users} u ON pm.uid = u.uid WHERE pm.nid = :nid ORDER BY u.name', array(':nid' => $nid));
+  foreach ($result as $maintainer) {
+    $maintainers[$maintainer->uid]['name'] = $maintainer->name;
+    foreach ($project_perms as $perm_name => $perm_info) {
+      $db_field = str_replace(' ', '_', $perm_name);
+      $maintainers[$maintainer->uid]['permissions'][$perm_name] = $maintainer->$db_field;
+    }
+  }
+
+  // Invoke hook_project_maintainer_project_load(). We can't use
+  // module_invoke_all() since we want a reference to the $maintainers array.
+  foreach (module_implements('project_maintainer_project_load') as $module) {
+    $function_name = $module . '_project_maintainer_project_load';
+    $function_name($nid, $maintainers);
+  }
+
+  return $maintainers;
+}
+
+/**
+ * Implements hook_node_load().
+ */
+function project_node_load($nodes, $types) {
+  foreach ($nodes as $node) {
+    if (project_node_is_project($node)) {
+      $node->project = array();
+      $node->project['maintainers'] = project_maintainer_project_load($node->nid);
+    }
+  }
+}
+
+/**
+ * Implements hook_theme().
+ */
+function project_theme() {
+  return array(
+    'project_maintainers_form' => array(
+      'file' => 'includes/project_maintainers.inc',
+      'render element' => 'element',
+    ),
+  );
+}
+
+/**
+ * Implements hook_node_insert().
+ */
+function project_node_insert($node) {
+  if (project_node_is_project($node)) {
+    $perms = array_fill_keys(array_keys(project_permission_load($node)), 1);
+    project_maintainer_save($node->nid, $node->uid, $perms);
+  }
+}
+
+/**
+ * Implements hook_node_insert().
+ */
+function project_node_update($node) {
+  if (project_node_is_project($node)) {
+    $perms = array_fill_keys(array_keys(project_permission_load($node)), 1);
+    project_maintainer_save($node->nid, $node->uid, $perms);
+  }
+}
diff --git a/project.test b/project.test
index ff1c3a6..6f27577 100644
--- a/project.test
+++ b/project.test
@@ -7,13 +7,6 @@ class ProjectWebTestCase extends DrupalWebTestCase {
   function setUp($modules = array()) {
     $modules = array_merge(array('project'), $modules);
     parent::setUp($modules);
-
-//    $perms = array('create full projects', 'access user profiles', 'access projects');
-
-//    $this->owner = $this->drupalCreateUser($perms);
-//    $this->drupalLogin($this->owner);
-//
-//    $this->maintainer = $this->drupalCreateUser($perms);
   }
 
   /**
@@ -86,6 +79,7 @@ class ProjectWebTestCase extends DrupalWebTestCase {
    */
   function createProject($settings = array()) {
     $defaults = array(
+      'type' => 'project',
       'title' => $this->randomName(),
       'body' => array(
         LANGUAGE_NONE => array(
@@ -426,108 +420,119 @@ class ProjectTestCase extends ProjectWebTestCase {
 //  }
 //}
 
-//class ProjectMaintainersTestCase extends ProjectWebTestCase {
-//  public static function getInfo() {
-//    return array(
-//      'name' => 'Project maintainers functionality',
-//      'description' => 'Test Project module maintainers access control system.',
-//      'group' => 'Project'
-//    );
-//  }
-//
-//  function setUp() {
-//    parent::setUp();
-//  }
-//
-//  /**
-//   * Test maintainer permissions.
-//   */
-//  function testProjectMaintainerPermissions() {
-//    // Create project, make sure Maintainers link is shown
-//    $project = $this->createProject();
-//
-//    // Check that owner can access
-//    $this->drupalGet("node/$project->nid/edit");
-//    $this->assertResponse(200, 'Project owner can edit project.');
-//
-//    // Check the maintainers tab is shown and owner is included correctly
-//    $this->drupalGet("node/$project->nid");
-//    $this->assertLink(t('Maintainers'), 0, ('Maintainers tab is shown.'));
-//    $this->drupalGet("node/$project->nid/maintainers");
-//    $this->assertLink($this->owner->name, 0, ('Project owner is displayed on form.'));
-//    $this->assertFieldDisabled("maintainers[{$this->owner->uid}][permissions][edit project]", 'Checkbox is disabled for project owner');
-//    $this->assertFieldDisabled("maintainers[{$this->owner->uid}][permissions][administer maintainers]", 'Checkbox is disabled for project owner');
-//    $this->assertFieldCheckedByName("maintainers[{$this->owner->uid}][permissions][edit project]", 'Owners permissions are automatically granted');
-//    $this->assertFieldCheckedByName("maintainers[{$this->owner->uid}][permissions][administer maintainers]", 'Owners permissions are automatically granted');
-//    $this->assertNoRaw("node/$project->nid/maintainers/delete/{$this->owner->uid}", 'No delete link is displayed for the project owner.');
-//
-//    // Try to delete the owner anyway and make sure it fails.
-//    $this->drupalGet("node/$project->nid/maintainers/delete/{$this->owner->uid}");
-//    $this->assertText("You can not delete the project owner ({$this->owner->name}) as a maintainer.", 'Project owner can not be deleted as a maintainer.');
-//
-//    // Verify that other users do not have access
-//    $this->drupalLogin($this->maintainer);
-//    $this->drupalGet("node/$project->nid/edit");
-//    $this->assertResponse(403, 'Project edit form is protected.');
-//    $this->drupalGet("node/$project->nid/maintainers");
-//    $this->assertResponse(403, 'Project maintainers form is protected.');
-//    $this->drupalGet("node/$project->nid/maintainers/delete/{$this->maintainer->uid}");
-//    $this->assertResponse(403, 'Project delete maintainer form is protected.');
-//
-//    // Add a new user and verify that they are added:
-//    // Login as owner
-//    $this->drupalLogin($this->owner);
-//    // Add new user
-//    $edit = array();
-//    $edit['new_maintainer[user]'] = $this->maintainer->name;
-//    $this->drupalPost("node/$project->nid/maintainers", $edit, t('Update'));
-//    $this->assertLink($this->maintainer->name, 0, 'New user is displayed on form correctly.');
-//    $this->assertNoFieldCheckedByName("maintainers[{$this->maintainer->uid}][permissions][edit project]", 'Permissions not explicitly granted.');
-//    $this->assertNoFieldCheckedByName("maintainers[{$this->maintainer->uid}][permissions][administer maintainers]", 'Permissions not explicitly granted.');
-//
-//    // Test validation for adding a duplicate maintainer
-//    $edit = array();
-//    $edit['new_maintainer[user]'] = $this->maintainer->name;
-//    $this->drupalPost("node/$project->nid/maintainers", $edit, t('Update'));
-//    $this->assertText("{$this->maintainer->name} is already a maintainer of this project.", 'Duplicate maintainers are not permitted.');
-//
-//    // Add permissions to user
-//    $edit = array();
-//    $edit["maintainers[{$this->maintainer->uid}][permissions][edit project]"] = TRUE;
-//    $this->drupalPost("node/$project->nid/maintainers", $edit, t('Update'));
-//    $this->assertFieldCheckedByName("maintainers[{$this->maintainer->uid}][permissions][edit project]", 'Permissions are displayed correctly on maintainers form.');
-//    // Login as maintainer and check access
-//    $this->drupalLogin($this->maintainer);
-//    $this->drupalGet("node/$project->nid/edit");
-//    $this->assertResponse(200, 'User is correctly granted access to project edit form.');
-//    $this->drupalGet("node/$project->nid/maintainers");
-//    $this->assertResponse(403, 'Project maintainers form is protected.');
-//    $this->drupalGet("node/$project->nid/maintainers/delete/{$this->maintainer->uid}");
-//    $this->assertResponse(403, 'Project delete maintainer form is protected.');
-//
-//    // Have owner grant administer maintainers permission
-//    $this->drupalLogin($this->owner);
-//    // Add permissions to user
-//    $edit = array();
-//    $edit["maintainers[{$this->maintainer->uid}][permissions][administer maintainers]"] = TRUE;
-//    $this->drupalPost("node/$project->nid/maintainers", $edit, t('Update'));
-//    $this->assertFieldCheckedByName("maintainers[{$this->maintainer->uid}][permissions][administer maintainers]", 'Permissions are displayed correctly on maintainers form.');
-//    // Login as maintainer and check access
-//    $this->drupalLogin($this->maintainer);
-//    $this->drupalGet("node/$project->nid/maintainers");
-//    $this->assertResponse(200, 'User is correctly granted access to project edit form.');
-//
-//    // Remove the user from the project
-//    $this->drupalLogin($this->owner);
-//    $this->drupalGet("node/$project->nid/maintainers/delete/{$this->maintainer->uid}");
-//    $this->assertText("Are you sure you want to delete {$this->maintainer->name} as a maintainer of {$project->title}?", 'Deletion page is displayed properly.');
-//    $this->drupalPost(NULL, array(), t('Delete'));
-//    $this->assertText("Removed {$this->maintainer->name} as a maintainer.", 'Project maintainer successfully deleted.');
-//    // Verify that access has been removed
-//    $this->drupalLogin($this->maintainer);
-//    $this->drupalGet("node/$project->nid/edit");
-//    $this->assertResponse(403, 'Project edit form is protected.');
-//    $this->drupalGet("node/$project->nid/maintainers");
-//    $this->assertResponse(403, 'Project maintainers form is protected.');
-//  }
-//}
+
+class ProjectMaintainersTestCase extends ProjectWebTestCase {
+  public static function getInfo() {
+    return array(
+      'name' => 'Project maintainers functionality',
+      'description' => 'Test Project module maintainers access control system.',
+      'group' => 'Project'
+    );
+  }
+
+  
+  function setUp() {
+    parent::setUp();
+
+    $perms = array('create project content', 'edit own project content', 'delete own project content', 'access user profiles');
+
+    $this->owner = $this->drupalCreateUser($perms);
+    $this->drupalLogin($this->owner);
+
+    $this->maintainer = $this->drupalCreateUser($perms);
+  }
+
+  /**
+   * Test maintainer permissions.
+   */
+  function testProjectMaintainerPermissions() {
+    // Create project, make sure Maintainers link is shown
+    $project = $this->createProject(array('uid' => $this->owner->uid));
+
+    // Check that owner can access
+    $this->drupalGet("node/$project->nid");
+    $this->assertResponse(200, 'Project owner can view project');
+    $this->drupalGet("node/$project->nid/edit");
+    $this->assertResponse(200, 'Project owner can edit project.');
+
+    // Check the maintainers tab is shown and owner is included correctly
+    $this->drupalGet("node/$project->nid");
+    $this->assertLink(t('Maintainers'), 0, ('Maintainers tab is shown.'));
+    $this->drupalGet("node/$project->nid/maintainers");
+    $this->assertLink($this->owner->name, 0, ('Project owner is displayed on form.'));
+    $this->assertFieldDisabled("maintainers[{$this->owner->uid}][permissions][edit project]", 'Checkbox is disabled for project owner');
+    $this->assertFieldDisabled("maintainers[{$this->owner->uid}][permissions][administer maintainers]", 'Checkbox is disabled for project owner');
+    $this->assertFieldCheckedByName("maintainers[{$this->owner->uid}][permissions][edit project]", 'Owners permissions are automatically granted');
+    $this->assertFieldCheckedByName("maintainers[{$this->owner->uid}][permissions][administer maintainers]", 'Owners permissions are automatically granted');
+    $this->assertNoRaw("node/$project->nid/maintainers/delete/{$this->owner->uid}", 'No delete link is displayed for the project owner.');
+
+    // Try to delete the owner anyway and make sure it fails.
+    $this->drupalGet("node/$project->nid/maintainers/delete/{$this->owner->uid}");
+    $this->assertText("You can not delete the project owner ({$this->owner->name}) as a maintainer.", 'Project owner can not be deleted as a maintainer.');
+
+    // Verify that other users do not have access
+    $this->drupalLogin($this->maintainer);
+    $this->drupalGet("node/$project->nid/edit");
+    $this->assertResponse(403, 'Project edit form is protected.');
+    $this->drupalGet("node/$project->nid/maintainers");
+    $this->assertResponse(403, 'Project maintainers form is protected.');
+    $this->drupalGet("node/$project->nid/maintainers/delete/{$this->maintainer->uid}");
+    $this->assertResponse(403, 'Project delete maintainer form is protected.');
+
+    // Add a new user and verify that they are added:
+    // Login as owner
+    $this->drupalLogin($this->owner);
+    // Add new user
+    $edit = array();
+    $edit['new_maintainer[user]'] = $this->maintainer->name;
+    $this->drupalPost("node/$project->nid/maintainers", $edit, t('Update'));
+    $this->assertLink($this->maintainer->name, 0, 'New user is displayed on form correctly.');
+    $this->assertNoFieldCheckedByName("maintainers[{$this->maintainer->uid}][permissions][edit project]", 'Permissions not explicitly granted.');
+    $this->assertNoFieldCheckedByName("maintainers[{$this->maintainer->uid}][permissions][administer maintainers]", 'Permissions not explicitly granted.');
+
+    // Test validation for adding a duplicate maintainer
+    $edit = array();
+    $edit['new_maintainer[user]'] = $this->maintainer->name;
+    $this->drupalPost("node/$project->nid/maintainers", $edit, t('Update'));
+    $this->assertText("{$this->maintainer->name} is already a maintainer of this project.", 'Duplicate maintainers are not permitted.');
+
+    // Add permissions to user
+    $edit = array();
+    $edit["maintainers[{$this->maintainer->uid}][permissions][edit project]"] = TRUE;
+    $this->drupalPost("node/$project->nid/maintainers", $edit, t('Update'));
+    $this->assertFieldCheckedByName("maintainers[{$this->maintainer->uid}][permissions][edit project]", 'Permissions are displayed correctly on maintainers form.');
+    // Login as maintainer and check access
+    $this->drupalLogin($this->maintainer);
+    $this->drupalGet("node/$project->nid/edit");
+    $this->assertResponse(200, 'User is correctly granted access to project edit form.');
+    $this->drupalGet("node/$project->nid/maintainers");
+    $this->assertResponse(403, 'Project maintainers form is protected.');
+    $this->drupalGet("node/$project->nid/maintainers/delete/{$this->maintainer->uid}");
+    $this->assertResponse(403, 'Project delete maintainer form is protected.');
+
+    // Have owner grant administer maintainers permission
+    $this->drupalLogin($this->owner);
+    // Add permissions to user
+    $edit = array();
+    $edit["maintainers[{$this->maintainer->uid}][permissions][administer maintainers]"] = TRUE;
+    $this->drupalPost("node/$project->nid/maintainers", $edit, t('Update'));
+    $this->assertFieldCheckedByName("maintainers[{$this->maintainer->uid}][permissions][administer maintainers]", 'Permissions are displayed correctly on maintainers form.');
+    // Login as maintainer and check access
+    $this->drupalLogin($this->maintainer);
+    $this->drupalGet("node/$project->nid/maintainers");
+    $this->assertResponse(200, 'User is correctly granted access to project edit form.');
+
+    // Remove the user from the project
+    $this->drupalLogin($this->owner);
+    $this->drupalGet("node/$project->nid/maintainers/delete/{$this->maintainer->uid}");
+    $this->assertText("Are you sure you want to delete {$this->maintainer->name} as a maintainer of {$project->title}?", 'Deletion page is displayed properly.');
+    $this->drupalPost(NULL, array(), t('Delete'));
+    $this->assertText("Removed {$this->maintainer->name} as a maintainer.", 'Project maintainer successfully deleted.');
+    // Verify that access has been removed
+    $this->drupalLogin($this->maintainer);
+    $this->drupalGet("node/$project->nid/edit");
+    $this->assertResponse(403, 'Project edit form is protected.');
+    $this->drupalGet("node/$project->nid/maintainers");
+    $this->assertResponse(403, 'Project maintainers form is protected.');
+  }
+}
