2013-01-25 02:23:05 +01:00
|
|
|
<?php
|
|
|
|
|
|
|
|
final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|
|
|
|
2013-05-31 01:37:51 +02:00
|
|
|
const ERROR_EMPTY_PARTICIPANTS = 'error-empty-participants';
|
|
|
|
const ERROR_EMPTY_MESSAGE = 'error-empty-message';
|
|
|
|
|
2014-08-12 21:28:41 +02:00
|
|
|
public function getEditorApplicationClass() {
|
|
|
|
return 'PhabricatorConpherenceApplication';
|
|
|
|
}
|
|
|
|
|
|
|
|
public function getEditorObjectsDescription() {
|
2015-06-25 22:14:20 +02:00
|
|
|
return pht('Conpherence Rooms');
|
2014-08-12 21:28:41 +02:00
|
|
|
}
|
|
|
|
|
2015-03-26 20:24:29 +01:00
|
|
|
public static function createThread(
|
2013-05-31 01:37:51 +02:00
|
|
|
PhabricatorUser $creator,
|
|
|
|
array $participant_phids,
|
|
|
|
$title,
|
|
|
|
$message,
|
|
|
|
PhabricatorContentSource $source) {
|
|
|
|
|
2015-06-25 22:14:20 +02:00
|
|
|
$conpherence = ConpherenceThread::initializeNewRoom($creator);
|
2013-05-31 01:37:51 +02:00
|
|
|
$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;
|
|
|
|
}
|
|
|
|
|
2014-04-24 01:30:38 +02:00
|
|
|
$file_phids = PhabricatorMarkupEngine::extractFilePHIDsFromEmbeddedFiles(
|
|
|
|
$creator,
|
|
|
|
array($message));
|
2013-05-31 01:37:51 +02:00
|
|
|
if ($file_phids) {
|
|
|
|
$files = id(new PhabricatorFileQuery())
|
|
|
|
->setViewer($creator)
|
|
|
|
->withPHIDs($file_phids)
|
|
|
|
->execute();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!$errors) {
|
|
|
|
$xactions = array();
|
|
|
|
$xactions[] = id(new ConpherenceTransaction())
|
2015-06-08 01:54:53 +02:00
|
|
|
->setTransactionType(ConpherenceTransaction::TYPE_PARTICIPANTS)
|
2013-05-31 01:37:51 +02:00
|
|
|
->setNewValue(array('+' => $participant_phids));
|
|
|
|
if ($files) {
|
|
|
|
$xactions[] = id(new ConpherenceTransaction())
|
2015-06-08 01:54:53 +02:00
|
|
|
->setTransactionType(ConpherenceTransaction::TYPE_FILES)
|
2013-05-31 01:37:51 +02:00
|
|
|
->setNewValue(array('+' => mpull($files, 'getPHID')));
|
|
|
|
}
|
|
|
|
if ($title) {
|
|
|
|
$xactions[] = id(new ConpherenceTransaction())
|
2015-06-08 01:54:53 +02:00
|
|
|
->setTransactionType(ConpherenceTransaction::TYPE_TITLE)
|
2013-05-31 01:37:51 +02:00
|
|
|
->setNewValue($title);
|
|
|
|
}
|
2015-03-24 21:04:33 +01:00
|
|
|
|
2013-05-31 01:37:51 +02:00
|
|
|
$xactions[] = id(new ConpherenceTransaction())
|
|
|
|
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
|
|
|
|
->attachComment(
|
|
|
|
id(new ConpherenceTransactionComment())
|
|
|
|
->setContent($message)
|
|
|
|
->setConpherencePHID($conpherence->getPHID()));
|
|
|
|
|
|
|
|
id(new ConpherenceEditor())
|
2015-03-26 20:24:29 +01:00
|
|
|
->setActor($creator)
|
2013-05-31 01:37:51 +02:00
|
|
|
->setContentSource($source)
|
|
|
|
->setContinueOnNoEffect(true)
|
|
|
|
->applyTransactions($conpherence, $xactions);
|
|
|
|
}
|
|
|
|
|
|
|
|
return array($errors, $conpherence);
|
|
|
|
}
|
|
|
|
|
2013-01-27 04:56:39 +01:00
|
|
|
public function generateTransactionsFromText(
|
2014-04-24 01:30:38 +02:00
|
|
|
PhabricatorUser $viewer,
|
2013-01-27 04:56:39 +01:00
|
|
|
ConpherenceThread $conpherence,
|
|
|
|
$text) {
|
|
|
|
|
|
|
|
$files = array();
|
2014-04-24 01:30:38 +02:00
|
|
|
$file_phids = PhabricatorMarkupEngine::extractFilePHIDsFromEmbeddedFiles(
|
|
|
|
$viewer,
|
|
|
|
array($text));
|
2013-01-27 04:56:39 +01:00
|
|
|
// 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())
|
2015-06-08 01:54:53 +02:00
|
|
|
->setTransactionType(ConpherenceTransaction::TYPE_FILES)
|
2013-01-27 04:56:39 +01:00
|
|
|
->setNewValue(array('+' => mpull($files, 'getPHID')));
|
|
|
|
}
|
|
|
|
$xactions[] = id(new ConpherenceTransaction())
|
|
|
|
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
|
|
|
|
->attachComment(
|
|
|
|
id(new ConpherenceTransactionComment())
|
|
|
|
->setContent($text)
|
2013-02-19 22:33:10 +01:00
|
|
|
->setConpherencePHID($conpherence->getPHID()));
|
2013-01-27 04:56:39 +01:00
|
|
|
return $xactions;
|
|
|
|
}
|
|
|
|
|
2013-01-25 02:23:05 +01:00
|
|
|
public function getTransactionTypes() {
|
|
|
|
$types = parent::getTransactionTypes();
|
|
|
|
|
|
|
|
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
|
|
|
|
2015-06-08 01:54:53 +02:00
|
|
|
$types[] = ConpherenceTransaction::TYPE_TITLE;
|
|
|
|
$types[] = ConpherenceTransaction::TYPE_PARTICIPANTS;
|
|
|
|
$types[] = ConpherenceTransaction::TYPE_FILES;
|
|
|
|
$types[] = ConpherenceTransaction::TYPE_PICTURE;
|
|
|
|
$types[] = ConpherenceTransaction::TYPE_PICTURE_CROP;
|
2015-03-24 21:04:33 +01:00
|
|
|
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
|
|
|
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
|
|
|
$types[] = PhabricatorTransactions::TYPE_JOIN_POLICY;
|
2013-01-25 02:23:05 +01:00
|
|
|
|
|
|
|
return $types;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getCustomTransactionOldValue(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
|
|
|
|
switch ($xaction->getTransactionType()) {
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_TITLE:
|
2013-01-25 02:23:05 +01:00
|
|
|
return $object->getTitle();
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_PICTURE:
|
2015-05-04 22:52:22 +02:00
|
|
|
return $object->getImagePHID(ConpherenceImageData::SIZE_ORIG);
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_PICTURE_CROP:
|
2015-05-04 22:52:22 +02:00
|
|
|
return $object->getImagePHID(ConpherenceImageData::SIZE_CROP);
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
2015-03-27 00:37:32 +01:00
|
|
|
if ($this->getIsNewObject()) {
|
|
|
|
return array();
|
|
|
|
}
|
2013-01-25 02:23:05 +01:00
|
|
|
return $object->getParticipantPHIDs();
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_FILES:
|
2013-01-25 02:23:05 +01:00
|
|
|
return $object->getFilePHIDs();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function getCustomTransactionNewValue(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
|
|
|
|
switch ($xaction->getTransactionType()) {
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_TITLE:
|
|
|
|
case ConpherenceTransaction::TYPE_PICTURE_CROP:
|
2013-01-25 02:23:05 +01:00
|
|
|
return $xaction->getNewValue();
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_PICTURE:
|
2015-05-04 22:52:22 +02:00
|
|
|
$file = $xaction->getNewValue();
|
|
|
|
return $file->getPHID();
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
|
|
|
case ConpherenceTransaction::TYPE_FILES:
|
2013-01-25 02:23:05 +01:00
|
|
|
return $this->getPHIDTransactionNewValue($xaction);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-05 01:57:38 +02:00
|
|
|
/**
|
|
|
|
* 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(
|
2013-01-25 02:23:05 +01:00
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
|
2013-04-05 01:57:38 +02:00
|
|
|
$lock = false;
|
2013-01-25 02:23:05 +01:00
|
|
|
switch ($xaction->getTransactionType()) {
|
2013-04-05 01:57:38 +02:00
|
|
|
case PhabricatorTransactions::TYPE_COMMENT:
|
|
|
|
$lock = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $lock;
|
|
|
|
}
|
|
|
|
|
2013-08-15 02:32:16 +02:00
|
|
|
/**
|
|
|
|
* We need to apply initial effects IFF the conpherence is new. We must
|
2015-03-26 20:24:29 +01:00
|
|
|
* 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.
|
2013-08-15 02:32:16 +02:00
|
|
|
*/
|
|
|
|
protected function shouldApplyInitialEffects(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
array $xactions) {
|
|
|
|
|
2015-03-26 20:24:29 +01:00
|
|
|
return $this->getIsNewObject();
|
2013-08-15 02:32:16 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function applyInitialEffects(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
array $xactions) {
|
|
|
|
|
|
|
|
$object->save();
|
|
|
|
|
2015-03-26 20:24:29 +01:00
|
|
|
foreach ($xactions as $xaction) {
|
|
|
|
switch ($xaction->getTransactionType()) {
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
2015-03-26 20:24:29 +01:00
|
|
|
// 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.
|
2014-12-04 20:54:17 +01:00
|
|
|
$participants = array();
|
2015-03-26 20:24:29 +01:00
|
|
|
$phids = $this->getPHIDTransactionNewValue($xaction, array());
|
|
|
|
foreach ($phids as $phid) {
|
2014-12-04 20:54:17 +01:00
|
|
|
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);
|
2015-03-26 20:24:29 +01:00
|
|
|
$object->setRecentParticipantPHIDs(array_keys($participants));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function applyCustomInternalTransaction(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
|
2015-04-09 23:02:35 +02:00
|
|
|
$make_author_recent_participant = true;
|
2015-03-26 20:24:29 +01:00
|
|
|
switch ($xaction->getTransactionType()) {
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_TITLE:
|
2015-03-26 20:24:29 +01:00
|
|
|
$object->setTitle($xaction->getNewValue());
|
|
|
|
break;
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_PICTURE:
|
2015-05-04 22:52:22 +02:00
|
|
|
$object->setImagePHID(
|
|
|
|
$xaction->getNewValue(),
|
|
|
|
ConpherenceImageData::SIZE_ORIG);
|
|
|
|
break;
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_PICTURE_CROP:
|
2015-05-04 22:52:22 +02:00
|
|
|
$object->setImagePHID(
|
|
|
|
$xaction->getNewValue(),
|
|
|
|
ConpherenceImageData::SIZE_CROP);
|
|
|
|
break;
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
2015-03-26 20:24:29 +01:00
|
|
|
if (!$this->getIsNewObject()) {
|
|
|
|
$old_map = array_fuse($xaction->getOldValue());
|
|
|
|
$new_map = array_fuse($xaction->getNewValue());
|
2015-04-09 23:02:35 +02:00
|
|
|
// if we added people, add them to the end of "recent" participants
|
2015-03-26 20:24:29 +01:00
|
|
|
$add = array_keys(array_diff_key($new_map, $old_map));
|
2015-04-09 23:02:35 +02:00
|
|
|
// if we remove people, then definintely remove them from "recent"
|
|
|
|
// participants
|
|
|
|
$del = array_keys(array_diff_key($old_map, $new_map));
|
|
|
|
if ($add || $del) {
|
2015-03-26 20:24:29 +01:00
|
|
|
$participants = $object->getRecentParticipantPHIDs();
|
2015-04-09 23:02:35 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2015-03-26 20:24:29 +01:00
|
|
|
$participants = array_slice(array_unique($participants), 0, 10);
|
|
|
|
$object->setRecentParticipantPHIDs($participants);
|
2014-12-04 20:54:17 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2013-01-25 02:23:05 +01:00
|
|
|
}
|
2015-04-09 23:02:35 +02:00
|
|
|
|
|
|
|
if ($make_author_recent_participant) {
|
|
|
|
$this->makeAuthorMostRecentParticipant($object, $xaction);
|
|
|
|
}
|
2013-04-05 01:57:38 +02:00
|
|
|
}
|
|
|
|
|
2015-05-19 21:33:55 +02:00
|
|
|
protected function applyBuiltinInternalTransaction(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
|
|
|
|
switch ($xaction->getTransactionType()) {
|
|
|
|
case PhabricatorTransactions::TYPE_COMMENT:
|
|
|
|
$object->setMessageCount((int)$object->getMessageCount() + 1);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return parent::applyBuiltinInternalTransaction($object, $xaction);
|
|
|
|
}
|
|
|
|
|
2015-04-09 23:02:35 +02:00
|
|
|
private function makeAuthorMostRecentParticipant(
|
2013-04-05 01:57:38 +02:00
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
|
|
|
|
$participants = $object->getRecentParticipantPHIDs();
|
|
|
|
array_unshift($participants, $xaction->getAuthorPHID());
|
|
|
|
$participants = array_slice(array_unique($participants), 0, 10);
|
|
|
|
|
|
|
|
$object->setRecentParticipantPHIDs($participants);
|
2013-01-25 02:23:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function applyCustomExternalTransaction(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
|
|
|
|
switch ($xaction->getTransactionType()) {
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_FILES:
|
2014-07-18 00:41:42 +02:00
|
|
|
$editor = new PhabricatorEdgeEditor();
|
2015-01-03 00:33:25 +01:00
|
|
|
$edge_type = PhabricatorObjectHasFileEdgeType::EDGECONST;
|
2013-03-08 19:40:06 +01:00
|
|
|
$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) {
|
2013-01-25 02:23:05 +01:00
|
|
|
$editor->addEdge(
|
|
|
|
$object->getPHID(),
|
|
|
|
$edge_type,
|
2013-02-19 22:33:10 +01:00
|
|
|
$file_phid);
|
2013-01-25 02:23:05 +01:00
|
|
|
}
|
2013-03-08 19:40:06 +01:00
|
|
|
foreach ($remove_edges as $file_phid) {
|
|
|
|
$editor->removeEdge(
|
|
|
|
$object->getPHID(),
|
|
|
|
$edge_type,
|
|
|
|
$file_phid);
|
|
|
|
}
|
2013-01-25 02:23:05 +01:00
|
|
|
$editor->save();
|
|
|
|
break;
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
2015-03-26 20:24:29 +01:00
|
|
|
if ($this->getIsNewObject()) {
|
|
|
|
continue;
|
|
|
|
}
|
2013-04-02 18:32:40 +02:00
|
|
|
$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) {
|
2015-03-26 20:24:29 +01:00
|
|
|
if ($phid == $this->getActor()->getPHID()) {
|
|
|
|
$status = ConpherenceParticipationStatus::UP_TO_DATE;
|
|
|
|
$message_count = $object->getMessageCount();
|
2013-01-25 02:23:05 +01:00
|
|
|
} else {
|
2015-03-26 20:24:29 +01:00
|
|
|
$status = ConpherenceParticipationStatus::BEHIND;
|
|
|
|
$message_count = 0;
|
2013-01-25 02:23:05 +01:00
|
|
|
}
|
2015-03-26 20:24:29 +01:00
|
|
|
$participants[$phid] =
|
|
|
|
id(new ConpherenceParticipant())
|
|
|
|
->setConpherencePHID($object->getPHID())
|
|
|
|
->setParticipantPHID($phid)
|
|
|
|
->setParticipationStatus($status)
|
|
|
|
->setDateTouched(time())
|
|
|
|
->setBehindTransactionPHID($xaction->getPHID())
|
|
|
|
->setSeenMessageCount($message_count)
|
|
|
|
->save();
|
2013-01-25 02:23:05 +01:00
|
|
|
}
|
2013-03-26 21:30:35 +01:00
|
|
|
$object->attachParticipants($participants);
|
2013-01-25 02:23:05 +01:00
|
|
|
break;
|
2013-04-26 19:30:41 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function applyFinalEffects(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
array $xactions) {
|
|
|
|
|
2015-03-25 02:38:16 +01:00
|
|
|
$message_count = 0;
|
|
|
|
foreach ($xactions as $xaction) {
|
|
|
|
switch ($xaction->getTransactionType()) {
|
|
|
|
case PhabricatorTransactions::TYPE_COMMENT:
|
|
|
|
$message_count++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-04-26 19:30:41 +02:00
|
|
|
// 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);
|
2015-03-25 02:38:16 +01:00
|
|
|
$participant->setSeenMessageCount(
|
|
|
|
$object->getMessageCount() - $message_count);
|
2013-04-26 19:30:41 +02:00
|
|
|
}
|
|
|
|
$participant->setParticipationStatus($behind);
|
|
|
|
$participant->setDateTouched($time);
|
|
|
|
} else {
|
|
|
|
$participant->setSeenMessageCount($object->getMessageCount());
|
2015-03-26 20:24:29 +01:00
|
|
|
$participant->setBehindTransactionPHID($xaction_phid);
|
2013-04-26 19:30:41 +02:00
|
|
|
$participant->setParticipationStatus($up_to_date);
|
|
|
|
$participant->setDateTouched($time);
|
|
|
|
}
|
|
|
|
$participant->save();
|
|
|
|
}
|
Update overall revision status after reviewers change
Summary:
Ref T2222. This doesn't feel super clean, but doesn't feel too bad either.
Basically, Differential transactions can have secondary state-based effects (changing the overall revision status) when reviewers resign, are removed, accept, or reject revisions.
To deal with this in ApplicationTransactions, I did this:
- `applyFinalEffects()` can now alter the transaction set (notably, add new ones). This mostly matters for email, notifications and feed.
- In Differential, check for an overall revision state transition in `applyFinalEffects()` (e.g., your reject moving the revision to a rejected state).
- I'm only writing the transaction if the transition is implied and indirect.
- For example, if you "Plan Changes", that action changes the state on its own so there's no implicit state change transaction added.
The transactions themselves are kind of fluff, but it seems useful to keep a record of when state changes occurred in the transaction log. If people complain we can hide/remove them.
Test Plan: {F118143}
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T2222
Differential Revision: https://secure.phabricator.com/D8339
2014-02-25 21:36:49 +01:00
|
|
|
|
2014-06-11 22:52:15 +02:00
|
|
|
if ($xactions) {
|
|
|
|
$data = array(
|
|
|
|
'type' => 'message',
|
|
|
|
'threadPHID' => $object->getPHID(),
|
|
|
|
'messageID' => last($xactions)->getID(),
|
|
|
|
'subscribers' => array($object->getPHID()),
|
|
|
|
);
|
|
|
|
|
|
|
|
PhabricatorNotificationClient::tryToPostMessage($data);
|
|
|
|
}
|
|
|
|
|
Update overall revision status after reviewers change
Summary:
Ref T2222. This doesn't feel super clean, but doesn't feel too bad either.
Basically, Differential transactions can have secondary state-based effects (changing the overall revision status) when reviewers resign, are removed, accept, or reject revisions.
To deal with this in ApplicationTransactions, I did this:
- `applyFinalEffects()` can now alter the transaction set (notably, add new ones). This mostly matters for email, notifications and feed.
- In Differential, check for an overall revision state transition in `applyFinalEffects()` (e.g., your reject moving the revision to a rejected state).
- I'm only writing the transaction if the transition is implied and indirect.
- For example, if you "Plan Changes", that action changes the state on its own so there's no implicit state change transaction added.
The transactions themselves are kind of fluff, but it seems useful to keep a record of when state changes occurred in the transaction log. If people complain we can hide/remove them.
Test Plan: {F118143}
Reviewers: btrahan
Reviewed By: btrahan
CC: aran
Maniphest Tasks: T2222
Differential Revision: https://secure.phabricator.com/D8339
2014-02-25 21:36:49 +01:00
|
|
|
return $xactions;
|
2013-01-25 02:23:05 +01:00
|
|
|
}
|
|
|
|
|
2015-03-25 19:48:22 +01:00
|
|
|
protected function requireCapabilities(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
|
|
|
|
parent::requireCapabilities($object, $xaction);
|
|
|
|
|
|
|
|
switch ($xaction->getTransactionType()) {
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
2015-03-25 19:48:22 +01:00
|
|
|
$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) {
|
2015-06-25 22:14:20 +02:00
|
|
|
// You need CAN_JOIN to join a room.
|
2015-03-25 19:48:22 +01:00
|
|
|
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;
|
2015-04-17 01:15:36 +02:00
|
|
|
// This is similar to PhabricatorTransactions::TYPE_COMMENT so
|
|
|
|
// use CAN_VIEW
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_FILES:
|
2015-04-17 01:15:36 +02:00
|
|
|
PhabricatorPolicyFilter::requireCapability(
|
|
|
|
$this->requireActor(),
|
|
|
|
$object,
|
|
|
|
PhabricatorPolicyCapability::CAN_VIEW);
|
|
|
|
break;
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_TITLE:
|
2015-03-25 19:48:22 +01:00
|
|
|
PhabricatorPolicyFilter::requireCapability(
|
|
|
|
$this->requireActor(),
|
|
|
|
$object,
|
|
|
|
PhabricatorPolicyCapability::CAN_EDIT);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-25 02:23:05 +01:00
|
|
|
protected function mergeTransactions(
|
|
|
|
PhabricatorApplicationTransaction $u,
|
|
|
|
PhabricatorApplicationTransaction $v) {
|
|
|
|
|
|
|
|
$type = $u->getTransactionType();
|
|
|
|
switch ($type) {
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_TITLE:
|
2013-01-25 02:23:05 +01:00
|
|
|
return $v;
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_FILES:
|
|
|
|
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
2013-03-28 16:34:34 +01:00
|
|
|
return $this->mergePHIDOrEdgeTransactions($u, $v);
|
2013-01-25 02:23:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return parent::mergeTransactions($u, $v);
|
|
|
|
}
|
|
|
|
|
2013-09-14 00:08:17 +02:00
|
|
|
protected function shouldSendMail(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
array $xactions) {
|
2013-01-26 01:03:54 +01:00
|
|
|
return true;
|
2013-01-25 02:23:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function buildReplyHandler(PhabricatorLiskDAO $object) {
|
|
|
|
return id(new ConpherenceReplyHandler())
|
2013-01-26 01:03:54 +01:00
|
|
|
->setActor($this->getActor())
|
2013-01-25 02:23:05 +01:00
|
|
|
->setMailReceiver($object);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function buildMailTemplate(PhabricatorLiskDAO $object) {
|
|
|
|
$id = $object->getID();
|
|
|
|
$title = $object->getTitle();
|
2013-01-26 01:03:54 +01:00
|
|
|
if (!$title) {
|
|
|
|
$title = pht(
|
|
|
|
'%s sent you a message.',
|
2013-02-19 22:33:10 +01:00
|
|
|
$this->getActor()->getUserName());
|
2013-01-26 01:03:54 +01:00
|
|
|
}
|
2013-01-25 02:23:05 +01:00
|
|
|
$phid = $object->getPHID();
|
|
|
|
|
|
|
|
return id(new PhabricatorMetaMTAMail())
|
2015-04-29 23:03:36 +02:00
|
|
|
->setSubject("Z{$id}: {$title}")
|
|
|
|
->addHeader('Thread-Topic', "Z{$id}: {$phid}");
|
2013-01-25 02:23:05 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
protected function getMailTo(PhabricatorLiskDAO $object) {
|
2013-04-02 18:32:40 +02:00
|
|
|
$to_phids = array();
|
2013-01-25 02:23:05 +01:00
|
|
|
$participants = $object->getParticipants();
|
2013-04-02 18:32:40 +02:00
|
|
|
if (empty($participants)) {
|
|
|
|
return $to_phids;
|
|
|
|
}
|
2013-03-26 21:30:35 +01:00
|
|
|
$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;
|
2013-01-25 02:23:05 +01:00
|
|
|
}
|
|
|
|
|
2013-01-26 01:03:54 +01:00
|
|
|
protected function getMailCC(PhabricatorLiskDAO $object) {
|
|
|
|
return array();
|
|
|
|
}
|
|
|
|
|
2013-01-25 02:23:05 +01:00
|
|
|
protected function buildMailBody(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
array $xactions) {
|
|
|
|
|
|
|
|
$body = parent::buildMailBody($object, $xactions);
|
2014-10-30 23:24:10 +01:00
|
|
|
$body->addLinkSection(
|
2013-01-25 02:23:05 +01:00
|
|
|
pht('CONPHERENCE DETAIL'),
|
2015-05-06 00:49:43 +02:00
|
|
|
PhabricatorEnv::getProductionURI('/'.$object->getMonogram()));
|
2013-01-25 02:23:05 +01:00
|
|
|
|
|
|
|
return $body;
|
|
|
|
}
|
|
|
|
|
2015-05-29 00:30:33 +02:00
|
|
|
protected function addEmailPreferenceSectionToMailBody(
|
|
|
|
PhabricatorMetaMTAMailBody $body,
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
array $xactions) {
|
|
|
|
|
|
|
|
$href = PhabricatorEnv::getProductionURI(
|
|
|
|
'/'.$object->getMonogram().'?settings');
|
2015-06-25 22:14:20 +02:00
|
|
|
$label = pht('EMAIL PREFERENCES FOR THIS ROOM');
|
2015-05-29 00:30:33 +02:00
|
|
|
$body->addLinkSection($label, $href);
|
|
|
|
}
|
|
|
|
|
2013-01-25 02:23:05 +01:00
|
|
|
protected function getMailSubjectPrefix() {
|
|
|
|
return PhabricatorEnv::getEnvConfig('metamta.conpherence.subject-prefix');
|
|
|
|
}
|
|
|
|
|
2014-03-05 02:01:33 +01:00
|
|
|
protected function shouldPublishFeedStory(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
array $xactions) {
|
2013-01-25 02:23:05 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
protected function supportsSearch() {
|
2015-01-06 19:24:30 +01:00
|
|
|
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,
|
|
|
|
);
|
2013-01-25 02:23:05 +01:00
|
|
|
}
|
2014-07-10 00:12:48 +02:00
|
|
|
|
2015-05-04 22:52:22 +02:00
|
|
|
protected function extractFilePHIDsFromCustomTransaction(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
|
|
|
|
switch ($xaction->getTransactionType()) {
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_PICTURE:
|
|
|
|
case ConpherenceTransaction::TYPE_PICTURE_CROP:
|
Extract PHIDs from transactions later, fixing Paste extraction/attachment
Summary:
Fixes T9787. Currently, file PHID extraction logic happens very early, before we normalize/merge/etc the transactions.
In D14390, I changed how the CONTENT transaction works: before, callers would pass in a file PHID. Afterward, they just pass in the content.
Passing in the content is generaly easier and feels more correct, but inadvertenly broke PHID extraction because converting the content into a file PHID now happened after we extracted the PHID. So we'd extract the entire text of the paste as a "file PHID", which wouldn't work.
Instead, extract file PHIDs later. This impacts a couple of other applications (Conpherence, Pholio) which receive an object or have an unusual file-oriented transaction.
Test Plan:
- Made a new paste, verified the raw file attached to it properly.
- Made and updated a mock, verified all the files attached properly.
- Updated a Conpherence room image, verified the files attached properly.
Reviewers: chad
Reviewed By: chad
Maniphest Tasks: T9787
Differential Revision: https://secure.phabricator.com/D14494
2015-11-16 18:53:08 +01:00
|
|
|
return array($xaction->getNewValue());
|
2015-05-04 22:52:22 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return parent::extractFilePHIDsFromCustomTransaction($object, $xaction);
|
|
|
|
}
|
|
|
|
|
2015-03-03 19:40:00 +01:00
|
|
|
protected function validateTransaction(
|
|
|
|
PhabricatorLiskDAO $object,
|
|
|
|
$type,
|
|
|
|
array $xactions) {
|
|
|
|
|
|
|
|
$errors = parent::validateTransaction($object, $type, $xactions);
|
|
|
|
|
|
|
|
switch ($type) {
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_TITLE:
|
2015-06-25 22:14:20 +02:00
|
|
|
if (empty($xactions)) {
|
|
|
|
break;
|
2015-03-24 21:04:33 +01:00
|
|
|
}
|
|
|
|
$missing = $this->validateIsEmptyTextField(
|
|
|
|
$object->getTitle(),
|
|
|
|
$xactions);
|
|
|
|
|
|
|
|
if ($missing) {
|
2015-06-25 22:14:20 +02:00
|
|
|
$detail = pht('Room title is required.');
|
2015-03-24 21:04:33 +01:00
|
|
|
$error = new PhabricatorApplicationTransactionValidationError(
|
|
|
|
$type,
|
|
|
|
pht('Required'),
|
|
|
|
$detail,
|
|
|
|
last($xactions));
|
|
|
|
|
|
|
|
$error->setIsMissingFieldError(true);
|
|
|
|
$errors[] = $error;
|
|
|
|
}
|
|
|
|
break;
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_PICTURE:
|
2015-05-04 22:52:22 +02:00
|
|
|
foreach ($xactions as $xaction) {
|
|
|
|
$file = $xaction->getNewValue();
|
|
|
|
if (!$file->isTransformableImage()) {
|
|
|
|
$detail = pht('This server only supports these image formats: %s.',
|
|
|
|
implode(', ', PhabricatorFile::getTransformableImageFormats()));
|
|
|
|
$error = new PhabricatorApplicationTransactionValidationError(
|
|
|
|
$type,
|
|
|
|
pht('Invalid'),
|
|
|
|
$detail,
|
|
|
|
last($xactions));
|
|
|
|
$errors[] = $error;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
2015-03-03 19:40:00 +01:00
|
|
|
foreach ($xactions as $xaction) {
|
2015-04-06 20:45:43 +02:00
|
|
|
$new_phids = $this->getPHIDTransactionNewValue($xaction, array());
|
|
|
|
$old_phids = nonempty($object->getParticipantPHIDs(), array());
|
|
|
|
$phids = array_diff($new_phids, $old_phids);
|
2015-03-03 19:40:00 +01:00
|
|
|
|
|
|
|
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'),
|
2015-06-25 22:14:20 +02:00
|
|
|
pht('New room participant "%s" is not a valid user.', $phid),
|
2015-03-03 19:40:00 +01:00
|
|
|
$xaction);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $errors;
|
|
|
|
}
|
2013-01-25 02:23:05 +01:00
|
|
|
}
|