Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/conpherence/__tests__/ConpherenceRoomTestCase.php b/src/applications/conpherence/__tests__/ConpherenceRoomTestCase.php
index b44873c931..d5e6caa322 100644
--- a/src/applications/conpherence/__tests__/ConpherenceRoomTestCase.php
+++ b/src/applications/conpherence/__tests__/ConpherenceRoomTestCase.php
@@ -1,170 +1,193 @@
<?php
final class ConpherenceRoomTestCase extends ConpherenceTestCase {
protected function getPhabricatorTestCaseConfiguration() {
return array(
self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES => true,
);
}
public function testOneUserRoomCreate() {
$creator = $this->generateNewTestUser();
$participant_phids = array($creator->getPHID());
$conpherence = $this->createRoom($creator, $participant_phids);
$this->assertTrue((bool)$conpherence->getID());
$this->assertEqual(1, count($conpherence->getParticipants()));
$this->assertEqual(
$participant_phids,
$conpherence->getRecentParticipantPHIDs());
}
public function testNUserRoomCreate() {
$creator = $this->generateNewTestUser();
$friend_1 = $this->generateNewTestUser();
$friend_2 = $this->generateNewTestUser();
$friend_3 = $this->generateNewTestUser();
$participant_phids = array(
$creator->getPHID(),
$friend_1->getPHID(),
$friend_2->getPHID(),
$friend_3->getPHID(),
);
$conpherence = $this->createRoom($creator, $participant_phids);
$this->assertTrue((bool)$conpherence->getID());
$this->assertEqual(4, count($conpherence->getParticipants()));
$this->assertEqual(
$participant_phids,
$conpherence->getRecentParticipantPHIDs());
}
public function testRoomParticipantAddition() {
$creator = $this->generateNewTestUser();
$friend_1 = $this->generateNewTestUser();
$friend_2 = $this->generateNewTestUser();
$friend_3 = $this->generateNewTestUser();
$participant_phids = array(
$creator->getPHID(),
$friend_1->getPHID(),
);
$conpherence = $this->createRoom($creator, $participant_phids);
$this->assertTrue((bool)$conpherence->getID());
$this->assertEqual(2, count($conpherence->getParticipants()));
$this->assertEqual(
$participant_phids,
$conpherence->getRecentParticipantPHIDs());
// test add by creator
$participant_phids[] = $friend_2->getPHID();
$this->addParticipants($creator, $conpherence, array($friend_2->getPHID()));
$this->assertEqual(
$participant_phids,
$conpherence->getRecentParticipantPHIDs());
// test policy error as another user tries to add
$caught = null;
try {
$this->addParticipants(
$friend_2,
$conpherence,
array($friend_3->getPHID()));
} catch (PhabricatorPolicyException $ex) {
$caught = $ex;
}
$this->assertTrue($caught instanceof PhabricatorPolicyException);
// update edit policy so user has a chance
$this->changeEditPolicy($creator, $conpherence, 'users');
// test add by other participant, so recent participation should
// meaningfully change
$participant_phids = array(
$friend_2->getPHID(), // actor
$creator->getPHID(), // last actor
$friend_1->getPHID(),
$friend_3->getPHID(), // new addition
);
$this->addParticipants(
$friend_2,
$conpherence,
array($friend_3->getPHID()));
$this->assertEqual(
$participant_phids,
$conpherence->getRecentParticipantPHIDs());
}
public function testRoomParticipantDeletion() {
$creator = $this->generateNewTestUser();
$friend_1 = $this->generateNewTestUser();
$friend_2 = $this->generateNewTestUser();
$friend_3 = $this->generateNewTestUser();
$participant_map = array(
$creator->getPHID() => $creator,
$friend_1->getPHID() => $friend_1,
$friend_2->getPHID() => $friend_2,
$friend_3->getPHID() => $friend_3,
);
$conpherence = $this->createRoom(
$creator,
array_keys($participant_map));
foreach ($participant_map as $phid => $user) {
$this->removeParticipants($user, $conpherence, array($phid));
unset($participant_map[$phid]);
$this->assertEqual(
count($participant_map),
count($conpherence->getParticipants()));
}
}
+ public function testAddMessageWithFileAttachments() {
+ $creator = $this->generateNewTestUser();
+ $friend_1 = $this->generateNewTestUser();
+ $join_via_add = $this->generateNewTestUser();
+
+ $participant_map = array(
+ $creator->getPHID() => $creator,
+ $friend_1->getPHID() => $friend_1,
+ );
+
+ $conpherence = $this->createRoom(
+ $creator,
+ array_keys($participant_map));
+
+ foreach ($participant_map as $phid => $user) {
+ $xactions = $this->addMessageWithFile($user, $conpherence);
+ $this->assertEqual(2, count($xactions));
+ }
+
+ $xactions = $this->addMessageWithFile($join_via_add, $conpherence);
+ $this->assertEqual(2, count($xactions));
+ }
+
private function createRoom(
PhabricatorUser $creator,
array $participant_phids) {
$conpherence = ConpherenceThread::initializeNewRoom($creator);
$xactions = array();
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(ConpherenceTransactionType::TYPE_PARTICIPANTS)
->setNewValue(array('+' => $participant_phids));
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(ConpherenceTransactionType::TYPE_TITLE)
->setNewValue('Test');
id(new ConpherenceEditor())
->setActor($creator)
->setContentSource(PhabricatorContentSource::newConsoleSource())
->setContinueOnNoEffect(true)
->applyTransactions($conpherence, $xactions);
return $conpherence;
}
private function changeEditPolicy(
PhabricatorUser $actor,
ConpherenceThread $room,
$policy) {
$xactions = array();
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
->setNewValue($policy);
id(new ConpherenceEditor())
->setActor($actor)
->setContentSource(PhabricatorContentSource::newConsoleSource())
->setContinueOnNoEffect(true)
->applyTransactions($room, $xactions);
}
}
diff --git a/src/applications/conpherence/__tests__/ConpherenceTestCase.php b/src/applications/conpherence/__tests__/ConpherenceTestCase.php
index 4528251100..97852755ae 100644
--- a/src/applications/conpherence/__tests__/ConpherenceTestCase.php
+++ b/src/applications/conpherence/__tests__/ConpherenceTestCase.php
@@ -1,37 +1,75 @@
<?php
abstract class ConpherenceTestCase extends PhabricatorTestCase {
protected function addParticipants(
PhabricatorUser $actor,
ConpherenceThread $conpherence,
array $participant_phids) {
$xactions = array(id(new ConpherenceTransaction())
->setTransactionType(ConpherenceTransactionType::TYPE_PARTICIPANTS)
->setNewValue(array('+' => $participant_phids)),
);
$editor = id(new ConpherenceEditor())
->setActor($actor)
->setContentSource(PhabricatorContentSource::newConsoleSource())
->applyTransactions($conpherence, $xactions);
}
protected function removeParticipants(
PhabricatorUser $actor,
ConpherenceThread $conpherence,
array $participant_phids) {
$xactions = array(id(new ConpherenceTransaction())
->setTransactionType(ConpherenceTransactionType::TYPE_PARTICIPANTS)
->setNewValue(array('-' => $participant_phids)),
);
$editor = id(new ConpherenceEditor())
->setActor($actor)
->setContentSource(PhabricatorContentSource::newConsoleSource())
->applyTransactions($conpherence, $xactions);
}
+ protected function addMessageWithFile(
+ PhabricatorUser $actor,
+ ConpherenceThread $conpherence) {
+
+ $file = $this->generateTestFile($actor);
+ $message = Filesystem::readRandomCharacters(64).
+ sprintf(' {%s} ', $file->getMonogram());
+
+ $editor = id(new ConpherenceEditor())
+ ->setActor($actor)
+ ->setContentSource(PhabricatorContentSource::newConsoleSource());
+
+ $xactions = $editor->generateTransactionsFromText(
+ $actor,
+ $conpherence,
+ $message);
+
+ return $editor->applyTransactions($conpherence, $xactions);
+ }
+
+ private function generateTestFile(PhabricatorUser $actor) {
+ $engine = new PhabricatorTestStorageEngine();
+ $data = Filesystem::readRandomCharacters(64);
+
+ $params = array(
+ 'name' => 'test.'.$actor->getPHID(),
+ 'viewPolicy' => $actor->getPHID(),
+ 'authorPHID' => $actor->getPHID(),
+ 'storageEngines' => array(
+ $engine,
+ ),
+ );
+
+ $file = PhabricatorFile::newFromFileData($data, $params);
+ $file->save();
+
+ return $file;
+ }
}
diff --git a/src/applications/conpherence/__tests__/ConpherenceThreadTestCase.php b/src/applications/conpherence/__tests__/ConpherenceThreadTestCase.php
index 4ed21f2f26..1f60f1e149 100644
--- a/src/applications/conpherence/__tests__/ConpherenceThreadTestCase.php
+++ b/src/applications/conpherence/__tests__/ConpherenceThreadTestCase.php
@@ -1,128 +1,169 @@
<?php
final class ConpherenceThreadTestCase extends ConpherenceTestCase {
protected function getPhabricatorTestCaseConfiguration() {
return array(
self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES => true,
);
}
public function testOneUserThreadCreate() {
$creator = $this->generateNewTestUser();
$participant_phids = array($creator->getPHID());
$conpherence = $this->createThread($creator, $participant_phids);
$this->assertTrue((bool)$conpherence->getID());
$this->assertEqual(1, count($conpherence->getParticipants()));
$this->assertEqual(
$participant_phids,
$conpherence->getRecentParticipantPHIDs());
}
public function testNUserThreadCreate() {
$creator = $this->generateNewTestUser();
$friend_1 = $this->generateNewTestUser();
$friend_2 = $this->generateNewTestUser();
$friend_3 = $this->generateNewTestUser();
$participant_phids = array(
$creator->getPHID(),
$friend_1->getPHID(),
$friend_2->getPHID(),
$friend_3->getPHID(),
);
$conpherence = $this->createThread($creator, $participant_phids);
$this->assertTrue((bool)$conpherence->getID());
$this->assertEqual(4, count($conpherence->getParticipants()));
$this->assertEqual(
$participant_phids,
$conpherence->getRecentParticipantPHIDs());
}
public function testThreadParticipantAddition() {
$creator = $this->generateNewTestUser();
$friend_1 = $this->generateNewTestUser();
$friend_2 = $this->generateNewTestUser();
$friend_3 = $this->generateNewTestUser();
$participant_phids = array(
$creator->getPHID(),
$friend_1->getPHID(),
);
$conpherence = $this->createThread($creator, $participant_phids);
$this->assertTrue((bool)$conpherence->getID());
$this->assertEqual(2, count($conpherence->getParticipants()));
$this->assertEqual(
$participant_phids,
$conpherence->getRecentParticipantPHIDs());
// test add by creator
$participant_phids[] = $friend_2->getPHID();
$this->addParticipants($creator, $conpherence, array($friend_2->getPHID()));
$this->assertEqual(
$participant_phids,
$conpherence->getRecentParticipantPHIDs());
// test add by other participant, so recent participation should
// meaningfully change
$participant_phids = array(
$friend_2->getPHID(), // actor
$creator->getPHID(), // last actor
$friend_1->getPHID(),
$friend_3->getPHID(), // new addition
);
$this->addParticipants(
$friend_2,
$conpherence,
array($friend_3->getPHID()));
$this->assertEqual(
$participant_phids,
$conpherence->getRecentParticipantPHIDs());
}
public function testThreadParticipantDeletion() {
$creator = $this->generateNewTestUser();
$friend_1 = $this->generateNewTestUser();
$friend_2 = $this->generateNewTestUser();
$friend_3 = $this->generateNewTestUser();
$participant_map = array(
$creator->getPHID() => $creator,
$friend_1->getPHID() => $friend_1,
$friend_2->getPHID() => $friend_2,
$friend_3->getPHID() => $friend_3,
);
$conpherence = $this->createThread(
$creator,
array_keys($participant_map));
foreach ($participant_map as $phid => $user) {
$this->removeParticipants($user, $conpherence, array($phid));
unset($participant_map[$phid]);
$this->assertEqual(
count($participant_map),
count($conpherence->getParticipants()));
}
}
+ public function testAddMessageWithFileAttachments() {
+ $creator = $this->generateNewTestUser();
+ $friend_1 = $this->generateNewTestUser();
+ $policy_exception_user = $this->generateNewTestUser();
+
+ $participant_map = array(
+ $creator->getPHID() => $creator,
+ $friend_1->getPHID() => $friend_1,
+ );
+
+ $conpherence = $this->createThread(
+ $creator,
+ array_keys($participant_map));
+
+ foreach ($participant_map as $phid => $user) {
+ $xactions = $this->addMessageWithFile($user, $conpherence);
+ $this->assertEqual(2, count($xactions), pht('hi'));
+ }
+
+ $caught = null;
+ try {
+ $xactions = $this->addMessageWithFile(
+ $policy_exception_user,
+ $conpherence);
+ } catch (PhabricatorPolicyException $ex) {
+ $caught = $ex;
+ }
+ $this->assertTrue(
+ $caught instanceof PhabricatorPolicyException,
+ pht(
+ 'User not participating in thread should get policy exception '.
+ 'trying to add message.'));
+ $this->assertTrue(
+ $conpherence->establishConnection('w')->isReadLocking(),
+ pht(
+ 'Conpherence object should still be read locked from policy '.
+ 'exception.'));
+ $conpherence->endReadLocking();
+ $conpherence->killTransaction();
+ }
+
private function createThread(
PhabricatorUser $creator,
array $participant_phids) {
list($errors, $conpherence) = ConpherenceEditor::createThread(
$creator,
$participant_phids,
'Test',
'Test',
PhabricatorContentSource::newConsoleSource());
return $conpherence;
}
}
diff --git a/src/applications/conpherence/editor/ConpherenceEditor.php b/src/applications/conpherence/editor/ConpherenceEditor.php
index 166ad055b1..8c68cc98ca 100644
--- a/src/applications/conpherence/editor/ConpherenceEditor.php
+++ b/src/applications/conpherence/editor/ConpherenceEditor.php
@@ -1,635 +1,642 @@
<?php
final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
const ERROR_EMPTY_PARTICIPANTS = 'error-empty-participants';
const ERROR_EMPTY_MESSAGE = 'error-empty-message';
public function getEditorApplicationClass() {
return 'PhabricatorConpherenceApplication';
}
public function getEditorObjectsDescription() {
return pht('Conpherence Threads');
}
public static function createThread(
PhabricatorUser $creator,
array $participant_phids,
$title,
$message,
PhabricatorContentSource $source) {
$conpherence = ConpherenceThread::initializeNewThread($creator);
$files = array();
$errors = array();
if (empty($participant_phids)) {
$errors[] = self::ERROR_EMPTY_PARTICIPANTS;
} else {
$participant_phids[] = $creator->getPHID();
$participant_phids = array_unique($participant_phids);
}
if (empty($message)) {
$errors[] = self::ERROR_EMPTY_MESSAGE;
}
$file_phids = PhabricatorMarkupEngine::extractFilePHIDsFromEmbeddedFiles(
$creator,
array($message));
if ($file_phids) {
$files = id(new PhabricatorFileQuery())
->setViewer($creator)
->withPHIDs($file_phids)
->execute();
}
if (!$errors) {
$xactions = array();
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(ConpherenceTransactionType::TYPE_PARTICIPANTS)
->setNewValue(array('+' => $participant_phids));
if ($files) {
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(ConpherenceTransactionType::TYPE_FILES)
->setNewValue(array('+' => mpull($files, 'getPHID')));
}
if ($title) {
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(ConpherenceTransactionType::TYPE_TITLE)
->setNewValue($title);
}
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
->attachComment(
id(new ConpherenceTransactionComment())
->setContent($message)
->setConpherencePHID($conpherence->getPHID()));
id(new ConpherenceEditor())
->setActor($creator)
->setContentSource($source)
->setContinueOnNoEffect(true)
->applyTransactions($conpherence, $xactions);
}
return array($errors, $conpherence);
}
public function generateTransactionsFromText(
PhabricatorUser $viewer,
ConpherenceThread $conpherence,
$text) {
$files = array();
$file_phids = PhabricatorMarkupEngine::extractFilePHIDsFromEmbeddedFiles(
$viewer,
array($text));
// Since these are extracted from text, we might be re-including the
// same file -- e.g. a mock under discussion. Filter files we
// already have.
$existing_file_phids = $conpherence->getFilePHIDs();
$file_phids = array_diff($file_phids, $existing_file_phids);
if ($file_phids) {
$files = id(new PhabricatorFileQuery())
->setViewer($this->getActor())
->withPHIDs($file_phids)
->execute();
}
$xactions = array();
if ($files) {
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(ConpherenceTransactionType::TYPE_FILES)
->setNewValue(array('+' => mpull($files, 'getPHID')));
}
$xactions[] = id(new ConpherenceTransaction())
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
->attachComment(
id(new ConpherenceTransactionComment())
->setContent($text)
->setConpherencePHID($conpherence->getPHID()));
return $xactions;
}
public function getTransactionTypes() {
$types = parent::getTransactionTypes();
$types[] = PhabricatorTransactions::TYPE_COMMENT;
$types[] = ConpherenceTransactionType::TYPE_TITLE;
$types[] = ConpherenceTransactionType::TYPE_PARTICIPANTS;
$types[] = ConpherenceTransactionType::TYPE_FILES;
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
$types[] = PhabricatorTransactions::TYPE_JOIN_POLICY;
return $types;
}
protected function getCustomTransactionOldValue(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case ConpherenceTransactionType::TYPE_TITLE:
return $object->getTitle();
case ConpherenceTransactionType::TYPE_PARTICIPANTS:
if ($this->getIsNewObject()) {
return array();
}
return $object->getParticipantPHIDs();
case ConpherenceTransactionType::TYPE_FILES:
return $object->getFilePHIDs();
}
}
protected function getCustomTransactionNewValue(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case ConpherenceTransactionType::TYPE_TITLE:
return $xaction->getNewValue();
case ConpherenceTransactionType::TYPE_PARTICIPANTS:
case ConpherenceTransactionType::TYPE_FILES:
return $this->getPHIDTransactionNewValue($xaction);
}
}
/**
* We really only need a read lock if we have a comment. In that case, we
* must update the messagesCount field on the conpherence and
* seenMessagesCount(s) for the participant(s).
*/
protected function shouldReadLock(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
$lock = false;
switch ($xaction->getTransactionType()) {
case PhabricatorTransactions::TYPE_COMMENT:
$lock = true;
break;
}
return $lock;
}
/**
* We need to apply initial effects IFF the conpherence is new. We must
* save the conpherence first thing to make sure we have an id and a phid, as
* well as create the initial set of participants so that we pass policy
* checks.
*/
protected function shouldApplyInitialEffects(
PhabricatorLiskDAO $object,
array $xactions) {
return $this->getIsNewObject();
}
protected function applyInitialEffects(
PhabricatorLiskDAO $object,
array $xactions) {
$object->save();
foreach ($xactions as $xaction) {
switch ($xaction->getTransactionType()) {
case ConpherenceTransactionType::TYPE_PARTICIPANTS:
// Since this is a new ConpherenceThread, we have to create the
// participation data asap to pass policy checks. For existing
// ConpherenceThreads, the existing participation is correct
// at this stage. Note that later in applyCustomExternalTransaction
// this participation data will be updated, particularly the
// behindTransactionPHID which is just a generated dummy for now.
$participants = array();
$phids = $this->getPHIDTransactionNewValue($xaction, array());
foreach ($phids as $phid) {
if ($phid == $this->getActor()->getPHID()) {
$status = ConpherenceParticipationStatus::UP_TO_DATE;
$message_count = 1;
} else {
$status = ConpherenceParticipationStatus::BEHIND;
$message_count = 0;
}
$participants[$phid] =
id(new ConpherenceParticipant())
->setConpherencePHID($object->getPHID())
->setParticipantPHID($phid)
->setParticipationStatus($status)
->setDateTouched(time())
->setBehindTransactionPHID($xaction->generatePHID())
->setSeenMessageCount($message_count)
->save();
$object->attachParticipants($participants);
$object->setRecentParticipantPHIDs(array_keys($participants));
}
break;
}
}
}
protected function applyCustomInternalTransaction(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
$make_author_recent_participant = true;
switch ($xaction->getTransactionType()) {
case PhabricatorTransactions::TYPE_COMMENT:
$object->setMessageCount((int)$object->getMessageCount() + 1);
break;
case ConpherenceTransactionType::TYPE_TITLE:
$object->setTitle($xaction->getNewValue());
break;
case ConpherenceTransactionType::TYPE_PARTICIPANTS:
if (!$this->getIsNewObject()) {
$old_map = array_fuse($xaction->getOldValue());
$new_map = array_fuse($xaction->getNewValue());
// if we added people, add them to the end of "recent" participants
$add = array_keys(array_diff_key($new_map, $old_map));
// if we remove people, then definintely remove them from "recent"
// participants
$del = array_keys(array_diff_key($old_map, $new_map));
if ($add || $del) {
$participants = $object->getRecentParticipantPHIDs();
if ($add) {
$participants = array_merge($participants, $add);
}
if ($del) {
$participants = array_diff($participants, $del);
$actor = $this->requireActor();
if (in_array($actor->getPHID(), $del)) {
$make_author_recent_participant = false;
}
}
$participants = array_slice(array_unique($participants), 0, 10);
$object->setRecentParticipantPHIDs($participants);
}
}
break;
}
if ($make_author_recent_participant) {
$this->makeAuthorMostRecentParticipant($object, $xaction);
}
}
private function makeAuthorMostRecentParticipant(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
$participants = $object->getRecentParticipantPHIDs();
array_unshift($participants, $xaction->getAuthorPHID());
$participants = array_slice(array_unique($participants), 0, 10);
$object->setRecentParticipantPHIDs($participants);
}
protected function applyCustomExternalTransaction(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
switch ($xaction->getTransactionType()) {
case ConpherenceTransactionType::TYPE_FILES:
$editor = new PhabricatorEdgeEditor();
$edge_type = PhabricatorObjectHasFileEdgeType::EDGECONST;
$old = array_fill_keys($xaction->getOldValue(), true);
$new = array_fill_keys($xaction->getNewValue(), true);
$add_edges = array_keys(array_diff_key($new, $old));
$remove_edges = array_keys(array_diff_key($old, $new));
foreach ($add_edges as $file_phid) {
$editor->addEdge(
$object->getPHID(),
$edge_type,
$file_phid);
}
foreach ($remove_edges as $file_phid) {
$editor->removeEdge(
$object->getPHID(),
$edge_type,
$file_phid);
}
$editor->save();
break;
case ConpherenceTransactionType::TYPE_PARTICIPANTS:
if ($this->getIsNewObject()) {
continue;
}
$participants = $object->getParticipants();
$old_map = array_fuse($xaction->getOldValue());
$new_map = array_fuse($xaction->getNewValue());
$remove = array_keys(array_diff_key($old_map, $new_map));
foreach ($remove as $phid) {
$remove_participant = $participants[$phid];
$remove_participant->delete();
unset($participants[$phid]);
}
$add = array_keys(array_diff_key($new_map, $old_map));
foreach ($add as $phid) {
if ($phid == $this->getActor()->getPHID()) {
$status = ConpherenceParticipationStatus::UP_TO_DATE;
$message_count = $object->getMessageCount();
} else {
$status = ConpherenceParticipationStatus::BEHIND;
$message_count = 0;
}
$participants[$phid] =
id(new ConpherenceParticipant())
->setConpherencePHID($object->getPHID())
->setParticipantPHID($phid)
->setParticipationStatus($status)
->setDateTouched(time())
->setBehindTransactionPHID($xaction->getPHID())
->setSeenMessageCount($message_count)
->save();
}
$object->attachParticipants($participants);
break;
}
}
protected function applyFinalEffects(
PhabricatorLiskDAO $object,
array $xactions) {
$message_count = 0;
foreach ($xactions as $xaction) {
switch ($xaction->getTransactionType()) {
case PhabricatorTransactions::TYPE_COMMENT:
$message_count++;
break;
}
}
// update everyone's participation status on the last xaction -only-
$xaction = end($xactions);
$xaction_phid = $xaction->getPHID();
$behind = ConpherenceParticipationStatus::BEHIND;
$up_to_date = ConpherenceParticipationStatus::UP_TO_DATE;
$participants = $object->getParticipants();
$user = $this->getActor();
$time = time();
foreach ($participants as $phid => $participant) {
if ($phid != $user->getPHID()) {
if ($participant->getParticipationStatus() != $behind) {
$participant->setBehindTransactionPHID($xaction_phid);
$participant->setSeenMessageCount(
$object->getMessageCount() - $message_count);
}
$participant->setParticipationStatus($behind);
$participant->setDateTouched($time);
} else {
$participant->setSeenMessageCount($object->getMessageCount());
$participant->setBehindTransactionPHID($xaction_phid);
$participant->setParticipationStatus($up_to_date);
$participant->setDateTouched($time);
}
$participant->save();
}
if ($xactions) {
$data = array(
'type' => 'message',
'threadPHID' => $object->getPHID(),
'messageID' => last($xactions)->getID(),
'subscribers' => array($object->getPHID()),
);
PhabricatorNotificationClient::tryToPostMessage($data);
}
return $xactions;
}
protected function requireCapabilities(
PhabricatorLiskDAO $object,
PhabricatorApplicationTransaction $xaction) {
parent::requireCapabilities($object, $xaction);
switch ($xaction->getTransactionType()) {
case ConpherenceTransactionType::TYPE_PARTICIPANTS:
$old_map = array_fuse($xaction->getOldValue());
$new_map = array_fuse($xaction->getNewValue());
$add = array_keys(array_diff_key($new_map, $old_map));
$rem = array_keys(array_diff_key($old_map, $new_map));
$actor_phid = $this->requireActor()->getPHID();
$is_join = (($add === array($actor_phid)) && !$rem);
$is_leave = (($rem === array($actor_phid)) && !$add);
if ($is_join) {
// You need CAN_JOIN to join a thread / room.
PhabricatorPolicyFilter::requireCapability(
$this->requireActor(),
$object,
PhabricatorPolicyCapability::CAN_JOIN);
} else if ($is_leave) {
// You don't need any capabilities to leave a conpherence thread.
} else {
// You need CAN_EDIT to change participants other than yourself.
PhabricatorPolicyFilter::requireCapability(
$this->requireActor(),
$object,
PhabricatorPolicyCapability::CAN_EDIT);
}
break;
+ // This is similar to PhabricatorTransactions::TYPE_COMMENT so
+ // use CAN_VIEW
case ConpherenceTransactionType::TYPE_FILES:
+ PhabricatorPolicyFilter::requireCapability(
+ $this->requireActor(),
+ $object,
+ PhabricatorPolicyCapability::CAN_VIEW);
+ break;
case ConpherenceTransactionType::TYPE_TITLE:
PhabricatorPolicyFilter::requireCapability(
$this->requireActor(),
$object,
PhabricatorPolicyCapability::CAN_EDIT);
break;
}
}
protected function mergeTransactions(
PhabricatorApplicationTransaction $u,
PhabricatorApplicationTransaction $v) {
$type = $u->getTransactionType();
switch ($type) {
case ConpherenceTransactionType::TYPE_TITLE:
return $v;
case ConpherenceTransactionType::TYPE_FILES:
case ConpherenceTransactionType::TYPE_PARTICIPANTS:
return $this->mergePHIDOrEdgeTransactions($u, $v);
}
return parent::mergeTransactions($u, $v);
}
protected function shouldSendMail(
PhabricatorLiskDAO $object,
array $xactions) {
return true;
}
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
return id(new ConpherenceReplyHandler())
->setActor($this->getActor())
->setMailReceiver($object);
}
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
$id = $object->getID();
$title = $object->getTitle();
if (!$title) {
$title = pht(
'%s sent you a message.',
$this->getActor()->getUserName());
}
$phid = $object->getPHID();
return id(new PhabricatorMetaMTAMail())
->setSubject("E{$id}: {$title}")
->addHeader('Thread-Topic', "E{$id}: {$phid}");
}
protected function getMailTo(PhabricatorLiskDAO $object) {
$to_phids = array();
$participants = $object->getParticipants();
if (empty($participants)) {
return $to_phids;
}
$preferences = id(new PhabricatorUserPreferences())
->loadAllWhere('userPHID in (%Ls)', array_keys($participants));
$preferences = mpull($preferences, null, 'getUserPHID');
foreach ($participants as $phid => $participant) {
$default = ConpherenceSettings::EMAIL_ALWAYS;
$preference = idx($preferences, $phid);
if ($preference) {
$default = $preference->getPreference(
PhabricatorUserPreferences::PREFERENCE_CONPH_NOTIFICATIONS,
ConpherenceSettings::EMAIL_ALWAYS);
}
$settings = $participant->getSettings();
$notifications = idx(
$settings,
'notifications',
$default);
if ($notifications == ConpherenceSettings::EMAIL_ALWAYS) {
$to_phids[] = $phid;
}
}
return $to_phids;
}
protected function getMailCC(PhabricatorLiskDAO $object) {
return array();
}
protected function buildMailBody(
PhabricatorLiskDAO $object,
array $xactions) {
$body = parent::buildMailBody($object, $xactions);
$body->addLinkSection(
pht('CONPHERENCE DETAIL'),
PhabricatorEnv::getProductionURI('/conpherence/'.$object->getID().'/'));
return $body;
}
protected function getMailSubjectPrefix() {
return PhabricatorEnv::getEnvConfig('metamta.conpherence.subject-prefix');
}
protected function shouldPublishFeedStory(
PhabricatorLiskDAO $object,
array $xactions) {
return false;
}
protected function supportsSearch() {
return true;
}
protected function getSearchContextParameter(
PhabricatorLiskDAO $object,
array $xactions) {
$comment_phids = array();
foreach ($xactions as $xaction) {
if ($xaction->hasComment()) {
$comment_phids[] = $xaction->getPHID();
}
}
return array(
'commentPHIDs' => $comment_phids,
);
}
protected function validateTransaction(
PhabricatorLiskDAO $object,
$type,
array $xactions) {
$errors = parent::validateTransaction($object, $type, $xactions);
switch ($type) {
case ConpherenceTransactionType::TYPE_TITLE:
if (!$object->getIsRoom()) {
continue;
}
$missing = $this->validateIsEmptyTextField(
$object->getTitle(),
$xactions);
if ($missing) {
if ($object->getIsRoom()) {
$detail = pht('Room title is required.');
} else {
$detail = pht('Thread title can not be blank.');
}
$error = new PhabricatorApplicationTransactionValidationError(
$type,
pht('Required'),
$detail,
last($xactions));
$error->setIsMissingFieldError(true);
$errors[] = $error;
}
break;
case ConpherenceTransactionType::TYPE_PARTICIPANTS:
foreach ($xactions as $xaction) {
$new_phids = $this->getPHIDTransactionNewValue($xaction, array());
$old_phids = nonempty($object->getParticipantPHIDs(), array());
$phids = array_diff($new_phids, $old_phids);
if (!$phids) {
continue;
}
$users = id(new PhabricatorPeopleQuery())
->setViewer($this->requireActor())
->withPHIDs($phids)
->execute();
$users = mpull($users, null, 'getPHID');
foreach ($phids as $phid) {
if (isset($users[$phid])) {
continue;
}
$errors[] = new PhabricatorApplicationTransactionValidationError(
$type,
pht('Invalid'),
pht('New thread member "%s" is not a valid user.', $phid),
$xaction);
}
}
break;
}
return $errors;
}
}

File Metadata

Mime Type
text/x-diff
Expires
Thu, Jul 3, 6:35 PM (3 h, 57 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
166179
Default Alt Text
(35 KB)

Event Timeline