private function buildJoinsClause($conn_r)
 {
     $affil_table = new PhabricatorProjectAffiliation();
     $joins = array();
     if ($this->owners) {
         $joins[] = qsprintf($conn_r, 'JOIN %T owner ON owner.projectPHID = p.phid AND owner.isOwner = 1
       AND owner.userPHID in (%Ls)', $affil_table->getTableName(), $this->owners);
     }
     if ($this->members) {
         $joins[] = qsprintf($conn_r, 'JOIN %T member ON member.projectPHID = p.phid
       AND member.userPHID in (%Ls)', $affil_table->getTableName(), $this->members);
     }
     return implode(' ', $joins);
 }
 public function processRequest()
 {
     $projects = id(new PhabricatorProject())->loadAllWhere('1 = 1 ORDER BY id DESC limit 100');
     $project_phids = mpull($projects, 'getPHID');
     $profiles = array();
     if ($projects) {
         $profiles = id(new PhabricatorProjectProfile())->loadAllWhere('projectPHID in (%Ls)', $project_phids);
         $profiles = mpull($profiles, null, 'getProjectPHID');
     }
     $affil_groups = array();
     if ($projects) {
         $affil_groups = PhabricatorProjectAffiliation::loadAllForProjectPHIDs($project_phids);
     }
     $author_phids = mpull($projects, 'getAuthorPHID');
     $handles = id(new PhabricatorObjectHandleData($author_phids))->loadHandles();
     $query = id(new ManiphestTaskQuery())->withProjects($project_phids)->withAnyProject(true)->withStatus(ManiphestTaskQuery::STATUS_OPEN)->setLimit(PHP_INT_MAX);
     $tasks = $query->execute();
     $groups = array();
     foreach ($tasks as $task) {
         foreach ($task->getProjectPHIDs() as $phid) {
             $groups[$phid][] = $task;
         }
     }
     $rows = array();
     foreach ($projects as $project) {
         $phid = $project->getPHID();
         $profile = $profiles[$phid];
         $affiliations = $affil_groups[$phid];
         $group = idx($groups, $phid, array());
         $task_count = count($group);
         $population = count($affiliations);
         $status = PhabricatorProjectStatus::getNameForStatus($project->getStatus());
         $blurb = $profile->getBlurb();
         $blurb = phutil_utf8_shorten($blurb, $columns = 100);
         $rows[] = array(phutil_escape_html($project->getName()), phutil_escape_html($blurb), $handles[$project->getAuthorPHID()]->renderLink(), phutil_escape_html($population), phutil_escape_html($status), phutil_render_tag('a', array('href' => '/maniphest/view/all/?projects=' . $phid), phutil_escape_html($task_count)), phutil_render_tag('a', array('class' => 'small grey button', 'href' => '/project/view/' . $project->getID() . '/'), 'View Project Profile'));
     }
     $table = new AphrontTableView($rows);
     $table->setHeaders(array('Project', 'Description', 'Mastermind', 'Population', 'Status', 'Open Tasks', ''));
     $table->setColumnClasses(array('pri', 'wide', '', 'right', '', 'right', 'action'));
     $panel = new AphrontPanelView();
     $panel->appendChild($table);
     $panel->setHeader('Project');
     $panel->setCreateButton('Create New Project', '/project/create/');
     return $this->buildStandardPageResponse($panel, array('title' => 'Projects'));
 }
 public function loadAffiliations()
 {
     $affils = PhabricatorProjectAffiliation::loadAllForProjectPHIDs(array($this->getPHID()));
     return $affils[$this->getPHID()];
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $project = id(new PhabricatorProject())->load($this->id);
     if (!$project) {
         return new Aphront404Response();
     }
     $affiliation = id(new PhabricatorProjectAffiliation())->loadOneWhere('projectPHID = %s AND userPHID = %s', $project->getPHID(), $user->getPHID());
     if (!$affiliation) {
         $affiliation = new PhabricatorProjectAffiliation();
         $affiliation->setUserPHID($user->getPHID());
         $affiliation->setProjectPHID($project->getPHID());
     }
     if ($request->isFormPost()) {
         $affiliation->setRole($request->getStr('role'));
         if (!strlen($affiliation->getRole())) {
             if ($affiliation->getID()) {
                 if ($affiliation->getIsOwner()) {
                     $affiliation->setRole('Owner');
                     $affiliation->save();
                 } else {
                     $affiliation->delete();
                 }
             }
         } else {
             $affiliation->save();
         }
         return id(new AphrontRedirectResponse())->setURI('/project/view/' . $project->getID() . '/');
     }
     $form = new AphrontFormView();
     $form->setUser($user)->setAction('/project/affiliation/' . $project->getID() . '/')->appendChild(id(new AphrontFormTextControl())->setLabel('Role')->setName('role')->setValue($affiliation->getRole()))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton('/project/view/' . $project->getID() . '/')->setValue('Save'));
     $panel = new AphrontPanelView();
     $panel->setHeader('Edit Project Affiliation');
     $panel->setWidth(AphrontPanelView::WIDTH_FORM);
     $panel->appendChild($form);
     return $this->buildStandardPageResponse($panel, array('title' => 'Edit Project Affiliation'));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $nav = new AphrontSideNavFilterView();
     $nav->setBaseURI(new PhutilURI('/project/filter/'))->addLabel('User')->addFilter('active', 'Active')->addFilter('owned', 'Owned')->addSpacer()->addLabel('All')->addFilter('all', 'All Projects');
     $this->filter = $nav->selectFilter($this->filter, 'active');
     $pager = new AphrontPagerView();
     $pager->setPageSize(250);
     $pager->setURI($request->getRequestURI(), 'page');
     $pager->setOffset($request->getInt('page'));
     $query = new PhabricatorProjectQuery();
     $query->setOffset($pager->getOffset());
     $query->setLimit($pager->getPageSize() + 1);
     $view_phid = $request->getUser()->getPHID();
     switch ($this->filter) {
         case 'active':
             $table_header = 'Active Projects';
             $query->setMembers(array($view_phid));
             break;
         case 'owned':
             $table_header = 'Owned Projects';
             $query->setOwners(array($view_phid));
             break;
         case 'all':
             $table_header = 'All Projects';
             break;
     }
     $projects = $query->execute();
     $projects = $pager->sliceResults($projects);
     $project_phids = mpull($projects, 'getPHID');
     $profiles = array();
     if ($projects) {
         $profiles = id(new PhabricatorProjectProfile())->loadAllWhere('projectPHID in (%Ls)', $project_phids);
         $profiles = mpull($profiles, null, 'getProjectPHID');
     }
     $affil_groups = array();
     if ($projects) {
         $affil_groups = PhabricatorProjectAffiliation::loadAllForProjectPHIDs($project_phids);
     }
     $tasks = array();
     $groups = array();
     if ($project_phids) {
         $query = id(new ManiphestTaskQuery())->withProjects($project_phids)->withAnyProject(true)->withStatus(ManiphestTaskQuery::STATUS_OPEN)->setLimit(PHP_INT_MAX);
         $tasks = $query->execute();
         foreach ($tasks as $task) {
             foreach ($task->getProjectPHIDs() as $phid) {
                 $groups[$phid][] = $task;
             }
         }
     }
     $rows = array();
     foreach ($projects as $project) {
         $phid = $project->getPHID();
         $profile = $profiles[$phid];
         $affiliations = $affil_groups[$phid];
         $group = idx($groups, $phid, array());
         $task_count = count($group);
         $population = count($affiliations);
         $blurb = $profile->getBlurb();
         $blurb = phutil_utf8_shorten($blurb, 64);
         $rows[] = array(phutil_render_tag('a', array('href' => '/project/view/' . $project->getID() . '/'), phutil_escape_html($project->getName())), phutil_escape_html($blurb), phutil_escape_html($population), phutil_render_tag('a', array('href' => '/maniphest/view/all/?projects=' . $phid), phutil_escape_html($task_count)));
     }
     $table = new AphrontTableView($rows);
     $table->setHeaders(array('Project', 'Description', 'Population', 'Open Tasks'));
     $table->setColumnClasses(array('pri', 'wide', '', ''));
     $panel = new AphrontPanelView();
     $panel->setHeader($table_header);
     $panel->setCreateButton('Create New Project', '/project/create/');
     $panel->appendChild($table);
     $panel->appendChild($pager);
     $nav->appendChild($panel);
     return $this->buildStandardPageResponse($nav, array('title' => 'Projects'));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $project = id(new PhabricatorProject())->load($this->id);
     if (!$project) {
         return new Aphront404Response();
     }
     $profile = $project->loadProfile();
     if (empty($profile)) {
         $profile = new PhabricatorProjectProfile();
     }
     if ($project->getSubprojectPHIDs()) {
         $phids = $project->getSubprojectPHIDs();
         $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
         $subprojects = mpull($handles, 'getFullName', 'getPHID');
     } else {
         $subprojects = array();
     }
     $options = PhabricatorProjectStatus::getStatusMap();
     $affiliations = $project->loadAffiliations();
     $affiliations = mpull($affiliations, null, 'getUserPHID');
     $e_name = true;
     $errors = array();
     $state = null;
     if ($request->isFormPost()) {
         $project->setName($request->getStr('name'));
         $project->setStatus($request->getStr('status'));
         $project->setSubprojectPHIDs($request->getArr('set_subprojects'));
         $profile->setBlurb($request->getStr('blurb'));
         if (!strlen($project->getName())) {
             $e_name = 'Required';
             $errors[] = 'Project name is required.';
         } else {
             $e_name = null;
         }
         if (!empty($_FILES['image'])) {
             $err = idx($_FILES['image'], 'error');
             if ($err != UPLOAD_ERR_NO_FILE) {
                 $file = PhabricatorFile::newFromPHPUpload($_FILES['image'], array('authorPHID' => $user->getPHID()));
                 $okay = $file->isTransformableImage();
                 if ($okay) {
                     $xformer = new PhabricatorImageTransformer();
                     $xformed = $xformer->executeProfileTransform($file, $width = 280, $min_height = 140, $max_height = 420);
                     $profile->setProfileImagePHID($xformed->getPHID());
                 } else {
                     $errors[] = 'Only valid image files (jpg, jpeg, png or gif) ' . 'will be accepted.';
                 }
             }
         }
         $resources = $request->getStr('resources');
         $resources = json_decode($resources, true);
         if (!is_array($resources)) {
             throw new Exception("Project resource information was not correctly encoded in the " . "request.");
         }
         $state = array();
         foreach ($resources as $resource) {
             $user_phid = $resource['phid'];
             if (!$user_phid) {
                 continue;
             }
             if (isset($state[$user_phid])) {
                 // TODO: We should deal with this better -- the user has entered
                 // the same resource more than once.
             }
             $state[$user_phid] = array('phid' => $user_phid, 'status' => $resource['status'], 'role' => $resource['role'], 'owner' => $resource['owner']);
         }
         $all_phids = array_merge(array_keys($state), array_keys($affiliations));
         $all_phids = array_unique($all_phids);
         $delete_affiliations = array();
         $save_affiliations = array();
         foreach ($all_phids as $phid) {
             $old = idx($affiliations, $phid);
             $new = idx($state, $phid);
             if ($old && !$new) {
                 $delete_affiliations[] = $affiliations[$phid];
                 continue;
             }
             if (!$old) {
                 $affil = new PhabricatorProjectAffiliation();
                 $affil->setUserPHID($phid);
             } else {
                 $affil = $old;
             }
             $affil->setRole((string) $new['role']);
             $affil->setStatus((string) $new['status']);
             $affil->setIsOwner((int) $new['owner']);
             $save_affiliations[] = $affil;
         }
         if (!$errors) {
             $project->save();
             $profile->setProjectPHID($project->getPHID());
             $profile->save();
             foreach ($delete_affiliations as $affil) {
                 $affil->delete();
             }
             foreach ($save_affiliations as $save) {
                 $save->setProjectPHID($project->getPHID());
                 $save->save();
             }
             return id(new AphrontRedirectResponse())->setURI('/project/view/' . $project->getID() . '/');
         } else {
             $phids = array_keys($state);
             $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
             foreach ($state as $phid => $info) {
                 $state[$phid]['name'] = $handles[$phid]->getFullName();
             }
         }
     } else {
         $phids = mpull($affiliations, 'getUserPHID');
         $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
         $state = array();
         foreach ($affiliations as $affil) {
             $user_phid = $affil->getUserPHID();
             $state[] = array('phid' => $user_phid, 'name' => $handles[$user_phid]->getFullName(), 'status' => $affil->getStatus(), 'role' => $affil->getRole(), 'owner' => $affil->getIsOwner());
         }
     }
     $error_view = null;
     if ($errors) {
         $error_view = new AphrontErrorView();
         $error_view->setTitle('Form Errors');
         $error_view->setErrors($errors);
     }
     $header_name = 'Edit Project';
     $title = 'Edit Project';
     $action = '/project/edit/' . $project->getID() . '/';
     require_celerity_resource('project-edit-css');
     $form = new AphrontFormView();
     $form->setID('project-edit-form')->setUser($user)->setAction($action)->setEncType('multipart/form-data')->appendChild(id(new AphrontFormTextControl())->setLabel('Name')->setName('name')->setValue($project->getName())->setError($e_name))->appendChild(id(new AphrontFormSelectControl())->setLabel('Project Status')->setName('status')->setOptions($options)->setValue($project->getStatus()))->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Blurb')->setName('blurb')->setValue($profile->getBlurb()))->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/projects/')->setLabel('Subprojects')->setName('set_subprojects')->setValue($subprojects))->appendChild(id(new AphrontFormFileControl())->setLabel('Change Image')->setName('image'))->appendChild('<h1>Resources</h1>' . '<input type="hidden" name="resources" id="resources" />' . '<div class="aphront-form-inset">' . '<div style="float: right;">' . javelin_render_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'add-resource', 'mustcapture' => true), 'Add New Resource') . '</div>' . '<p></p>' . '<div style="clear: both;"></div>' . javelin_render_tag('table', array('sigil' => 'resources', 'class' => 'project-resource-table'), '') . '</div>')->appendChild(id(new AphrontFormSubmitControl())->addCancelButton('/project/view/' . $project->getID() . '/')->setValue('Save'));
     $template = new AphrontTokenizerTemplateView();
     $template = $template->render();
     Javelin::initBehavior('projects-resource-editor', array('root' => 'project-edit-form', 'tokenizerTemplate' => $template, 'tokenizerSource' => '/typeahead/common/users/', 'input' => 'resources', 'state' => array_values($state)));
     $panel = new AphrontPanelView();
     $panel->setHeader($header_name);
     $panel->setWidth(AphrontPanelView::WIDTH_WIDE);
     $panel->appendChild($form);
     return $this->buildStandardPageResponse(array($error_view, $panel), array('title' => $title));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     $project = id(new PhabricatorProject())->load($this->id);
     if (!$project) {
         return new Aphront404Response();
     }
     $profile = $project->loadProfile();
     if (empty($profile)) {
         $profile = new PhabricatorProjectProfile();
     }
     $img_src = $profile->loadProfileImageURI();
     if ($project->getSubprojectPHIDs()) {
         $phids = $project->getSubprojectPHIDs();
         $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
         $subprojects = mpull($handles, 'getFullName', 'getPHID');
     } else {
         $subprojects = array();
     }
     $options = PhabricatorProjectStatus::getStatusMap();
     $affiliations = $project->loadAffiliations();
     $affiliations = mpull($affiliations, null, 'getUserPHID');
     $supported_formats = PhabricatorFile::getTransformableImageFormats();
     $e_name = true;
     $e_image = null;
     $errors = array();
     $state = null;
     if ($request->isFormPost()) {
         try {
             $xactions = array();
             $xaction = new PhabricatorProjectTransaction();
             $xaction->setTransactionType(PhabricatorProjectTransactionType::TYPE_NAME);
             $xaction->setNewValue($request->getStr('name'));
             $xactions[] = $xaction;
             $xaction = new PhabricatorProjectTransaction();
             $xaction->setTransactionType(PhabricatorProjectTransactionType::TYPE_STATUS);
             $xaction->setNewValue($request->getStr('status'));
             $xactions[] = $xaction;
             $editor = new PhabricatorProjectEditor($project);
             $editor->setUser($user);
             $editor->applyTransactions($xactions);
         } catch (PhabricatorProjectNameCollisionException $ex) {
             $e_name = 'Not Unique';
             $errors[] = $ex->getMessage();
         }
         $project->setSubprojectPHIDs($request->getArr('set_subprojects'));
         $profile->setBlurb($request->getStr('blurb'));
         if (!strlen($project->getName())) {
             $e_name = 'Required';
             $errors[] = 'Project name is required.';
         } else {
             $e_name = null;
         }
         $default_image = $request->getExists('default_image');
         if ($default_image) {
             $profile->setProfileImagePHID(null);
         } else {
             if (!empty($_FILES['image'])) {
                 $err = idx($_FILES['image'], 'error');
                 if ($err != UPLOAD_ERR_NO_FILE) {
                     $file = PhabricatorFile::newFromPHPUpload($_FILES['image'], array('authorPHID' => $user->getPHID()));
                     $okay = $file->isTransformableImage();
                     if ($okay) {
                         $xformer = new PhabricatorImageTransformer();
                         $xformed = $xformer->executeThumbTransform($file, $x = 50, $y = 50);
                         $profile->setProfileImagePHID($xformed->getPHID());
                     } else {
                         $e_image = 'Not Supported';
                         $errors[] = 'This server only supports these image formats: ' . implode(', ', $supported_formats) . '.';
                     }
                 }
             }
         }
         $resources = $request->getStr('resources');
         $resources = json_decode($resources, true);
         if (!is_array($resources)) {
             throw new Exception("Project resource information was not correctly encoded in the " . "request.");
         }
         $state = array();
         foreach ($resources as $resource) {
             $user_phid = $resource['phid'];
             if (!$user_phid) {
                 continue;
             }
             if (isset($state[$user_phid])) {
                 // TODO: We should deal with this better -- the user has entered
                 // the same resource more than once.
             }
             $state[$user_phid] = array('phid' => $user_phid, 'role' => $resource['role'], 'owner' => $resource['owner']);
         }
         $all_phids = array_merge(array_keys($state), array_keys($affiliations));
         $all_phids = array_unique($all_phids);
         $delete_affiliations = array();
         $save_affiliations = array();
         foreach ($all_phids as $phid) {
             $old = idx($affiliations, $phid);
             $new = idx($state, $phid);
             if ($old && !$new) {
                 $delete_affiliations[] = $affiliations[$phid];
                 continue;
             }
             if (!$old) {
                 $affil = new PhabricatorProjectAffiliation();
                 $affil->setUserPHID($phid);
             } else {
                 $affil = $old;
             }
             $affil->setRole((string) $new['role']);
             $affil->setIsOwner((int) $new['owner']);
             $save_affiliations[] = $affil;
         }
         if (!$errors) {
             $project->save();
             $profile->setProjectPHID($project->getPHID());
             $profile->save();
             foreach ($delete_affiliations as $affil) {
                 $affil->delete();
             }
             foreach ($save_affiliations as $save) {
                 $save->setProjectPHID($project->getPHID());
                 $save->save();
             }
             return id(new AphrontRedirectResponse())->setURI('/project/view/' . $project->getID() . '/');
         } else {
             $phids = array_keys($state);
             $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
             foreach ($state as $phid => $info) {
                 $state[$phid]['name'] = $handles[$phid]->getFullName();
             }
         }
     } else {
         $phids = mpull($affiliations, 'getUserPHID');
         $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
         $state = array();
         foreach ($affiliations as $affil) {
             $user_phid = $affil->getUserPHID();
             $state[] = array('phid' => $user_phid, 'name' => $handles[$user_phid]->getFullName(), 'role' => $affil->getRole(), 'owner' => $affil->getIsOwner());
         }
     }
     $error_view = null;
     if ($errors) {
         $error_view = new AphrontErrorView();
         $error_view->setTitle('Form Errors');
         $error_view->setErrors($errors);
     }
     $header_name = 'Edit Project';
     $title = 'Edit Project';
     $action = '/project/edit/' . $project->getID() . '/';
     require_celerity_resource('project-edit-css');
     $form = new AphrontFormView();
     $form->setID('project-edit-form')->setUser($user)->setAction($action)->setEncType('multipart/form-data')->appendChild(id(new AphrontFormTextControl())->setLabel('Name')->setName('name')->setValue($project->getName())->setError($e_name))->appendChild(id(new AphrontFormSelectControl())->setLabel('Project Status')->setName('status')->setOptions($options)->setValue($project->getStatus()))->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Blurb')->setName('blurb')->setValue($profile->getBlurb()))->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/projects/')->setLabel('Subprojects')->setName('set_subprojects')->setValue($subprojects))->appendChild(id(new AphrontFormMarkupControl())->setLabel('Profile Image')->setValue(phutil_render_tag('img', array('src' => $img_src))))->appendChild(id(new AphrontFormImageControl())->setLabel('Change Image')->setName('image')->setError($e_image)->setCaption('Supported formats: ' . implode(', ', $supported_formats)))->appendChild(id(new AphrontFormInsetView())->setTitle('Resources')->setRightButton(javelin_render_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'add-resource', 'mustcapture' => true), 'Add New Resource'))->appendChild(phutil_render_tag('input', array('type' => 'hidden', 'name' => 'resources', 'id' => 'resources')))->setContent(javelin_render_tag('table', array('sigil' => 'resources', 'class' => 'project-resource-table'), '')))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton('/project/view/' . $project->getID() . '/')->setValue('Save'));
     $template = new AphrontTokenizerTemplateView();
     $template = $template->render();
     Javelin::initBehavior('projects-resource-editor', array('root' => 'project-edit-form', 'tokenizerTemplate' => $template, 'tokenizerSource' => '/typeahead/common/users/', 'input' => 'resources', 'state' => array_values($state)));
     $panel = new AphrontPanelView();
     $panel->setHeader($header_name);
     $panel->setWidth(AphrontPanelView::WIDTH_WIDE);
     $panel->appendChild($form);
     return $this->buildStandardPageResponse(array($error_view, $panel), array('title' => $title));
 }
 private function applyTransactionEffect(PhabricatorProject $project, PhabricatorProjectTransaction $xaction)
 {
     $type = $xaction->getTransactionType();
     switch ($type) {
         case PhabricatorProjectTransactionType::TYPE_NAME:
             $project->setName($xaction->getNewValue());
             $project->setPhrictionSlug($xaction->getNewValue());
             $this->validateName($project);
             break;
         case PhabricatorProjectTransactionType::TYPE_STATUS:
             $project->setStatus($xaction->getNewValue());
             break;
         case PhabricatorProjectTransactionType::TYPE_MEMBERS:
             $old = array_fill_keys($xaction->getOldValue(), true);
             $new = array_fill_keys($xaction->getNewValue(), true);
             $add = array();
             $rem = array();
             foreach ($project->getAffiliations() as $affil) {
                 if (empty($new[$affil->getUserPHID()])) {
                     $rem[] = $affil;
                 }
             }
             foreach ($new as $phid => $ignored) {
                 if (empty($old[$phid])) {
                     $affil = new PhabricatorProjectAffiliation();
                     $affil->setRole('');
                     $affil->setUserPHID($phid);
                     $add[] = $affil;
                 }
             }
             $this->addAffiliations = $add;
             $this->remAffiliations = $rem;
             break;
         default:
             throw new Exception("Unknown transaction type '{$type}'!");
     }
 }