mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-03 04:02:43 +01:00
06de605992
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
707 lines
23 KiB
PHP
707 lines
23 KiB
PHP
<?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 Rooms');
|
|
}
|
|
|
|
public static function createThread(
|
|
PhabricatorUser $creator,
|
|
array $participant_phids,
|
|
$title,
|
|
$message,
|
|
PhabricatorContentSource $source) {
|
|
|
|
$conpherence = ConpherenceThread::initializeNewRoom($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(ConpherenceTransaction::TYPE_PARTICIPANTS)
|
|
->setNewValue(array('+' => $participant_phids));
|
|
if ($files) {
|
|
$xactions[] = id(new ConpherenceTransaction())
|
|
->setTransactionType(ConpherenceTransaction::TYPE_FILES)
|
|
->setNewValue(array('+' => mpull($files, 'getPHID')));
|
|
}
|
|
if ($title) {
|
|
$xactions[] = id(new ConpherenceTransaction())
|
|
->setTransactionType(ConpherenceTransaction::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(ConpherenceTransaction::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[] = ConpherenceTransaction::TYPE_TITLE;
|
|
$types[] = ConpherenceTransaction::TYPE_PARTICIPANTS;
|
|
$types[] = ConpherenceTransaction::TYPE_FILES;
|
|
$types[] = ConpherenceTransaction::TYPE_PICTURE;
|
|
$types[] = ConpherenceTransaction::TYPE_PICTURE_CROP;
|
|
$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 ConpherenceTransaction::TYPE_TITLE:
|
|
return $object->getTitle();
|
|
case ConpherenceTransaction::TYPE_PICTURE:
|
|
return $object->getImagePHID(ConpherenceImageData::SIZE_ORIG);
|
|
case ConpherenceTransaction::TYPE_PICTURE_CROP:
|
|
return $object->getImagePHID(ConpherenceImageData::SIZE_CROP);
|
|
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
|
if ($this->getIsNewObject()) {
|
|
return array();
|
|
}
|
|
return $object->getParticipantPHIDs();
|
|
case ConpherenceTransaction::TYPE_FILES:
|
|
return $object->getFilePHIDs();
|
|
}
|
|
}
|
|
|
|
protected function getCustomTransactionNewValue(
|
|
PhabricatorLiskDAO $object,
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
switch ($xaction->getTransactionType()) {
|
|
case ConpherenceTransaction::TYPE_TITLE:
|
|
case ConpherenceTransaction::TYPE_PICTURE_CROP:
|
|
return $xaction->getNewValue();
|
|
case ConpherenceTransaction::TYPE_PICTURE:
|
|
$file = $xaction->getNewValue();
|
|
return $file->getPHID();
|
|
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
|
case ConpherenceTransaction::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 ConpherenceTransaction::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 ConpherenceTransaction::TYPE_TITLE:
|
|
$object->setTitle($xaction->getNewValue());
|
|
break;
|
|
case ConpherenceTransaction::TYPE_PICTURE:
|
|
$object->setImagePHID(
|
|
$xaction->getNewValue(),
|
|
ConpherenceImageData::SIZE_ORIG);
|
|
break;
|
|
case ConpherenceTransaction::TYPE_PICTURE_CROP:
|
|
$object->setImagePHID(
|
|
$xaction->getNewValue(),
|
|
ConpherenceImageData::SIZE_CROP);
|
|
break;
|
|
case ConpherenceTransaction::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);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
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 ConpherenceTransaction::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 ConpherenceTransaction::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 ConpherenceTransaction::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 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 ConpherenceTransaction::TYPE_FILES:
|
|
PhabricatorPolicyFilter::requireCapability(
|
|
$this->requireActor(),
|
|
$object,
|
|
PhabricatorPolicyCapability::CAN_VIEW);
|
|
break;
|
|
case ConpherenceTransaction::TYPE_TITLE:
|
|
PhabricatorPolicyFilter::requireCapability(
|
|
$this->requireActor(),
|
|
$object,
|
|
PhabricatorPolicyCapability::CAN_EDIT);
|
|
break;
|
|
}
|
|
}
|
|
|
|
protected function mergeTransactions(
|
|
PhabricatorApplicationTransaction $u,
|
|
PhabricatorApplicationTransaction $v) {
|
|
|
|
$type = $u->getTransactionType();
|
|
switch ($type) {
|
|
case ConpherenceTransaction::TYPE_TITLE:
|
|
return $v;
|
|
case ConpherenceTransaction::TYPE_FILES:
|
|
case ConpherenceTransaction::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("Z{$id}: {$title}")
|
|
->addHeader('Thread-Topic', "Z{$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('/'.$object->getMonogram()));
|
|
|
|
return $body;
|
|
}
|
|
|
|
protected function addEmailPreferenceSectionToMailBody(
|
|
PhabricatorMetaMTAMailBody $body,
|
|
PhabricatorLiskDAO $object,
|
|
array $xactions) {
|
|
|
|
$href = PhabricatorEnv::getProductionURI(
|
|
'/'.$object->getMonogram().'?settings');
|
|
$label = pht('EMAIL PREFERENCES FOR THIS ROOM');
|
|
$body->addLinkSection($label, $href);
|
|
}
|
|
|
|
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 extractFilePHIDsFromCustomTransaction(
|
|
PhabricatorLiskDAO $object,
|
|
PhabricatorApplicationTransaction $xaction) {
|
|
|
|
switch ($xaction->getTransactionType()) {
|
|
case ConpherenceTransaction::TYPE_PICTURE:
|
|
case ConpherenceTransaction::TYPE_PICTURE_CROP:
|
|
return array($xaction->getNewValue());
|
|
}
|
|
|
|
return parent::extractFilePHIDsFromCustomTransaction($object, $xaction);
|
|
}
|
|
|
|
protected function validateTransaction(
|
|
PhabricatorLiskDAO $object,
|
|
$type,
|
|
array $xactions) {
|
|
|
|
$errors = parent::validateTransaction($object, $type, $xactions);
|
|
|
|
switch ($type) {
|
|
case ConpherenceTransaction::TYPE_TITLE:
|
|
if (empty($xactions)) {
|
|
break;
|
|
}
|
|
$missing = $this->validateIsEmptyTextField(
|
|
$object->getTitle(),
|
|
$xactions);
|
|
|
|
if ($missing) {
|
|
$detail = pht('Room title is required.');
|
|
$error = new PhabricatorApplicationTransactionValidationError(
|
|
$type,
|
|
pht('Required'),
|
|
$detail,
|
|
last($xactions));
|
|
|
|
$error->setIsMissingFieldError(true);
|
|
$errors[] = $error;
|
|
}
|
|
break;
|
|
case ConpherenceTransaction::TYPE_PICTURE:
|
|
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;
|
|
case ConpherenceTransaction::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 room participant "%s" is not a valid user.', $phid),
|
|
$xaction);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
return $errors;
|
|
}
|
|
}
|