diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index 02785ac..ab8f92f 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1,20 +1,22 @@ 2, 'class' => array( 'DeepcloneApplication' => 'deepclone/application/DeepcloneApplication.php', + 'DeepcloneController' => 'deepclone/controller/DeepcloneController.php', 'DeepcloneUIEventListener' => 'deepclone/events/DeepcloneUIEventListener.php', ), 'function' => array(), 'xmap' => array( 'DeepcloneApplication' => 'PhabricatorApplication', + 'DeepcloneController' => 'ManiphestController', 'DeepcloneUIEventListener' => 'PhabricatorEventListener', ), )); diff --git a/src/deepclone/application/DeepcloneApplication.php b/src/deepclone/application/DeepcloneApplication.php index fa2c0e4..3d98440 100644 --- a/src/deepclone/application/DeepcloneApplication.php +++ b/src/deepclone/application/DeepcloneApplication.php @@ -1,13 +1,31 @@ .*?)/' => 'DeepcloneController', + ); + } + + protected function getEditRoutePattern($base = null) { + return $base.'(?:'. + '(?P[0-9]\d*)/)?'. + '(?:'. + '(?:'. + '(?Pparameters|nodefault|nocreate|nomanage|comment)/'. + '|'. + '(?:form/(?P[^/]+)/)?(?:page/(?P[^/]+)/)?'. + ')'. + ')?'; + } } diff --git a/src/deepclone/controller/DeepcloneController.php b/src/deepclone/controller/DeepcloneController.php new file mode 100644 index 0000000..2dc5555 --- /dev/null +++ b/src/deepclone/controller/DeepcloneController.php @@ -0,0 +1,189 @@ +getURIData('id'); + $viewer = $this->getViewer(); + + if (!$task_id) { + throw new Exception("Task ID: $task_id"); + return new Aphront404Response(); + } + + $task = id(new ManiphestTaskQuery()) + ->setViewer($viewer) + ->withPHIDs(array($task_id)) + ->requireCapabilities( + array( + PhabricatorPolicyCapability::CAN_VIEW, + PhabricatorPolicyCapability::CAN_EDIT, + ) + ) + ->needSubscriberPHIDs(true) + ->executeOne(); + + if (!$task) { + throw new Exception("Task ID: $task_id"); + return new Aphront404Response(); + } + + if ($request->isFormPost()) { + return $this->triggerTransaction($request, $task); + // $properties = $provider->readFormValuesFromRequest($request); + // list($errors, $issues, $properties) = $provider->processEditForm( + // $request, + // $properties); + + // $xactions = array(); + + // if (!$errors) { + // if ($is_new) { + // if (!phutil_nonempty_string($config->getProviderType())) { + // $config->setProviderType($provider->getProviderType()); + // } + // if (!phutil_nonempty_string($config->getProviderDomain())) { + // $config->setProviderDomain($provider->getProviderDomain()); + // } + // } + + // $xactions[] = id(new PhabricatorAuthProviderConfigTransaction()) + // ->setTransactionType( + // PhabricatorAuthProviderConfigTransaction::TYPE_LOGIN) + // ->setNewValue($request->getInt('allowLogin', 0)); + + // $xactions[] = id(new PhabricatorAuthProviderConfigTransaction()) + // ->setTransactionType( + // PhabricatorAuthProviderConfigTransaction::TYPE_REGISTRATION) + // ->setNewValue($request->getInt('allowRegistration', 0)); + + // $xactions[] = id(new PhabricatorAuthProviderConfigTransaction()) + // ->setTransactionType( + // PhabricatorAuthProviderConfigTransaction::TYPE_LINK) + // ->setNewValue($request->getInt('allowLink', 0)); + + // $xactions[] = id(new PhabricatorAuthProviderConfigTransaction()) + // ->setTransactionType( + // PhabricatorAuthProviderConfigTransaction::TYPE_UNLINK) + // ->setNewValue($request->getInt('allowUnlink', 0)); + + // $xactions[] = id(new PhabricatorAuthProviderConfigTransaction()) + // ->setTransactionType( + // PhabricatorAuthProviderConfigTransaction::TYPE_TRUST_EMAILS) + // ->setNewValue($request->getInt('trustEmails', 0)); + + // if ($provider->supportsAutoLogin()) { + // $xactions[] = id(new PhabricatorAuthProviderConfigTransaction()) + // ->setTransactionType( + // PhabricatorAuthProviderConfigTransaction::TYPE_AUTO_LOGIN) + // ->setNewValue($request->getInt('autoLogin', 0)); + // } + + // foreach ($properties as $key => $value) { + // $xactions[] = id(new PhabricatorAuthProviderConfigTransaction()) + // ->setTransactionType( + // PhabricatorAuthProviderConfigTransaction::TYPE_PROPERTY) + // ->setMetadataValue('auth:property', $key) + // ->setNewValue($value); + // } + + // if ($is_new) { + // $config->save(); + // } + + // $editor = id(new PhabricatorAuthProviderConfigEditor()) + // ->setActor($viewer) + // ->setContentSourceFromRequest($request) + // ->setContinueOnNoEffect(true); + + // try { + // $editor->applyTransactions($config, $xactions); + // $next_uri = $config->getURI(); + + // return id(new AphrontRedirectResponse())->setURI($next_uri); + // } catch (Exception $ex) { + // $validation_exception = $ex; + // } + // } + } else { + return $this->buildForm($task); + } + } + + private function buildForm(ManiphestTask $task) + { + $form = id(new AphrontFormView()) + ->setUser($this->getViewer()) + ->appendChild( + id(new AphrontFormCheckboxControl()) + ->setLabel(pht('Copy Comments')) + ->addCheckbox( + 'copy_comments', + 1, + pht('Copy all the comments of the task/s to the new task/s'), + ) + ) + ->appendChild( + id(new AphrontFormCheckboxControl()) + ->setLabel('Deep Clone Task') + ->addCheckbox( + 'deep_clone', + 1, + 'Create a clone of all the sub tasks of this task', + ) + ); + + $handle = $this->getHandle($task); + + $cancel_uri = "/{$handle->getName()}"; + + $form + ->appendChild( + id(new AphrontFormSubmitControl()) + ->addCancelButton($cancel_uri) + ->setValue(pht('Clone')) + ); + + $form_box = id(new PHUIObjectBoxView()) + ->setHeaderText($this->generateTitle($task)) + // ->setFormErrors($errors) + // ->setValidationException($validation_exception) + ->setBackground(PHUIObjectBoxView::BLUE_PROPERTY) + ->setForm($form); + + $view = id(new PHUITwoColumnView()) + ->setFooter(array( + $form_box, + )); + + return $this->newPage() + ->setTitle($this->generateTitle($task)) + ->appendChild($view); + } + + private function generateTitle(ManiphestTask $task) + { + $handle = $this->getHandle($task); + + return pht('Deep clone task "%s" (%s)', $task->getTitle(), $handle->getName()); + } + + private function getHandle(ManiphestTask $task) + { + $viewer = $this->getViewer(); + $handles = $viewer->loadHandles(array($task->getPHID())); + $handle = $handles[$task->getPHID()]; + + return $handle; + } + + private function triggerTransaction(AphrontRequest $request, ManiphestTask $task) { + $deepCloneRaw = $request->getStr('deep_clone'); + $deepClone = $deepCloneRaw === '1'; + $copyCommentsRaw = $request->getStr('copy_comments'); + $copyComments = $copyCommentsRaw === '1'; + + throw new Exception("Deep Clone $deepClone $deepCloneRaw Copy Comments $copyComments $copyCommentsRaw"); + } +} diff --git a/src/deepclone/events/DeepcloneUIEventListener.php b/src/deepclone/events/DeepcloneUIEventListener.php index 16a2ee5..69b5e65 100644 --- a/src/deepclone/events/DeepcloneUIEventListener.php +++ b/src/deepclone/events/DeepcloneUIEventListener.php @@ -1,38 +1,41 @@ listen(PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS); } public function handleEvent(PhutilEvent $event) { switch ($event->getType()) { case PhabricatorEventType::TYPE_UI_DIDRENDERACTIONS: $this->handleActionEvent($event); break; } } private function handleActionEvent($event) { $viewer = $event->getUser(); $object = $event->getValue('object'); if (!$object || !$object->getPHID()) { // If we have no object, or the object doesn't have a PHID, we can't // do anything useful. return; } + if (!($object instanceof ManiphestTask)) { + return; + } + $phid = $object->getPHID(); $button = id(new PhabricatorActionView()) ->setIcon('fa-asterisk') - ->setName(pht('Clone')) - ->setHref(urisprintf('/clone/%s/', $phid)) - ->setWorkflow(true); + ->setName(pht('Clone Task')) + ->setHref(urisprintf('/maniphest/task/clone/%s/', $phid)); $actions = $event->getValue('actions'); $actions[] = $button; $event->setValue('actions', $actions); } }