@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.

Conpherence - Differentiate audience of Threads/Rooms with icon

Summary:
Fixes T7629 plus an un filed bug that's breaking creating new threads since we need to add participants EVEN EARLIER than we were doing it now that policy is actually enforced.

Back to the main thrust of this, there is one UI corner case - in the main view if you go from 1:1 to 1:1:1 (i.e. add a 3rd recipient, or Nth in a row) the icon only updates on page reload. I figure this will get sorted out at a later refactor as we make the client better / share more code with durable column.

One other small behavioral oddity is in the main view sometime we start loading with no conpherence. in that case, rather than show some incorrect icon, we show no icon (and "no title") and then things change at load. Seems okay-ish.

Finally, @chad - the CSS is a very work-man-like "use the built in stuff you can specify from PHP" so I'm sure it needs some love.

Test Plan: made all sorts of rooms and threads and liked the icons. noted smooth loading action as i switched around

Reviewers: chad, epriestley

Reviewed By: epriestley

Subscribers: Korvin, chad, epriestley

Maniphest Tasks: T7629

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

+452 -70
+12 -12
resources/celerity/map.php
··· 353 353 'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18', 354 354 'rsrc/js/application/config/behavior-reorder-fields.js' => '14a827de', 355 355 'rsrc/js/application/conpherence/ConpherenceThreadManager.js' => 'bb928342', 356 - 'rsrc/js/application/conpherence/behavior-durable-column.js' => 'eedc463c', 356 + 'rsrc/js/application/conpherence/behavior-durable-column.js' => '70787038', 357 357 'rsrc/js/application/conpherence/behavior-menu.js' => 'de5579b4', 358 358 'rsrc/js/application/conpherence/behavior-pontificate.js' => '21ba5861', 359 359 'rsrc/js/application/conpherence/behavior-quicksand-blacklist.js' => '7927a7d3', ··· 583 583 'javelin-behavior-diffusion-locate-file' => '6d3e1947', 584 584 'javelin-behavior-diffusion-pull-lastmodified' => '2b228192', 585 585 'javelin-behavior-doorkeeper-tag' => 'e5822781', 586 - 'javelin-behavior-durable-column' => 'eedc463c', 586 + 'javelin-behavior-durable-column' => '70787038', 587 587 'javelin-behavior-error-log' => '6882e80a', 588 588 'javelin-behavior-fancy-datepicker' => 'c51ae228', 589 589 'javelin-behavior-global-drag-and-drop' => 'bbdf75ca', ··· 1324 1324 '6f7a9da8' => array( 1325 1325 'javelin-install', 1326 1326 ), 1327 + 70787038 => array( 1328 + 'javelin-behavior', 1329 + 'javelin-dom', 1330 + 'javelin-stratcom', 1331 + 'javelin-behavior-device', 1332 + 'javelin-scrollbar', 1333 + 'javelin-quicksand', 1334 + 'phabricator-keyboard-shortcut', 1335 + 'conpherence-thread-manager', 1336 + ), 1327 1337 '70baed2f' => array( 1328 1338 'javelin-install', 1329 1339 'javelin-dom', ··· 1898 1908 'javelin-aphlict', 1899 1909 'phabricator-phtize', 1900 1910 'javelin-dom', 1901 - ), 1902 - 'eedc463c' => array( 1903 - 'javelin-behavior', 1904 - 'javelin-dom', 1905 - 'javelin-stratcom', 1906 - 'javelin-behavior-device', 1907 - 'javelin-scrollbar', 1908 - 'javelin-quicksand', 1909 - 'phabricator-keyboard-shortcut', 1910 - 'conpherence-thread-manager', 1911 1911 ), 1912 1912 'efe49472' => array( 1913 1913 'javelin-install',
+6
src/__phutil_library_map__.php
··· 249 249 'ConpherenceQueryTransactionConduitAPIMethod' => 'applications/conpherence/conduit/ConpherenceQueryTransactionConduitAPIMethod.php', 250 250 'ConpherenceReplyHandler' => 'applications/conpherence/mail/ConpherenceReplyHandler.php', 251 251 'ConpherenceRoomListController' => 'applications/conpherence/controller/ConpherenceRoomListController.php', 252 + 'ConpherenceRoomTestCase' => 'applications/conpherence/__tests__/ConpherenceRoomTestCase.php', 252 253 'ConpherenceSchemaSpec' => 'applications/conpherence/storage/ConpherenceSchemaSpec.php', 253 254 'ConpherenceSettings' => 'applications/conpherence/constants/ConpherenceSettings.php', 255 + 'ConpherenceTestCase' => 'applications/conpherence/__tests__/ConpherenceTestCase.php', 254 256 'ConpherenceThread' => 'applications/conpherence/storage/ConpherenceThread.php', 255 257 'ConpherenceThreadIndexer' => 'applications/conpherence/search/ConpherenceThreadIndexer.php', 256 258 'ConpherenceThreadListView' => 'applications/conpherence/view/ConpherenceThreadListView.php', 257 259 'ConpherenceThreadMailReceiver' => 'applications/conpherence/mail/ConpherenceThreadMailReceiver.php', 258 260 'ConpherenceThreadQuery' => 'applications/conpherence/query/ConpherenceThreadQuery.php', 259 261 'ConpherenceThreadSearchEngine' => 'applications/conpherence/query/ConpherenceThreadSearchEngine.php', 262 + 'ConpherenceThreadTestCase' => 'applications/conpherence/__tests__/ConpherenceThreadTestCase.php', 260 263 'ConpherenceTransaction' => 'applications/conpherence/storage/ConpherenceTransaction.php', 261 264 'ConpherenceTransactionComment' => 'applications/conpherence/storage/ConpherenceTransactionComment.php', 262 265 'ConpherenceTransactionQuery' => 'applications/conpherence/query/ConpherenceTransactionQuery.php', ··· 3414 3417 'ConpherenceQueryTransactionConduitAPIMethod' => 'ConpherenceConduitAPIMethod', 3415 3418 'ConpherenceReplyHandler' => 'PhabricatorMailReplyHandler', 3416 3419 'ConpherenceRoomListController' => 'ConpherenceController', 3420 + 'ConpherenceRoomTestCase' => 'ConpherenceTestCase', 3417 3421 'ConpherenceSchemaSpec' => 'PhabricatorConfigSchemaSpec', 3418 3422 'ConpherenceSettings' => 'ConpherenceConstants', 3423 + 'ConpherenceTestCase' => 'PhabricatorTestCase', 3419 3424 'ConpherenceThread' => array( 3420 3425 'ConpherenceDAO', 3421 3426 'PhabricatorPolicyInterface', ··· 3425 3430 'ConpherenceThreadMailReceiver' => 'PhabricatorObjectMailReceiver', 3426 3431 'ConpherenceThreadQuery' => 'PhabricatorCursorPagedPolicyAwareQuery', 3427 3432 'ConpherenceThreadSearchEngine' => 'PhabricatorApplicationSearchEngine', 3433 + 'ConpherenceThreadTestCase' => 'ConpherenceTestCase', 3428 3434 'ConpherenceTransaction' => 'PhabricatorApplicationTransaction', 3429 3435 'ConpherenceTransactionComment' => 'PhabricatorApplicationTransactionComment', 3430 3436 'ConpherenceTransactionQuery' => 'PhabricatorApplicationTransactionQuery',
+144
src/applications/conpherence/__tests__/ConpherenceRoomTestCase.php
··· 1 + <?php 2 + 3 + final class ConpherenceRoomTestCase extends ConpherenceTestCase { 4 + 5 + protected function getPhabricatorTestCaseConfiguration() { 6 + return array( 7 + self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES => true, 8 + ); 9 + } 10 + 11 + public function testOneUserRoomCreate() { 12 + $creator = $this->generateNewTestUser(); 13 + $participant_phids = array($creator->getPHID()); 14 + 15 + $conpherence = $this->createRoom($creator, $participant_phids); 16 + 17 + $this->assertTrue((bool)$conpherence->getID()); 18 + $this->assertEqual(1, count($conpherence->getParticipants())); 19 + $this->assertEqual( 20 + $participant_phids, 21 + $conpherence->getRecentParticipantPHIDs()); 22 + } 23 + 24 + public function testNUserRoomCreate() { 25 + $creator = $this->generateNewTestUser(); 26 + $friend_1 = $this->generateNewTestUser(); 27 + $friend_2 = $this->generateNewTestUser(); 28 + $friend_3 = $this->generateNewTestUser(); 29 + 30 + $participant_phids = array( 31 + $creator->getPHID(), 32 + $friend_1->getPHID(), 33 + $friend_2->getPHID(), 34 + $friend_3->getPHID(), 35 + ); 36 + 37 + $conpherence = $this->createRoom($creator, $participant_phids); 38 + 39 + $this->assertTrue((bool)$conpherence->getID()); 40 + $this->assertEqual(4, count($conpherence->getParticipants())); 41 + $this->assertEqual( 42 + $participant_phids, 43 + $conpherence->getRecentParticipantPHIDs()); 44 + } 45 + 46 + public function testRoomParticipantAddition() { 47 + $creator = $this->generateNewTestUser(); 48 + $friend_1 = $this->generateNewTestUser(); 49 + $friend_2 = $this->generateNewTestUser(); 50 + $friend_3 = $this->generateNewTestUser(); 51 + 52 + $participant_phids = array( 53 + $creator->getPHID(), 54 + $friend_1->getPHID(), 55 + ); 56 + 57 + $conpherence = $this->createRoom($creator, $participant_phids); 58 + 59 + $this->assertTrue((bool)$conpherence->getID()); 60 + $this->assertEqual(2, count($conpherence->getParticipants())); 61 + $this->assertEqual( 62 + $participant_phids, 63 + $conpherence->getRecentParticipantPHIDs()); 64 + 65 + // test add by creator 66 + $participant_phids[] = $friend_2->getPHID(); 67 + $this->addParticipants($creator, $conpherence, array($friend_2->getPHID())); 68 + $this->assertEqual( 69 + $participant_phids, 70 + $conpherence->getRecentParticipantPHIDs()); 71 + 72 + // test policy error as another user tries to add 73 + $caught = null; 74 + try { 75 + $this->addParticipants( 76 + $friend_2, 77 + $conpherence, 78 + array($friend_3->getPHID())); 79 + } catch (PhabricatorPolicyException $ex) { 80 + $caught = $ex; 81 + } 82 + $this->assertTrue($caught instanceof PhabricatorPolicyException); 83 + 84 + // update edit policy so user has a chance 85 + $this->changeEditPolicy($creator, $conpherence, 'users'); 86 + // test add by other participant, so recent participation should 87 + // meaningfully change 88 + $participant_phids = array( 89 + $friend_2->getPHID(), // actor 90 + $creator->getPHID(), // last actor 91 + $friend_1->getPHID(), 92 + $friend_3->getPHID(), // new addition 93 + ); 94 + $this->addParticipants( 95 + $friend_2, 96 + $conpherence, 97 + array($friend_3->getPHID())); 98 + $this->assertEqual( 99 + $participant_phids, 100 + $conpherence->getRecentParticipantPHIDs()); 101 + } 102 + 103 + private function createRoom( 104 + PhabricatorUser $creator, 105 + array $participant_phids) { 106 + 107 + $conpherence = ConpherenceThread::initializeNewRoom($creator); 108 + 109 + $xactions = array(); 110 + $xactions[] = id(new ConpherenceTransaction()) 111 + ->setTransactionType(ConpherenceTransactionType::TYPE_PARTICIPANTS) 112 + ->setNewValue(array('+' => $participant_phids)); 113 + $xactions[] = id(new ConpherenceTransaction()) 114 + ->setTransactionType(ConpherenceTransactionType::TYPE_TITLE) 115 + ->setNewValue('Test'); 116 + 117 + id(new ConpherenceEditor()) 118 + ->setActor($creator) 119 + ->setContentSource(PhabricatorContentSource::newConsoleSource()) 120 + ->setContinueOnNoEffect(true) 121 + ->applyTransactions($conpherence, $xactions); 122 + 123 + return $conpherence; 124 + } 125 + 126 + private function changeEditPolicy( 127 + PhabricatorUser $actor, 128 + ConpherenceThread $room, 129 + $policy) { 130 + 131 + $xactions = array(); 132 + $xactions[] = id(new ConpherenceTransaction()) 133 + ->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY) 134 + ->setNewValue($policy); 135 + 136 + id(new ConpherenceEditor()) 137 + ->setActor($actor) 138 + ->setContentSource(PhabricatorContentSource::newConsoleSource()) 139 + ->setContinueOnNoEffect(true) 140 + ->applyTransactions($room, $xactions); 141 + } 142 + 143 + 144 + }
+20
src/applications/conpherence/__tests__/ConpherenceTestCase.php
··· 1 + <?php 2 + 3 + abstract class ConpherenceTestCase extends PhabricatorTestCase { 4 + 5 + protected function addParticipants( 6 + PhabricatorUser $actor, 7 + ConpherenceThread $conpherence, 8 + array $participant_phids) { 9 + 10 + $xactions = array(id(new ConpherenceTransaction()) 11 + ->setTransactionType(ConpherenceTransactionType::TYPE_PARTICIPANTS) 12 + ->setNewValue(array('+' => $participant_phids)),); 13 + $editor = id(new ConpherenceEditor()) 14 + ->setActor($actor) 15 + ->setContentSource(PhabricatorContentSource::newConsoleSource()) 16 + ->applyTransactions($conpherence, $xactions); 17 + 18 + } 19 + 20 + }
+102
src/applications/conpherence/__tests__/ConpherenceThreadTestCase.php
··· 1 + <?php 2 + 3 + final class ConpherenceThreadTestCase extends ConpherenceTestCase { 4 + 5 + protected function getPhabricatorTestCaseConfiguration() { 6 + return array( 7 + self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES => true, 8 + ); 9 + } 10 + 11 + public function testOneUserThreadCreate() { 12 + $creator = $this->generateNewTestUser(); 13 + $participant_phids = array($creator->getPHID()); 14 + 15 + $conpherence = $this->createThread($creator, $participant_phids); 16 + 17 + $this->assertTrue((bool)$conpherence->getID()); 18 + $this->assertEqual(1, count($conpherence->getParticipants())); 19 + $this->assertEqual( 20 + $participant_phids, 21 + $conpherence->getRecentParticipantPHIDs()); 22 + } 23 + 24 + public function testNUserThreadCreate() { 25 + $creator = $this->generateNewTestUser(); 26 + $friend_1 = $this->generateNewTestUser(); 27 + $friend_2 = $this->generateNewTestUser(); 28 + $friend_3 = $this->generateNewTestUser(); 29 + 30 + $participant_phids = array( 31 + $creator->getPHID(), 32 + $friend_1->getPHID(), 33 + $friend_2->getPHID(), 34 + $friend_3->getPHID(), 35 + ); 36 + 37 + $conpherence = $this->createThread($creator, $participant_phids); 38 + 39 + $this->assertTrue((bool)$conpherence->getID()); 40 + $this->assertEqual(4, count($conpherence->getParticipants())); 41 + $this->assertEqual( 42 + $participant_phids, 43 + $conpherence->getRecentParticipantPHIDs()); 44 + } 45 + 46 + public function testThreadParticipantAddition() { 47 + $creator = $this->generateNewTestUser(); 48 + $friend_1 = $this->generateNewTestUser(); 49 + $friend_2 = $this->generateNewTestUser(); 50 + $friend_3 = $this->generateNewTestUser(); 51 + 52 + $participant_phids = array( 53 + $creator->getPHID(), 54 + $friend_1->getPHID(), 55 + ); 56 + 57 + $conpherence = $this->createThread($creator, $participant_phids); 58 + 59 + $this->assertTrue((bool)$conpherence->getID()); 60 + $this->assertEqual(2, count($conpherence->getParticipants())); 61 + $this->assertEqual( 62 + $participant_phids, 63 + $conpherence->getRecentParticipantPHIDs()); 64 + 65 + // test add by creator 66 + $participant_phids[] = $friend_2->getPHID(); 67 + $this->addParticipants($creator, $conpherence, array($friend_2->getPHID())); 68 + $this->assertEqual( 69 + $participant_phids, 70 + $conpherence->getRecentParticipantPHIDs()); 71 + 72 + // test add by other participant, so recent participation should 73 + // meaningfully change 74 + $participant_phids = array( 75 + $friend_2->getPHID(), // actor 76 + $creator->getPHID(), // last actor 77 + $friend_1->getPHID(), 78 + $friend_3->getPHID(), // new addition 79 + ); 80 + $this->addParticipants( 81 + $friend_2, 82 + $conpherence, 83 + array($friend_3->getPHID())); 84 + $this->assertEqual( 85 + $participant_phids, 86 + $conpherence->getRecentParticipantPHIDs()); 87 + } 88 + 89 + private function createThread( 90 + PhabricatorUser $creator, 91 + array $participant_phids) { 92 + 93 + list($errors, $conpherence) = ConpherenceEditor::createThread( 94 + $creator, 95 + $participant_phids, 96 + 'Test', 97 + 'Test', 98 + PhabricatorContentSource::newConsoleSource()); 99 + return $conpherence; 100 + } 101 + 102 + }
+11 -1
src/applications/conpherence/controller/ConpherenceController.php
··· 74 74 return $crumbs; 75 75 } 76 76 77 - protected function buildHeaderPaneContent(ConpherenceThread $conpherence) { 77 + protected function buildHeaderPaneContent( 78 + ConpherenceThread $conpherence, 79 + array $policy_objects) { 80 + assert_instances_of($policy_objects, 'PhabricatorPolicy'); 81 + 78 82 $crumbs = $this->buildApplicationCrumbs(); 79 83 $title = $this->getConpherenceTitle($conpherence); 84 + if ($conpherence->getID()) { 85 + $icon = $conpherence->getPolicyIconName($policy_objects); 86 + } else { 87 + $icon = null; 88 + } 80 89 $crumbs->addCrumb( 81 90 id(new PHUICrumbView()) 91 + ->setIcon($icon) 82 92 ->setName($title) 83 93 ->setHref($this->getApplicationURI('update/'.$conpherence->getID().'/')) 84 94 ->setWorkflow(true));
+9 -2
src/applications/conpherence/controller/ConpherenceListController.php
··· 157 157 ->setThreadView($thread_view) 158 158 ->setRole('list'); 159 159 if ($conpherence) { 160 - $layout->setHeader($this->buildHeaderPaneContent($conpherence)); 160 + $policy_objects = id(new PhabricatorPolicyQuery()) 161 + ->setViewer($user) 162 + ->setObject($conpherence) 163 + ->execute(); 164 + $layout->setHeader($this->buildHeaderPaneContent( 165 + $conpherence, 166 + $policy_objects)); 161 167 $layout->setThread($conpherence); 162 168 } else { 163 169 $layout->setHeader( 164 170 $this->buildHeaderPaneContent( 165 171 id(new ConpherenceThread()) 166 - ->makeEphemeral())); 172 + ->makeEphemeral(), 173 + array())); 167 174 } 168 175 $response = $this->buildApplicationPage( 169 176 $layout,
+5 -1
src/applications/conpherence/controller/ConpherenceUpdateController.php
··· 377 377 $file_widget = null; 378 378 switch ($action) { 379 379 case ConpherenceUpdateActions::METADATA: 380 - $header = $this->buildHeaderPaneContent($conpherence); 380 + $policy_objects = id(new PhabricatorPolicyQuery()) 381 + ->setViewer($user) 382 + ->setObject($conpherence) 383 + ->execute(); 384 + $header = $this->buildHeaderPaneContent($conpherence, $policy_objects); 381 385 $nav_item = id(new ConpherenceThreadListView()) 382 386 ->setUser($user) 383 387 ->setBaseURI($this->getApplicationURI())
+5 -1
src/applications/conpherence/controller/ConpherenceViewController.php
··· 47 47 $form = null; 48 48 $content = array('messages' => $messages); 49 49 } else { 50 - $header = $this->buildHeaderPaneContent($conpherence); 50 + $policy_objects = id(new PhabricatorPolicyQuery()) 51 + ->setViewer($user) 52 + ->setObject($conpherence) 53 + ->execute(); 54 + $header = $this->buildHeaderPaneContent($conpherence, $policy_objects); 51 55 $form = $this->renderFormContent(); 52 56 $content = array( 53 57 'header' => $header,
+64 -46
src/applications/conpherence/editor/ConpherenceEditor.php
··· 13 13 return pht('Conpherence Threads'); 14 14 } 15 15 16 - public static function createConpherence( 16 + public static function createThread( 17 17 PhabricatorUser $creator, 18 18 array $participant_phids, 19 19 $title, ··· 28 28 } else { 29 29 $participant_phids[] = $creator->getPHID(); 30 30 $participant_phids = array_unique($participant_phids); 31 - $conpherence->setRecentParticipantPHIDs( 32 - array_slice($participant_phids, 0, 10)); 33 31 } 34 32 35 33 if (empty($message)) { ··· 70 68 ->setConpherencePHID($conpherence->getPHID())); 71 69 72 70 id(new ConpherenceEditor()) 71 + ->setActor($creator) 73 72 ->setContentSource($source) 74 73 ->setContinueOnNoEffect(true) 75 - ->setActor($creator) 76 74 ->applyTransactions($conpherence, $xactions); 77 75 } 78 76 ··· 177 175 178 176 /** 179 177 * We need to apply initial effects IFF the conpherence is new. We must 180 - * save the conpherence first thing to make sure we have an id and a phid. 178 + * save the conpherence first thing to make sure we have an id and a phid, as 179 + * well as create the initial set of participants so that we pass policy 180 + * checks. 181 181 */ 182 182 protected function shouldApplyInitialEffects( 183 183 PhabricatorLiskDAO $object, 184 184 array $xactions) { 185 185 186 - return !$object->getID(); 186 + return $this->getIsNewObject(); 187 187 } 188 188 189 189 protected function applyInitialEffects( ··· 191 191 array $xactions) { 192 192 193 193 $object->save(); 194 - } 195 194 196 - protected function applyCustomInternalTransaction( 197 - PhabricatorLiskDAO $object, 198 - PhabricatorApplicationTransaction $xaction) { 199 - switch ($xaction->getTransactionType()) { 200 - case PhabricatorTransactions::TYPE_COMMENT: 201 - $object->setMessageCount((int)$object->getMessageCount() + 1); 202 - break; 203 - case ConpherenceTransactionType::TYPE_TITLE: 204 - $object->setTitle($xaction->getNewValue()); 205 - break; 206 - case ConpherenceTransactionType::TYPE_PARTICIPANTS: 207 - // If this is a new ConpherenceThread, we have to create the 208 - // participation data asap to pass policy checks. For existing 209 - // ConpherenceThreads, the existing participation is correct 210 - // at this stage. Note that later in applyCustomExternalTransaction 211 - // this participation data will be updated, particularly the 212 - // behindTransactionPHID which is just a generated dummy for now. 213 - if ($this->getIsNewObject()) { 195 + foreach ($xactions as $xaction) { 196 + switch ($xaction->getTransactionType()) { 197 + case ConpherenceTransactionType::TYPE_PARTICIPANTS: 198 + // Since this is a new ConpherenceThread, we have to create the 199 + // participation data asap to pass policy checks. For existing 200 + // ConpherenceThreads, the existing participation is correct 201 + // at this stage. Note that later in applyCustomExternalTransaction 202 + // this participation data will be updated, particularly the 203 + // behindTransactionPHID which is just a generated dummy for now. 214 204 $participants = array(); 215 - foreach ($xaction->getNewValue() as $phid) { 205 + $phids = $this->getPHIDTransactionNewValue($xaction, array()); 206 + foreach ($phids as $phid) { 216 207 if ($phid == $this->getActor()->getPHID()) { 217 208 $status = ConpherenceParticipationStatus::UP_TO_DATE; 218 209 $message_count = 1; ··· 230 221 ->setSeenMessageCount($message_count) 231 222 ->save(); 232 223 $object->attachParticipants($participants); 224 + $object->setRecentParticipantPHIDs(array_keys($participants)); 225 + } 226 + break; 227 + } 228 + } 229 + } 230 + 231 + protected function applyCustomInternalTransaction( 232 + PhabricatorLiskDAO $object, 233 + PhabricatorApplicationTransaction $xaction) { 234 + 235 + switch ($xaction->getTransactionType()) { 236 + case PhabricatorTransactions::TYPE_COMMENT: 237 + $object->setMessageCount((int)$object->getMessageCount() + 1); 238 + break; 239 + case ConpherenceTransactionType::TYPE_TITLE: 240 + $object->setTitle($xaction->getNewValue()); 241 + break; 242 + case ConpherenceTransactionType::TYPE_PARTICIPANTS: 243 + if (!$this->getIsNewObject()) { 244 + // if we added people, add them to the end of "recent" participants 245 + $old_map = array_fuse($xaction->getOldValue()); 246 + $new_map = array_fuse($xaction->getNewValue()); 247 + $add = array_keys(array_diff_key($new_map, $old_map)); 248 + if ($add) { 249 + $participants = $object->getRecentParticipantPHIDs(); 250 + $participants = array_merge($participants, $add); 251 + $participants = array_slice(array_unique($participants), 0, 10); 252 + $object->setRecentParticipantPHIDs($participants); 233 253 } 234 254 } 235 255 break; ··· 275 295 $editor->save(); 276 296 break; 277 297 case ConpherenceTransactionType::TYPE_PARTICIPANTS: 298 + if ($this->getIsNewObject()) { 299 + continue; 300 + } 278 301 $participants = $object->getParticipants(); 279 302 280 303 $old_map = array_fuse($xaction->getOldValue()); ··· 289 312 290 313 $add = array_keys(array_diff_key($new_map, $old_map)); 291 314 foreach ($add as $phid) { 292 - if ($this->getIsNewObject()) { 293 - $participants[$phid] 294 - ->setBehindTransactionPHID($xaction->getPHID()) 295 - ->save(); 315 + if ($phid == $this->getActor()->getPHID()) { 316 + $status = ConpherenceParticipationStatus::UP_TO_DATE; 317 + $message_count = $object->getMessageCount(); 296 318 } else { 297 - if ($phid == $this->getActor()->getPHID()) { 298 - $status = ConpherenceParticipationStatus::UP_TO_DATE; 299 - $message_count = $object->getMessageCount(); 300 - } else { 301 - $status = ConpherenceParticipationStatus::BEHIND; 302 - $message_count = 0; 303 - } 304 - $participants[$phid] = 305 - id(new ConpherenceParticipant()) 306 - ->setConpherencePHID($object->getPHID()) 307 - ->setParticipantPHID($phid) 308 - ->setParticipationStatus($status) 309 - ->setDateTouched(time()) 310 - ->setBehindTransactionPHID($xaction->getPHID()) 311 - ->setSeenMessageCount($message_count) 312 - ->save(); 319 + $status = ConpherenceParticipationStatus::BEHIND; 320 + $message_count = 0; 313 321 } 322 + $participants[$phid] = 323 + id(new ConpherenceParticipant()) 324 + ->setConpherencePHID($object->getPHID()) 325 + ->setParticipantPHID($phid) 326 + ->setParticipationStatus($status) 327 + ->setDateTouched(time()) 328 + ->setBehindTransactionPHID($xaction->getPHID()) 329 + ->setSeenMessageCount($message_count) 330 + ->save(); 314 331 } 315 332 $object->attachParticipants($participants); 316 333 break; ··· 349 366 $participant->setDateTouched($time); 350 367 } else { 351 368 $participant->setSeenMessageCount($object->getMessageCount()); 369 + $participant->setBehindTransactionPHID($xaction_phid); 352 370 $participant->setParticipationStatus($up_to_date); 353 371 $participant->setDateTouched($time); 354 372 }
+14 -3
src/applications/conpherence/storage/ConpherenceThread.php
··· 31 31 } 32 32 33 33 public static function initializeNewRoom(PhabricatorUser $creator) { 34 - $participant_phids = array($creator->getPHID()); 35 34 36 35 return id(new ConpherenceThread()) 37 36 ->setIsRoom(1) ··· 41 40 ->attachFilePHIDs(array()) 42 41 ->setViewPolicy(PhabricatorPolicies::POLICY_USER) 43 42 ->setEditPolicy($creator->getPHID()) 44 - ->setJoinPolicy(PhabricatorPolicies::POLICY_USER) 45 - ->setRecentParticipantPHIDs($participant_phids); 43 + ->setJoinPolicy(PhabricatorPolicies::POLICY_USER); 46 44 } 47 45 48 46 protected function getConfiguration() { ··· 275 273 } else { 276 274 return pht('Participants in a thread can always view and edit it.'); 277 275 } 276 + } 277 + 278 + public function getPolicyIconName(array $policy_objects) { 279 + assert_instances_of($policy_objects, 'PhabricatorPolicy'); 280 + 281 + if ($this->getIsRoom()) { 282 + $icon = $policy_objects[$this->getViewPolicy()]->getIcon(); 283 + } else if (count($this->getRecentParticipantPHIDs()) > 2) { 284 + $icon = 'fa-users'; 285 + } else { 286 + $icon = 'fa-user'; 287 + } 288 + return $icon; 278 289 } 279 290 280 291 }
+59 -3
src/applications/conpherence/view/ConpherenceDurableColumnView.php
··· 8 8 private $transactions; 9 9 private $visible; 10 10 private $initialLoad = false; 11 + private $policyObjects; 11 12 12 13 public function setConpherences(array $conpherences) { 13 14 assert_instances_of($conpherences, 'ConpherenceThread'); ··· 66 67 return $this->initialLoad; 67 68 } 68 69 70 + public function setPolicyObjects(array $objects) { 71 + assert_instances_of($objects, 'PhabricatorPolicy'); 72 + 73 + $this->policyObjects = $objects; 74 + return $this; 75 + } 76 + 77 + public function getPolicyObjects() { 78 + return $this->policyObjects; 79 + } 80 + 69 81 protected function getTagAttributes() { 70 82 if ($this->getVisible()) { 71 83 $style = null; ··· 96 108 'settingsURI' => '/settings/adjust/?key='.$column_key, 97 109 )); 98 110 111 + $policies = array(); 112 + $conpherences = $this->getConpherences(); 113 + foreach ($conpherences as $conpherence) { 114 + if (!$conpherence->getIsRoom()) { 115 + continue; 116 + } 117 + $policies[] = $conpherence->getViewPolicy(); 118 + } 119 + $policy_objects = array(); 120 + if ($policies) { 121 + $policy_objects = id(new PhabricatorPolicyQuery()) 122 + ->setViewer($this->getUser()) 123 + ->withPHIDs($policies) 124 + ->execute(); 125 + } 126 + $this->setPolicyObjects($policy_objects); 127 + 99 128 $classes = array(); 100 129 $classes[] = 'conpherence-durable-column-header'; 101 130 $classes[] = 'sprite-main-header'; ··· 178 207 ); 179 208 } 180 209 210 + private function getPolicyIcon( 211 + ConpherenceThread $conpherence, 212 + array $policy_objects) { 213 + 214 + assert_instances_of($policy_objects, 'PhabricatorPolicy'); 215 + 216 + $icon = $conpherence->getPolicyIconName($policy_objects); 217 + return id(new PHUIIconView()) 218 + ->addClass('mmr') 219 + ->setIconFont($icon.' lightgreytext'); 220 + } 221 + 181 222 private function buildIconBar() { 182 223 $icons = array(); 183 224 $selected_conpherence = $this->getSelectedConpherence(); ··· 189 230 $classes[] = 'selected'; 190 231 } 191 232 $data = $conpherence->getDisplayData($this->getUser()); 233 + $icon = $this->getPolicyIcon($conpherence, $this->getPolicyObjects()); 234 + $thread_title = phutil_tag( 235 + 'span', 236 + array(), 237 + array( 238 + $icon, 239 + $data['js_title'], 240 + )); 192 241 $image = $data['image']; 193 242 Javelin::initBehavior('phabricator-tooltips'); 194 243 $icons[] = ··· 200 249 'sigil' => 'conpherence-durable-column-thread-icon has-tooltip', 201 250 'meta' => array( 202 251 'threadID' => $conpherence->getID(), 203 - 'threadTitle' => $data['js_title'], 252 + 'threadTitle' => hsprintf('%s', $thread_title), 204 253 'tip' => $data['js_title'], 205 254 'align' => 'S', 206 255 ), ··· 220 269 221 270 if (!$conpherence) { 222 271 223 - $title = null; 272 + $header = null; 224 273 $settings_button = null; 225 274 $settings_menu = null; 226 275 ··· 282 331 if (!$title) { 283 332 $title = pht('[No Title]'); 284 333 } 334 + $header = phutil_tag( 335 + 'span', 336 + array(), 337 + array( 338 + $this->getPolicyIcon($conpherence, $this->getPolicyObjects()), 339 + $title, 340 + )); 285 341 } 286 342 287 343 return ··· 297 353 'sigil' => 'conpherence-durable-column-header-text', 298 354 'class' => 'conpherence-durable-column-header-text', 299 355 ), 300 - $title), 356 + $header), 301 357 $settings_button, 302 358 $settings_menu,)); 303 359
+1 -1
webroot/rsrc/js/application/conpherence/behavior-durable-column.js
··· 183 183 'selected', 184 184 cdata.threadID == data.threadID); 185 185 } 186 - JX.DOM.setContent(_getColumnTitleNode(), data.threadTitle); 186 + JX.DOM.setContent(_getColumnTitleNode(), JX.$H(data.threadTitle)); 187 187 threadManager.loadThreadByID(data.threadID); 188 188 }); 189 189