private function checkAuditReasons(PhabricatorRepositoryCommit $commit, PhabricatorOwnersPackage $package)
 {
     $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID());
     $reasons = array();
     if ($data->getCommitDetail('vsDiff')) {
         $reasons[] = pht('Changed After Revision Was Accepted');
     }
     $commit_author_phid = $data->getCommitDetail('authorPHID');
     if (!$commit_author_phid) {
         $reasons[] = pht('Commit Author Not Recognized');
     }
     $revision_id = $data->getCommitDetail('differential.revisionID');
     $revision_author_phid = null;
     $commit_reviewedby_phid = null;
     if ($revision_id) {
         $revision = id(new DifferentialRevisionQuery())->setViewer(PhabricatorUser::getOmnipotentUser())->withIDs(array($revision_id))->executeOne();
         if ($revision) {
             $revision_author_phid = $revision->getAuthorPHID();
             $commit_reviewedby_phid = $data->getCommitDetail('reviewerPHID');
             if ($revision_author_phid !== $commit_author_phid) {
                 $reasons[] = pht('Author Not Matching with Revision');
             }
         } else {
             $reasons[] = pht('Revision Not Found');
         }
     } else {
         $reasons[] = pht('No Revision Specified');
     }
     $owners_phids = PhabricatorOwnersOwner::loadAffiliatedUserPHIDs(array($package->getID()));
     if (!($commit_author_phid && in_array($commit_author_phid, $owners_phids) || $commit_reviewedby_phid && in_array($commit_reviewedby_phid, $owners_phids))) {
         $reasons[] = pht('Owners Not Involved');
     }
     return $reasons;
 }
 private function checkAuditReasons(PhabricatorRepositoryCommit $commit, PhabricatorOwnersPackage $package, $author_phid, $revision)
 {
     $owner_phids = PhabricatorOwnersOwner::loadAffiliatedUserPHIDs(array($package->getID()));
     $owner_phids = array_fuse($owner_phids);
     $reasons = array();
     if (!$author_phid) {
         $reasons[] = pht('Commit Author Not Recognized');
     } else {
         if (isset($owner_phids[$author_phid])) {
             return $reasons;
         }
     }
     if (!$revision) {
         $reasons[] = pht('No Revision Specified');
         return $reasons;
     }
     $accepted_statuses = array(DifferentialReviewerStatus::STATUS_ACCEPTED, DifferentialReviewerStatus::STATUS_ACCEPTED_OLDER);
     $accepted_statuses = array_fuse($accepted_statuses);
     $found_accept = false;
     foreach ($revision->getReviewerStatus() as $reviewer) {
         $reviewer_phid = $reviewer->getReviewerPHID();
         // If this reviewer isn't a package owner, just ignore them.
         if (empty($owner_phids[$reviewer_phid])) {
             continue;
         }
         // If this reviewer accepted the revision and owns the package, we're
         // all clear and do not need to trigger an audit.
         if (isset($accepted_statuses[$reviewer->getStatus()])) {
             $found_accept = true;
             break;
         }
     }
     if (!$found_accept) {
         $reasons[] = pht('Owners Not Involved');
     }
     return $reasons;
 }
 private function checkAuditReasons(PhabricatorRepositoryCommit $commit, PhabricatorOwnersPackage $package)
 {
     $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID());
     $reasons = array();
     if ($data->getCommitDetail('vsDiff')) {
         $reasons[] = 'Changed After Revision Was Accepted';
     }
     $commit_author_phid = $data->getCommitDetail('authorPHID');
     if (!$commit_author_phid) {
         $reasons[] = 'Commit Author Not Recognized';
     }
     $revision_id = $data->getCommitDetail('differential.revisionID');
     $revision_author_phid = null;
     $commit_reviewedby_phid = null;
     if ($revision_id) {
         // TODO: (T603) This is probably safe to use an omnipotent user on,
         // but check things more closely.
         $revision = id(new DifferentialRevision())->load($revision_id);
         if ($revision) {
             $revision_author_phid = $revision->getAuthorPHID();
             $commit_reviewedby_phid = $data->getCommitDetail('reviewerPHID');
             if ($revision_author_phid !== $commit_author_phid) {
                 $reasons[] = 'Author Not Matching with Revision';
             }
         } else {
             $reasons[] = 'Revision Not Found';
         }
     } else {
         $reasons[] = 'No Revision Specified';
     }
     $owners_phids = PhabricatorOwnersOwner::loadAffiliatedUserPHIDs(array($package->getID()));
     if (!($commit_author_phid && in_array($commit_author_phid, $owners_phids) || $commit_reviewedby_phid && in_array($commit_reviewedby_phid, $owners_phids))) {
         $reasons[] = 'Owners Not Involved';
     }
     return $reasons;
 }
 private function checkAuditReasons(PhabricatorRepositoryCommit $commit, PhabricatorOwnersPackage $package)
 {
     $data = id(new PhabricatorRepositoryCommitData())->loadOneWhere('commitID = %d', $commit->getID());
     $reasons = array();
     $commit_author_phid = $data->getCommitDetail('authorPHID');
     if (!$commit_author_phid) {
         $reasons[] = "Commit Author Not Recognized";
     }
     $revision_id = $data->getCommitDetail('differential.revisionID');
     $revision_author_phid = null;
     if ($revision_id) {
         $revision = id(new DifferentialRevision())->load($revision_id);
         if ($revision) {
             $revision->loadRelationships();
             $revision_author_phid = $revision->getAuthorPHID();
             $revision_reviewedby_phid = $revision->loadReviewedBy();
             $commit_reviewedby_phid = $data->getCommitDetail('reviewerPHID');
             if ($revision_author_phid !== $commit_author_phid) {
                 $reasons[] = "Author Not Matching with Revision";
             }
             if ($revision_reviewedby_phid !== $commit_reviewedby_phid) {
                 $reasons[] = "ReviewedBy Not Matching with Revision";
             }
         } else {
             $reasons[] = "Revision Not Found";
         }
     } else {
         $reasons[] = "No Revision Specified";
     }
     $owners = id(new PhabricatorOwnersOwner())->loadAllWhere('packageID = %d', $package->getID());
     $owners_phids = mpull($owners, 'getUserPHID');
     if (!($commit_author_phid && in_array($commit_author_phid, $owners_phids) || $revision_author_phid && in_array($revision_author_phid, $owners_phids))) {
         $reasons[] = "Owners Not Involved";
     }
     return $reasons;
 }
 private function buildPackageActionView(PhabricatorOwnersPackage $package)
 {
     $viewer = $this->getViewer();
     // TODO: Implement this capability.
     $can_edit = true;
     $id = $package->getID();
     $edit_uri = $this->getApplicationURI("/edit/{$id}/");
     $paths_uri = $this->getApplicationURI("/paths/{$id}/");
     $view = id(new PhabricatorActionListView())->setUser($viewer)->setObject($package)->addAction(id(new PhabricatorActionView())->setName(pht('Edit Package'))->setIcon('fa-pencil')->setDisabled(!$can_edit)->setWorkflow(!$can_edit)->setHref($edit_uri))->addAction(id(new PhabricatorActionView())->setName(pht('Edit Paths'))->setIcon('fa-folder-open')->setDisabled(!$can_edit)->setWorkflow(!$can_edit)->setHref($paths_uri));
     return $view;
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     if ($this->id) {
         $package = id(new PhabricatorOwnersPackage())->load($this->id);
         if (!$package) {
             return new Aphront404Response();
         }
     } else {
         $package = new PhabricatorOwnersPackage();
         $package->setPrimaryOwnerPHID($user->getPHID());
     }
     $e_name = true;
     $e_primary = true;
     $errors = array();
     if ($request->isFormPost()) {
         $package->setName($request->getStr('name'));
         $package->setDescription($request->getStr('description'));
         $old_auditing_enabled = $package->getAuditingEnabled();
         $package->setAuditingEnabled($request->getStr('auditing') === 'enabled' ? 1 : 0);
         $primary = $request->getArr('primary');
         $primary = reset($primary);
         $old_primary = $package->getPrimaryOwnerPHID();
         $package->setPrimaryOwnerPHID($primary);
         $owners = $request->getArr('owners');
         if ($primary) {
             array_unshift($owners, $primary);
         }
         $owners = array_unique($owners);
         $paths = $request->getArr('path');
         $repos = $request->getArr('repo');
         $excludes = $request->getArr('exclude');
         $path_refs = array();
         for ($ii = 0; $ii < count($paths); $ii++) {
             if (empty($paths[$ii]) || empty($repos[$ii])) {
                 continue;
             }
             $path_refs[] = array('repositoryPHID' => $repos[$ii], 'path' => $paths[$ii], 'excluded' => $excludes[$ii]);
         }
         if (!strlen($package->getName())) {
             $e_name = pht('Required');
             $errors[] = pht('Package name is required.');
         } else {
             $e_name = null;
         }
         if (!$package->getPrimaryOwnerPHID()) {
             $e_primary = pht('Required');
             $errors[] = pht('Package must have a primary owner.');
         } else {
             $e_primary = null;
         }
         if (!$path_refs) {
             $errors[] = pht('Package must include at least one path.');
         }
         if (!$errors) {
             $package->attachUnsavedOwners($owners);
             $package->attachUnsavedPaths($path_refs);
             $package->attachOldAuditingEnabled($old_auditing_enabled);
             $package->attachOldPrimaryOwnerPHID($old_primary);
             $package->attachActorPHID($user->getPHID());
             try {
                 $package->save();
                 return id(new AphrontRedirectResponse())->setURI('/owners/package/' . $package->getID() . '/');
             } catch (AphrontDuplicateKeyQueryException $ex) {
                 $e_name = pht('Duplicate');
                 $errors[] = pht('Package name must be unique.');
             }
         }
     } else {
         $owners = $package->loadOwners();
         $owners = mpull($owners, 'getUserPHID');
         $paths = $package->loadPaths();
         $path_refs = array();
         foreach ($paths as $path) {
             $path_refs[] = array('repositoryPHID' => $path->getRepositoryPHID(), 'path' => $path->getPath(), 'excluded' => $path->getExcluded());
         }
     }
     $handles = $this->loadViewerHandles($owners);
     $primary = $package->getPrimaryOwnerPHID();
     if ($primary && isset($handles[$primary])) {
         $handle_primary_owner = array($handles[$primary]);
     } else {
         $handle_primary_owner = array();
     }
     $handles_all_owners = array_select_keys($handles, $owners);
     if ($package->getID()) {
         $title = pht('Edit Package');
         $side_nav_filter = 'edit/' . $this->id;
     } else {
         $title = pht('New Package');
         $side_nav_filter = 'new';
     }
     $this->setSideNavFilter($side_nav_filter);
     $repos = id(new PhabricatorRepositoryQuery())->setViewer($user)->execute();
     $default_paths = array();
     foreach ($repos as $repo) {
         $default_path = $repo->getDetail('default-owners-path');
         if ($default_path) {
             $default_paths[$repo->getPHID()] = $default_path;
         }
     }
     $repos = mpull($repos, 'getCallsign', 'getPHID');
     $template = new AphrontTypeaheadTemplateView();
     $template = $template->render();
     Javelin::initBehavior('owners-path-editor', array('root' => 'path-editor', 'table' => 'paths', 'add_button' => 'addpath', 'repositories' => $repos, 'input_template' => $template, 'pathRefs' => $path_refs, 'completeURI' => '/diffusion/services/path/complete/', 'validateURI' => '/diffusion/services/path/validate/', 'repositoryDefaultPaths' => $default_paths));
     require_celerity_resource('owners-path-editor-css');
     $cancel_uri = $package->getID() ? '/owners/package/' . $package->getID() . '/' : '/owners/';
     $form = id(new AphrontFormView())->setUser($user)->appendChild(id(new AphrontFormTextControl())->setLabel(pht('Name'))->setName('name')->setValue($package->getName())->setError($e_name))->appendChild(id(new AphrontFormTokenizerControl())->setDatasource(new PhabricatorProjectOrUserDatasource())->setLabel(pht('Primary Owner'))->setName('primary')->setLimit(1)->setValue($handle_primary_owner)->setError($e_primary))->appendChild(id(new AphrontFormTokenizerControl())->setDatasource(new PhabricatorProjectOrUserDatasource())->setLabel(pht('Owners'))->setName('owners')->setValue($handles_all_owners))->appendChild(id(new AphrontFormSelectControl())->setName('auditing')->setLabel(pht('Auditing'))->setCaption(pht('With auditing enabled, all future commits that touch ' . 'this package will be reviewed to make sure an owner ' . 'of the package is involved and the commit message has ' . 'a valid revision, reviewed by, and author.'))->setOptions(array('disabled' => pht('Disabled'), 'enabled' => pht('Enabled')))->setValue($package->getAuditingEnabled() ? 'enabled' : 'disabled'))->appendChild(id(new AphrontFormInsetView())->setTitle(pht('Paths'))->addDivAttributes(array('id' => 'path-editor'))->setRightButton(javelin_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'addpath', 'mustcapture' => true), pht('Add New Path')))->setDescription(pht('Specify the files and directories which comprise ' . 'this package.'))->setContent(javelin_tag('table', array('class' => 'owners-path-editor-table', 'sigil' => 'paths'), '')))->appendChild(id(new AphrontFormTextAreaControl())->setLabel(pht('Description'))->setName('description')->setValue($package->getDescription()))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue(pht('Save Package')));
     $form_box = id(new PHUIObjectBoxView())->setHeaderText($title)->setFormErrors($errors)->setForm($form);
     $nav = $this->buildSideNavView();
     $nav->appendChild($form_box);
     return $this->buildApplicationPage(array($nav), array('title' => $title));
 }
 public function processRequest()
 {
     $request = $this->getRequest();
     $user = $request->getUser();
     if ($this->id) {
         $package = id(new PhabricatorOwnersPackage())->load($this->id);
         if (!$package) {
             return new Aphront404Response();
         }
     } else {
         $package = new PhabricatorOwnersPackage();
         $package->setPrimaryOwnerPHID($user->getPHID());
     }
     $e_name = true;
     $e_primary = true;
     $e_owners = true;
     $errors = array();
     if ($request->isFormPost()) {
         $package->setName($request->getStr('name'));
         $package->setDescription($request->getStr('description'));
         $primary = $request->getArr('primary');
         $primary = reset($primary);
         $package->setPrimaryOwnerPHID($primary);
         $owners = $request->getArr('owners');
         if ($primary) {
             array_unshift($owners, $primary);
         }
         $owners = array_unique($owners);
         $paths = $request->getArr('path');
         $repos = $request->getArr('repo');
         $path_refs = array();
         for ($ii = 0; $ii < count($paths); $ii++) {
             if (empty($paths[$ii]) || empty($repos[$ii])) {
                 continue;
             }
             $path_refs[] = array('repositoryPHID' => $repos[$ii], 'path' => $paths[$ii]);
         }
         if (!strlen($package->getName())) {
             $e_name = 'Required';
             $errors[] = 'Package name is required.';
         } else {
             $e_name = null;
         }
         if (!$package->getPrimaryOwnerPHID()) {
             $e_primary = 'Required';
             $errors[] = 'Package must have a primary owner.';
         } else {
             $e_primary = null;
         }
         if (!$owners) {
             $e_owners = 'Required';
             $errors[] = 'Package must have at least one owner.';
         } else {
             $e_owners = null;
         }
         if (!$path_refs) {
             $errors[] = 'Package must include at least one path.';
         }
         if (!$errors) {
             $package->attachUnsavedOwners($owners);
             $package->attachUnsavedPaths($path_refs);
             try {
                 $package->save();
                 return id(new AphrontRedirectResponse())->setURI('/owners/package/' . $package->getID() . '/');
             } catch (AphrontQueryDuplicateKeyException $ex) {
                 $e_name = 'Duplicate';
                 $errors[] = 'Package name must be unique.';
             }
         }
     } else {
         $owners = $package->loadOwners();
         $owners = mpull($owners, 'getUserPHID');
         $paths = $package->loadPaths();
         $path_refs = array();
         foreach ($paths as $path) {
             $path_refs[] = array('repositoryPHID' => $path->getRepositoryPHID(), 'path' => $path->getPath());
         }
     }
     $error_view = null;
     if ($errors) {
         $error_view = new AphrontErrorView();
         $error_view->setTitle('Package Errors');
         $error_view->setErrors($errors);
     }
     $handles = id(new PhabricatorObjectHandleData($owners))->loadHandles();
     $primary = $package->getPrimaryOwnerPHID();
     if ($primary && isset($handles[$primary])) {
         $token_primary_owner = array($primary => $handles[$primary]->getFullName());
     } else {
         $token_primary_owner = array();
     }
     $token_all_owners = array_select_keys($handles, $owners);
     $token_all_owners = mpull($token_all_owners, 'getFullName');
     $title = $package->getID() ? 'Edit Package' : 'New Package';
     $repos = id(new PhabricatorRepository())->loadAll();
     $default_paths = array();
     foreach ($repos as $repo) {
         $default_path = $repo->getDetail('default-owners-path');
         if ($default_path) {
             $default_paths[$repo->getPHID()] = $default_path;
         }
     }
     $repos = mpull($repos, 'getCallsign', 'getPHID');
     $template = new AphrontTypeaheadTemplateView();
     $template = $template->render();
     Javelin::initBehavior('owners-path-editor', array('root' => 'path-editor', 'table' => 'paths', 'add_button' => 'addpath', 'repositories' => $repos, 'input_template' => $template, 'pathRefs' => $path_refs, 'completeURI' => '/diffusion/services/path/complete/', 'validateURI' => '/diffusion/services/path/validate/', 'repositoryDefaultPaths' => $default_paths));
     require_celerity_resource('owners-path-editor-css');
     $cancel_uri = $package->getID() ? '/owners/package/' . $package->getID() . '/' : '/owners/';
     $form = id(new AphrontFormView())->setUser($user)->appendChild(id(new AphrontFormTextControl())->setLabel('Name')->setName('name')->setValue($package->getName())->setError($e_name))->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/users/')->setLabel('Primary Owner')->setName('primary')->setLimit(1)->setValue($token_primary_owner)->setError($e_primary))->appendChild(id(new AphrontFormTokenizerControl())->setDatasource('/typeahead/common/users/')->setLabel('Owners')->setName('owners')->setValue($token_all_owners)->setError($e_owners))->appendChild('<h1>Paths</h1>' . '<div class="aphront-form-inset" id="path-editor">' . '<div style="float: right;">' . javelin_render_tag('a', array('href' => '#', 'class' => 'button green', 'sigil' => 'addpath', 'mustcapture' => true), 'Add New Path') . '</div>' . '<p>Specify the files and directories which comprise this ' . 'package.</p>' . '<div style="clear: both;"></div>' . javelin_render_tag('table', array('class' => 'owners-path-editor-table', 'sigil' => 'paths'), '') . '</div>')->appendChild(id(new AphrontFormTextAreaControl())->setLabel('Description')->setName('description')->setValue($package->getDescription()))->appendChild(id(new AphrontFormSubmitControl())->addCancelButton($cancel_uri)->setValue('Save Package'));
     $panel = new AphrontPanelView();
     $panel->setHeader($title);
     $panel->setWidth(AphrontPanelView::WIDTH_WIDE);
     $panel->appendChild($error_view);
     $panel->appendChild($form);
     return $this->buildStandardPageResponse($panel, array('title' => $title));
 }
 private function renderCommitTable($data, PhabricatorOwnersPackage $package)
 {
     $commit_phids = array_keys($data);
     $loader = new PhabricatorObjectHandleData($commit_phids);
     $handles = $loader->loadHandles();
     $objects = $loader->loadObjects();
     $owners = id(new PhabricatorOwnersOwner())->loadAllWhere('packageID = %d', $package->getID());
     $owners_phids = mpull($owners, 'getUserPHID');
     if ($this->user->getIsAdmin() || in_array($this->user->getPHID(), $owners_phids)) {
         $allowed_to_audit = true;
     } else {
         $allowed_to_audit = false;
     }
     $rows = array();
     foreach ($commit_phids as $commit_phid) {
         $handle = $handles[$commit_phid];
         $object = $objects[$commit_phid];
         $commit_data = $object->getCommitData();
         $epoch = $handle->getTimeStamp();
         $date = phabricator_date($epoch, $this->user);
         $time = phabricator_time($epoch, $this->user);
         $link = phutil_render_tag('a', array('href' => $handle->getURI()), phutil_escape_html($handle->getName()));
         $row = array($link, $date, $time, phutil_escape_html($commit_data->getSummary()));
         if ($this->view === 'audit') {
             $relationship = $data[$commit_phid];
             $status_link = phutil_escape_html(idx(PhabricatorAuditStatusConstants::getStatusNameMap(), $relationship['auditStatus']));
             if ($allowed_to_audit) {
                 $status_link = phutil_render_tag('a', array('href' => sprintf('/audit/edit/?c-phid=%s&p-phid=%s', idx($relationship, 'commitPHID'), $this->packagePHID)), $status_link);
             }
             $reasons = json_decode($relationship['auditReasons'], true);
             $reasons = array_map('phutil_escape_html', $reasons);
             $reasons = implode($reasons, '<br>');
             $row = array_merge($row, array($status_link, $reasons));
         }
         $rows[] = $row;
     }
     $commit_table = new AphrontTableView($rows);
     $headers = array('Commit', 'Date', 'Time', 'Summary');
     if ($this->view === 'audit') {
         $headers = array_merge($headers, array('Audit Status', 'Audit Reasons'));
     }
     $commit_table->setHeaders($headers);
     $column_classes = array('', '', 'right', 'wide');
     if ($this->view === 'audit') {
         $column_classes = array_merge($column_classes, array('', ''));
     }
     $commit_table->setColumnClasses($column_classes);
     $list_panel = new AphrontPanelView();
     $list_panel->setHeader('Commits Related to package "' . phutil_render_tag('a', array('href' => '/owners/package/' . $package->getID() . '/'), phutil_escape_html($package->getName())) . '"' . ($this->view === 'audit' ? ' and need attention' : ''));
     $list_panel->appendChild($commit_table);
     return $list_panel;
 }