1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-09 16:32:39 +01:00

Task -> Project assocation, file uploads

Summary:

Test Plan:

Reviewers:

CC:
This commit is contained in:
epriestley 2011-02-20 20:08:16 -08:00
parent fdd510ba17
commit 7fb9a48690
16 changed files with 211 additions and 23 deletions

View file

@ -0,0 +1,2 @@
alter table maniphest_task add projectPHIDs longblob not null;
update maniphest_task set projectPHIDs = '[]';

View file

@ -22,6 +22,7 @@ final class ManiphestTransactionType {
const TYPE_STATUS = 'status';
const TYPE_OWNER = 'reassign';
const TYPE_CCS = 'ccs';
const TYPE_PROJECTS = 'projects';
const TYPE_PRIORITY = 'priority';
const TYPE_ATTACH = 'attach';
@ -36,6 +37,8 @@ final class ManiphestTransactionType {
self::TYPE_OWNER => 'Reassign / Claim',
self::TYPE_CCS => 'Add CCs',
self::TYPE_PRIORITY => 'Change Priority',
self::TYPE_ATTACH => 'Upload File',
self::TYPE_PROJECTS => 'Associate Projects',
);
}

View file

@ -48,6 +48,9 @@ class ManiphestTaskDetailController extends ManiphestController {
foreach ($task->getCCPHIDs() as $phid) {
$phids[$phid] = true;
}
foreach ($task->getProjectPHIDs() as $phid) {
$phids[$phid] = true;
}
if ($task->getOwnerPHID()) {
$phids[$task->getOwnerPHID()] = true;
}
@ -93,6 +96,17 @@ class ManiphestTaskDetailController extends ManiphestController {
$dict['Author'] = $handles[$task->getAuthorPHID()]->renderLink();
$projects = $task->getProjectPHIDs();
if ($projects) {
$project_links = array();
foreach ($projects as $phid) {
$project_links[] = $handles[$phid]->renderLink();
}
$dict['Projects'] = implode(', ', $project_links);
} else {
$dict['Projects'] = '<em>None</em>';
}
if (idx($attached, 'DREV')) {
$revs = idx($attached, 'DREV');
$rev_links = array();
@ -103,6 +117,17 @@ class ManiphestTaskDetailController extends ManiphestController {
$dict['Revisions'] = $rev_links;
}
if (idx($attached, 'FILE')) {
$revs = idx($attached, 'FILE');
$rev_links = array();
foreach ($revs as $rev => $info) {
$rev_links[] = $handles[$rev]->renderLink();
}
$rev_links = implode(', ', $rev_links);
$dict['Files'] = $rev_links;
}
$dict['Description'] =
'<div class="maniphest-task-description">'.
'<div class="phabricator-remarkup">'.
@ -134,11 +159,6 @@ class ManiphestTaskDetailController extends ManiphestController {
$action->setClass('action-edit');
$actions[] = $action;
$action = new AphrontHeadsupActionView();
$action->setName('Upload File');
$action->setClass('action-upload unavailable');
$actions[] = $action;
$action = new AphrontHeadsupActionView();
$action->setName('Edit Differential Revisions');
$action->setClass('action-attach unavailable');
@ -188,6 +208,7 @@ class ManiphestTaskDetailController extends ManiphestController {
$comment_form
->setUser($user)
->setAction('/maniphest/transaction/save/')
->setEncType('multipart/form-data')
->addHiddenInput('taskID', $task->getID())
->appendChild(
id(new AphrontFormSelectControl())
@ -226,6 +247,20 @@ class ManiphestTaskDetailController extends ManiphestController {
->setControlID('priority')
->setControlStyle('display: none')
->setValue($task->getPriority()))
->appendChild(
id(new AphrontFormTokenizerControl())
->setLabel('Projects')
->setName('projects')
->setControlID('projects')
->setControlStyle('display: none')
->setID('projects-tokenizer')
->setDisableBehavior(true))
->appendChild(
id(new AphrontFormFileControl())
->setLabel('File')
->setName('file')
->setControlID('file')
->setControlStyle('display: none'))
->appendChild(
id(new AphrontFormTextAreaControl())
->setLabel('Comments')
@ -242,8 +277,14 @@ class ManiphestTaskDetailController extends ManiphestController {
ManiphestTransactionType::TYPE_OWNER => 'assign_to',
ManiphestTransactionType::TYPE_CCS => 'ccs',
ManiphestTransactionType::TYPE_PRIORITY => 'priority',
ManiphestTransactionType::TYPE_PROJECTS => 'projects',
ManiphestTransactionType::TYPE_ATTACH => 'file',
),
'tokenizers' => array(
ManiphestTransactionType::TYPE_PROJECTS => array(
'id' => 'projects-tokenizer',
'src' => '/typeahead/common/projects/',
),
ManiphestTransactionType::TYPE_OWNER => array(
'id' => 'assign-tokenizer',
'src' => '/typeahead/common/users/',

View file

@ -60,6 +60,8 @@ class ManiphestTaskEditController extends ManiphestController {
} else {
$task->setTitle($new_title);
$task->setDescription($new_desc);
$changes[ManiphestTransactionType::TYPE_STATUS] =
ManiphestTaskStatus::STATUS_OPEN;
}
$owner_tokenizer = $request->getArr('assigned_to');
@ -72,22 +74,25 @@ class ManiphestTaskEditController extends ManiphestController {
if (!$errors) {
$changes[ManiphestTransactionType::TYPE_STATUS] =
ManiphestTaskStatus::STATUS_OPEN;
if ($request->getInt('priority') != $task->getPriority()) {
$changes[ManiphestTransactionType::TYPE_PRIORITY] =
$request->getInt('priority');
}
if ($owner_phid) {
if ($owner_phid != $task->getOwnerPHID()) {
$changes[ManiphestTransactionType::TYPE_OWNER] = $owner_phid;
}
if ($request->getArr('cc')) {
if ($request->getArr('cc') != $task->getCCPHIDs()) {
$changes[ManiphestTransactionType::TYPE_CCS] = $request->getArr('cc');
}
if ($request->getArr('projects') != $task->getProjectPHIDs()) {
$changes[ManiphestTransactionType::TYPE_PROJECTS]
= $request->getArr('projects');
}
$template = new ManiphestTransaction();
$template->setAuthorPHID($user->getPHID());
$transactions = array();
@ -115,7 +120,8 @@ class ManiphestTaskEditController extends ManiphestController {
$phids = array_merge(
array($task->getOwnerPHID()),
$task->getCCPHIDs());
$task->getCCPHIDs(),
$task->getProjectPHIDs());
$phids = array_filter($phids);
$phids = array_unique($phids);
@ -147,6 +153,12 @@ class ManiphestTaskEditController extends ManiphestController {
$cc_value = array();
}
if ($task->getProjectPHIDs()) {
$projects_value = array_select_keys($tvalues, $task->getProjectPHIDs());
} else {
$projects_value = array();
}
if ($task->getID()) {
$cancel_uri = '/T'.$task->getID();
$button_name = 'Save Task';
@ -186,6 +198,12 @@ class ManiphestTaskEditController extends ManiphestController {
->setName('priority')
->setOptions($priority_map)
->setValue($task->getPriority()))
->appendChild(
id(new AphrontFormTokenizerControl())
->setLabel('Projects')
->setName('projects')
->setValue($projects_value)
->setDatasource('/typeahead/common/projects/'))
->appendChild(
id(new AphrontFormTextAreaControl())
->setLabel('Description')

View file

@ -46,6 +46,13 @@ class ManiphestTransactionSaveController extends ManiphestController {
$assign_to = reset($assign_to);
$transaction->setNewValue($assign_to);
break;
case ManiphestTransactionType::TYPE_PROJECTS:
$projects = $request->getArr('projects');
$projects = array_merge($projects, $task->getProjectPHIDs());
$projects = array_filter($projects);
$projects = array_unique($projects);
$transaction->setNewValue($projects);
break;
case ManiphestTransactionType::TYPE_CCS:
$ccs = $request->getArr('ccs');
$ccs = array_merge($ccs, $task->getCCPHIDs());
@ -56,6 +63,30 @@ class ManiphestTransactionSaveController extends ManiphestController {
case ManiphestTransactionType::TYPE_PRIORITY:
$transaction->setNewValue($request->getInt('priority'));
break;
case ManiphestTransactionType::TYPE_ATTACH:
// This means "attach a file" even though we store other types of data
// as 'attached'.
$phid = null;
if (!empty($_FILES['file'])) {
$err = idx($_FILES['file'], 'error');
if ($err != UPLOAD_ERR_NO_FILE) {
$file = PhabricatorFile::newFromPHPUpload($_FILES['file']);
$phid = $file->getPHID();
}
}
if ($phid) {
$new = $task->getAttached();
if (empty($new['FILE'])) {
$new['FILE'] = array();
}
$new['FILE'][$phid] = array();
}
var_dump($new);
die();
$transaction->setNewValue($new);
break;
default:
throw new Exception('unknown action');
}

View file

@ -8,6 +8,7 @@
phutil_require_module('phabricator', 'aphront/response/404');
phutil_require_module('phabricator', 'aphront/response/redirect');
phutil_require_module('phabricator', 'applications/files/storage/file');
phutil_require_module('phabricator', 'applications/maniphest/constants/transactiontype');
phutil_require_module('phabricator', 'applications/maniphest/controller/base');
phutil_require_module('phabricator', 'applications/maniphest/editor/transaction');

View file

@ -55,6 +55,9 @@ class ManiphestTransactionEditor {
case ManiphestTransactionType::TYPE_DESCRIPTION:
$old = $task->getDescription();
break;
case ManiphestTransactionType::TYPE_PROJECTS:
$old = $task->getProjectPHIDs();
break;
default:
throw new Exception('Unknown action type.');
}
@ -96,6 +99,9 @@ class ManiphestTransactionEditor {
case ManiphestTransactionType::TYPE_DESCRIPTION:
$task->setDescription($new);
break;
case ManiphestTransactionType::TYPE_PROJECTS:
$task->setProjectPHIDs($new);
break;
default:
throw new Exception('Unknown action type.');
}

View file

@ -21,7 +21,7 @@ class ManiphestTask extends ManiphestDAO {
protected $phid;
protected $authorPHID;
protected $ownerPHID;
protected $ccPHIDs;
protected $ccPHIDs = array();
protected $status;
protected $priority;
@ -30,6 +30,7 @@ class ManiphestTask extends ManiphestDAO {
protected $description;
protected $attached = array();
protected $projectPHIDs = array();
public function getConfiguration() {
return array(
@ -37,6 +38,7 @@ class ManiphestTask extends ManiphestDAO {
self::CONFIG_SERIALIZATION => array(
'ccPHIDs' => self::SERIALIZATION_JSON,
'attached' => self::SERIALIZATION_JSON,
'projectPHIDs' => self::SERIALIZATION_JSON,
),
) + parent::getConfiguration();
}

View file

@ -40,6 +40,7 @@ class ManiphestTransaction extends ManiphestDAO {
switch ($this->getTransactionType()) {
case ManiphestTransactionType::TYPE_CCS:
case ManiphestTransactionType::TYPE_PROJECTS:
foreach ($this->getOldValue() as $phid) {
$phids[] = $phid;
}

View file

@ -204,6 +204,29 @@ class ManiphestTransactionDetailView extends AphrontView {
'removed: '.$this->renderHandles($removed);
}
break;
case ManiphestTransactionType::TYPE_PROJECTS:
$added = array_diff($new, $old);
$removed = array_diff($old, $new);
if ($added && !$removed) {
$verb = 'Added Project';
if (count($added) == 1) {
$desc = 'added project '.$this->renderHandles($added);
} else {
$desc = 'added projects: '.$this->renderHandles($added);
}
} else if ($removed && !$added) {
$verb = 'Removed Project';
if (count($removed) == 1) {
$desc = 'removed project '.$this->renderHandles($removed);
} else {
$desc = 'removed projectss: '.$this->renderHandles($removed);
}
} else {
$verb = 'Changed Projects';
$desc = 'changed projects, added: '.$this->renderHandles($added).'; '.
'removed: '.$this->renderHandles($removed);
}
break;
case ManiphestTransactionType::TYPE_STATUS:
if ($new == ManiphestTaskStatus::STATUS_OPEN) {
if ($old) {
@ -240,34 +263,51 @@ class ManiphestTransactionDetailView extends AphrontView {
}
break;
case ManiphestTransactionType::TYPE_ATTACH:
$old = nonempty($old, array());
$new = nonempty($new, array());
$old_raw = nonempty($old, array());
$new_raw = nonempty($new, array());
foreach (array('DREV', 'FILE') as $type) {
$old = array_keys(idx($old_raw, $type, array()));
$new = array_keys(idx($new_raw, $type, array()));
if ($old != $new) {
break;
}
}
$old = array_keys(idx($old, 'DREV', array()));
$new = array_keys(idx($new, 'DREV', array()));
$added = array_diff($new, $old);
$removed = array_diff($old, $new);
$add_desc = $this->renderHandles($added);
$rem_desc = $this->renderHandles($removed);
switch ($type) {
case 'DREV':
$singular = 'Differential Revision';
$plural = 'Differential Revisions';
break;
case 'FILE':
$singular = 'file';
$plural = 'files';
break;
}
if ($added && !$removed) {
$verb = 'Attached';
if (count($added) == 1) {
$desc = 'attached Differential Revision: '.$add_desc;
$desc = 'attached '.$singular.': '.$add_desc;
} else {
$desc = 'attached Differential Revisions: '.$add_desc;
$desc = 'attached '.$plural.': '.$add_desc;
}
} else if ($removed && !$added) {
$verb = 'Detached';
if (count($removed) == 1) {
$desc = 'detached Differential Revision: '.$rem_desc;
$desc = 'detached '.$singular.': '.$rem_desc;
} else {
$desc = 'detached Differential Revisions: '.$rem_desc;
$desc = 'detached '.$plural.': '.$rem_desc;
}
} else {
$desc = 'changed attached Differential Revisions, added: '.$add_desc.
'removed: '.$rem_desc;
$desc = 'changed attached '.$plural.', added: '.$add_desc.
'removed: '.$rem_desc;
}
break;
default:

View file

@ -59,7 +59,10 @@ class PhabricatorObjectHandle {
}
public function getFullName() {
return $this->fullName;
if ($this->fullName !== null) {
return $this->fullName;
}
return $this->getName();
}
public function setType($type) {

View file

@ -167,12 +167,36 @@ class PhabricatorObjectHandleData {
$handles[$phid] = $handle;
}
break;
case 'PROJ':
$class = 'PhabricatorProject';
PhutilSymbolLoader::loadClass($class);
$object = newv($class, array());
$projects = $object->loadAllWhere('phid IN (%Ls)', $phids);
$projects = mpull($projects, null, 'getPHID');
foreach ($phids as $phid) {
$handle = new PhabricatorObjectHandle();
$handle->setPHID($phid);
if (empty($projects[$phid])) {
$handle->setType(self::TYPE_UNKNOWN);
$handle->setName('Unknown Project');
} else {
$project = $projects[$phid];
$handle->setType($type);
$handle->setName($project->getName());
$handle->setURI('/project/view/'.$project->getID().'/');
}
$handles[$phid] = $handle;
}
break;
default:
foreach ($phids as $phid) {
$handle = new PhabricatorObjectHandle();
$handle->setType($type);
$handle->setPHID($phid);
$handle->setName('Unknown Object');
$handle->setFullName('An Unknown Object');
$handles[$phid] = $handle;
}
break;

View file

@ -34,7 +34,7 @@ class PhabricatorProjectListController
'class' => 'small grey button',
'href' => '/project/view/'.$project->getID().'/',
),
'View Profile'),
'View Project Project Profile'),
);
}

View file

@ -27,6 +27,7 @@ class PhabricatorTypeaheadCommonDatasourceController
$need_users = false;
$need_lists = false;
$need_projs = false;
switch ($this->type) {
case 'users':
$need_users = true;
@ -35,6 +36,9 @@ class PhabricatorTypeaheadCommonDatasourceController
$need_users = true;
$need_lists = true;
break;
case 'projects':
$need_projs = true;
break;
}
$data = array();
@ -62,6 +66,17 @@ class PhabricatorTypeaheadCommonDatasourceController
}
}
if ($need_projs) {
$projs = id(new PhabricatorProject())->loadAll();
foreach ($projs as $proj) {
$data[] = array(
$proj->getName(),
'/project/view/'.$proj->getID().'/',
$proj->getPHID(),
);
}
}
return id(new AphrontAjaxResponse())
->setContent($data);
}

View file

@ -9,6 +9,7 @@
phutil_require_module('phabricator', 'aphront/response/ajax');
phutil_require_module('phabricator', 'applications/metamta/storage/mailinglist');
phutil_require_module('phabricator', 'applications/people/storage/user');
phutil_require_module('phabricator', 'applications/project/storage/project');
phutil_require_module('phabricator', 'applications/typeahead/controller/base');
phutil_require_module('phutil', 'utils');