public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $capabilities = array(PhabricatorPolicyCapability::CAN_VIEW);
     $process_action = false;
     switch ($this->action) {
         case 'join':
             $capabilities[] = PhabricatorPolicyCapability::CAN_JOIN;
             $process_action = $request->isFormPost();
             break;
         case 'leave':
             $process_action = $request->isDialogFormPost();
             break;
         default:
             return new Aphront404Response();
     }
     $project = id(new PhabricatorProjectQuery())->setViewer($user)->withIDs(array($this->id))->needMembers(true)->requireCapabilities($capabilities)->executeOne();
     if (!$project) {
         return new Aphront404Response();
     }
     $project_uri = '/project/view/' . $project->getID() . '/';
     if ($process_action) {
         switch ($this->action) {
             case 'join':
                 PhabricatorProjectEditor::applyJoinProject($project, $user);
                 break;
             case 'leave':
                 PhabricatorProjectEditor::applyLeaveProject($project, $user);
                 break;
         }
         return id(new AphrontRedirectResponse())->setURI($project_uri);
     }
     $dialog = null;
     switch ($this->action) {
         case 'leave':
             $dialog = new AphrontDialogView();
             $dialog->setUser($user);
             $dialog->setTitle('Really leave project?');
             $dialog->appendChild('<p>Your tremendous contributions to this project will be sorely ' . 'missed. Are you sure you want to leave?</p>');
             $dialog->addCancelButton($project_uri);
             $dialog->addSubmitButton('Leave Project');
             break;
         default:
             return new Aphront404Response();
     }
     return id(new AphrontDialogResponse())->setDialog($dialog);
 }
 public function testJoinLeaveProject()
 {
     $user = $this->createUser();
     $user->save();
     $proj = $this->createProjectWithNewAuthor();
     $proj->save();
     $proj = $this->refreshProject($proj, $user, true);
     $this->assertEqual(true, (bool) $proj, 'Assumption that projects are default visible to any user when created.');
     $this->assertEqual(false, $proj->isUserMember($user->getPHID()), 'Arbitrary user not member of project.');
     // Join the project.
     PhabricatorProjectEditor::applyJoinProject($proj, $user);
     $proj = $this->refreshProject($proj, $user, true);
     $this->assertEqual(true, (bool) $proj);
     $this->assertEqual(true, $proj->isUserMember($user->getPHID()), 'Join works.');
     // Join the project again.
     PhabricatorProjectEditor::applyJoinProject($proj, $user);
     $proj = $this->refreshProject($proj, $user, true);
     $this->assertEqual(true, (bool) $proj);
     $this->assertEqual(true, $proj->isUserMember($user->getPHID()), 'Joining an already-joined project is a no-op.');
     // Leave the project.
     PhabricatorProjectEditor::applyLeaveProject($proj, $user);
     $proj = $this->refreshProject($proj, $user, true);
     $this->assertEqual(true, (bool) $proj);
     $this->assertEqual(false, $proj->isUserMember($user->getPHID()), 'Leave works.');
     // Leave the project again.
     PhabricatorProjectEditor::applyLeaveProject($proj, $user);
     $proj = $this->refreshProject($proj, $user, true);
     $this->assertEqual(true, (bool) $proj);
     $this->assertEqual(false, $proj->isUserMember($user->getPHID()), 'Leaving an already-left project is a no-op.');
     // If a user can't edit or join a project, joining fails.
     $proj->setEditPolicy(PhabricatorPolicies::POLICY_NOONE);
     $proj->setJoinPolicy(PhabricatorPolicies::POLICY_NOONE);
     $proj->save();
     $proj = $this->refreshProject($proj, $user, true);
     $caught = null;
     try {
         PhabricatorProjectEditor::applyJoinProject($proj, $user);
     } catch (Exception $ex) {
         $caught = $ex;
     }
     $this->assertEqual(true, $ex instanceof Exception);
     // If a user can edit a project, they can join.
     $proj->setEditPolicy(PhabricatorPolicies::POLICY_USER);
     $proj->setJoinPolicy(PhabricatorPolicies::POLICY_NOONE);
     $proj->save();
     $proj = $this->refreshProject($proj, $user, true);
     PhabricatorProjectEditor::applyJoinProject($proj, $user);
     $proj = $this->refreshProject($proj, $user, true);
     $this->assertEqual(true, $proj->isUserMember($user->getPHID()), 'Join allowed with edit permission.');
     PhabricatorProjectEditor::applyLeaveProject($proj, $user);
     // If a user can join a project, they can join, even if they can't edit.
     $proj->setEditPolicy(PhabricatorPolicies::POLICY_NOONE);
     $proj->setJoinPolicy(PhabricatorPolicies::POLICY_USER);
     $proj->save();
     $proj = $this->refreshProject($proj, $user, true);
     PhabricatorProjectEditor::applyJoinProject($proj, $user);
     $proj = $this->refreshProject($proj, $user, true);
     $this->assertEqual(true, $proj->isUserMember($user->getPHID()), 'Join allowed with join permission.');
     // A user can leave a project even if they can't edit it or join.
     $proj->setEditPolicy(PhabricatorPolicies::POLICY_NOONE);
     $proj->setJoinPolicy(PhabricatorPolicies::POLICY_NOONE);
     $proj->save();
     $proj = $this->refreshProject($proj, $user, true);
     PhabricatorProjectEditor::applyLeaveProject($proj, $user);
     $proj = $this->refreshProject($proj, $user, true);
     $this->assertEqual(false, $proj->isUserMember($user->getPHID()), 'Leave allowed without any permission.');
 }