@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
at upstream/main 214 lines 5.7 kB view raw
1<?php 2 3/** 4 * @task action Handling Action Requests 5 */ 6abstract class NuanceSourceDefinition extends Phobject { 7 8 private $viewer; 9 private $source; 10 11 public function setViewer(PhabricatorUser $viewer) { 12 $this->viewer = $viewer; 13 return $this; 14 } 15 16 public function getViewer() { 17 if (!$this->viewer) { 18 throw new PhutilInvalidStateException('setViewer'); 19 } 20 return $this->viewer; 21 } 22 23 public function setSource(NuanceSource $source) { 24 $this->source = $source; 25 return $this; 26 } 27 28 public function getSource() { 29 if (!$this->source) { 30 throw new PhutilInvalidStateException('setSource'); 31 } 32 return $this->source; 33 } 34 35 public function getSourceViewActions(AphrontRequest $request) { 36 return array(); 37 } 38 39 public static function getAllDefinitions() { 40 return id(new PhutilClassMapQuery()) 41 ->setAncestorClass(self::class) 42 ->setUniqueMethod('getSourceTypeConstant') 43 ->execute(); 44 } 45 46 public function hasImportCursors() { 47 return false; 48 } 49 50 final public function getImportCursors() { 51 if (!$this->hasImportCursors()) { 52 throw new Exception( 53 pht('This source has no input cursors.')); 54 } 55 56 $viewer = PhabricatorUser::getOmnipotentUser(); 57 $source = $this->getSource(); 58 $cursors = $this->newImportCursors(); 59 60 $data = id(new NuanceImportCursorDataQuery()) 61 ->setViewer($viewer) 62 ->withSourcePHIDs(array($source->getPHID())) 63 ->execute(); 64 $data = mpull($data, null, 'getCursorKey'); 65 66 $map = array(); 67 foreach ($cursors as $cursor) { 68 if (!($cursor instanceof NuanceImportCursor)) { 69 throw new Exception( 70 pht( 71 'Source "%s" (of class "%s") returned an invalid value from '. 72 'method "%s": all values must be objects of class "%s".', 73 $this->getName(), 74 get_class($this), 75 'newImportCursors()', 76 'NuanceImportCursor')); 77 } 78 79 $key = $cursor->getCursorKey(); 80 if (!strlen($key)) { 81 throw new Exception( 82 pht( 83 'Source "%s" (of class "%s") returned an import cursor with '. 84 'a missing key from "%s". Each cursor must have a unique, '. 85 'nonempty key.', 86 $this->getName(), 87 get_class($this), 88 'newImportCursors()')); 89 } 90 91 $other = idx($map, $key); 92 if ($other) { 93 throw new Exception( 94 pht( 95 'Source "%s" (of class "%s") returned two cursors from method '. 96 '"%s" with the same key ("%s"). Each cursor must have a unique '. 97 'key.', 98 $this->getName(), 99 get_class($this), 100 'newImportCursors()', 101 $key)); 102 } 103 104 $map[$key] = $cursor; 105 106 $cursor_data = idx($data, $key); 107 if (!$cursor_data) { 108 $cursor_data = $cursor->newEmptyCursorData($source); 109 } 110 111 $cursor 112 ->setViewer($viewer) 113 ->setSource($source) 114 ->setCursorData($cursor_data); 115 } 116 117 return $map; 118 } 119 120 protected function newImportCursors() { 121 throw new PhutilMethodNotImplementedException(); 122 } 123 124 /** 125 * A human readable string like "Twitter" or "Phabricator Form". 126 */ 127 abstract public function getName(); 128 129 130 /** 131 * Human readable description of this source, a sentence or two long. 132 */ 133 abstract public function getSourceDescription(); 134 135 /** 136 * This should be a any VARCHAR(32). 137 * 138 * @{method:getAllDefinitions} will throw if you choose a string that 139 * collides with another @{class:NuanceSourceDefinition} class. 140 */ 141 abstract public function getSourceTypeConstant(); 142 143 public function renderView() { 144 return null; 145 } 146 147 public function renderListView() { 148 return null; 149 } 150 151 protected function newItemFromProperties( 152 $item_type, 153 $author_phid, 154 array $properties, 155 PhabricatorContentSource $content_source) { 156 157 // TODO: Should we have a tighter actor/viewer model? Requestors will 158 // often have no real user associated with them... 159 $actor = PhabricatorUser::getOmnipotentUser(); 160 $source = $this->getSource(); 161 162 $item = NuanceItem::initializeNewItem($item_type); 163 164 $xactions = array(); 165 166 $xactions[] = id(new NuanceItemTransaction()) 167 ->setTransactionType(NuanceItemSourceTransaction::TRANSACTIONTYPE) 168 ->setNewValue($source->getPHID()); 169 170 // TODO: Eventually, apply real routing rules. For now, just put everything 171 // in the default queue for the source. 172 $xactions[] = id(new NuanceItemTransaction()) 173 ->setTransactionType(NuanceItemQueueTransaction::TRANSACTIONTYPE) 174 ->setNewValue($source->getDefaultQueuePHID()); 175 176 // TODO: Maybe this should all be modular transactions now? 177 foreach ($properties as $key => $property) { 178 $xactions[] = id(new NuanceItemTransaction()) 179 ->setTransactionType(NuanceItemPropertyTransaction::TRANSACTIONTYPE) 180 ->setMetadataValue(NuanceItemTransaction::PROPERTY_KEY, $key) 181 ->setNewValue($property); 182 } 183 184 $editor = id(new NuanceItemEditor()) 185 ->setActor($actor) 186 ->setActingAsPHID($author_phid) 187 ->setContentSource($content_source); 188 189 $editor->applyTransactions($item, $xactions); 190 191 return $item; 192 } 193 194 public function renderItemEditProperties( 195 PhabricatorUser $viewer, 196 NuanceItem $item, 197 PHUIPropertyListView $view) { 198 return; 199 } 200 201 202/* -( Handling Action Requests )------------------------------------------- */ 203 204 205 public function handleActionRequest(AphrontRequest $request) { 206 return new Aphront404Response(); 207 } 208 209 public function getActionURI($path = '') { 210 $source_id = $this->getSource()->getID(); 211 return '/action/'.$source_id.'/'.ltrim($path, '/'); 212 } 213 214}