@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 456 lines 15 kB view raw
1<?php 2 3final class ConpherenceUpdateController 4 extends ConpherenceController { 5 6 public function handleRequest(AphrontRequest $request) { 7 $user = $request->getUser(); 8 $conpherence_id = $request->getURIData('id'); 9 if (!$conpherence_id) { 10 return new Aphront404Response(); 11 } 12 13 $need_participants = false; 14 $needed_capabilities = array(PhabricatorPolicyCapability::CAN_VIEW); 15 $action = $request->getStr('action'); 16 switch ($action) { 17 case ConpherenceUpdateActions::REMOVE_PERSON: 18 $person_phid = $request->getStr('remove_person'); 19 if ($person_phid != $user->getPHID()) { 20 $needed_capabilities[] = PhabricatorPolicyCapability::CAN_EDIT; 21 } 22 break; 23 case ConpherenceUpdateActions::ADD_PERSON: 24 $needed_capabilities[] = PhabricatorPolicyCapability::CAN_EDIT; 25 break; 26 case ConpherenceUpdateActions::LOAD: 27 break; 28 } 29 $conpherence = id(new ConpherenceThreadQuery()) 30 ->setViewer($user) 31 ->withIDs(array($conpherence_id)) 32 ->needParticipants($need_participants) 33 ->requireCapabilities($needed_capabilities) 34 ->executeOne(); 35 36 $latest_transaction_id = null; 37 $response_mode = $request->isAjax() ? 'ajax' : 'redirect'; 38 $error_view = null; 39 $e_file = array(); 40 $errors = array(); 41 $delete_draft = false; 42 $xactions = array(); 43 if ($request->isFormPost() || ($action == ConpherenceUpdateActions::LOAD)) { 44 $editor = id(new ConpherenceEditor()) 45 ->setContinueOnNoEffect($request->isContinueRequest()) 46 ->setContentSourceFromRequest($request) 47 ->setActor($user); 48 49 switch ($action) { 50 case ConpherenceUpdateActions::DRAFT: 51 $draft = PhabricatorDraft::newFromUserAndKey( 52 $user, 53 $conpherence->getPHID()); 54 $draft->setDraft($request->getStr('text')); 55 $draft->replaceOrDelete(); 56 return new AphrontAjaxResponse(); 57 case ConpherenceUpdateActions::JOIN_ROOM: 58 $xactions[] = id(new ConpherenceTransaction()) 59 ->setTransactionType( 60 ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE) 61 ->setNewValue(array('+' => array($user->getPHID()))); 62 $delete_draft = true; 63 $message = $request->getStr('text'); 64 if ($message) { 65 $message_xactions = $editor->generateTransactionsFromText( 66 $user, 67 $conpherence, 68 $message); 69 $xactions = array_merge($xactions, $message_xactions); 70 } 71 // for now, just redirect back to the conpherence so everything 72 // will work okay...! 73 $response_mode = 'redirect'; 74 break; 75 case ConpherenceUpdateActions::MESSAGE: 76 $message = $request->getStr('text'); 77 if (strlen($message)) { 78 $xactions = $editor->generateTransactionsFromText( 79 $user, 80 $conpherence, 81 $message); 82 83 $xaction_comment = PhabricatorTransactions::findOneByType( 84 $xactions, 85 PhabricatorTransactions::TYPE_COMMENT); 86 87 $text_metadata = $request->getStr('text_metadata'); 88 if ($text_metadata) { 89 $text_metadata = phutil_json_decode($text_metadata); 90 $attached_file_phids = idx( 91 $text_metadata, 92 'attachedFilePHIDs', 93 array()); 94 95 if ($attached_file_phids) { 96 $metadata_object = array( 97 'remarkup.control' => array( 98 'attachedFilePHIDs' => $attached_file_phids, 99 ), 100 ); 101 102 $xaction_comment->setMetadata($metadata_object); 103 } 104 } 105 106 $delete_draft = true; 107 } else { 108 $action = ConpherenceUpdateActions::LOAD; 109 $updated = false; 110 $response_mode = 'ajax'; 111 } 112 break; 113 case ConpherenceUpdateActions::ADD_PERSON: 114 $person_phids = $request->getArr('add_person'); 115 if (!empty($person_phids)) { 116 $xactions[] = id(new ConpherenceTransaction()) 117 ->setTransactionType( 118 ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE) 119 ->setNewValue(array('+' => $person_phids)); 120 } 121 break; 122 case ConpherenceUpdateActions::REMOVE_PERSON: 123 if (!$request->isContinueRequest()) { 124 // do nothing; we'll display a confirmation dialog instead 125 break; 126 } 127 $person_phid = $request->getStr('remove_person'); 128 if ($person_phid) { 129 $xactions[] = id(new ConpherenceTransaction()) 130 ->setTransactionType( 131 ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE) 132 ->setNewValue(array('-' => array($person_phid))); 133 $response_mode = 'go-home'; 134 } 135 break; 136 case ConpherenceUpdateActions::LOAD: 137 $updated = false; 138 $response_mode = 'ajax'; 139 break; 140 default: 141 throw new Exception(pht('Unknown action: %s', $action)); 142 } 143 144 if ($xactions) { 145 try { 146 $xactions = $editor->applyTransactions($conpherence, $xactions); 147 if ($delete_draft) { 148 $draft = PhabricatorDraft::newFromUserAndKey( 149 $user, 150 $conpherence->getPHID()); 151 $draft->delete(); 152 } 153 } catch (PhabricatorApplicationTransactionNoEffectException $ex) { 154 return id(new PhabricatorApplicationTransactionNoEffectResponse()) 155 ->setCancelURI($this->getApplicationURI($conpherence_id.'/')) 156 ->setException($ex); 157 } 158 // xactions had no effect...! 159 if (empty($xactions)) { 160 $errors[] = pht( 161 'That was a non-update. Try cancel.'); 162 } 163 } 164 165 if ($xactions || ($action == ConpherenceUpdateActions::LOAD)) { 166 switch ($response_mode) { 167 case 'ajax': 168 $latest_transaction_id = $request->getInt('latest_transaction_id'); 169 $content = $this->loadAndRenderUpdates( 170 $action, 171 $conpherence_id, 172 $latest_transaction_id); 173 return id(new AphrontAjaxResponse()) 174 ->setContent($content); 175 case 'go-home': 176 $content = array( 177 'href' => $this->getApplicationURI(), 178 ); 179 return id(new AphrontAjaxResponse()) 180 ->setContent($content); 181 case 'redirect': 182 default: 183 return id(new AphrontRedirectResponse()) 184 ->setURI('/'.$conpherence->getMonogram()); 185 } 186 } 187 } 188 189 if ($errors) { 190 $error_view = id(new PHUIInfoView()) 191 ->setErrors($errors); 192 } 193 194 switch ($action) { 195 case ConpherenceUpdateActions::ADD_PERSON: 196 $dialog = $this->renderAddPersonDialog($conpherence); 197 break; 198 case ConpherenceUpdateActions::REMOVE_PERSON: 199 $dialog = $this->renderRemovePersonDialog($conpherence); 200 break; 201 } 202 203 return 204 $dialog 205 ->setUser($user) 206 ->setWidth(AphrontDialogView::WIDTH_FORM) 207 ->setSubmitURI($this->getApplicationURI('update/'.$conpherence_id.'/')) 208 ->addSubmitButton() 209 ->addCancelButton($this->getApplicationURI($conpherence->getID().'/')); 210 211 } 212 213 private function renderAddPersonDialog( 214 ConpherenceThread $conpherence) { 215 216 $request = $this->getRequest(); 217 $user = $request->getUser(); 218 $add_person = $request->getStr('add_person'); 219 220 $form = id(new AphrontFormView()) 221 ->setUser($user) 222 ->setFullWidth(true) 223 ->appendControl( 224 id(new AphrontFormTokenizerControl()) 225 ->setName('add_person') 226 ->setUser($user) 227 ->setDatasource(new PhabricatorPeopleDatasource())); 228 229 $view = id(new AphrontDialogView()) 230 ->setTitle(pht('Add Participants')) 231 ->addHiddenInput('action', 'add_person') 232 ->addHiddenInput( 233 'latest_transaction_id', 234 $request->getInt('latest_transaction_id')) 235 ->appendForm($form); 236 237 return $view; 238 } 239 240 private function renderRemovePersonDialog( 241 ConpherenceThread $conpherence) { 242 243 $request = $this->getRequest(); 244 $viewer = $request->getUser(); 245 $remove_person = $request->getStr('remove_person'); 246 $participants = $conpherence->getParticipants(); 247 248 $removed_user = id(new PhabricatorPeopleQuery()) 249 ->setViewer($viewer) 250 ->withPHIDs(array($remove_person)) 251 ->executeOne(); 252 if (!$removed_user) { 253 return new Aphront404Response(); 254 } 255 256 $is_self = ($viewer->getPHID() == $removed_user->getPHID()); 257 $is_last = (count($participants) == 1); 258 259 $test_conpherence = clone $conpherence; 260 $test_conpherence->attachParticipants(array()); 261 $still_visible = PhabricatorPolicyFilter::hasCapability( 262 $removed_user, 263 $test_conpherence, 264 PhabricatorPolicyCapability::CAN_VIEW); 265 266 $body = array(); 267 268 if ($is_self) { 269 $title = pht('Leave Room'); 270 $body[] = pht( 271 'Are you sure you want to leave this room?'); 272 } else { 273 $title = pht('Remove Participant'); 274 $body[] = pht( 275 'Remove %s from this room?', 276 phutil_tag('strong', array(), $removed_user->getUsername())); 277 } 278 279 if ($still_visible) { 280 if ($is_self) { 281 $body[] = pht( 282 'You will be able to rejoin the room later.'); 283 } else { 284 $body[] = pht( 285 'They will be able to rejoin the room later.'); 286 } 287 } else { 288 if ($is_self) { 289 if ($is_last) { 290 $body[] = pht( 291 'You are the last member, so you will never be able to rejoin '. 292 'the room.'); 293 } else { 294 $body[] = pht( 295 'You will not be able to rejoin the room on your own, but '. 296 'someone else can invite you later.'); 297 } 298 } else { 299 $body[] = pht( 300 'They will not be able to rejoin the room unless invited '. 301 'again.'); 302 } 303 } 304 305 $dialog = id(new AphrontDialogView()) 306 ->setTitle($title) 307 ->addHiddenInput('action', 'remove_person') 308 ->addHiddenInput('remove_person', $remove_person) 309 ->addHiddenInput( 310 'latest_transaction_id', 311 $request->getInt('latest_transaction_id')) 312 ->addHiddenInput('__continue__', true); 313 314 foreach ($body as $paragraph) { 315 $dialog->appendParagraph($paragraph); 316 } 317 318 return $dialog; 319 } 320 321 private function loadAndRenderUpdates( 322 $action, 323 $conpherence_id, 324 $latest_transaction_id) { 325 326 $need_transactions = false; 327 switch ($action) { 328 case ConpherenceUpdateActions::ADD_PERSON: 329 case ConpherenceUpdateActions::LOAD: 330 case ConpherenceUpdateActions::MESSAGE: 331 $need_transactions = true; 332 break; 333 case ConpherenceUpdateActions::REMOVE_PERSON: 334 default: 335 break; 336 337 } 338 $user = $this->getRequest()->getUser(); 339 $conpherence = id(new ConpherenceThreadQuery()) 340 ->setViewer($user) 341 ->setAfterTransactionID($latest_transaction_id) 342 ->needProfileImage(true) 343 ->needParticipants(true) 344 ->needTransactions($need_transactions) 345 ->withIDs(array($conpherence_id)) 346 ->executeOne(); 347 348 $non_update = false; 349 350 // The User is always available. The Participant may not. See: 351 // User: it's you, lurking the Chat (maybe it's a public chat). 352 // Participant: it's you, if you are a Chat Member. 353 // https://we.phorge.it/T15497 354 $participant = $conpherence->getParticipantIfExists($user->getPHID()); 355 356 if ($need_transactions && $conpherence->getTransactions()) { 357 $data = ConpherenceTransactionRenderer::renderTransactions( 358 $user, 359 $conpherence); 360 $key = PhabricatorConpherenceColumnMinimizeSetting::SETTINGKEY; 361 $minimized = $user->getUserSetting($key); 362 if (!$minimized && $participant) { 363 $participant->markUpToDate($conpherence); 364 } 365 } else if ($need_transactions) { 366 $non_update = true; 367 $data = array(); 368 } else { 369 $data = array(); 370 } 371 $rendered_transactions = idx($data, 'transactions'); 372 $new_latest_transaction_id = idx($data, 'latest_transaction_id'); 373 374 $update_uri = $this->getApplicationURI('update/'.$conpherence->getID().'/'); 375 $nav_item = null; 376 $header = null; 377 $people_widget = null; 378 switch ($action) { 379 case ConpherenceUpdateActions::ADD_PERSON: 380 $people_widget = id(new ConpherenceParticipantView()) 381 ->setUser($user) 382 ->setConpherence($conpherence) 383 ->setUpdateURI($update_uri); 384 $people_widget = hsprintf('%s', $people_widget->render()); 385 break; 386 case ConpherenceUpdateActions::REMOVE_PERSON: 387 default: 388 break; 389 } 390 $data = $conpherence->getDisplayData($user); 391 $dropdown_query = id(new AphlictDropdownDataQuery()) 392 ->setViewer($user); 393 $dropdown_query->execute(); 394 395 $map = ConpherenceRoomSettings::getSoundMap(); 396 $default_receive = ConpherenceRoomSettings::DEFAULT_RECEIVE_SOUND; 397 $receive_sound = $map[$default_receive]['rsrc']; 398 $mention_sound = null; 399 400 // Get the user's defaults if logged in 401 if ($participant) { 402 $sounds = $this->getSoundForParticipant($user, $participant); 403 $receive_sound = $sounds[ConpherenceRoomSettings::SOUND_RECEIVE]; 404 $mention_sound = $sounds[ConpherenceRoomSettings::SOUND_MENTION]; 405 } 406 407 $content = array( 408 'non_update' => $non_update, 409 'transactions' => hsprintf('%s', $rendered_transactions), 410 'conpherence_title' => (string)$data['title'], 411 'latest_transaction_id' => $new_latest_transaction_id, 412 'nav_item' => $nav_item, 413 'conpherence_phid' => $conpherence->getPHID(), 414 'header' => $header, 415 'people_widget' => $people_widget, 416 'aphlictDropdownData' => array( 417 $dropdown_query->getNotificationData(), 418 $dropdown_query->getConpherenceData(), 419 ), 420 'sound' => array( 421 'receive' => $receive_sound, 422 'mention' => $mention_sound, 423 ), 424 ); 425 426 return $content; 427 } 428 429 protected function getSoundForParticipant( 430 PhabricatorUser $user, 431 ConpherenceParticipant $participant) { 432 433 $sound_key = PhabricatorConpherenceSoundSetting::SETTINGKEY; 434 $sound_default = $user->getUserSetting($sound_key); 435 436 $settings = $participant->getSettings(); 437 $sounds = idx($settings, 'sounds', array()); 438 $map = PhabricatorConpherenceSoundSetting::getDefaultSound($sound_default); 439 440 $receive = idx($sounds, 441 ConpherenceRoomSettings::SOUND_RECEIVE, 442 $map[ConpherenceRoomSettings::SOUND_RECEIVE]); 443 $mention = idx($sounds, 444 ConpherenceRoomSettings::SOUND_MENTION, 445 $map[ConpherenceRoomSettings::SOUND_MENTION]); 446 447 $sound_map = ConpherenceRoomSettings::getSoundMap(); 448 449 return array( 450 ConpherenceRoomSettings::SOUND_RECEIVE => $sound_map[$receive]['rsrc'], 451 ConpherenceRoomSettings::SOUND_MENTION => $sound_map[$mention]['rsrc'], 452 ); 453 454 } 455 456}