1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2025-01-03 11:21:01 +01:00

Some owners write workflows.

This commit is contained in:
epriestley 2011-04-03 22:03:27 -07:00
parent 5038ab850c
commit 23f882a0ee
24 changed files with 730 additions and 174 deletions

View file

@ -1,6 +1,6 @@
CREATE DATABASE phabricator_owners;
CREATE TABLE phabricator_owners.onwners_package (
CREATE TABLE phabricator_owners.owners_package (
id int unsigned not null auto_increment primary key,
phid varchar(64) binary not null,
unique key(phid),
@ -23,6 +23,5 @@ CREATE TABLE phabricator_owners.owners_path (
packageID int unsigned not null,
key(packageID),
repositoryPHID varchar(64) binary not null,
path varchar(255) not null,
unique key (repositoryPHID, path)
path varchar(255) not null
);

View file

@ -63,7 +63,7 @@ celerity_register_resource_map(array(
),
'aphront-list-filter-view-css' =>
array(
'uri' => '/res/89f641c5/rsrc/css/aphront/list-filter-view.css',
'uri' => '/res/50a790ae/rsrc/css/aphront/list-filter-view.css',
'type' => 'css',
'requires' =>
array(
@ -81,7 +81,7 @@ celerity_register_resource_map(array(
),
'aphront-panel-view-css' =>
array(
'uri' => '/res/63672373/rsrc/css/aphront/panel-view.css',
'uri' => '/res/8f9f3632/rsrc/css/aphront/panel-view.css',
'type' => 'css',
'requires' =>
array(
@ -643,7 +643,7 @@ celerity_register_resource_map(array(
), array (
'packages' =>
array (
'e3ec35d7' =>
'2de9aa4e' =>
array (
'name' => 'core.pkg.css',
'symbols' =>
@ -663,7 +663,7 @@ celerity_register_resource_map(array(
12 => 'phabricator-remarkup-css',
13 => 'syntax-highlighting-css',
),
'uri' => '/res/pkg/e3ec35d7/core.pkg.css',
'uri' => '/res/pkg/2de9aa4e/core.pkg.css',
'type' => 'css',
),
'76f3c1f8' =>
@ -710,20 +710,20 @@ celerity_register_resource_map(array(
),
'reverse' =>
array (
'phabricator-core-css' => 'e3ec35d7',
'phabricator-core-buttons-css' => 'e3ec35d7',
'phabricator-standard-page-view' => 'e3ec35d7',
'aphront-dialog-view-css' => 'e3ec35d7',
'aphront-form-view-css' => 'e3ec35d7',
'aphront-panel-view-css' => 'e3ec35d7',
'aphront-side-nav-view-css' => 'e3ec35d7',
'aphront-table-view-css' => 'e3ec35d7',
'aphront-crumbs-view-css' => 'e3ec35d7',
'aphront-tokenizer-control-css' => 'e3ec35d7',
'aphront-typeahead-control-css' => 'e3ec35d7',
'phabricator-directory-css' => 'e3ec35d7',
'phabricator-remarkup-css' => 'e3ec35d7',
'syntax-highlighting-css' => 'e3ec35d7',
'phabricator-core-css' => '2de9aa4e',
'phabricator-core-buttons-css' => '2de9aa4e',
'phabricator-standard-page-view' => '2de9aa4e',
'aphront-dialog-view-css' => '2de9aa4e',
'aphront-form-view-css' => '2de9aa4e',
'aphront-panel-view-css' => '2de9aa4e',
'aphront-side-nav-view-css' => '2de9aa4e',
'aphront-table-view-css' => '2de9aa4e',
'aphront-crumbs-view-css' => '2de9aa4e',
'aphront-tokenizer-control-css' => '2de9aa4e',
'aphront-typeahead-control-css' => '2de9aa4e',
'phabricator-directory-css' => '2de9aa4e',
'phabricator-remarkup-css' => '2de9aa4e',
'syntax-highlighting-css' => '2de9aa4e',
'differential-core-view-css' => '76f3c1f8',
'differential-changeset-view-css' => '76f3c1f8',
'differential-revision-detail-css' => '76f3c1f8',

View file

@ -320,7 +320,9 @@ phutil_register_library_map(array(
'PhabricatorObjectSelectorDialog' => 'view/control/objectselector',
'PhabricatorOwnersController' => 'applications/owners/controller/base',
'PhabricatorOwnersDAO' => 'applications/owners/storage/base',
'PhabricatorOwnersDeleteController' => 'applications/owners/controller/delete',
'PhabricatorOwnersDetailController' => 'applications/owners/controller/detail',
'PhabricatorOwnersEditController' => 'applications/owners/controller/edit',
'PhabricatorOwnersListController' => 'applications/owners/controller/list',
'PhabricatorOwnersOwner' => 'applications/owners/storage/owner',
'PhabricatorOwnersPackage' => 'applications/owners/storage/package',
@ -677,7 +679,9 @@ phutil_register_library_map(array(
'PhabricatorOAuthUnlinkController' => 'PhabricatorAuthController',
'PhabricatorOwnersController' => 'PhabricatorController',
'PhabricatorOwnersDAO' => 'PhabricatorLiskDAO',
'PhabricatorOwnersDeleteController' => 'PhabricatorOwnersController',
'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController',
'PhabricatorOwnersEditController' => 'PhabricatorOwnersController',
'PhabricatorOwnersListController' => 'PhabricatorOwnersController',
'PhabricatorOwnersOwner' => 'PhabricatorOwnersDAO',
'PhabricatorOwnersPackage' => 'PhabricatorOwnersDAO',

View file

@ -260,8 +260,10 @@ class AphrontDefaultApplicationConfiguration
'/owners/' => array(
'$' => 'PhabricatorOwnersListController',
'view/(?P<view>[^/]+)/$' => 'PhabricatorOwnersListController',
'edit/(?P<id>\d+)/$' => 'PhabricatorOwnersEditController',
'new/$' => 'PhabricatorOwnersEditController',
'package/(?P<id>\d+)/$' => 'PhabricatorOwnersDetailController',
'new/$' => 'PhabricatorOwnersDetailController',
'delete/(?P<id>\d+)/$' => 'PhabricatorOwnersDeleteController',
),
);

View file

@ -47,8 +47,7 @@ class DiffusionPathCompleteController extends DiffusionController {
$drequest = DiffusionRequest::newFromAphrontRequestDictionary(
array(
'callsign' => $repository->getCallsign(),
'path' => $query_dir,
'nobranch' => true,
'path' => ':/'.$query_dir,
));
$browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest);

View file

@ -39,8 +39,7 @@ class DiffusionPathValidateController extends DiffusionController {
$drequest = DiffusionRequest::newFromAphrontRequestDictionary(
array(
'callsign' => $repository->getCallsign(),
'path' => $path,
'nobranch' => true,
'path' => ':/'.$path,
));
$browse_query = DiffusionBrowseQuery::newFromDiffusionRequest($drequest);

View file

@ -24,8 +24,8 @@ class DiffusionGitRequest extends DiffusionRequest {
$path = $this->path;
$parts = explode('/', $path);
if (empty($data['nobranch'])) {
$branch = array_shift($parts);
$branch = array_shift($parts);
if ($branch != ':') {
$this->branch = $this->decodeBranchName($branch);
}

View file

@ -20,6 +20,14 @@ class DiffusionSvnRequest extends DiffusionRequest {
private $loadedCommit;
protected function initializeFromAphrontRequestDictionary(array $data) {
parent::initializeFromAphrontRequestDictionary($data);
if (!strncmp($this->path, ':', 1)) {
$this->path = substr($this->path, 1);
$this->path = ltrim($this->path, '/');
}
}
public function getCommit() {
if ($this->commit) {
return $this->commit;

View file

@ -0,0 +1,55 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorOwnersDeleteController extends PhabricatorOwnersController {
private $id;
public function willProcessRequest(array $data) {
$this->id = $data['id'];
}
public function processRequest() {
$request = $this->getRequest();
$user = $request->getUser();
$package = id(new PhabricatorOwnersPackage())->load($this->id);
if (!$package) {
return new Aphront404Response();
}
if ($request->isDialogFormPost()) {
$package->delete();
return id(new AphrontRedirectResponse())->setURI('/owners/');
}
$dialog = id(new AphrontDialogView())
->setUser($user)
->setTitle('Really delete this package?')
->appendChild(
'<p>Are you sure you want to delete the "'.
phutil_escape_html($package->getName()).'" package? This operation '.
'can not be undone.</p>')
->addSubmitButton('Delete')
->addCancelButton('/owners/package/'.$package->getID().'/')
->setSubmitURI($request->getRequestURI());
return id(new AphrontDialogResponse())->setDialog($dialog);
}
}

View file

@ -0,0 +1,19 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'aphront/response/dialog');
phutil_require_module('phabricator', 'aphront/response/redirect');
phutil_require_module('phabricator', 'applications/owners/controller/base');
phutil_require_module('phabricator', 'applications/owners/storage/package');
phutil_require_module('phabricator', 'view/dialog');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorOwnersDeleteController.php');

View file

@ -21,132 +21,122 @@ class PhabricatorOwnersDetailController extends PhabricatorOwnersController {
private $id;
public function willProcessRequest(array $data) {
$this->id = idx($data, 'id');
$this->id = $data['id'];
}
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());
$package = id(new PhabricatorOwnersPackage())->load($this->id);
if (!$package) {
return new Aphront404Response();
}
$e_name = true;
$e_primary = true;
$paths = $package->loadPaths();
$owners = $package->loadOwners();
$token_primary_owner = array();
$token_all_owners = array();
$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;
}
$phids = array();
foreach ($paths as $path) {
$phids[$path->getRepositoryPHID()] = true;
}
foreach ($owners as $owner) {
$phids[$owner->getUserPHID()] = true;
}
$phids = array_keys($phids);
$repos = mpull($repos, 'getCallsign', 'getPHID');
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
$template = new AphrontTypeaheadTemplateView();
$template = $template->render();
$rows = array();
$rows[] = array(
'Name',
phutil_escape_html($package->getName()));
$rows[] = array(
'Description',
phutil_escape_html($package->getDescription()));
Javelin::initBehavior(
'owners-path-editor',
$primary_owner = null;
$primary_phid = $package->getPrimaryOwnerPHID();
if ($primary_phid && isset($handles[$primary_phid])) {
$primary_owner =
'<strong>'.$handles[$primary_phid]->renderLink().'</strong>';
}
$rows[] = array(
'Primary Owner',
$primary_owner,
);
$owner_links = array();
foreach ($owners as $owner) {
$owner_links[] = $handles[$owner->getUserPHID()]->renderLink();
}
$owner_links = implode('<br />', $owner_links);
$rows[] = array(
'Owners',
$owner_links);
$path_links = array();
foreach ($paths as $path) {
$callsign = $handles[$path->getRepositoryPHID()]->getName();
$repo = phutil_escape_html('r'.$callsign);
$path_link = phutil_render_tag(
'a',
array(
'href' => '/diffusion/'.$callsign.'/browse/:'.$path->getPath(),
),
phutil_escape_html($path->getPath()));
$path_links[] = $repo.' '.$path_link;
}
$path_links = implode('<br />', $path_links);
$rows[] = array(
'Paths',
$path_links);
$table = new AphrontTableView($rows);
$table->setColumnClasses(
array(
'root' => 'path-editor',
'table' => 'paths',
'add_button' => 'addpath',
'repositories' => $repos,
'input_template' => $template,
'path_refs' => array(),
'completeURI' => '/diffusion/services/path/complete/',
'validateURI' => '/diffusion/services/path/validate/',
'repositoryDefaultPaths' => $default_paths,
'header',
'wide',
));
require_celerity_resource('owners-path-editor-css');
$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_primary))
->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())
->setValue('Save Package'));
$panel = new AphrontPanelView();
$panel->setHeader($title);
$panel->setWidth(AphrontPanelView::WIDTH_WIDE);
$panel->appendChild($form);
$panel->setHeader(
'Package Details for "'.phutil_escape_html($package->getName()).'"');
$panel->addButton(
javelin_render_tag(
'a',
array(
'href' => '/owners/delete/'.$package->getID().'/',
'class' => 'button grey',
'sigil' => 'workflow',
),
'Delete Package'));
$panel->addButton(
phutil_render_tag(
'a',
array(
'href' => '/owners/edit/'.$package->getID().'/',
'class' => 'button',
),
'Edit Package'));
$panel->appendChild($table);
$nav = new AphrontSideNavView();
$nav->appendChild($panel);
$nav->addNavItem(
phutil_render_tag(
'a',
array(
'href' => '/owners/package/'.$package->getID().'/',
'class' => 'aphront-side-nav-selected',
),
'Package Details'));
return $this->buildStandardPageResponse(
$panel,
$nav,
array(
'title' => $title,
'title' => "Package '".$package->getName()."'",
));
}

View file

@ -9,14 +9,13 @@
phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'applications/owners/controller/base');
phutil_require_module('phabricator', 'applications/owners/storage/package');
phutil_require_module('phabricator', 'applications/repository/storage/repository');
phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'infrastructure/javelin/api');
phutil_require_module('phabricator', 'view/control/typeahead');
phutil_require_module('phabricator', 'view/form/base');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'infrastructure/javelin/markup');
phutil_require_module('phabricator', 'view/control/table');
phutil_require_module('phabricator', 'view/layout/panel');
phutil_require_module('phabricator', 'view/layout/sidenav');
phutil_require_module('phutil', 'markup');
phutil_require_module('phutil', 'utils');

View file

@ -0,0 +1,258 @@
<?php
/*
* Copyright 2011 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
class PhabricatorOwnersEditController extends PhabricatorOwnersController {
private $id;
public function willProcessRequest(array $data) {
$this->id = idx($data, 'id');
}
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,
));
}
}

View file

@ -0,0 +1,26 @@
<?php
/**
* This file is automatically generated. Lint this module to rebuild it.
* @generated
*/
phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'aphront/response/redirect');
phutil_require_module('phabricator', 'applications/owners/controller/base');
phutil_require_module('phabricator', 'applications/owners/storage/package');
phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'applications/repository/storage/repository');
phutil_require_module('phabricator', 'infrastructure/celerity/api');
phutil_require_module('phabricator', 'infrastructure/javelin/api');
phutil_require_module('phabricator', 'view/control/typeahead');
phutil_require_module('phabricator', 'view/form/base');
phutil_require_module('phabricator', 'view/form/control/submit');
phutil_require_module('phabricator', 'view/form/error');
phutil_require_module('phabricator', 'view/layout/panel');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorOwnersEditController.php');

View file

@ -58,18 +58,42 @@ class PhabricatorOwnersListController extends PhabricatorOwnersController {
phutil_escape_html($name)));
}
$package = new PhabricatorOwnersPackage();
switch ($this->view) {
case 'search':
$content = $this->renderPackageTable(array(), 'Search Results');
$packages = array();
$header = 'Search Results';
$nodata = 'No packages match your query.';
break;
case 'owned':
$content = $this->renderOwnedView();
$owner = new PhabricatorOwnersOwner();
$data = queryfx_all(
$package->establishConnection('r'),
'SELECT p.* FROM %T p JOIN %T o ON p.id = o.packageID
WHERE o.userPHID = %s GROUP BY p.id',
$package->getTableName(),
$owner->getTableName(),
$user->getPHID());
$packages = $package->loadAllFromArray($data);
$header = 'Owned Packages';
$nodata = 'No owned packages';
break;
case 'all':
$content = $this->renderAllView();
$packages = $package->loadAll();
$header = 'All Packages';
$nodata = 'There are no defined packages.';
break;
}
$content = $this->renderPackageTable(
$packages,
$header,
$nodata);
$filter = new AphrontListFilterView();
$filter->addButton(
phutil_render_tag(
@ -127,26 +151,68 @@ class PhabricatorOwnersListController extends PhabricatorOwnersController {
));
}
private function renderOwnedView() {
$packages = array();
private function renderPackageTable(array $packages, $header, $nodata) {
return $this->renderPackageTable($packages, 'Owned Packages');
}
if ($packages) {
$package_ids = mpull($packages, 'getID');
private function renderAllView() {
$packages = array();
$owners = id(new PhabricatorOwnersOwner())->loadAllWhere(
'packageID IN (%Ld)',
$package_ids);
return $this->renderPackageTable($packages, 'All Packages');
}
$paths = id(new PhabricatorOwnersPath())->loadAllWhere(
'packageID in (%Ld)',
$package_ids);
private function renderPackageTable(array $packages, $header) {
$phids = array();
foreach ($owners as $owner) {
$phids[$owner->getUserPHID()] = true;
}
foreach ($paths as $path) {
$phids[$path->getRepositoryPHID()] = true;
}
$phids = array_keys($phids);
$handles = id(new PhabricatorObjectHandleData($phids))->loadHandles();
$owners = mgroup($owners, 'getPackageID');
$paths = mgroup($paths, 'getPackageID');
} else {
$handles = array();
$owners = array();
$paths = array();
}
$rows = array();
foreach ($packages as $package) {
$pkg_owners = idx($owners, $package->getID(), array());
foreach ($pkg_owners as $key => $owner) {
$pkg_owners[$key] = $handles[$owner->getUserPHID()]->renderLink();
if ($owner->getUserPHID() == $package->getPrimaryOwnerPHID()) {
$pkg_owners[$key] = '<strong>'.$pkg_owners[$key].'</strong>';
}
}
$pkg_owners = implode('<br />', $pkg_owners);
$pkg_paths = idx($paths, $package->getID(), array());
foreach ($pkg_paths as $key => $path) {
$repo = $handles[$path->getRepositoryPHID()]->getName();
$pkg_paths[$key] =
'<strong>'.$repo.'</strong> '.
phutil_escape_html($path->getPath());
}
$pkg_paths = implode('<br />', $pkg_paths);
$rows[] = array(
'x',
'y',
'z',
phutil_render_tag(
'a',
array(
'href' => '/owners/package/'.$package->getID().'/',
),
phutil_escape_html($package->getName())),
$pkg_owners,
$pkg_paths,
);
}
@ -159,7 +225,7 @@ class PhabricatorOwnersListController extends PhabricatorOwnersController {
));
$table->setColumnClasses(
array(
'',
'pri',
'',
'wide wrap',
));

View file

@ -7,7 +7,11 @@
phutil_require_module('phabricator', 'applications/owners/controller/base');
phutil_require_module('phabricator', 'applications/owners/storage/owner');
phutil_require_module('phabricator', 'applications/owners/storage/package');
phutil_require_module('phabricator', 'applications/owners/storage/path');
phutil_require_module('phabricator', 'applications/phid/handle/data');
phutil_require_module('phabricator', 'storage/queryfx');
phutil_require_module('phabricator', 'view/control/table');
phutil_require_module('phabricator', 'view/form/base');
phutil_require_module('phabricator', 'view/form/control/submit');

View file

@ -24,7 +24,7 @@ class PhabricatorOwnersOwner extends PhabricatorOwnersDAO {
public function getConfiguration() {
return array(
self::CONFIG_TIMESTAMPS => false,
);
) + parent::getConfiguration();
}
}

View file

@ -23,16 +23,110 @@ class PhabricatorOwnersPackage extends PhabricatorOwnersDAO {
protected $description;
protected $primaryOwnerPHID;
private $unsavedOwners;
private $unsavedPaths;
public function getConfiguration() {
return array(
// This information is better available from the history table.
self::CONFIG_TIMESTAMPS => false,
self::CONFIG_AUX_PHID => true,
);
) + parent::getConfiguration();
}
public function generatePHID() {
return PhabricatorPHID::generateNew('OPKG');
return PhabricatorPHID::generateNewPHID('OPKG');
}
public function attachUnsavedOwners(array $owners) {
$this->unsavedOwners = $owners;
return $this;
}
public function attachUnsavedPaths(array $paths) {
$this->unsavedPaths = $paths;
return $this;
}
public function loadOwners() {
if (!$this->getID()) {
return array();
}
return id(new PhabricatorOwnersOwner())->loadAllWhere(
'packageID = %d',
$this->getID());
}
public function loadPaths() {
if (!$this->getID()) {
return array();
}
return id(new PhabricatorOwnersPath())->loadAllWhere(
'packageID = %d',
$this->getID());
}
public function save() {
// TODO: Transactions!
$ret = parent::save();
if ($this->unsavedOwners) {
$new_owners = array_fill_keys($this->unsavedOwners, true);
$cur_owners = array();
foreach ($this->loadOwners() as $owner) {
if (empty($new_owners[$owner->getUserPHID()])) {
$owner->delete();
continue;
}
$cur_owners[$owner->getUserPHID()] = true;
}
$add_owners = array_diff_key($new_owners, $cur_owners);
foreach ($add_owners as $phid => $ignored) {
$owner = new PhabricatorOwnersOwner();
$owner->setPackageID($this->getID());
$owner->setUserPHID($phid);
$owner->save();
}
unset($this->unsavedOwners);
}
if ($this->unsavedPaths) {
$new_paths = igroup($this->unsavedPaths, 'repositoryPHID', 'path');
$cur_paths = $this->loadPaths();
foreach ($cur_paths as $key => $path) {
if (empty($new_paths[$path->getRepositoryPHID()][$path->getPath()])) {
$path->delete();
unset($cur_paths[$key]);
}
}
$cur_paths = mgroup($cur_paths, 'getRepositoryPHID', 'getPath');
foreach ($new_paths as $repository_phid => $paths) {
foreach ($paths as $path => $ignored) {
if (empty($cur_paths[$repository_phid][$path])) {
$obj = new PhabricatorOwnersPath();
$obj->setPackageID($this->getID());
$obj->setRepositoryPHID($repository_phid);
$obj->setPath($path);
$obj->save();
}
}
}
unset($this->unsavedPaths);
}
return $ret;
}
public function delete() {
foreach ($this->loadOwners() as $owner) {
$owner->delete();
}
foreach ($this->loadPaths() as $path) {
$path->delete();
}
return parent::delete();
}
}

View file

@ -7,7 +7,11 @@
phutil_require_module('phabricator', 'applications/owners/storage/base');
phutil_require_module('phabricator', 'applications/owners/storage/owner');
phutil_require_module('phabricator', 'applications/owners/storage/path');
phutil_require_module('phabricator', 'applications/phid/storage/phid');
phutil_require_module('phutil', 'utils');
phutil_require_source('PhabricatorOwnersPackage.php');

View file

@ -25,7 +25,7 @@ class PhabricatorOwnersPath extends PhabricatorOwnersDAO {
public function getConfiguration() {
return array(
self::CONFIG_TIMESTAMPS => false,
);
) + parent::getConfiguration();
}
}

View file

@ -201,6 +201,28 @@ class PhabricatorObjectHandleData {
$handles[$phid] = $handle;
}
break;
case PhabricatorPHIDConstants::PHID_TYPE_REPO:
$class = 'PhabricatorRepository';
PhutilSymbolLoader::loadClass($class);
$object = newv($class, array());
$repositories = $object->loadAllWhere('phid in (%Ls)', $phids);
$repositories = mpull($repositories, null, 'getPHID');
foreach ($phids as $phid) {
$handle = new PhabricatorObjectHandle();
$handle->setPHID($phid);
$handle->setType($type);
if (empty($repositories[$phid])) {
$handle->setName('Unknown Repository');
} else {
$repository = $repositories[$phid];
$handle->setName($repository->getCallsign());
$handle->setURI('/diffusion/'.$repository->getCallsign().'/');
}
$handles[$phid] = $handle;
}
break;
default:
$loader = null;
if (isset($external_loaders[$type])) {

View file

@ -22,20 +22,25 @@ final class AphrontPanelView extends AphrontView {
const WIDTH_FORM = 'form';
const WIDTH_WIDE = 'wide';
private $createButton;
private $buttons = array();
private $header;
private $width;
public function setCreateButton($create_button, $href) {
$this->addButton(
phutil_render_tag(
'a',
array(
'href' => $href,
'class' => 'button green',
),
$create_button));
$this->createButton = phutil_render_tag(
'a',
array(
'href' => $href,
'class' => 'create-button button green',
),
$create_button);
return $this;
}
public function addButton($button) {
$this->buttons[] = $button;
return $this;
}
@ -56,10 +61,12 @@ final class AphrontPanelView extends AphrontView {
$header = null;
}
if ($this->createButton !== null) {
$button = $this->createButton;
} else {
$button = null;
$buttons = null;
if ($this->buttons) {
$buttons =
'<div class="aphront-panel-view-buttons">'.
implode(" ", $this->buttons).
'</div>';
}
$table = $this->renderChildren();
@ -73,7 +80,7 @@ final class AphrontPanelView extends AphrontView {
return
'<div class="'.implode(' ', $class).'">'.
$button.
$buttons.
$header.
$table.
'</div>';

View file

@ -6,6 +6,7 @@
background: #f6f6f6;
border-bottom: 1px solid #bbbbbb;
width: 100%;
margin-bottom: 2em;
}
.aphront-list-filter-view-buttons {
@ -24,7 +25,7 @@
.aphront-list-filter-view-controls .aphront-form-view {
border-width: 0;
padding: 0 0 6px;
padding: 12px 0 6px;
}
.aphront-list-filter-view-controls .aphront-form-view .aphront-form-label {

View file

@ -17,7 +17,7 @@
padding: 2px 0 8px;
}
.aphront-panel-view a.create-button {
.aphront-panel-view-buttons {
float: right;
}