@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<?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}