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() {
|
|
|
|
return pht('Conpherence Threads');
|
|
|
|
}
|
|
|
|
|
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-03-18 01:04:44 +01:00
|
|
|
$conpherence = ConpherenceThread::initializeNewThread($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) {
|
|
|
|
// 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;
|
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');
|
|
|
|
if ($object->getIsRoom()) {
|
|
|
|
$label = pht('EMAIL PREFERENCES FOR THIS ROOM');
|
|
|
|
} else {
|
|
|
|
$label = pht('EMAIL PREFERENCES FOR THIS MESSAGE');
|
|
|
|
}
|
|
|
|
$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:
|
2015-05-04 22:52:22 +02:00
|
|
|
return array($xaction->getNewValue()->getPHID());
|
2015-06-08 01:54:53 +02:00
|
|
|
case ConpherenceTransaction::TYPE_PICTURE_CROP:
|
2015-05-04 22:52:22 +02:00
|
|
|
return array($xaction->getNewValue());
|
|
|
|
}
|
|
|
|
|
|
|
|
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-03-25 19:48:22 +01:00
|
|
|
if (!$object->getIsRoom()) {
|
2015-03-24 21:04:33 +01:00
|
|
|
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;
|
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'),
|
|
|
|
pht('New thread member "%s" is not a valid user.', $phid),
|
|
|
|
$xaction);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return $errors;
|
|
|
|
}
|
2013-01-25 02:23:05 +01:00
|
|
|
}
|