@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 recaptime-dev/main 378 lines 13 kB view raw
1<?php 2 3final class PholioMockEditController extends PholioController { 4 5 public function handleRequest(AphrontRequest $request) { 6 $viewer = $request->getViewer(); 7 $id = $request->getURIData('id'); 8 9 if ($id) { 10 $mock = id(new PholioMockQuery()) 11 ->setViewer($viewer) 12 ->needImages(true) 13 ->requireCapabilities( 14 array( 15 PhabricatorPolicyCapability::CAN_VIEW, 16 PhabricatorPolicyCapability::CAN_EDIT, 17 )) 18 ->withIDs(array($id)) 19 ->executeOne(); 20 21 if (!$mock) { 22 return new Aphront404Response(); 23 } 24 25 $title = pht('Edit Mock: %s', $mock->getName()); 26 27 $is_new = false; 28 $mock_images = $mock->getActiveImages(); 29 $files = mpull($mock_images, 'getFile'); 30 $mock_images = mpull($mock_images, null, 'getFilePHID'); 31 } else { 32 $mock = PholioMock::initializeNewMock($viewer); 33 34 $title = pht('Create Mock'); 35 36 $is_new = true; 37 $files = array(); 38 $mock_images = array(); 39 } 40 41 if ($is_new) { 42 $v_projects = array(); 43 } else { 44 $v_projects = PhabricatorEdgeQuery::loadDestinationPHIDs( 45 $mock->getPHID(), 46 PhabricatorProjectObjectHasProjectEdgeType::EDGECONST); 47 $v_projects = array_reverse($v_projects); 48 } 49 50 $e_name = true; 51 $e_images = count($mock_images) ? null : true; 52 $errors = array(); 53 $posted_mock_images = array(); 54 55 $v_name = $mock->getName(); 56 $v_desc = $mock->getDescription(); 57 $v_view = $mock->getViewPolicy(); 58 $v_edit = $mock->getEditPolicy(); 59 $v_cc = PhabricatorSubscribersQuery::loadSubscribersForPHID( 60 $mock->getPHID()); 61 $v_space = $mock->getSpacePHID(); 62 63 if ($request->isFormPost()) { 64 $xactions = array(); 65 66 $type_name = PholioMockNameTransaction::TRANSACTIONTYPE; 67 $type_desc = PholioMockDescriptionTransaction::TRANSACTIONTYPE; 68 $type_view = PhabricatorTransactions::TYPE_VIEW_POLICY; 69 $type_edit = PhabricatorTransactions::TYPE_EDIT_POLICY; 70 $type_cc = PhabricatorTransactions::TYPE_SUBSCRIBERS; 71 $type_space = PhabricatorTransactions::TYPE_SPACE; 72 73 $v_name = $request->getStr('name'); 74 $v_desc = $request->getStr('description'); 75 $v_view = $request->getStr('can_view'); 76 $v_edit = $request->getStr('can_edit'); 77 $v_cc = $request->getArr('cc'); 78 $v_projects = $request->getArr('projects'); 79 $v_space = $request->getStr('spacePHID'); 80 81 $mock_xactions = array(); 82 $mock_xactions[$type_name] = $v_name; 83 $mock_xactions[$type_desc] = $v_desc; 84 $mock_xactions[$type_view] = $v_view; 85 $mock_xactions[$type_edit] = $v_edit; 86 $mock_xactions[$type_cc] = array('=' => $v_cc); 87 $mock_xactions[$type_space] = $v_space; 88 89 $file_phids = $request->getArr('file_phids'); 90 if ($file_phids) { 91 $files = id(new PhabricatorFileQuery()) 92 ->setViewer($viewer) 93 ->withPHIDs($file_phids) 94 ->execute(); 95 $files = mpull($files, null, 'getPHID'); 96 $files = array_select_keys($files, $file_phids); 97 } else { 98 $files = array(); 99 } 100 101 if (!$files) { 102 $e_images = pht('Required'); 103 $errors[] = pht('You must add at least one image to the mock.'); 104 } else { 105 $mock->setCoverPHID(head($files)->getPHID()); 106 } 107 108 foreach ($mock_xactions as $type => $value) { 109 $xactions[$type] = id(new PholioTransaction()) 110 ->setTransactionType($type) 111 ->setIsCreateTransaction($is_new) 112 ->setNewValue($value); 113 } 114 115 $order = $request->getStrList('imageOrder'); 116 $sequence_map = array_flip($order); 117 $replaces = $request->getArr('replaces'); 118 $replaces_map = array_flip($replaces); 119 120 /** 121 * Foreach file posted, check to see whether we are replacing an image, 122 * adding an image, or simply updating image metadata. Create 123 * transactions for these cases as appropos. 124 */ 125 foreach ($files as $file_phid => $file) { 126 $replaces_image_phid = null; 127 if (isset($replaces_map[$file_phid])) { 128 $old_file_phid = $replaces_map[$file_phid]; 129 if ($old_file_phid != $file_phid) { 130 $old_image = idx($mock_images, $old_file_phid); 131 if ($old_image) { 132 $replaces_image_phid = $old_image->getPHID(); 133 } 134 } 135 } 136 137 $existing_image = idx($mock_images, $file_phid); 138 139 $img_title = (string)$request->getStr('title_'.$file_phid); 140 $description = (string)$request->getStr('description_'.$file_phid); 141 $sequence = $sequence_map[$file_phid]; 142 143 if ($replaces_image_phid) { 144 $replace_image = PholioImage::initializeNewImage() 145 ->setAuthorPHID($viewer->getPHID()) 146 ->setReplacesImagePHID($replaces_image_phid) 147 ->setFilePHID($file_phid) 148 ->attachFile($file) 149 ->setName(strlen($img_title) ? $img_title : $file->getName()) 150 ->setDescription($description) 151 ->setSequence($sequence) 152 ->save(); 153 154 $xactions[] = id(new PholioTransaction()) 155 ->setTransactionType(PholioImageReplaceTransaction::TRANSACTIONTYPE) 156 ->setNewValue($replace_image->getPHID()); 157 158 $posted_mock_images[] = $replace_image; 159 } else if (!$existing_image) { // this is an add 160 $add_image = PholioImage::initializeNewImage() 161 ->setAuthorPHID($viewer->getPHID()) 162 ->setFilePHID($file_phid) 163 ->attachFile($file) 164 ->setName(strlen($img_title) ? $img_title : $file->getName()) 165 ->setDescription($description) 166 ->setSequence($sequence) 167 ->save(); 168 169 $xactions[] = id(new PholioTransaction()) 170 ->setTransactionType(PholioImageFileTransaction::TRANSACTIONTYPE) 171 ->setNewValue( 172 array('+' => array($add_image->getPHID()))); 173 $posted_mock_images[] = $add_image; 174 } else { 175 $xactions[] = id(new PholioTransaction()) 176 ->setTransactionType(PholioImageNameTransaction::TRANSACTIONTYPE) 177 ->setNewValue( 178 array($existing_image->getPHID() => $img_title)); 179 $xactions[] = id(new PholioTransaction()) 180 ->setTransactionType( 181 PholioImageDescriptionTransaction::TRANSACTIONTYPE) 182 ->setNewValue( 183 array($existing_image->getPHID() => $description)); 184 $xactions[] = id(new PholioTransaction()) 185 ->setTransactionType( 186 PholioImageSequenceTransaction::TRANSACTIONTYPE) 187 ->setNewValue( 188 array($existing_image->getPHID() => $sequence)); 189 190 $posted_mock_images[] = $existing_image; 191 } 192 } 193 foreach ($mock_images as $file_phid => $mock_image) { 194 if (!isset($files[$file_phid]) && !isset($replaces[$file_phid])) { 195 // this is an outright delete 196 $xactions[] = id(new PholioTransaction()) 197 ->setTransactionType(PholioImageFileTransaction::TRANSACTIONTYPE) 198 ->setNewValue( 199 array('-' => array($mock_image->getPHID()))); 200 } 201 } 202 203 if (!$errors) { 204 $proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST; 205 $xactions[] = id(new PholioTransaction()) 206 ->setTransactionType(PhabricatorTransactions::TYPE_EDGE) 207 ->setMetadataValue('edge:type', $proj_edge_type) 208 ->setNewValue(array('=' => array_fuse($v_projects))); 209 210 $editor = id(new PholioMockEditor()) 211 ->setContentSourceFromRequest($request) 212 ->setContinueOnNoEffect(true) 213 ->setActor($viewer); 214 215 try { 216 $xactions = $editor->applyTransactions($mock, $xactions); 217 return id(new AphrontRedirectResponse()) 218 ->setURI('/M'.$mock->getID()); 219 } catch (PhabricatorApplicationTransactionValidationException $ex) { 220 $errors = mpull($ex->getErrors(), 'getMessage'); 221 } 222 } 223 } 224 225 if ($id) { 226 $submit = id(new AphrontFormSubmitControl()) 227 ->addCancelButton('/M'.$id) 228 ->setValue(pht('Save')); 229 } else { 230 $submit = id(new AphrontFormSubmitControl()) 231 ->addCancelButton($this->getApplicationURI()) 232 ->setValue(pht('Create')); 233 } 234 235 $policies = id(new PhabricatorPolicyQuery()) 236 ->setViewer($viewer) 237 ->setObject($mock) 238 ->execute(); 239 240 // NOTE: Make this show up correctly on the rendered form. 241 $mock->setViewPolicy($v_view); 242 $mock->setEditPolicy($v_edit); 243 244 $image_elements = array(); 245 if ($posted_mock_images) { 246 $display_mock_images = $posted_mock_images; 247 } else { 248 $display_mock_images = $mock_images; 249 } 250 foreach ($display_mock_images as $mock_image) { 251 $image_elements[] = id(new PholioUploadedImageView()) 252 ->setViewer($viewer) 253 ->setImage($mock_image) 254 ->setReplacesPHID($mock_image->getFilePHID()); 255 } 256 257 $list_id = celerity_generate_unique_node_id(); 258 $drop_id = celerity_generate_unique_node_id(); 259 $order_id = celerity_generate_unique_node_id(); 260 261 $list_control = phutil_tag( 262 'div', 263 array( 264 'id' => $list_id, 265 'class' => 'pholio-edit-list', 266 ), 267 $image_elements); 268 269 $drop_control = phutil_tag( 270 'a', 271 array( 272 'id' => $drop_id, 273 'class' => 'pholio-edit-drop', 274 ), 275 pht('Click here, or drag and drop images to add them to the mock.')); 276 277 $order_control = phutil_tag( 278 'input', 279 array( 280 'type' => 'hidden', 281 'name' => 'imageOrder', 282 'id' => $order_id, 283 )); 284 285 Javelin::initBehavior( 286 'pholio-mock-edit', 287 array( 288 'listID' => $list_id, 289 'dropID' => $drop_id, 290 'orderID' => $order_id, 291 'uploadURI' => '/file/dropupload/', 292 'renderURI' => $this->getApplicationURI('image/upload/'), 293 'pht' => array( 294 'uploading' => pht('Uploading Image...'), 295 'uploaded' => pht('Upload Complete...'), 296 'undo' => pht('Undo'), 297 'removed' => pht('This image will be removed from the mock.'), 298 ), 299 )); 300 301 require_celerity_resource('pholio-edit-css'); 302 $form = id(new AphrontFormView()) 303 ->setViewer($viewer) 304 ->appendChild($order_control) 305 ->appendChild( 306 id(new AphrontFormTextControl()) 307 ->setName('name') 308 ->setValue($v_name) 309 ->setLabel(pht('Name')) 310 ->setError($e_name)) 311 ->appendChild( 312 id(new PhabricatorRemarkupControl()) 313 ->setName('description') 314 ->setValue($v_desc) 315 ->setLabel(pht('Description')) 316 ->setViewer($viewer)) 317 ->appendControl( 318 id(new AphrontFormTokenizerControl()) 319 ->setLabel(pht('Project Tags')) 320 ->setName('projects') 321 ->setValue($v_projects) 322 ->setDatasource(new PhabricatorProjectDatasource())) 323 ->appendControl( 324 id(new AphrontFormTokenizerControl()) 325 ->setLabel(pht('Subscribers')) 326 ->setName('cc') 327 ->setValue($v_cc) 328 ->setViewer($viewer) 329 ->setDatasource(new PhabricatorMetaMTAMailableDatasource())) 330 ->appendChild( 331 id(new AphrontFormPolicyControl()) 332 ->setViewer($viewer) 333 ->setCapability(PhabricatorPolicyCapability::CAN_VIEW) 334 ->setPolicyObject($mock) 335 ->setPolicies($policies) 336 ->setSpacePHID($v_space) 337 ->setName('can_view')) 338 ->appendChild( 339 id(new AphrontFormPolicyControl()) 340 ->setViewer($viewer) 341 ->setCapability(PhabricatorPolicyCapability::CAN_EDIT) 342 ->setPolicyObject($mock) 343 ->setPolicies($policies) 344 ->setName('can_edit')) 345 ->appendChild( 346 id(new AphrontFormMarkupControl()) 347 ->setValue($list_control)) 348 ->appendChild( 349 id(new AphrontFormMarkupControl()) 350 ->setValue($drop_control) 351 ->setError($e_images)) 352 ->appendChild($submit); 353 354 $form_box = id(new PHUIObjectBoxView()) 355 ->setHeaderText($title) 356 ->setFormErrors($errors) 357 ->setBackground(PHUIObjectBoxView::WHITE_CONFIG) 358 ->setForm($form); 359 360 $crumbs = $this->buildApplicationCrumbs(); 361 if (!$is_new) { 362 $crumbs->addTextCrumb($mock->getMonogram(), '/'.$mock->getMonogram()); 363 } 364 $crumbs->addTextCrumb($title); 365 $crumbs->setBorder(true); 366 367 $view = id(new PHUITwoColumnView()) 368 ->setFooter($form_box); 369 370 return $this->newPage() 371 ->setTitle($title) 372 ->setCrumbs($crumbs) 373 ->addQuicksandConfig( 374 array('mockEditConfig' => true)) 375 ->appendChild($view); 376 } 377 378}