private function materializeProject(PhabricatorProject $project) { if ($project->isMilestone()) { return; } $material_type = PhabricatorProjectMaterializedMemberEdgeType::EDGECONST; $member_type = PhabricatorProjectProjectHasMemberEdgeType::EDGECONST; $project_phid = $project->getPHID(); $descendants = id(new PhabricatorProjectQuery())->setViewer($this->getViewer())->withAncestorProjectPHIDs(array($project->getPHID()))->withIsMilestone(false)->withHasSubprojects(false)->execute(); $descendant_phids = mpull($descendants, 'getPHID'); if ($descendant_phids) { $source_phids = $descendant_phids; $has_subprojects = true; } else { $source_phids = array($project->getPHID()); $has_subprojects = false; } $conn_w = $project->establishConnection('w'); $project->openTransaction(); // Delete any existing materialized member edges. queryfx($conn_w, 'DELETE FROM %T WHERE src = %s AND type = %s', PhabricatorEdgeConfig::TABLE_NAME_EDGE, $project_phid, $material_type); // Copy current member edges to create new materialized edges. queryfx($conn_w, 'INSERT IGNORE INTO %T (src, type, dst, dateCreated, seq) SELECT %s, %d, dst, dateCreated, seq FROM %T WHERE src IN (%Ls) AND type = %d', PhabricatorEdgeConfig::TABLE_NAME_EDGE, $project_phid, $material_type, PhabricatorEdgeConfig::TABLE_NAME_EDGE, $source_phids, $member_type); // Update the hasSubprojects flag. queryfx($conn_w, 'UPDATE %T SET hasSubprojects = %d WHERE id = %d', $project->getTableName(), (int) $has_subprojects, $project->getID()); $project->saveTransaction(); }
public function processRequest() { $request = $this->getRequest(); $user = $request->getUser(); $project = new PhabricatorProject(); $project->setAuthorPHID($user->getPHID()); $profile = new PhabricatorProjectProfile(); $e_name = true; $errors = array(); if ($request->isFormPost()) { try { $editor = new PhabricatorProjectEditor($project); $editor->setUser($user); $editor->setName($request->getStr('name')); $editor->save(); } catch (PhabricatorProjectNameCollisionException $ex) { $e_name = 'Not Unique'; $errors[] = $ex->getMessage(); } $project->setStatus(PhabricatorProjectStatus::ONGOING); $profile->setBlurb($request->getStr('blurb')); if (!$errors) { $project->save(); $profile->setProjectPHID($project->getPHID()); $profile->save(); id(new PhabricatorProjectAffiliation())->setUserPHID($user->getPHID())->setProjectPHID($project->getPHID())->setRole('Owner')->setIsOwner(true)->save(); if ($request->isAjax()) { return id(new AphrontAjaxResponse())->setContent(array('phid' => $project->getPHID(), 'name' => $project->getName())); } else { return id(new AphrontRedirectResponse())->setURI('/project/view/' . $project->getID() . '/'); } } } $error_view = null; if ($errors) { $error_view = new AphrontErrorView(); $error_view->setTitle('Form Errors'); $error_view->setErrors($errors); } if ($request->isAjax()) { $form = new AphrontFormLayoutView(); } else { $form = new AphrontFormView(); $form->setUser($user); } $form->appendChild(id(new AphrontFormTextControl())->setLabel('Name')->setName('name')->setValue($project->getName())->setError($e_name))->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Blurb')->setName('blurb')->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT)->setValue($profile->getBlurb())); if ($request->isAjax()) { if ($error_view) { $error_view->setWidth(AphrontErrorView::WIDTH_DIALOG); } $dialog = id(new AphrontDialogView())->setUser($user)->setWidth(AphrontDialogView::WIDTH_FORM)->setTitle('Create a New Project')->appendChild($error_view)->appendChild($form)->addSubmitButton('Create Project')->addCancelButton('/project/'); return id(new AphrontDialogResponse())->setDialog($dialog); } else { $form->appendChild(id(new AphrontFormSubmitControl())->setValue('Create')->addCancelButton('/project/')); $panel = new AphrontPanelView(); $panel->setWidth(AphrontPanelView::WIDTH_FORM)->setHeader('Create a New Project')->appendChild($form); return $this->buildStandardPageResponse(array($error_view, $panel), array('title' => 'Create new Project')); } }
public static function updateProjectSubproject(PhabricatorProject $project) { $dao = new PhabricatorProjectSubproject(); $conn = $dao->establishConnection('w'); $sql = array(); foreach ($project->getSubprojectPHIDs() as $subproject_phid) { $sql[] = qsprintf($conn, '(%s, %s)', $project->getPHID(), $subproject_phid); } queryfx($conn, 'DELETE FROM %T WHERE projectPHID = %s', $dao->getTableName(), $project->getPHID()); if ($sql) { queryfx($conn, 'INSERT INTO %T (projectPHID, subprojectPHID) VALUES %Q', $dao->getTableName(), implode(', ', $sql)); } }
protected function buildLocalNavigation(PhabricatorProject $project) { $id = $project->getID(); $nav_view = new AphrontSideNavFilterView(); $uri = new PhutilURI('/project/view/' . $id . '/'); $nav_view->setBaseURI($uri); $external_arrow = "↗"; $tasks_uri = '/maniphest/view/all/?projects=' . $project->getPHID(); $slug = PhabricatorSlug::normalize($project->getName()); $phriction_uri = '/w/projects/' . $slug; $edit_uri = '/project/edit/' . $id . '/'; $members_uri = '/project/members/' . $id . '/'; $nav_view->addFilter('dashboard', 'Dashboard'); $nav_view->addSpacer(); $nav_view->addFilter('feed', 'Feed'); $nav_view->addFilter(null, 'Tasks ' . $external_arrow, $tasks_uri); $nav_view->addFilter(null, 'Wiki ' . $external_arrow, $phriction_uri); $nav_view->addFilter('people', 'People'); $nav_view->addFilter('about', 'About'); $user = $this->getRequest()->getUser(); $can_edit = PhabricatorPolicyCapability::CAN_EDIT; $nav_view->addSpacer(); if (PhabricatorPolicyFilter::hasCapability($user, $project, $can_edit)) { $nav_view->addFilter('edit', "Edit Project…", $edit_uri); $nav_view->addFilter('members', "Edit Members…", $members_uri); } else { $nav_view->addFilter('edit', "Edit Project…", $edit_uri, $relative = false, 'disabled'); $nav_view->addFilter('members', "Edit Members…", $members_uri, $relative = false, 'disabled'); } return $nav_view; }
private function buildPropertyListView(PhabricatorProject $project, PhabricatorActionListView $actions) { $request = $this->getRequest(); $viewer = $request->getUser(); $view = id(new PHUIPropertyListView())->setUser($viewer)->setActionList($actions); $view->addProperty(pht('Looks Like'), $viewer->renderHandle($project->getPHID())->setAsTag(true)); return $view; }
private function buildPropertyListView(PhabricatorProject $project) { $viewer = $this->getViewer(); $view = id(new PHUIPropertyListView())->setUser($viewer); $view->addProperty(pht('Looks Like'), $viewer->renderHandle($project->getPHID())->setAsTag(true)); $field_list = PhabricatorCustomField::getObjectFields($project, PhabricatorCustomField::ROLE_VIEW); $field_list->appendFieldsToPropertyList($project, $viewer, $view); return $view; }
private function renderFeedPage(PhabricatorProject $project) { $query = new PhabricatorFeedQuery(); $query->setFilterPHIDs(array($project->getPHID())); $query->setViewer($this->getRequest()->getUser()); $query->setLimit(100); $stories = $query->execute(); if (!$stories) { return pht('There are no stories about this project.'); } return $this->renderStories($stories); }
private function renderTasksPage(PhabricatorProject $project) { $user = $this->getRequest()->getUser(); $query = id(new ManiphestTaskQuery())->setViewer($user)->withAnyProjects(array($project->getPHID()))->withStatuses(ManiphestTaskStatus::getOpenStatusConstants())->setOrderBy(ManiphestTaskQuery::ORDER_PRIORITY)->setLimit(10); $tasks = $query->execute(); $phids = mpull($tasks, 'getOwnerPHID'); $phids = array_merge($phids, array_mergev(mpull($tasks, 'getProjectPHIDs'))); $phids = array_filter($phids); $handles = $this->loadViewerHandles($phids); $task_list = new ManiphestTaskListView(); $task_list->setUser($user); $task_list->setTasks($tasks); $task_list->setHandles($handles); $phid = $project->getPHID(); $view_uri = urisprintf('/maniphest/?statuses=%s&allProjects=%s#R', implode(',', ManiphestTaskStatus::getOpenStatusConstants()), $phid); $create_uri = '/maniphest/task/create/?projects=' . $phid; $icon = id(new PHUIIconView())->setIconFont('fa-list'); $button_view = id(new PHUIButtonView())->setTag('a')->setText(pht('View All'))->setHref($view_uri)->setIcon($icon); $icon_new = id(new PHUIIconView())->setIconFont('fa-plus'); $button_add = id(new PHUIButtonView())->setTag('a')->setText(pht('New Task'))->setHref($create_uri)->setIcon($icon_new); $header = id(new PHUIHeaderView())->setHeader(pht('Open Tasks'))->addActionLink($button_add)->addActionLink($button_view); $content = id(new PHUIObjectBoxView())->setHeader($header)->appendChild($task_list); return $content; }
private function removeSlugs(PhabricatorProject $project, array $slugs) { $slugs = $this->normalizeSlugs($slugs); if (!$slugs) { return; } $objects = id(new PhabricatorProjectSlug())->loadAllWhere('projectPHID = %s AND slug IN (%Ls)', $project->getPHID(), $slugs); foreach ($objects as $object) { $object->delete(); } }
private function publishTransactionStory(PhabricatorProject $project, PhabricatorProjectTransaction $xaction) { $related_phids = array($project->getPHID(), $xaction->getAuthorPHID()); id(new PhabricatorFeedStoryPublisher())->setStoryType(PhabricatorFeedStoryTypeConstants::STORY_PROJECT)->setStoryData(array('projectPHID' => $project->getPHID(), 'transactionID' => $xaction->getID(), 'type' => $xaction->getTransactionType(), 'old' => $xaction->getOldValue(), 'new' => $xaction->getNewValue()))->setStoryTime(time())->setStoryAuthorPHID($xaction->getAuthorPHID())->setRelatedPHIDs($related_phids)->publish(); }
private function renderDefaultForm(PhabricatorProject $project) { $viewer = $this->getViewer(); $compose_color = $project->getDisplayIconComposeColor(); $compose_icon = $project->getDisplayIconComposeIcon(); $default_builtin = id(new PhabricatorFilesComposeIconBuiltinFile())->setColor($compose_color)->setIcon($compose_icon); $file_builtins = PhabricatorFile::loadBuiltins($viewer, array($default_builtin)); $file_builtin = head($file_builtins); $default_button = javelin_tag('button', array('class' => 'grey profile-image-button', 'sigil' => 'has-tooltip', 'meta' => array('tip' => pht('Use Icon and Color'), 'size' => 300)), phutil_tag('img', array('height' => 50, 'width' => 50, 'src' => $file_builtin->getBestURI()))); $inputs = array('projectPHID' => $project->getPHID(), 'icon' => $compose_icon, 'color' => $compose_color); foreach ($inputs as $key => $value) { $inputs[$key] = javelin_tag('input', array('type' => 'hidden', 'name' => $key, 'value' => $value)); } $default_form = phabricator_form($viewer, array('class' => 'profile-image-form', 'method' => 'POST', 'action' => '/file/compose/'), array($inputs, $default_button)); return $default_form; }
public function buildSprintIconNavView(PhabricatorProject $project) { $viewer = $this->getViewer(); $id = $project->getID(); $picture = $project->getProfileImageURI(); $name = $project->getName(); $enable_phragile = PhabricatorEnv::getEnvConfig('sprint.enable-phragile'); $phragile_base_uri = PhabricatorEnv::getEnvConfig('sprint.phragile-uri'); $phragile_uri = new PhutilURI($phragile_base_uri . $id); $columns = id(new PhabricatorProjectColumnQuery())->setViewer($viewer)->withProjectPHIDs(array($project->getPHID()))->execute(); if ($columns) { $board_icon = 'fa-columns'; } else { $board_icon = 'fa-columns grey'; } $nav = new AphrontSideNavFilterView(); $nav->setIconNav(true); if ($this->isSprint($project) !== false) { $nav->setBaseURI(new PhutilURI($this->getApplicationURI())); $nav->addIcon("profile/{$id}/", $name, null, $picture, null); $nav->addIcon("burn/{$id}/", pht('Burndown'), 'fa-fire', null, null); if ($enable_phragile) { $nav->addIcon("sprints/{$id}/", pht('Phragile'), 'fa-pie-chart', null, $phragile_uri); } $nav->addIcon("board/{$id}/", pht('Sprint Board'), $board_icon, null, null); $nav->addIcon('.', pht('Sprint List'), 'fa-bar-chart', null, null); } else { $nav->setBaseURI(new PhutilURI($this->getProjectsURI())); $nav->addIcon("profile/{$id}/", $name, null, $picture); $nav->addIcon("board/{$id}/", pht('Workboard'), $board_icon); } $class = 'PhabricatorManiphestApplication'; if (PhabricatorApplication::isClassInstalledForViewer($class, $viewer)) { $phid = $project->getPHID(); $query_uri = urisprintf('/maniphest/?statuses=open()&projects=%s#R', $phid); $nav->addIcon(null, pht('Open Tasks'), 'fa-anchor', null, $query_uri); } $nav->addIcon("feed/{$id}/", pht('Feed'), 'fa-newspaper-o', null, null); $nav->addIcon("members/{$id}/", pht('Members'), 'fa-group', null, null); $nav->addIcon("details/{$id}/", pht('Edit Details'), 'fa-pencil', null, null); return $nav; }
private function createProject(PhabricatorUser $user, PhabricatorProject $parent = null, $is_milestone = false) { $project = PhabricatorProject::initializeNewProject($user); $name = pht('Test Project %d', mt_rand()); $xactions = array(); $xactions[] = id(new PhabricatorProjectTransaction())->setTransactionType(PhabricatorProjectTransaction::TYPE_NAME)->setNewValue($name); if ($parent) { if ($is_milestone) { $xactions[] = id(new PhabricatorProjectTransaction())->setTransactionType(PhabricatorProjectTransaction::TYPE_MILESTONE)->setNewValue($parent->getPHID()); } else { $xactions[] = id(new PhabricatorProjectTransaction())->setTransactionType(PhabricatorProjectTransaction::TYPE_PARENT)->setNewValue($parent->getPHID()); } } $this->applyTransactions($project, $user, $xactions); return $project; }
private function buildInitializeContent(PhabricatorProject $project) { $request = $this->getRequest(); $viewer = $this->getViewer(); $type = $request->getStr('initialize-type'); $id = $project->getID(); $profile_uri = $this->getApplicationURI("profile/{$id}/"); $board_uri = $this->getApplicationURI("board/{$id}/"); $import_uri = $this->getApplicationURI("board/{$id}/import/"); $set_default = $request->getBool('default'); if ($set_default) { $this->getProfilePanelEngine()->adjustDefault(PhabricatorProject::PANEL_WORKBOARD); } if ($request->isFormPost()) { if ($type == 'backlog-only') { $column = PhabricatorProjectColumn::initializeNewColumn($viewer)->setSequence(0)->setProperty('isDefault', true)->setProjectPHID($project->getPHID())->save(); $project->setHasWorkboard(1)->save(); return id(new AphrontRedirectResponse())->setURI($board_uri); } else { return id(new AphrontRedirectResponse())->setURI($import_uri); } } $new_selector = id(new AphrontFormRadioButtonControl())->setLabel(pht('Columns'))->setName('initialize-type')->setValue('backlog-only')->addButton('backlog-only', pht('New Empty Board'), pht('Create a new board with just a backlog column.'))->addButton('import', pht('Import Columns'), pht('Import board columns from another project.')); $default_checkbox = id(new AphrontFormCheckboxControl())->setLabel(pht('Make Default'))->addCheckbox('default', 1, pht('Make the workboard the default view for this project.'), true); $form = id(new AphrontFormView())->setUser($viewer)->appendRemarkupInstructions(pht('The workboard for this project has not been created yet.'))->appendControl($new_selector)->appendControl($default_checkbox)->appendControl(id(new AphrontFormSubmitControl())->addCancelButton($profile_uri)->setValue(pht('Create Workboard'))); $box = id(new PHUIObjectBoxView())->setHeaderText(pht('Create Workboard'))->setForm($form); return $box; }
private function buildSubprojectList(PhabricatorProject $project) { if (!$project->getHasSubprojects()) { return null; } $viewer = $this->getViewer(); $id = $project->getID(); $limit = 25; $subprojects = id(new PhabricatorProjectQuery())->setViewer($viewer)->withParentProjectPHIDs(array($project->getPHID()))->needImages(true)->withStatuses(array(PhabricatorProjectStatus::STATUS_ACTIVE))->withIsMilestone(false)->setLimit($limit)->execute(); if (!$subprojects) { return null; } $subproject_list = id(new PhabricatorProjectListView())->setUser($viewer)->setProjects($subprojects)->renderList(); $view_all = id(new PHUIButtonView())->setTag('a')->setIcon(id(new PHUIIconView())->setIcon('fa-list-ul'))->setText(pht('View All'))->setHref("/project/subprojects/{$id}/"); $header = id(new PHUIHeaderView())->setHeader(pht('Subprojects'))->addActionLink($view_all); return id(new PHUIObjectBoxView())->setHeader($header)->setBackground(PHUIBoxView::GREY)->setObjectList($subproject_list); }
protected function buildProjectInfoDictionary(PhabricatorProject $project) { $results = $this->buildProjectInfoDictionaries(array($project)); return idx($results, $project->getPHID()); }
private function renderTasksPage(PhabricatorProject $project, PhabricatorProjectProfile $profile) { $query = id(new ManiphestTaskQuery())->withProjects(array($project->getPHID()))->withStatus(ManiphestTaskQuery::STATUS_OPEN)->setOrderBy(ManiphestTaskQuery::ORDER_PRIORITY)->setLimit(10)->setCalculateRows(true); $tasks = $query->execute(); $count = $query->getRowCount(); $phids = mpull($tasks, 'getOwnerPHID'); $phids = array_filter($phids); $handles = id(new PhabricatorObjectHandleData($phids))->loadHandles(); $task_views = array(); foreach ($tasks as $task) { $view = id(new ManiphestTaskSummaryView())->setTask($task)->setHandles($handles)->setUser($this->getRequest()->getUser()); $task_views[] = $view->render(); } if (empty($tasks)) { $task_views = '<em>No open tasks.</em>'; } else { $task_views = implode('', $task_views); } $open = number_format($count); $more_link = phutil_render_tag('a', array('href' => '/maniphest/view/all/?projects=' . $project->getPHID()), "View All Open Tasks »"); $content = '<div class="phabricator-profile-info-group"> <h1 class="phabricator-profile-info-header">' . "Open Tasks ({$open})" . '</h1>' . '<div class="phabricator-profile-info-pane">' . $task_views . '<div class="phabricator-profile-info-pane-more-link">' . $more_link . '</div>' . '</div> </div>'; return $content; }
private function isProjectSilenced(PhabricatorProject $project) { $viewer = $this->getViewer(); $viewer_phid = $viewer->getPHID(); if (!$viewer_phid) { return false; } $edge_type = PhabricatorProjectSilencedEdgeType::EDGECONST; $silenced = PhabricatorEdgeQuery::loadDestinationPHIDs($project->getPHID(), $edge_type); $silenced = array_fuse($silenced); return isset($silenced[$viewer_phid]); }
private function removeSlugs(PhabricatorProject $project, array $slugs) { if (!$slugs) { return; } // We're going to try to delete both the literal and normalized versions // of all slugs. This allows us to destroy old slugs that are no longer // valid. foreach ($this->normalizeSlugs($slugs) as $slug) { $slugs[] = $slug; } $objects = id(new PhabricatorProjectSlug())->loadAllWhere('projectPHID = %s AND slug IN (%Ls)', $project->getPHID(), $slugs); foreach ($objects as $object) { $object->delete(); } }
private function createProject(PhabricatorUser $user, PhabricatorProject $parent = null, $is_milestone = false) { $project = PhabricatorProject::initializeNewProject($user); $name = pht('Test Project %d', mt_rand()); $xactions = array(); $xactions[] = id(new PhabricatorProjectTransaction())->setTransactionType(PhabricatorProjectTransaction::TYPE_NAME)->setNewValue($name); if ($parent) { if ($is_milestone) { $xactions[] = id(new PhabricatorProjectTransaction())->setTransactionType(PhabricatorProjectTransaction::TYPE_MILESTONE)->setNewValue($parent->getPHID()); } else { $xactions[] = id(new PhabricatorProjectTransaction())->setTransactionType(PhabricatorProjectTransaction::TYPE_PARENT)->setNewValue($parent->getPHID()); } } $this->applyTransactions($project, $user, $xactions); // Force these values immediately; they are normally updated by the // index engine. if ($parent) { if ($is_milestone) { $parent->setHasMilestones(1)->save(); } else { $parent->setHasSubprojects(1)->save(); } } return $project; }