Page MenuHomePhabricator

D18426.id44277.diff
No OneTemporary

D18426.id44277.diff

diff --git a/src/applications/search/application/PhabricatorSearchApplication.php b/src/applications/search/application/PhabricatorSearchApplication.php
--- a/src/applications/search/application/PhabricatorSearchApplication.php
+++ b/src/applications/search/application/PhabricatorSearchApplication.php
@@ -33,11 +33,18 @@
'index/(?P<phid>[^/]+)/' => 'PhabricatorSearchIndexController',
'hovercard/'
=> 'PhabricatorSearchHovercardController',
- 'edit/(?P<queryKey>[^/]+)/' => 'PhabricatorSearchEditController',
+ 'edit/' => array(
+ 'key/(?P<queryKey>[^/]+)/' => 'PhabricatorSearchEditController',
+ 'id/(?P<id>[^/]+)/' => 'PhabricatorSearchEditController',
+ ),
'default/(?P<queryKey>[^/]+)/(?P<engine>[^/]+)/'
=> 'PhabricatorSearchDefaultController',
- 'delete/(?P<queryKey>[^/]+)/(?P<engine>[^/]+)/'
- => 'PhabricatorSearchDeleteController',
+ 'delete/' => array(
+ 'key/(?P<queryKey>[^/]+)/(?P<engine>[^/]+)/'
+ => 'PhabricatorSearchDeleteController',
+ 'id/(?P<id>[^/]+)/'
+ => 'PhabricatorSearchDeleteController',
+ ),
'order/(?P<engine>[^/]+)/' => 'PhabricatorSearchOrderController',
'rel/(?P<relationshipKey>[^/]+)/(?P<sourcePHID>[^/]+)/'
=> 'PhabricatorSearchRelationshipController',
diff --git a/src/applications/search/controller/PhabricatorApplicationSearchController.php b/src/applications/search/controller/PhabricatorApplicationSearchController.php
--- a/src/applications/search/controller/PhabricatorApplicationSearchController.php
+++ b/src/applications/search/controller/PhabricatorApplicationSearchController.php
@@ -174,7 +174,7 @@
if ($run_query && !$named_query && $user->isLoggedIn()) {
$save_button = id(new PHUIButtonView())
->setTag('a')
- ->setHref('/search/edit/'.$saved_query->getQueryKey().'/')
+ ->setHref('/search/edit/key/'.$saved_query->getQueryKey().'/')
->setText(pht('Save Query'))
->setIcon('fa-floppy-o');
$submit->addButton($save_button);
@@ -377,7 +377,7 @@
private function processEditRequest() {
$parent = $this->getDelegatingController();
$request = $this->getRequest();
- $user = $request->getUser();
+ $viewer = $request->getUser();
$engine = $this->getSearchEngine();
$nav = $this->getNavigation();
@@ -387,21 +387,89 @@
$named_queries = $engine->loadAllNamedQueries();
- $list_id = celerity_generate_unique_node_id();
+ $can_global = $viewer->getIsAdmin();
+
+ $groups = array(
+ 'personal' => array(
+ 'name' => pht('Personal Saved Queries'),
+ 'items' => array(),
+ 'edit' => true,
+ ),
+ 'global' => array(
+ 'name' => pht('Global Saved Queries'),
+ 'items' => array(),
+ 'edit' => $can_global,
+ ),
+ );
- $list = new PHUIObjectItemListView();
- $list->setUser($user);
- $list->setID($list_id);
+ foreach ($named_queries as $named_query) {
+ if ($named_query->isGlobal()) {
+ $group = 'global';
+ } else {
+ $group = 'personal';
+ }
- Javelin::initBehavior(
- 'search-reorder-queries',
- array(
- 'listID' => $list_id,
- 'orderURI' => '/search/order/'.get_class($engine).'/',
- ));
+ $groups[$group]['items'][] = $named_query;
+ }
$default_key = $engine->getDefaultQueryKey();
+ $lists = array();
+ foreach ($groups as $group) {
+ $lists[] = $this->newQueryListView(
+ $group['name'],
+ $group['items'],
+ $default_key,
+ $group['edit']);
+ }
+
+ $crumbs = $parent
+ ->buildApplicationCrumbs()
+ ->addTextCrumb(pht('Saved Queries'), $engine->getQueryManagementURI())
+ ->setBorder(true);
+
+ $nav->selectFilter('query/edit');
+
+ $header = id(new PHUIHeaderView())
+ ->setHeader(pht('Saved Queries'))
+ ->setProfileHeader(true);
+
+ $view = id(new PHUITwoColumnView())
+ ->setHeader($header)
+ ->setFooter($lists);
+
+ return $this->newPage()
+ ->setApplicationMenu($this->buildApplicationMenu())
+ ->setTitle(pht('Saved Queries'))
+ ->setCrumbs($crumbs)
+ ->setNavigation($nav)
+ ->appendChild($view);
+ }
+
+ private function newQueryListView(
+ $list_name,
+ array $named_queries,
+ $default_key,
+ $can_edit) {
+
+ $engine = $this->getSearchEngine();
+ $viewer = $this->getViewer();
+
+ $list = id(new PHUIObjectItemListView())
+ ->setViewer($viewer);
+
+ if ($can_edit) {
+ $list_id = celerity_generate_unique_node_id();
+ $list->setID($list_id);
+
+ Javelin::initBehavior(
+ 'search-reorder-queries',
+ array(
+ 'listID' => $list_id,
+ 'orderURI' => '/search/order/'.get_class($engine).'/',
+ ));
+ }
+
foreach ($named_queries as $named_query) {
$class = get_class($engine);
$key = $named_query->getQueryKey();
@@ -410,25 +478,43 @@
->setHeader($named_query->getQueryName())
->setHref($engine->getQueryResultsPageURI($key));
- if ($named_query->getIsBuiltin() && $named_query->getIsDisabled()) {
- $icon = 'fa-plus';
- $disable_name = pht('Enable');
- } else {
- $icon = 'fa-times';
- if ($named_query->getIsBuiltin()) {
- $disable_name = pht('Disable');
+ if ($named_query->getIsDisabled()) {
+ if ($can_edit) {
+ $item->setDisabled(true);
} else {
- $disable_name = pht('Delete');
+ // If an item is disabled and you don't have permission to edit it,
+ // just skip it.
+ continue;
}
}
- $item->addAction(
- id(new PHUIListItemView())
- ->setIcon($icon)
- ->setHref('/search/delete/'.$key.'/'.$class.'/')
- ->setRenderNameAsTooltip(true)
- ->setName($disable_name)
- ->setWorkflow(true));
+ if ($can_edit) {
+ if ($named_query->getIsBuiltin() && $named_query->getIsDisabled()) {
+ $icon = 'fa-plus';
+ $disable_name = pht('Enable');
+ } else {
+ $icon = 'fa-times';
+ if ($named_query->getIsBuiltin()) {
+ $disable_name = pht('Disable');
+ } else {
+ $disable_name = pht('Delete');
+ }
+ }
+
+ if ($named_query->getID()) {
+ $disable_href = '/search/delete/id/'.$named_query->getID().'/';
+ } else {
+ $disable_href = '/search/delete/key/'.$key.'/'.$class.'/';
+ }
+
+ $item->addAction(
+ id(new PHUIListItemView())
+ ->setIcon($icon)
+ ->setHref($disable_href)
+ ->setRenderNameAsTooltip(true)
+ ->setName($disable_name)
+ ->setWorkflow(true));
+ }
$default_disabled = $named_query->getIsDisabled();
$default_icon = 'fa-thumb-tack';
@@ -448,31 +534,29 @@
->setWorkflow(true)
->setDisabled($default_disabled));
- if ($named_query->getIsBuiltin()) {
- $edit_icon = 'fa-lock lightgreytext';
- $edit_disabled = true;
- $edit_name = pht('Builtin');
- $edit_href = null;
- } else {
- $edit_icon = 'fa-pencil';
- $edit_disabled = false;
- $edit_name = pht('Edit');
- $edit_href = '/search/edit/'.$key.'/';
- }
-
- $item->addAction(
- id(new PHUIListItemView())
- ->setIcon($edit_icon)
- ->setHref($edit_href)
- ->setRenderNameAsTooltip(true)
- ->setName($edit_name)
- ->setDisabled($edit_disabled));
+ if ($can_edit) {
+ if ($named_query->getIsBuiltin()) {
+ $edit_icon = 'fa-lock lightgreytext';
+ $edit_disabled = true;
+ $edit_name = pht('Builtin');
+ $edit_href = null;
+ } else {
+ $edit_icon = 'fa-pencil';
+ $edit_disabled = false;
+ $edit_name = pht('Edit');
+ $edit_href = '/search/edit/id/'.$named_query->getID().'/';
+ }
- if ($named_query->getIsDisabled()) {
- $item->setDisabled(true);
+ $item->addAction(
+ id(new PHUIListItemView())
+ ->setIcon($edit_icon)
+ ->setHref($edit_href)
+ ->setRenderNameAsTooltip(true)
+ ->setName($edit_name)
+ ->setDisabled($edit_disabled));
}
- $item->setGrippable(true);
+ $item->setGrippable($can_edit);
$item->addSigil('named-query');
$item->setMetadata(
array(
@@ -484,31 +568,10 @@
$list->setNoDataString(pht('No saved queries.'));
- $crumbs = $parent
- ->buildApplicationCrumbs()
- ->addTextCrumb(pht('Saved Queries'), $engine->getQueryManagementURI())
- ->setBorder(true);
-
- $nav->selectFilter('query/edit');
-
- $header = id(new PHUIHeaderView())
- ->setHeader(pht('Saved Queries'))
- ->setProfileHeader(true);
-
- $box = id(new PHUIObjectBoxView())
- ->setHeader($header)
- ->setObjectList($list)
- ->addClass('application-search-results');
-
- $nav->addClass('application-search-view');
- require_celerity_resource('application-search-view-css');
-
- return $this->newPage()
- ->setApplicationMenu($this->buildApplicationMenu())
- ->setTitle(pht('Saved Queries'))
- ->setCrumbs($crumbs)
- ->setNavigation($nav)
- ->appendChild($box);
+ return id(new PHUIObjectBoxView())
+ ->setHeaderText($list_name)
+ ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
+ ->setObjectList($list);
}
public function buildApplicationMenu() {
diff --git a/src/applications/search/controller/PhabricatorSearchDefaultController.php b/src/applications/search/controller/PhabricatorSearchDefaultController.php
--- a/src/applications/search/controller/PhabricatorSearchDefaultController.php
+++ b/src/applications/search/controller/PhabricatorSearchDefaultController.php
@@ -21,7 +21,11 @@
->setViewer($viewer)
->withEngineClassNames(array($engine_class))
->withQueryKeys(array($key))
- ->withUserPHIDs(array($viewer->getPHID()))
+ ->withUserPHIDs(
+ array(
+ $viewer->getPHID(),
+ PhabricatorNamedQuery::SCOPE_GLOBAL,
+ ))
->executeOne();
if (!$named_query && $engine->isBuiltinQuery($key)) {
diff --git a/src/applications/search/controller/PhabricatorSearchDeleteController.php b/src/applications/search/controller/PhabricatorSearchDeleteController.php
--- a/src/applications/search/controller/PhabricatorSearchDeleteController.php
+++ b/src/applications/search/controller/PhabricatorSearchDeleteController.php
@@ -5,30 +5,43 @@
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
- $key = $request->getURIData('queryKey');
- $engine_class = $request->getURIData('engine');
- $base_class = 'PhabricatorApplicationSearchEngine';
- if (!is_subclass_of($engine_class, $base_class)) {
- return new Aphront400Response();
- }
+ $id = $request->getURIData('id');
+ if ($id) {
+ $named_query = id(new PhabricatorNamedQueryQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$named_query) {
+ return new Aphront404Response();
+ }
- $engine = newv($engine_class, array());
- $engine->setViewer($viewer);
+ $engine = newv($named_query->getEngineClassName(), array());
+ $engine->setViewer($viewer);
- $named_query = id(new PhabricatorNamedQueryQuery())
- ->setViewer($viewer)
- ->withEngineClassNames(array($engine_class))
- ->withQueryKeys(array($key))
- ->withUserPHIDs(array($viewer->getPHID()))
- ->executeOne();
+ $key = $named_query->getQueryKey();
+ } else {
+ $key = $request->getURIData('queryKey');
+ $engine_class = $request->getURIData('engine');
- if (!$named_query && $engine->isBuiltinQuery($key)) {
- $named_query = $engine->getBuiltinQuery($key);
- }
+ $base_class = 'PhabricatorApplicationSearchEngine';
+ if (!is_subclass_of($engine_class, $base_class)) {
+ return new Aphront400Response();
+ }
+
+ $engine = newv($engine_class, array());
+ $engine->setViewer($viewer);
- if (!$named_query) {
- return new Aphront404Response();
+ if (!$engine->isBuiltinQuery($key)) {
+ return new Aphront404Response();
+ }
+
+ $named_query = $engine->getBuiltinQuery($key);
}
$builtin = null;
diff --git a/src/applications/search/controller/PhabricatorSearchEditController.php b/src/applications/search/controller/PhabricatorSearchEditController.php
--- a/src/applications/search/controller/PhabricatorSearchEditController.php
+++ b/src/applications/search/controller/PhabricatorSearchEditController.php
@@ -6,9 +6,30 @@
public function handleRequest(AphrontRequest $request) {
$viewer = $this->getViewer();
+ $id = $request->getURIData('id');
+ if ($id) {
+ $named_query = id(new PhabricatorNamedQueryQuery())
+ ->setViewer($viewer)
+ ->withIDs(array($id))
+ ->requireCapabilities(
+ array(
+ PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
+ ))
+ ->executeOne();
+ if (!$named_query) {
+ return new Aphront404Response();
+ }
+
+ $query_key = $named_query->getQueryKey();
+ } else {
+ $query_key = $request->getURIData('queryKey');
+ $named_query = null;
+ }
+
$saved_query = id(new PhabricatorSavedQueryQuery())
->setViewer($viewer)
- ->withQueryKeys(array($request->getURIData('queryKey')))
+ ->withQueryKeys(array($query_key))
->executeOne();
if (!$saved_query) {
return new Aphront404Response();
@@ -19,11 +40,6 @@
$complete_uri = $engine->getQueryManagementURI();
$cancel_uri = $complete_uri;
- $named_query = id(new PhabricatorNamedQueryQuery())
- ->setViewer($viewer)
- ->withQueryKeys(array($saved_query->getQueryKey()))
- ->withUserPHIDs(array($viewer->getPHID()))
- ->executeOne();
if (!$named_query) {
$named_query = id(new PhabricatorNamedQuery())
->setUserPHID($viewer->getPHID())
@@ -35,12 +51,27 @@
// management interface.
$cancel_uri = $engine->getQueryResultsPageURI(
$saved_query->getQueryKey());
+
+ $is_new = true;
+ } else {
+ $is_new = false;
}
+ $can_global = ($viewer->getIsAdmin() && $is_new);
+
+ $v_global = false;
+
$e_name = true;
$errors = array();
if ($request->isFormPost()) {
+ if ($can_global) {
+ $v_global = $request->getBool('global');
+ if ($v_global) {
+ $named_query->setUserPHID(PhabricatorNamedQuery::SCOPE_GLOBAL);
+ }
+ }
+
$named_query->setQueryName($request->getStr('name'));
if (!strlen($named_query->getQueryName())) {
$e_name = pht('Required');
@@ -50,6 +81,7 @@
}
if (!$errors) {
+
$named_query->save();
return id(new AphrontRedirectResponse())->setURI($complete_uri);
}
@@ -65,6 +97,18 @@
->setValue($named_query->getQueryName())
->setError($e_name));
+ if ($can_global) {
+ $form->appendChild(
+ id(new AphrontFormCheckboxControl())
+ ->addCheckbox(
+ 'global',
+ '1',
+ pht(
+ 'Save this query as a global query, making it visible to '.
+ 'all users.'),
+ $v_global));
+ }
+
$form->appendChild(
id(new AphrontFormSubmitControl())
->setValue(pht('Save Query'))
diff --git a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php
--- a/src/applications/search/engine/PhabricatorApplicationSearchEngine.php
+++ b/src/applications/search/engine/PhabricatorApplicationSearchEngine.php
@@ -474,8 +474,12 @@
if ($this->namedQueries === null) {
$named_queries = id(new PhabricatorNamedQueryQuery())
->setViewer($viewer)
- ->withUserPHIDs(array($viewer->getPHID()))
->withEngineClassNames(array(get_class($this)))
+ ->withUserPHIDs(
+ array(
+ $viewer->getPHID(),
+ PhabricatorNamedQuery::SCOPE_GLOBAL,
+ ))
->execute();
$named_queries = mpull($named_queries, null, 'getQueryKey');
@@ -494,7 +498,7 @@
unset($builtin[$key]);
}
- $named_queries = msort($named_queries, 'getSortKey');
+ $named_queries = msortv($named_queries, 'getNamedQuerySortVector');
$this->namedQueries = $named_queries;
}
@@ -631,7 +635,7 @@
$sequence = 0;
foreach ($names as $key => $name) {
$queries[$key] = id(new PhabricatorNamedQuery())
- ->setUserPHID($this->requireViewer()->getPHID())
+ ->setUserPHID(PhabricatorNamedQuery::SCOPE_GLOBAL)
->setEngineClassName(get_class($this))
->setQueryName($name)
->setQueryKey($key)
diff --git a/src/applications/search/storage/PhabricatorNamedQuery.php b/src/applications/search/storage/PhabricatorNamedQuery.php
--- a/src/applications/search/storage/PhabricatorNamedQuery.php
+++ b/src/applications/search/storage/PhabricatorNamedQuery.php
@@ -12,6 +12,8 @@
protected $isDisabled = 0;
protected $sequence = 0;
+ const SCOPE_GLOBAL = 'scope.global';
+
protected function getConfiguration() {
return array(
self::CONFIG_COLUMN_SCHEMA => array(
@@ -31,8 +33,29 @@
) + parent::getConfiguration();
}
- public function getSortKey() {
- return sprintf('~%010d%010d', $this->sequence, $this->getID());
+ public function isGlobal() {
+ if ($this->getIsBuiltin()) {
+ return true;
+ }
+
+ if ($this->getUserPHID() === self::SCOPE_GLOBAL) {
+ return true;
+ }
+
+ return false;
+ }
+
+ public function getNamedQuerySortVector() {
+ if (!$this->isGlobal()) {
+ $phase = 0;
+ } else {
+ $phase = 1;
+ }
+
+ return id(new PhutilSortVector())
+ ->addInt($phase)
+ ->addInt($this->sequence)
+ ->addInt($this->getID());
}
/* -( PhabricatorPolicyInterface )----------------------------------------- */
@@ -41,6 +64,7 @@
public function getCapabilities() {
return array(
PhabricatorPolicyCapability::CAN_VIEW,
+ PhabricatorPolicyCapability::CAN_EDIT,
);
}
@@ -49,9 +73,19 @@
}
public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
- if ($viewer->getPHID() == $this->userPHID) {
+ if ($viewer->getPHID() == $this->getUserPHID()) {
return true;
}
+
+ if ($this->isGlobal()) {
+ switch ($capability) {
+ case PhabricatorPolicyCapability::CAN_VIEW:
+ return true;
+ case PhabricatorPolicyCapability::CAN_EDIT:
+ return $viewer->getIsAdmin();
+ }
+ }
+
return false;
}

File Metadata

Mime Type
text/plain
Expires
Sun, Mar 30, 1:25 PM (3 w, 3 d ago)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7725229
Default Alt Text
D18426.id44277.diff (18 KB)

Event Timeline