@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Give Nuance form sources a web UI

Summary:
Ref T8434. Hard-codes form sources as a complaint form.

This form is close to perfect and I'm not actually sure we need to let users customize it at all.

Test Plan: {F473587}

Reviewers: btrahan

Reviewed By: btrahan

Subscribers: epriestley

Maniphest Tasks: T8434

Differential Revision: https://secure.phabricator.com/D13166

+362 -39
+7 -1
src/__phutil_library_map__.php
··· 1140 1140 'NuanceRequestorViewController' => 'applications/nuance/controller/NuanceRequestorViewController.php', 1141 1141 'NuanceSchemaSpec' => 'applications/nuance/storage/NuanceSchemaSpec.php', 1142 1142 'NuanceSource' => 'applications/nuance/storage/NuanceSource.php', 1143 + 'NuanceSourceActionController' => 'applications/nuance/controller/NuanceSourceActionController.php', 1143 1144 'NuanceSourceCreateController' => 'applications/nuance/controller/NuanceSourceCreateController.php', 1144 1145 'NuanceSourceDefaultEditCapability' => 'applications/nuance/capability/NuanceSourceDefaultEditCapability.php', 1145 1146 'NuanceSourceDefaultViewCapability' => 'applications/nuance/capability/NuanceSourceDefaultViewCapability.php', ··· 4473 4474 'NuanceQueueTransactionComment' => 'PhabricatorApplicationTransactionComment', 4474 4475 'NuanceQueueTransactionQuery' => 'PhabricatorApplicationTransactionQuery', 4475 4476 'NuanceQueueViewController' => 'NuanceController', 4476 - 'NuanceRequestor' => 'NuanceDAO', 4477 + 'NuanceRequestor' => array( 4478 + 'NuanceDAO', 4479 + 'PhabricatorPolicyInterface', 4480 + 'PhabricatorApplicationTransactionInterface', 4481 + ), 4477 4482 'NuanceRequestorEditController' => 'NuanceController', 4478 4483 'NuanceRequestorEditor' => 'PhabricatorApplicationTransactionEditor', 4479 4484 'NuanceRequestorPHIDType' => 'PhabricatorPHIDType', ··· 4489 4494 'PhabricatorApplicationTransactionInterface', 4490 4495 'PhabricatorPolicyInterface', 4491 4496 ), 4497 + 'NuanceSourceActionController' => 'NuanceController', 4492 4498 'NuanceSourceCreateController' => 'NuanceController', 4493 4499 'NuanceSourceDefaultEditCapability' => 'PhabricatorPolicyCapability', 4494 4500 'NuanceSourceDefaultViewCapability' => 'PhabricatorPolicyCapability',
+3
src/applications/nuance/application/PhabricatorNuanceApplication.php
··· 62 62 'new/' => 'NuanceRequestorEditController', 63 63 ), 64 64 ), 65 + '/action/' => array( 66 + '(?P<id>[1-9]\d*)/(?P<path>.*)' => 'NuanceSourceActionController', 67 + ), 65 68 ); 66 69 } 67 70
+1 -1
src/applications/nuance/conduit/NuanceCreateItemConduitAPIMethod.php
··· 36 36 37 37 $user = $request->getUser(); 38 38 39 - $item = NuanceItem::initializeNewItem($user); 39 + $item = NuanceItem::initializeNewItem(); 40 40 $xactions = array(); 41 41 42 42 if ($source_phid) {
+38
src/applications/nuance/controller/NuanceSourceActionController.php
··· 1 + <?php 2 + 3 + final class NuanceSourceActionController extends NuanceController { 4 + 5 + public function handleRequest(AphrontRequest $request) { 6 + $viewer = $this->getViewer(); 7 + 8 + $source = id(new NuanceSourceQuery()) 9 + ->setViewer($viewer) 10 + ->withIDs(array($request->getURIData('id'))) 11 + ->executeOne(); 12 + if (!$source) { 13 + return new Aphront404Response(); 14 + } 15 + 16 + $def = NuanceSourceDefinition::getDefinitionForSource($source); 17 + $def->setActor($viewer); 18 + 19 + $response = $def->handleActionRequest($request); 20 + if ($response instanceof AphrontResponse) { 21 + return $response; 22 + } 23 + 24 + $title = $source->getName(); 25 + $crumbs = $this->buildApplicationCrumbs(); 26 + $crumbs->addTextCrumb($title); 27 + 28 + return $this->buildApplicationPage( 29 + array( 30 + $crumbs, 31 + $response, 32 + ), 33 + array( 34 + 'title' => $title, 35 + )); 36 + } 37 + 38 + }
+12
src/applications/nuance/editor/NuanceItemEditor.php
··· 17 17 $types[] = NuanceItemTransaction::TYPE_OWNER; 18 18 $types[] = NuanceItemTransaction::TYPE_SOURCE; 19 19 $types[] = NuanceItemTransaction::TYPE_REQUESTOR; 20 + $types[] = NuanceItemTransaction::TYPE_PROPERTY; 20 21 21 22 $types[] = PhabricatorTransactions::TYPE_EDGE; 22 23 $types[] = PhabricatorTransactions::TYPE_COMMENT; ··· 37 38 return $object->getSourcePHID(); 38 39 case NuanceItemTransaction::TYPE_OWNER: 39 40 return $object->getOwnerPHID(); 41 + case NuanceItemTransaction::TYPE_PROPERTY: 42 + $key = $xaction->getMetadataValue( 43 + NuanceItemTransaction::PROPERTY_KEY); 44 + return $object->getNuanceProperty($key); 40 45 } 41 46 42 47 return parent::getCustomTransactionOldValue($object, $xaction); ··· 50 55 case NuanceItemTransaction::TYPE_REQUESTOR: 51 56 case NuanceItemTransaction::TYPE_SOURCE: 52 57 case NuanceItemTransaction::TYPE_OWNER: 58 + case NuanceItemTransaction::TYPE_PROPERTY: 53 59 return $xaction->getNewValue(); 54 60 } 55 61 ··· 70 76 case NuanceItemTransaction::TYPE_OWNER: 71 77 $object->setOwnerPHID($xaction->getNewValue()); 72 78 break; 79 + case NuanceItemTransaction::TYPE_PROPERTY: 80 + $key = $xaction->getMetadataValue( 81 + NuanceItemTransaction::PROPERTY_KEY); 82 + $object->setNuanceProperty($key, $xaction->getNewValue()); 83 + break; 73 84 } 74 85 } 75 86 ··· 81 92 case NuanceItemTransaction::TYPE_REQUESTOR: 82 93 case NuanceItemTransaction::TYPE_SOURCE: 83 94 case NuanceItemTransaction::TYPE_OWNER: 95 + case NuanceItemTransaction::TYPE_PROPERTY: 84 96 return; 85 97 } 86 98
+52 -2
src/applications/nuance/editor/NuanceRequestorEditor.php
··· 14 14 public function getTransactionTypes() { 15 15 $types = parent::getTransactionTypes(); 16 16 17 - $types[] = PhabricatorTransactions::TYPE_EDGE; 18 - $types[] = PhabricatorTransactions::TYPE_COMMENT; 17 + $types[] = NuanceRequestorTransaction::TYPE_PROPERTY; 18 + 19 19 $types[] = PhabricatorTransactions::TYPE_VIEW_POLICY; 20 20 $types[] = PhabricatorTransactions::TYPE_EDIT_POLICY; 21 21 22 22 return $types; 23 23 } 24 24 25 + protected function getCustomTransactionOldValue( 26 + PhabricatorLiskDAO $object, 27 + PhabricatorApplicationTransaction $xaction) { 28 + 29 + switch ($xaction->getTransactionType()) { 30 + case NuanceRequestorTransaction::TYPE_PROPERTY: 31 + $key = $xaction->getMetadataValue( 32 + NuanceRequestorTransaction::PROPERTY_KEY); 33 + return $object->getNuanceProperty($key); 34 + } 35 + 36 + return parent::getCustomTransactionOldValue($object, $xaction); 37 + } 38 + 39 + protected function getCustomTransactionNewValue( 40 + PhabricatorLiskDAO $object, 41 + PhabricatorApplicationTransaction $xaction) { 42 + 43 + switch ($xaction->getTransactionType()) { 44 + case NuanceRequestorTransaction::TYPE_PROPERTY: 45 + return $xaction->getNewValue(); 46 + } 47 + 48 + return parent::getCustomTransactionNewValue($object, $xaction); 49 + } 50 + 51 + protected function applyCustomInternalTransaction( 52 + PhabricatorLiskDAO $object, 53 + PhabricatorApplicationTransaction $xaction) { 54 + 55 + switch ($xaction->getTransactionType()) { 56 + case NuanceRequestorTransaction::TYPE_PROPERTY: 57 + $key = $xaction->getMetadataValue( 58 + NuanceRequestorTransaction::PROPERTY_KEY); 59 + $object->setNuanceProperty($key, $xaction->getNewValue()); 60 + break; 61 + } 62 + } 63 + 64 + protected function applyCustomExternalTransaction( 65 + PhabricatorLiskDAO $object, 66 + PhabricatorApplicationTransaction $xaction) { 67 + 68 + switch ($xaction->getTransactionType()) { 69 + case NuanceRequestorTransaction::TYPE_PROPERTY: 70 + return; 71 + } 72 + 73 + return parent::applyCustomExternalTransaction($object, $xaction); 74 + } 25 75 }
+21 -23
src/applications/nuance/query/NuanceItemQuery.php
··· 5 5 6 6 private $ids; 7 7 private $phids; 8 - private $sourceIDs; 8 + private $sourcePHIDs; 9 9 10 10 public function withIDs(array $ids) { 11 11 $this->ids = $ids; ··· 17 17 return $this; 18 18 } 19 19 20 - public function withSourceIDs($source_ids) { 21 - $this->sourceIDs = $source_ids; 20 + public function withSourcePHIDs($source_phids) { 21 + $this->sourcePHIDs = $source_phids; 22 22 return $this; 23 23 } 24 24 25 - 26 25 protected function loadPage() { 27 26 $table = new NuanceItem(); 28 - $conn_r = $table->establishConnection('r'); 27 + $conn = $table->establishConnection('r'); 29 28 30 29 $data = queryfx_all( 31 - $conn_r, 32 - 'SELECT FROM %T %Q %Q %Q', 30 + $conn, 31 + '%Q FROM %T %Q %Q %Q', 32 + $this->buildSelectClause($conn), 33 33 $table->getTableName(), 34 - $this->buildWhereClause($conn_r), 35 - $this->buildOrderClause($conn_r), 36 - $this->buildLimitClause($conn_r)); 34 + $this->buildWhereClause($conn), 35 + $this->buildOrderClause($conn), 36 + $this->buildLimitClause($conn)); 37 37 38 38 return $table->loadAllFromArray($data); 39 39 } 40 40 41 - protected function buildWhereClause(AphrontDatabaseConnection $conn_r) { 42 - $where = array(); 43 - 44 - $where[] = $this->buildPagingClause($conn_r); 41 + protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) { 42 + $where = parent::buildWhereClauseParts($conn); 45 43 46 - if ($this->sourceID) { 44 + if ($this->sourcePHIDs !== null) { 47 45 $where[] = qsprintf( 48 - $conn_r, 49 - 'sourceID IN (%Ld)', 50 - $this->sourceIDs); 46 + $conn, 47 + 'sourcePHID IN (%Ls)', 48 + $this->sourcePHIDs); 51 49 } 52 50 53 - if ($this->ids) { 51 + if ($this->ids !== null) { 54 52 $where[] = qsprintf( 55 - $conn_r, 53 + $conn, 56 54 'id IN (%Ld)', 57 55 $this->ids); 58 56 } 59 57 60 - if ($this->phids) { 58 + if ($this->phids !== null) { 61 59 $where[] = qsprintf( 62 - $conn_r, 60 + $conn, 63 61 'phid IN (%Ls)', 64 62 $this->phids); 65 63 } 66 64 67 - return $this->formatWhereClause($where); 65 + return $where; 68 66 } 69 67 70 68 }
+47
src/applications/nuance/source/NuancePhabricatorFormSourceDefinition.php
··· 42 42 43 43 public function renderListView() {} 44 44 45 + 46 + public function handleActionRequest(AphrontRequest $request) { 47 + $viewer = $request->getViewer(); 48 + 49 + // TODO: As above, this would eventually be driven by custom logic. 50 + 51 + if ($request->isFormPost()) { 52 + $properties = array( 53 + 'complaint' => (string)$request->getStr('text'), 54 + ); 55 + 56 + $content_source = PhabricatorContentSource::newFromRequest($request); 57 + 58 + $requestor = NuanceRequestor::newFromPhabricatorUser( 59 + $viewer, 60 + $content_source); 61 + 62 + $item = $this->newItemFromProperties( 63 + $requestor, 64 + $properties, 65 + $content_source); 66 + 67 + $uri = $item->getURI(); 68 + return id(new AphrontRedirectResponse())->setURI($uri); 69 + } 70 + 71 + $form = id(new AphrontFormView()) 72 + ->setUser($viewer) 73 + ->appendRemarkupInstructions( 74 + pht('IMPORTANT: This is a very rough prototype.')) 75 + ->appendRemarkupInstructions( 76 + pht('Got a complaint? Complain here! We love complaints.')) 77 + ->appendChild( 78 + id(new AphrontFormTextAreaControl()) 79 + ->setName('complaint') 80 + ->setLabel(pht('Complaint'))) 81 + ->appendChild( 82 + id(new AphrontFormSubmitControl()) 83 + ->setValue(pht('Submit Complaint'))); 84 + 85 + $box = id(new PHUIObjectBoxView()) 86 + ->setHeaderText(pht('Complaint Form')) 87 + ->appendChild($form); 88 + 89 + return $box; 90 + } 91 + 45 92 }
+53
src/applications/nuance/source/NuanceSourceDefinition.php
··· 1 1 <?php 2 2 3 + /** 4 + * @task action Handling Action Requests 5 + */ 3 6 abstract class NuanceSourceDefinition extends Phobject { 4 7 5 8 private $actor; ··· 254 257 abstract public function renderView(); 255 258 256 259 abstract public function renderListView(); 260 + 261 + 262 + protected function newItemFromProperties( 263 + NuanceRequestor $requestor, 264 + array $properties, 265 + PhabricatorContentSource $content_source) { 266 + 267 + // TODO: Should we have a tighter actor/viewer model? Requestors will 268 + // often have no real user associated with them... 269 + $actor = PhabricatorUser::getOmnipotentUser(); 270 + 271 + $source = $this->requireSourceObject(); 272 + 273 + $item = NuanceItem::initializeNewItem(); 274 + 275 + $xactions = array(); 276 + 277 + $xactions[] = id(new NuanceItemTransaction()) 278 + ->setTransactionType(NuanceItemTransaction::TYPE_SOURCE) 279 + ->setNewValue($source->getPHID()); 280 + 281 + $xactions[] = id(new NuanceItemTransaction()) 282 + ->setTransactionType(NuanceItemTransaction::TYPE_REQUESTOR) 283 + ->setNewValue($requestor->getPHID()); 284 + 285 + foreach ($properties as $key => $property) { 286 + $xactions[] = id(new NuanceItemTransaction()) 287 + ->setTransactionType(NuanceItemTransaction::TYPE_PROPERTY) 288 + ->setMetadataValue(NuanceItemTransaction::PROPERTY_KEY, $key) 289 + ->setNewValue($property); 290 + } 291 + 292 + $editor = id(new NuanceItemEditor()) 293 + ->setActor($actor) 294 + ->setActingAsPHID($requestor->getActingAsPHID()) 295 + ->setContentSource($content_source); 296 + 297 + $editor->applyTransactions($item, $xactions); 298 + 299 + return $item; 300 + } 301 + 302 + 303 + /* -( Handling Action Requests )------------------------------------------- */ 304 + 305 + 306 + public function handleActionRequest(AphrontRequest $request) { 307 + return new Aphront404Response(); 308 + } 309 + 257 310 }
+11 -2
src/applications/nuance/storage/NuanceItem.php
··· 13 13 protected $requestorPHID; 14 14 protected $sourcePHID; 15 15 protected $sourceLabel; 16 - protected $data; 16 + protected $data = array(); 17 17 protected $mailKey; 18 18 protected $dateNuanced; 19 19 20 - public static function initializeNewItem(PhabricatorUser $user) { 20 + public static function initializeNewItem() { 21 21 return id(new NuanceItem()) 22 22 ->setDateNuanced(time()) 23 23 ->setStatus(self::STATUS_OPEN); ··· 92 92 93 93 public function attachSource(NuanceSource $source) { 94 94 $this->source = $source; 95 + } 96 + 97 + public function getNuanceProperty($key, $default = null) { 98 + return idx($this->data, $key, $default); 99 + } 100 + 101 + public function setNuanceProperty($key, $value) { 102 + $this->data[$key] = $value; 103 + return $this; 95 104 } 96 105 97 106 public function getCapabilities() {
+6 -3
src/applications/nuance/storage/NuanceItemTransaction.php
··· 3 3 final class NuanceItemTransaction 4 4 extends NuanceTransaction { 5 5 6 - const TYPE_OWNER = 'item-owner'; 7 - const TYPE_REQUESTOR = 'item-requestor'; 8 - const TYPE_SOURCE = 'item-source'; 6 + const PROPERTY_KEY = 'property.key'; 7 + 8 + const TYPE_OWNER = 'nuance.item.owner'; 9 + const TYPE_REQUESTOR = 'nuance.item.requestor'; 10 + const TYPE_SOURCE = 'nuance.item.source'; 11 + const TYPE_PROPERTY = 'nuance.item.property'; 9 12 10 13 public function getApplicationTransactionType() { 11 14 return NuanceItemPHIDType::TYPECONST;
+107 -7
src/applications/nuance/storage/NuanceRequestor.php
··· 1 1 <?php 2 2 3 3 final class NuanceRequestor 4 - extends NuanceDAO { 4 + extends NuanceDAO 5 + implements 6 + PhabricatorPolicyInterface, 7 + PhabricatorApplicationTransactionInterface { 5 8 6 - protected $data; 9 + protected $data = array(); 7 10 8 11 protected function getConfiguration() { 9 12 return array( ··· 19 22 NuanceRequestorPHIDType::TYPECONST); 20 23 } 21 24 22 - public function save() { 23 - if (!$this->getMailKey()) { 24 - $this->setMailKey(Filesystem::readRandomCharacters(20)); 25 - } 26 - return parent::save(); 25 + public static function initializeNewRequestor() { 26 + return new NuanceRequestor(); 27 27 } 28 28 29 29 public function getURI() { ··· 32 32 33 33 public function getPhabricatorUserPHID() { 34 34 return idx($this->getData(), 'phabricatorUserPHID'); 35 + } 36 + 37 + public function getActingAsPHID() { 38 + $user_phid = $this->getPhabricatorUserPHID(); 39 + if ($user_phid) { 40 + return $user_phid; 41 + } 42 + 43 + return id(new PhabricatorNuanceApplication())->getPHID(); 44 + } 45 + 46 + public static function newFromPhabricatorUser( 47 + PhabricatorUser $viewer, 48 + PhabricatorContentSource $content_source) { 49 + 50 + // TODO: This is real sketchy and creates a new requestor every time. It 51 + // shouldn't do that. 52 + 53 + $requestor = self::initializeNewRequestor(); 54 + 55 + $xactions = array(); 56 + 57 + $properties = array( 58 + 'phabricatorUserPHID' => $viewer->getPHID(), 59 + ); 60 + 61 + foreach ($properties as $key => $value) { 62 + $xactions[] = id(new NuanceRequestorTransaction()) 63 + ->setTransactionType(NuanceRequestorTransaction::TYPE_PROPERTY) 64 + ->setMetadataValue(NuanceRequestorTransaction::PROPERTY_KEY, $key) 65 + ->setNewValue($value); 66 + } 67 + 68 + $editor = id(new NuanceRequestorEditor()) 69 + ->setActor($viewer) 70 + ->setContentSource($content_source); 71 + 72 + $editor->applyTransactions($requestor, $xactions); 73 + 74 + return $requestor; 75 + } 76 + 77 + public function getNuanceProperty($key, $default = null) { 78 + return idx($this->data, $key, $default); 79 + } 80 + 81 + public function setNuanceProperty($key, $value) { 82 + $this->data[$key] = $value; 83 + return $this; 84 + } 85 + 86 + 87 + /* -( PhabricatorPolicyInterface )----------------------------------------- */ 88 + 89 + 90 + public function getCapabilities() { 91 + return array( 92 + PhabricatorPolicyCapability::CAN_VIEW, 93 + PhabricatorPolicyCapability::CAN_EDIT, 94 + ); 95 + } 96 + 97 + public function getPolicy($capability) { 98 + switch ($capability) { 99 + case PhabricatorPolicyCapability::CAN_VIEW: 100 + return PhabricatorPolicies::POLICY_USER; 101 + case PhabricatorPolicyCapability::CAN_EDIT: 102 + return PhabricatorPolicies::POLICY_USER; 103 + } 104 + } 105 + 106 + public function hasAutomaticCapability($capability, PhabricatorUser $viewer) { 107 + return false; 108 + } 109 + 110 + public function describeAutomaticCapability($capability) { 111 + return null; 112 + } 113 + 114 + 115 + /* -( PhabricatorApplicationTransactionInterface )------------------------- */ 116 + 117 + 118 + public function getApplicationTransactionEditor() { 119 + return new NuanceRequestorEditor(); 120 + } 121 + 122 + public function getApplicationTransactionObject() { 123 + return $this; 124 + } 125 + 126 + public function getApplicationTransactionTemplate() { 127 + return new NuanceRequestorTransaction(); 128 + } 129 + 130 + public function willRenderTimeline( 131 + PhabricatorApplicationTransactionView $timeline, 132 + AphrontRequest $request) { 133 + 134 + return $timeline; 35 135 } 36 136 37 137 }
+4
src/applications/nuance/storage/NuanceRequestorTransaction.php
··· 3 3 final class NuanceRequestorTransaction 4 4 extends NuanceTransaction { 5 5 6 + const PROPERTY_KEY = 'property.key'; 7 + 8 + const TYPE_PROPERTY = 'nuance.requestor.property'; 9 + 6 10 public function getApplicationTransactionType() { 7 11 return NuanceRequestorPHIDType::TYPECONST; 8 12 }