Page MenuHomestyx hydra

No OneTemporary

diff --git a/src/applications/conpherence/controller/ConpherenceListController.php b/src/applications/conpherence/controller/ConpherenceListController.php
index e637c1a668..de79d1c720 100644
--- a/src/applications/conpherence/controller/ConpherenceListController.php
+++ b/src/applications/conpherence/controller/ConpherenceListController.php
@@ -1,287 +1,274 @@
<?php
final class ConpherenceListController extends ConpherenceController {
const SELECTED_MODE = 'selected';
const UNSELECTED_MODE = 'unselected';
const PAGING_MODE = 'paging';
- private $conpherenceID;
-
- public function setConpherenceID($conpherence_id) {
- $this->conpherenceID = $conpherence_id;
- return $this;
- }
- public function getConpherenceID() {
- return $this->conpherenceID;
- }
-
- public function willProcessRequest(array $data) {
- $this->setConpherenceID(idx($data, 'id'));
- }
-
/**
* Three main modes of operation...
*
* 1 - /conpherence/ - UNSELECTED_MODE
* 2 - /conpherence/<id>/ - SELECTED_MODE
* 3 - /conpherence/?direction='up'&... - PAGING_MODE
*
* UNSELECTED_MODE is not an Ajax request while the other two are Ajax
* requests.
*/
private function determineMode() {
$request = $this->getRequest();
$mode = self::UNSELECTED_MODE;
if ($request->isAjax()) {
if ($request->getStr('direction')) {
$mode = self::PAGING_MODE;
} else {
$mode = self::SELECTED_MODE;
}
}
return $mode;
}
- public function processRequest() {
- $request = $this->getRequest();
+
+ public function handleRequest(AphrontRequest $request) {
$user = $request->getUser();
$title = pht('Conpherence');
$conpherence = null;
$scroll_up_participant = $this->getEmptyParticipant();
$scroll_down_participant = $this->getEmptyParticipant();
$too_many = ConpherenceParticipantQuery::LIMIT + 1;
$all_participation = array();
$mode = $this->determineMode();
switch ($mode) {
case self::SELECTED_MODE:
- $conpherence_id = $this->getConpherenceID();
+ $conpherence_id = $request->getURIData('id');
$conpherence = id(new ConpherenceThreadQuery())
->setViewer($user)
->withIDs(array($conpherence_id))
->executeOne();
if (!$conpherence) {
return new Aphront404Response();
}
if ($conpherence->getTitle()) {
$title = $conpherence->getTitle();
}
$cursor = $conpherence->getParticipantIfExists($user->getPHID());
- if ($cursor) {
- $data = $this->loadParticipationWithMidCursor($cursor);
- $all_participation = $data['all_participation'];
- $scroll_up_participant = $data['scroll_up_participant'];
- $scroll_down_participant = $data['scroll_down_participant'];
- } else {
+ if (!$cursor || $conpherence->getIsRoom()) {
$data = $this->loadDefaultParticipation($too_many);
$all_participation = $data['all_participation'];
$scroll_down_participant = $data['scroll_down_participant'];
$menu_participation = $this->getEmptyParticipant()
->setConpherencePHID($conpherence->getPHID())
->setParticipantPHID($user->getPHID());
$all_participation =
array($conpherence->getPHID() => $menu_participation) +
$all_participation;
+
+ } else {
+ $data = $this->loadParticipationWithMidCursor($cursor);
+ $all_participation = $data['all_participation'];
+ $scroll_up_participant = $data['scroll_up_participant'];
+ $scroll_down_participant = $data['scroll_down_participant'];
}
break;
case self::PAGING_MODE:
$direction = $request->getStr('direction');
$id = $request->getInt('participant_id');
$date_touched = $request->getInt('date_touched');
$conpherence_phid = $request->getStr('conpherence_phid');
if ($direction == 'up') {
$order = ConpherenceParticipantQuery::ORDER_NEWER;
} else {
$order = ConpherenceParticipantQuery::ORDER_OLDER;
}
$scroller_participant = id(new ConpherenceParticipant())
->makeEphemeral()
->setID($id)
->setDateTouched($date_touched)
->setConpherencePHID($conpherence_phid);
$participation = id(new ConpherenceParticipantQuery())
->withParticipantPHIDs(array($user->getPHID()))
->withParticipantCursor($scroller_participant)
->setOrder($order)
->setLimit($too_many)
->execute();
if (count($participation) == $too_many) {
if ($direction == 'up') {
$node = $scroll_up_participant = reset($participation);
} else {
$node = $scroll_down_participant = end($participation);
}
unset($participation[$node->getConpherencePHID()]);
}
$all_participation = $participation;
break;
case self::UNSELECTED_MODE:
default:
$data = $this->loadDefaultParticipation($too_many);
$all_participation = $data['all_participation'];
$scroll_down_participant = $data['scroll_down_participant'];
break;
}
$threads = $this->loadConpherenceThreadData(
$all_participation);
$thread_view = id(new ConpherenceThreadListView())
->setUser($user)
->setBaseURI($this->getApplicationURI())
->setThreads($threads)
->setScrollUpParticipant($scroll_up_participant)
->setScrollDownParticipant($scroll_down_participant);
switch ($mode) {
case self::SELECTED_MODE:
$response = id(new AphrontAjaxResponse())->setContent($thread_view);
break;
case self::PAGING_MODE:
$thread_html = $thread_view->renderThreadsHTML();
$phids = array_keys($participation);
$content = array(
'html' => $thread_html,
'phids' => $phids,
);
$response = id(new AphrontAjaxResponse())->setContent($content);
break;
case self::UNSELECTED_MODE:
default:
$layout = id(new ConpherenceLayoutView())
->setUser($user)
->setBaseURI($this->getApplicationURI())
->setThreadView($thread_view)
->setRole('list');
if ($conpherence) {
$policy_objects = id(new PhabricatorPolicyQuery())
->setViewer($user)
->setObject($conpherence)
->execute();
$layout->setHeader($this->buildHeaderPaneContent(
$conpherence,
$policy_objects));
$layout->setThread($conpherence);
} else {
$layout->setHeader(
$this->buildHeaderPaneContent(
id(new ConpherenceThread())
->makeEphemeral(),
array()));
}
$response = $this->buildApplicationPage(
$layout,
array(
'title' => $title,
));
break;
}
return $response;
}
private function loadDefaultParticipation($too_many) {
$viewer = $this->getRequest()->getUser();
$scroll_down_participant = $this->getEmptyParticipant();
$all_participation = id(new ConpherenceParticipantQuery())
->withParticipantPHIDs(array($viewer->getPHID()))
->setLimit($too_many)
->execute();
if (count($all_participation) == $too_many) {
$node = end($all_participation);
unset($all_participation[$node->getConpherencePHID()]);
$scroll_down_participant = $node;
}
return array(
'all_participation' => $all_participation,
'scroll_down_participant' => $scroll_down_participant,);
}
/**
* Handles the curious case when we are visiting a conpherence directly
* by issuing two separate queries. Otherwise, additional conpherences
* are fetched asynchronously. Note these can be earlier or later
* (up or down), depending on what conpherence was selected on initial
* load.
*/
private function loadParticipationWithMidCursor(
ConpherenceParticipant $cursor) {
$user = $this->getRequest()->getUser();
$scroll_up_participant = $this->getEmptyParticipant();
$scroll_down_participant = $this->getEmptyParticipant();
// Note this is a bit dodgy since there may be less than this
// amount in either the up or down direction, thus having us fail
// to fetch LIMIT in total. Whatevs for now and re-visit if we're
// fine-tuning this loading process.
$too_many = ceil(ConpherenceParticipantQuery::LIMIT / 2) + 1;
$participant_query = id(new ConpherenceParticipantQuery())
->withParticipantPHIDs(array($user->getPHID()))
->setLimit($too_many);
$current_selection_epoch = $cursor->getDateTouched();
$set_one = $participant_query
->withParticipantCursor($cursor)
->setOrder(ConpherenceParticipantQuery::ORDER_NEWER)
->execute();
if (count($set_one) == $too_many) {
$node = reset($set_one);
unset($set_one[$node->getConpherencePHID()]);
$scroll_up_participant = $node;
}
$set_two = $participant_query
->withParticipantCursor($cursor)
->setOrder(ConpherenceParticipantQuery::ORDER_OLDER)
->execute();
if (count($set_two) == $too_many) {
$node = end($set_two);
unset($set_two[$node->getConpherencePHID()]);
$scroll_down_participant = $node;
}
$participation = array_merge(
$set_one,
$set_two);
return array(
'scroll_up_participant' => $scroll_up_participant,
'scroll_down_participant' => $scroll_down_participant,
'all_participation' => $participation,
);
}
private function loadConpherenceThreadData($participation) {
$user = $this->getRequest()->getUser();
$conpherence_phids = array_keys($participation);
$conpherences = array();
if ($conpherence_phids) {
$conpherences = id(new ConpherenceThreadQuery())
->setViewer($user)
->withPHIDs($conpherence_phids)
->needParticipantCache(true)
->execute();
// this will re-sort by participation data
$conpherences = array_select_keys($conpherences, $conpherence_phids);
}
return $conpherences;
}
private function getEmptyParticipant() {
return id(new ConpherenceParticipant())
->makeEphemeral();
}
}
diff --git a/src/applications/conpherence/editor/ConpherenceEditor.php b/src/applications/conpherence/editor/ConpherenceEditor.php
index 7813273f40..0f5be65547 100644
--- a/src/applications/conpherence/editor/ConpherenceEditor.php
+++ b/src/applications/conpherence/editor/ConpherenceEditor.php
@@ -1,616 +1,619 @@
<?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) {
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()) {
// if we added people, add them to the end of "recent" participants
$old_map = array_fuse($xaction->getOldValue());
$new_map = array_fuse($xaction->getNewValue());
$add = array_keys(array_diff_key($new_map, $old_map));
if ($add) {
$participants = $object->getRecentParticipantPHIDs();
$participants = array_merge($participants, $add);
$participants = array_slice(array_unique($participants), 0, 10);
$object->setRecentParticipantPHIDs($participants);
}
}
break;
}
$this->updateRecentParticipantPHIDs($object, $xaction);
}
private function updateRecentParticipantPHIDs(
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;
case ConpherenceTransactionType::TYPE_FILES:
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) {
$phids = $this->getPHIDTransactionNewValue(
$xaction,
nonempty($object->getParticipantPHIDs(), array()));
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;
}
}
diff --git a/src/applications/conpherence/storage/ConpherenceTransaction.php b/src/applications/conpherence/storage/ConpherenceTransaction.php
index d7f90974c4..464e8da57b 100644
--- a/src/applications/conpherence/storage/ConpherenceTransaction.php
+++ b/src/applications/conpherence/storage/ConpherenceTransaction.php
@@ -1,150 +1,242 @@
<?php
final class ConpherenceTransaction extends PhabricatorApplicationTransaction {
public function getApplicationName() {
return 'conpherence';
}
public function getApplicationTransactionType() {
return PhabricatorConpherenceThreadPHIDType::TYPECONST;
}
public function getApplicationTransactionCommentObject() {
return new ConpherenceTransactionComment();
}
public function getNoEffectDescription() {
switch ($this->getTransactionType()) {
case ConpherenceTransactionType::TYPE_PARTICIPANTS:
return pht(
'You can not add a participant who has already been added.');
break;
}
return parent::getNoEffectDescription();
}
public function shouldHide() {
$old = $this->getOldValue();
switch ($this->getTransactionType()) {
case ConpherenceTransactionType::TYPE_PARTICIPANTS:
return ($old === null);
case ConpherenceTransactionType::TYPE_TITLE:
case ConpherenceTransactionType::TYPE_DATE_MARKER:
return false;
case ConpherenceTransactionType::TYPE_FILES:
return true;
// we used to have them so just always hide
case ConpherenceTransactionType::TYPE_PICTURE:
case ConpherenceTransactionType::TYPE_PICTURE_CROP:
return true;
}
return parent::shouldHide();
}
public function getTitle() {
$author_phid = $this->getAuthorPHID();
$old = $this->getOldValue();
$new = $this->getNewValue();
switch ($this->getTransactionType()) {
case ConpherenceTransactionType::TYPE_TITLE:
- if ($old && $new) {
- $title = pht(
- '%s renamed this thread from "%s" to "%s".',
- $this->renderHandleLink($author_phid),
- $old,
- $new);
- } else if ($old) {
- $title = pht(
- '%s deleted the thread name "%s".',
- $this->renderHandleLink($author_phid),
- $old);
+ case PhabricatorTransactions::TYPE_VIEW_POLICY:
+ case PhabricatorTransactions::TYPE_EDIT_POLICY:
+ case PhabricatorTransactions::TYPE_JOIN_POLICY:
+ if ($this->getObject()->getIsRoom()) {
+ return $this->getRoomTitle();
} else {
- $title = pht(
- '%s named this thread "%s".',
- $this->renderHandleLink($author_phid),
- $new);
+ return $this->getThreadTitle();
}
- return $title;
+ break;
case ConpherenceTransactionType::TYPE_FILES:
$add = array_diff($new, $old);
$rem = array_diff($old, $new);
if ($add && $rem) {
$title = pht(
'%s edited files(s), added %d and removed %d.',
$this->renderHandleLink($author_phid),
count($add),
count($rem));
} else if ($add) {
$title = pht(
'%s added %d files(s).',
$this->renderHandleLink($author_phid),
count($add));
} else {
$title = pht(
'%s removed %d file(s).',
$this->renderHandleLink($author_phid),
count($rem));
}
return $title;
break;
case ConpherenceTransactionType::TYPE_PARTICIPANTS:
$add = array_diff($new, $old);
$rem = array_diff($old, $new);
if ($add && $rem) {
$title = pht(
'%s edited participant(s), added %d: %s; removed %d: %s.',
$this->renderHandleLink($author_phid),
count($add),
$this->renderHandleList($add),
count($rem),
$this->renderHandleList($rem));
} else if ($add) {
$title = pht(
'%s added %d participant(s): %s.',
$this->renderHandleLink($author_phid),
count($add),
$this->renderHandleList($add));
} else {
$title = pht(
'%s removed %d participant(s): %s.',
$this->renderHandleLink($author_phid),
count($rem),
$this->renderHandleList($rem));
}
return $title;
break;
}
return parent::getTitle();
}
+ private function getRoomTitle() {
+ $author_phid = $this->getAuthorPHID();
+
+ $old = $this->getOldValue();
+ $new = $this->getNewValue();
+
+ switch ($this->getTransactionType()) {
+ case ConpherenceTransactionType::TYPE_TITLE:
+ if ($old && $new) {
+ $title = pht(
+ '%s renamed this room from "%s" to "%s".',
+ $this->renderHandleLink($author_phid),
+ $old,
+ $new);
+ } else if ($old) {
+ $title = pht(
+ '%s deleted the room name "%s".',
+ $this->renderHandleLink($author_phid),
+ $old);
+ } else {
+ $title = pht(
+ '%s named this room "%s".',
+ $this->renderHandleLink($author_phid),
+ $new);
+ }
+ return $title;
+ break;
+ case PhabricatorTransactions::TYPE_VIEW_POLICY:
+ return pht(
+ '%s changed the visibility of this room from "%s" to "%s".',
+ $this->renderHandleLink($author_phid),
+ $this->renderPolicyName($old, 'old'),
+ $this->renderPolicyName($new, 'new'));
+ break;
+ case PhabricatorTransactions::TYPE_EDIT_POLICY:
+ return pht(
+ '%s changed the edit policy of this room from "%s" to "%s".',
+ $this->renderHandleLink($author_phid),
+ $this->renderPolicyName($old, 'old'),
+ $this->renderPolicyName($new, 'new'));
+ break;
+ case PhabricatorTransactions::TYPE_JOIN_POLICY:
+ return pht(
+ '%s changed the join policy of this room from "%s" to "%s".',
+ $this->renderHandleLink($author_phid),
+ $this->renderPolicyName($old, 'old'),
+ $this->renderPolicyName($new, 'new'));
+ break;
+ }
+ }
+
+ private function getThreadTitle() {
+ $author_phid = $this->getAuthorPHID();
+
+ $old = $this->getOldValue();
+ $new = $this->getNewValue();
+
+ switch ($this->getTransactionType()) {
+ case ConpherenceTransactionType::TYPE_TITLE:
+ if ($old && $new) {
+ $title = pht(
+ '%s renamed this thread from "%s" to "%s".',
+ $this->renderHandleLink($author_phid),
+ $old,
+ $new);
+ } else if ($old) {
+ $title = pht(
+ '%s deleted the thread name "%s".',
+ $this->renderHandleLink($author_phid),
+ $old);
+ } else {
+ $title = pht(
+ '%s named this thread "%s".',
+ $this->renderHandleLink($author_phid),
+ $new);
+ }
+ return $title;
+ break;
+ case PhabricatorTransactions::TYPE_VIEW_POLICY:
+ return pht(
+ '%s changed the visibility of this thread from "%s" to "%s".',
+ $this->renderHandleLink($author_phid),
+ $this->renderPolicyName($old, 'old'),
+ $this->renderPolicyName($new, 'new'));
+ break;
+ case PhabricatorTransactions::TYPE_EDIT_POLICY:
+ return pht(
+ '%s changed the edit policy of this thread from "%s" to "%s".',
+ $this->renderHandleLink($author_phid),
+ $this->renderPolicyName($old, 'old'),
+ $this->renderPolicyName($new, 'new'));
+ break;
+ case PhabricatorTransactions::TYPE_JOIN_POLICY:
+ return pht(
+ '%s changed the join policy of this thread from "%s" to "%s".',
+ $this->renderHandleLink($author_phid),
+ $this->renderPolicyName($old, 'old'),
+ $this->renderPolicyName($new, 'new'));
+ break;
+ }
+ }
+
public function getRequiredHandlePHIDs() {
$phids = parent::getRequiredHandlePHIDs();
$old = $this->getOldValue();
$new = $this->getNewValue();
$phids[] = $this->getAuthorPHID();
switch ($this->getTransactionType()) {
case ConpherenceTransactionType::TYPE_TITLE:
case ConpherenceTransactionType::TYPE_FILES:
case ConpherenceTransactionType::TYPE_DATE_MARKER:
break;
case ConpherenceTransactionType::TYPE_PARTICIPANTS:
$phids = array_merge($phids, $this->getOldValue());
$phids = array_merge($phids, $this->getNewValue());
break;
}
return $phids;
}
-
}
diff --git a/src/applications/conpherence/view/ConpherenceThreadListView.php b/src/applications/conpherence/view/ConpherenceThreadListView.php
index 38ee054141..66ded65c4d 100644
--- a/src/applications/conpherence/view/ConpherenceThreadListView.php
+++ b/src/applications/conpherence/view/ConpherenceThreadListView.php
@@ -1,179 +1,268 @@
<?php
final class ConpherenceThreadListView extends AphrontView {
private $baseURI;
private $threads;
private $scrollUpParticipant;
private $scrollDownParticipant;
public function setThreads(array $threads) {
assert_instances_of($threads, 'ConpherenceThread');
$this->threads = $threads;
return $this;
}
public function setScrollUpParticipant(
ConpherenceParticipant $participant) {
$this->scrollUpParticipant = $participant;
return $this;
}
public function setScrollDownParticipant(
ConpherenceParticipant $participant) {
$this->scrollDownParticipant = $participant;
return $this;
}
public function setBaseURI($base_uri) {
$this->baseURI = $base_uri;
return $this;
}
public function render() {
require_celerity_resource('conpherence-menu-css');
+ $grouped = mgroup($this->threads, 'getIsRoom');
+ $rooms = idx($grouped, true, array());
+ $rooms = array_slice($grouped[true], 0, 5);
+
+ $policies = array();
+ foreach ($rooms as $room) {
+ $policies[] = $room->getViewPolicy();
+ }
+ $policy_objects = array();
+ if ($policies) {
+ $policy_objects = id(new PhabricatorPolicyQuery())
+ ->setViewer($this->getUser())
+ ->withPHIDs($policies)
+ ->execute();
+ }
+
$menu = id(new PHUIListView())
->addClass('conpherence-menu')
->setID('conpherence-menu');
- $this->addThreadsToMenu($menu, $this->threads);
+ $this->addRoomsToMenu($menu, $rooms, $policy_objects);
+ $messages = idx($grouped, false, array());
+ $this->addThreadsToMenu($menu, $messages);
return $menu;
}
public function renderSingleThread(ConpherenceThread $thread) {
- return $this->renderThread($thread);
+ $policy_objects = id(new PhabricatorPolicyQuery())
+ ->setViewer($this->getUser())
+ ->setObject($thread)
+ ->execute();
+ return $this->renderThread($thread, $policy_objects);
}
public function renderThreadsHTML() {
$thread_html = array();
if ($this->scrollUpParticipant->getID()) {
$thread_html[] = $this->getScrollMenuItem(
$this->scrollUpParticipant,
'up');
}
foreach ($this->threads as $thread) {
$thread_html[] = $this->renderSingleThread($thread);
}
if ($this->scrollDownParticipant->getID()) {
$thread_html[] = $this->getScrollMenuItem(
$this->scrollDownParticipant,
'down');
}
return phutil_implode_html('', $thread_html);
}
- private function renderThreadItem(ConpherenceThread $thread) {
+ private function renderThreadItem(
+ ConpherenceThread $thread,
+ $policy_objects = array()) {
return id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_CUSTOM)
- ->setName($this->renderThread($thread));
+ ->setName($this->renderThread($thread, $policy_objects));
}
- private function renderThread(ConpherenceThread $thread) {
+ private function renderThread(
+ ConpherenceThread $thread,
+ array $policy_objects) {
+
$user = $this->getUser();
$uri = $this->baseURI.$thread->getID().'/';
$data = $thread->getDisplayData($user);
- $title = $data['title'];
+ $title = phutil_tag(
+ 'span',
+ array(),
+ array(
+ id(new PHUIIconView())
+ ->addClass('mmr')
+ ->setIconFont($thread->getPolicyIconName($policy_objects)),
+ $data['title'],
+ ));
$subtitle = $data['subtitle'];
$unread_count = $data['unread_count'];
$epoch = $data['epoch'];
$image = $data['image'];
$dom_id = $thread->getPHID().'-nav-item';
return id(new ConpherenceMenuItemView())
->setUser($user)
->setTitle($title)
->setSubtitle($subtitle)
->setHref($uri)
->setEpoch($epoch)
->setImageURI($image)
->setUnreadCount($unread_count)
->setID($thread->getPHID().'-nav-item')
->addSigil('conpherence-menu-click')
->setMetadata(
array(
'title' => $data['js_title'],
'id' => $dom_id,
'threadID' => $thread->getID(),
));
}
+ private function addRoomsToMenu(
+ PHUIListView $menu,
+ array $conpherences,
+ array $policy_objects) {
+
+ $header = $this->renderMenuItemHeader(pht('Rooms'));
+ $menu->addMenuItem($header);
+
+ if (empty($conpherences)) {
+ $join_item = id(new PHUIListItemView())
+ ->setType(PHUIListItemView::TYPE_LINK)
+ ->setHref('/conpherence/room/')
+ ->setName(pht('Join a Room'));
+ $menu->addMenuItem($join_item);
+
+ $create_item = id(new PHUIListItemView())
+ ->setType(PHUIListItemView::TYPE_LINK)
+ ->setHref('/conpherence/room/new/')
+ ->setWorkflow(true)
+ ->setName(pht('Create a Room'));
+ $menu->addMenuItem($create_item);
+
+ return $menu;
+ }
+
+ foreach ($conpherences as $conpherence) {
+ $item = $this->renderThreadItem($conpherence, $policy_objects);
+ $menu->addMenuItem($item);
+ }
+
+ $more_item = id(new PHUIListItemView())
+ ->setType(PHUIListItemView::TYPE_LINK)
+ ->setHref('/conpherence/room/query/participant/')
+ ->setName(pht('See More'));
+ $menu->addMenuItem($more_item);
+
+ return $menu;
+ }
+
+
private function addThreadsToMenu(
PHUIListView $menu,
array $conpherences) {
if ($this->scrollUpParticipant->getID()) {
$item = $this->getScrollMenuItem($this->scrollUpParticipant, 'up');
$menu->addMenuItem($item);
}
- $header = $this->renderMenuItemHeader(pht('Recent'));
+ $header = $this->renderMenuItemHeader(pht('Messages'));
$menu->addMenuItem($header);
foreach ($conpherences as $conpherence) {
$item = $this->renderThreadItem($conpherence);
$menu->addMenuItem($item);
}
if (empty($conpherences)) {
$menu->addMenuItem($this->getNoConpherencesMenuItem());
}
if ($this->scrollDownParticipant->getID()) {
$item = $this->getScrollMenuItem($this->scrollDownParticipant, 'down');
$menu->addMenuItem($item);
}
return $menu;
}
private function renderMenuItemHeader($title) {
$item = id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_LABEL)
->setName($title);
return $item;
}
public function getScrollMenuItem(
ConpherenceParticipant $participant,
$direction) {
if ($direction == 'up') {
$name = pht('Load Newer Threads');
} else {
$name = pht('Load Older Threads');
}
$item = id(new PHUIListItemView())
->addSigil('conpherence-menu-scroller')
->setName($name)
->setHref($this->baseURI)
->setType(PHUIListItemView::TYPE_BUTTON)
->setMetadata(array(
'participant_id' => $participant->getID(),
'conpherence_phid' => $participant->getConpherencePHID(),
'date_touched' => $participant->getDateTouched(),
'direction' => $direction,
));
return $item;
}
- private function getNoConpherencesMenuItem() {
+ private function getNoMessagesMenuItem() {
$message = phutil_tag(
'div',
array(
'class' => 'no-conpherences-menu-item',
),
- pht('No Conpherences'));
+ pht('No Messages'));
return id(new PHUIListItemView())
->setType(PHUIListItemView::TYPE_CUSTOM)
->setName($message);
}
+ private function getNoRoomsMenuItem() {
+ $message = phutil_tag(
+ 'div',
+ array(
+ 'class' => 'no-conpherences-menu-item',
+ ),
+ pht('No Rooms'));
+
+ return id(new PHUIListItemView())
+ ->setType(PHUIListItemView::TYPE_CUSTOM)
+ ->setName($message);
+ }
+
+
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Sep 7, 9:39 AM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
222947
Default Alt Text
(47 KB)

Event Timeline