Merge branch 'github-facebook-master' into blender-tweaks
Before Width: | Height: | Size: 993 B After Width: | Height: | Size: 293 B |
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 360 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 375 B |
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 370 B |
BIN
resources/builtin/image-400x400.png
Normal file
After Width: | Height: | Size: 456 B |
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 546 B |
BIN
resources/builtin/image-800x800.png
Normal file
After Width: | Height: | Size: 666 B |
@@ -46,6 +46,7 @@ return array(
|
|||||||
'javelin-behavior-toggle-class',
|
'javelin-behavior-toggle-class',
|
||||||
'javelin-behavior-lightbox-attachments',
|
'javelin-behavior-lightbox-attachments',
|
||||||
'phabricator-busy',
|
'phabricator-busy',
|
||||||
|
'javelin-sound',
|
||||||
'javelin-aphlict',
|
'javelin-aphlict',
|
||||||
'phabricator-notification',
|
'phabricator-notification',
|
||||||
'javelin-behavior-aphlict-listen',
|
'javelin-behavior-aphlict-listen',
|
||||||
@@ -138,7 +139,6 @@ return array(
|
|||||||
|
|
||||||
'font-fontawesome',
|
'font-fontawesome',
|
||||||
'font-lato',
|
'font-lato',
|
||||||
'font-aleo',
|
|
||||||
'phui-font-icon-base-css',
|
'phui-font-icon-base-css',
|
||||||
'phui-fontkit-css',
|
'phui-fontkit-css',
|
||||||
'phui-box-css',
|
'phui-box-css',
|
||||||
@@ -161,6 +161,7 @@ return array(
|
|||||||
'conpherence.pkg.css' => array(
|
'conpherence.pkg.css' => array(
|
||||||
'conpherence-durable-column-view',
|
'conpherence-durable-column-view',
|
||||||
'conpherence-menu-css',
|
'conpherence-menu-css',
|
||||||
|
'conpherence-color-css',
|
||||||
'conpherence-message-pane-css',
|
'conpherence-message-pane-css',
|
||||||
'conpherence-notification-css',
|
'conpherence-notification-css',
|
||||||
'conpherence-transaction-css',
|
'conpherence-transaction-css',
|
||||||
|
@@ -1,34 +1,4 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
// Rebuild all Conpherence Room images to profile standards
|
// This migration once resized room images for Conpherence, but the File table
|
||||||
//
|
// later changed significantly. See T12628.
|
||||||
$table = new ConpherenceThread();
|
|
||||||
$conn = $table->establishConnection('w');
|
|
||||||
$table_name = 'conpherence_thread';
|
|
||||||
|
|
||||||
foreach (new LiskRawMigrationIterator($conn, $table_name) as $row) {
|
|
||||||
|
|
||||||
$images = phutil_json_decode($row['imagePHIDs']);
|
|
||||||
if (!$images) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
$file_phid = idx($images, 'original');
|
|
||||||
|
|
||||||
$file = id(new PhabricatorFileQuery())
|
|
||||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
|
||||||
->withPHIDs(array($file_phid))
|
|
||||||
->executeOne();
|
|
||||||
|
|
||||||
$xform = PhabricatorFileTransform::getTransformByKey(
|
|
||||||
PhabricatorFileThumbnailTransform::TRANSFORM_PROFILE);
|
|
||||||
$xformed = $xform->executeTransform($file);
|
|
||||||
$new_phid = $xformed->getPHID();
|
|
||||||
|
|
||||||
queryfx(
|
|
||||||
$conn,
|
|
||||||
'UPDATE %T SET profileImagePHID = %s WHERE id = %d',
|
|
||||||
$table->getTableName(),
|
|
||||||
$new_phid,
|
|
||||||
$row['id']);
|
|
||||||
}
|
|
||||||
|
@@ -1,7 +1,15 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
$search_engine = PhabricatorFulltextStorageEngine::loadEngine();
|
|
||||||
$use_mysql = ($search_engine instanceof PhabricatorMySQLFulltextStorageEngine);
|
$use_mysql = false;
|
||||||
|
|
||||||
|
$services = PhabricatorSearchService::getAllServices();
|
||||||
|
foreach ($services as $service) {
|
||||||
|
$engine = $service->getEngine();
|
||||||
|
if ($engine instanceof PhabricatorMySQLFulltextStorageEngine) {
|
||||||
|
$use_mysql = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($use_mysql) {
|
if ($use_mysql) {
|
||||||
$field = new PhabricatorSearchDocumentField();
|
$field = new PhabricatorSearchDocumentField();
|
||||||
|
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE {$NAMESPACE}_differential.differential_reviewer
|
||||||
|
ADD lastActionDiffPHID VARBINARY(64);
|
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE {$NAMESPACE}_differential.differential_reviewer
|
||||||
|
ADD lastCommentDiffPHID VARBINARY(64);
|
125
resources/sql/autopatches/20170320.reviewers.03.migrate.php
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$table = new DifferentialRevision();
|
||||||
|
$diff_table = new DifferentialDiff();
|
||||||
|
$reviewer_table = new DifferentialReviewer();
|
||||||
|
|
||||||
|
$table_name = PhabricatorEdgeConfig::TABLE_NAME_EDGE;
|
||||||
|
$data_name = PhabricatorEdgeConfig::TABLE_NAME_EDGEDATA;
|
||||||
|
|
||||||
|
$conn = $table->establishConnection('w');
|
||||||
|
|
||||||
|
// Previously "DifferentialRevisionHasReviewerEdgeType::EDGECONST".
|
||||||
|
$edge_type = 35;
|
||||||
|
|
||||||
|
// NOTE: We can't use normal migration iterators for edges because they don't
|
||||||
|
// have an "id" column. For now, try just loading the whole result set: the
|
||||||
|
// actual size of the rows is small. If we run into issues, we could write an
|
||||||
|
// EdgeIterator.
|
||||||
|
$every_edge = queryfx_all(
|
||||||
|
$conn,
|
||||||
|
'SELECT * FROM %T edge LEFT JOIN %T data ON edge.dataID = data.id
|
||||||
|
WHERE edge.type = %d',
|
||||||
|
$table_name,
|
||||||
|
$data_name,
|
||||||
|
$edge_type);
|
||||||
|
|
||||||
|
foreach ($every_edge as $edge) {
|
||||||
|
if ($edge['type'] != $edge_type) {
|
||||||
|
// Ignore edges which aren't "reviewers", like subscribers.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$data = phutil_json_decode($edge['data']);
|
||||||
|
$data = idx($data, 'data');
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
// Just ignore any kind of issue with the edge data, we'll use a default
|
||||||
|
// below.
|
||||||
|
$data = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$data) {
|
||||||
|
$data = array(
|
||||||
|
'status' => 'added',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$status = idx($data, 'status');
|
||||||
|
|
||||||
|
$diff_phid = null;
|
||||||
|
|
||||||
|
// NOTE: At one point, the code to populate "diffID" worked correctly, but
|
||||||
|
// it seems to have later been broken. Salvage it if we can, and look up
|
||||||
|
// the corresponding diff PHID.
|
||||||
|
$diff_id = idx($data, 'diffID');
|
||||||
|
if ($diff_id) {
|
||||||
|
$row = queryfx_one(
|
||||||
|
$conn,
|
||||||
|
'SELECT phid FROM %T WHERE id = %d',
|
||||||
|
$diff_table->getTableName(),
|
||||||
|
$diff_id);
|
||||||
|
if ($row) {
|
||||||
|
$diff_phid = $row['phid'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$diff_phid) {
|
||||||
|
// If the status is "accepted" or "rejected", look up the current diff
|
||||||
|
// PHID so we can distinguish between "accepted" and "accepted older".
|
||||||
|
switch ($status) {
|
||||||
|
case 'accepted':
|
||||||
|
case 'rejected':
|
||||||
|
case 'commented':
|
||||||
|
$row = queryfx_one(
|
||||||
|
$conn,
|
||||||
|
'SELECT diff.phid FROM %T diff JOIN %T revision
|
||||||
|
ON diff.revisionID = revision.id
|
||||||
|
WHERE revision.phid = %s
|
||||||
|
ORDER BY diff.id DESC LIMIT 1',
|
||||||
|
$diff_table->getTableName(),
|
||||||
|
$table->getTableName(),
|
||||||
|
$edge['src']);
|
||||||
|
if ($row) {
|
||||||
|
$diff_phid = $row['phid'];
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We now represent some states (like "Commented" and "Accepted Older") as
|
||||||
|
// a primary state plus an extra flag, instead of making "Commented" a
|
||||||
|
// primary state. Map old states to new states and flags.
|
||||||
|
|
||||||
|
if ($status == 'commented') {
|
||||||
|
$status = 'added';
|
||||||
|
$comment_phid = $diff_phid;
|
||||||
|
$action_phid = null;
|
||||||
|
} else {
|
||||||
|
$comment_phid = null;
|
||||||
|
$action_phid = $diff_phid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($status == 'accepted-older') {
|
||||||
|
$status = 'accepted';
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($status == 'rejected-older') {
|
||||||
|
$status = 'rejected';
|
||||||
|
}
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'INSERT INTO %T (revisionPHID, reviewerPHID, reviewerStatus,
|
||||||
|
lastActionDiffPHID, lastCommentDiffPHID, dateCreated, dateModified)
|
||||||
|
VALUES (%s, %s, %s, %ns, %ns, %d, %d)
|
||||||
|
ON DUPLICATE KEY UPDATE dateCreated = VALUES(dateCreated)',
|
||||||
|
$reviewer_table->getTableName(),
|
||||||
|
$edge['src'],
|
||||||
|
$edge['dst'],
|
||||||
|
$status,
|
||||||
|
$action_phid,
|
||||||
|
$comment_phid,
|
||||||
|
$edge['dateCreated'],
|
||||||
|
$edge['dateCreated']);
|
||||||
|
}
|
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE {$NAMESPACE}_differential.differential_reviewer
|
||||||
|
ADD lastActorPHID VARBINARY(64);
|
2
resources/sql/autopatches/20170328.reviewers.01.void.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE {$NAMESPACE}_differential.differential_reviewer
|
||||||
|
ADD voidedPHID VARBINARY(64);
|
8
resources/sql/autopatches/20170406.hmac.01.keystore.sql
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
CREATE TABLE {$NAMESPACE}_auth.auth_hmackey (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
keyName VARCHAR(64) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
keyValue VARCHAR(128) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
UNIQUE KEY `key_name` (keyName)
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
42
resources/sql/autopatches/20170410.calendar.01.repair.php
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
// See T12488. Some events survived "20161004.cal.01.noepoch.php" without
|
||||||
|
// having "utcInstanceEpoch" computed, which breaks ICS export. This appears
|
||||||
|
// to be the result of some bug which has been fixed in the meantime, so just
|
||||||
|
// redo this part of the migration.
|
||||||
|
|
||||||
|
$table = new PhabricatorCalendarEvent();
|
||||||
|
$conn = $table->establishConnection('w');
|
||||||
|
$table_name = $table->getTableName();
|
||||||
|
|
||||||
|
$viewer = PhabricatorUser::getOmnipotentUser();
|
||||||
|
$all_events = id(new PhabricatorCalendarEventQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->execute();
|
||||||
|
foreach ($all_events as $event) {
|
||||||
|
$id = $event->getID();
|
||||||
|
|
||||||
|
if (!$event->getInstanceOfEventPHID()) {
|
||||||
|
// Not a child event, so no instance epoch.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($event->getUTCInstanceEpoch()) {
|
||||||
|
// Already has an instance epoch.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$event->updateUTCEpochs();
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
phlog($ex);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'UPDATE %T SET utcInstanceEpoch = %nd WHERE id = %d',
|
||||||
|
$table_name,
|
||||||
|
$event->getUTCInstanceEpoch(),
|
||||||
|
$id);
|
||||||
|
}
|
@@ -0,0 +1,2 @@
|
|||||||
|
DELETE FROM {$NAMESPACE}_conpherence.conpherence_transaction
|
||||||
|
WHERE transactionType = 'picture-crop';
|
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE {$NAMESPACE}_conpherence.conpherence_thread
|
||||||
|
DROP COLUMN recentParticipantPHIDs;
|
7
resources/sql/autopatches/20170417.files.ngrams.sql
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
CREATE TABLE {$NAMESPACE}_file.file_filename_ngrams (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
objectID INT UNSIGNED NOT NULL,
|
||||||
|
ngram CHAR(3) NOT NULL COLLATE {$COLLATE_TEXT},
|
||||||
|
KEY `key_object` (objectID),
|
||||||
|
KEY `key_ngram` (ngram, objectID)
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
@@ -0,0 +1,19 @@
|
|||||||
|
CREATE TABLE {$NAMESPACE}_application.application_applicationtransaction (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
phid VARBINARY(64) NOT NULL,
|
||||||
|
authorPHID VARBINARY(64) NOT NULL,
|
||||||
|
objectPHID VARBINARY(64) NOT NULL,
|
||||||
|
viewPolicy VARBINARY(64) NOT NULL,
|
||||||
|
editPolicy VARBINARY(64) NOT NULL,
|
||||||
|
commentPHID VARBINARY(64) DEFAULT NULL,
|
||||||
|
commentVersion INT UNSIGNED NOT NULL,
|
||||||
|
transactionType VARCHAR(32) COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
oldValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
newValue LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
contentSource LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
metadata LONGTEXT COLLATE {$COLLATE_TEXT} NOT NULL,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
UNIQUE KEY `key_phid` (`phid`),
|
||||||
|
KEY `key_object` (`objectPHID`)
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
16
resources/sql/autopatches/20170418.1.application.02.edge.sql
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
CREATE TABLE {$NAMESPACE}_application.edge (
|
||||||
|
src VARBINARY(64) NOT NULL,
|
||||||
|
type INT UNSIGNED NOT NULL,
|
||||||
|
dst VARBINARY(64) NOT NULL,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
seq INT UNSIGNED NOT NULL,
|
||||||
|
dataID INT UNSIGNED,
|
||||||
|
PRIMARY KEY (src, type, dst),
|
||||||
|
KEY `src` (src, type, dateCreated, seq),
|
||||||
|
UNIQUE KEY `key_dst` (dst, type, src)
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
||||||
|
|
||||||
|
CREATE TABLE {$NAMESPACE}_application.edgedata (
|
||||||
|
id INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||||
|
data LONGTEXT NOT NULL COLLATE {$COLLATE_TEXT}
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
2
resources/sql/autopatches/20170418.files.isDeleted.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE {$NAMESPACE}_file.file
|
||||||
|
ADD isDeleted BOOL NOT NULL DEFAULT 0;
|
7
resources/sql/autopatches/20170419.app.01.table.sql
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
CREATE TABLE {$NAMESPACE}_application.application_application (
|
||||||
|
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||||
|
phid VARBINARY(64) NOT NULL,
|
||||||
|
dateCreated INT UNSIGNED NOT NULL,
|
||||||
|
dateModified INT UNSIGNED NOT NULL,
|
||||||
|
UNIQUE KEY `key_phid` (phid)
|
||||||
|
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
2
resources/sql/autopatches/20170419.thread.01.behind.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE {$NAMESPACE}_conpherence.conpherence_participant
|
||||||
|
DROP behindTransactionPHID;
|
2
resources/sql/autopatches/20170419.thread.02.status.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE {$NAMESPACE}_conpherence.conpherence_participant
|
||||||
|
DROP participationStatus;
|
2
resources/sql/autopatches/20170419.thread.03.touched.sql
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
ALTER TABLE {$NAMESPACE}_conpherence.conpherence_participant
|
||||||
|
DROP dateTouched;
|
34
resources/sql/autopatches/20170424.user.01.verify.php
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
$table = new PhabricatorUser();
|
||||||
|
$conn = $table->establishConnection('w');
|
||||||
|
|
||||||
|
foreach (new LiskMigrationIterator($table) as $user) {
|
||||||
|
// Ignore users who are verified.
|
||||||
|
if ($user->getIsEmailVerified()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ignore unverified users with missing (rare) or unverified (common)
|
||||||
|
// primary emails: it's correct that their accounts are not verified.
|
||||||
|
$primary = $user->loadPrimaryEmail();
|
||||||
|
if (!$primary) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$primary->getIsVerified()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
queryfx(
|
||||||
|
$conn,
|
||||||
|
'UPDATE %T SET isEmailVerified = 1 WHERE id = %d',
|
||||||
|
$table->getTableName(),
|
||||||
|
$user->getID());
|
||||||
|
|
||||||
|
echo tsprintf(
|
||||||
|
"%s\n",
|
||||||
|
pht(
|
||||||
|
'Corrected account verification state for user "%s".',
|
||||||
|
$user->getUsername()));
|
||||||
|
}
|
@@ -14,7 +14,7 @@ foreach ($sessions as $session) {
|
|||||||
$conn,
|
$conn,
|
||||||
'UPDATE %T SET sessionKey = %s WHERE userPHID = %s AND type = %s',
|
'UPDATE %T SET sessionKey = %s WHERE userPHID = %s AND type = %s',
|
||||||
PhabricatorUser::SESSION_TABLE,
|
PhabricatorUser::SESSION_TABLE,
|
||||||
PhabricatorHash::digest($session['sessionKey']),
|
PhabricatorHash::weakDigest($session['sessionKey']),
|
||||||
$session['userPHID'],
|
$session['userPHID'],
|
||||||
$session['type']);
|
$session['type']);
|
||||||
}
|
}
|
||||||
|
543
resources/sql/stopwords_myisam.txt
Normal file
@@ -0,0 +1,543 @@
|
|||||||
|
a's
|
||||||
|
able
|
||||||
|
about
|
||||||
|
above
|
||||||
|
according
|
||||||
|
accordingly
|
||||||
|
across
|
||||||
|
actually
|
||||||
|
after
|
||||||
|
afterwards
|
||||||
|
again
|
||||||
|
against
|
||||||
|
ain't
|
||||||
|
all
|
||||||
|
allow
|
||||||
|
allows
|
||||||
|
almost
|
||||||
|
alone
|
||||||
|
along
|
||||||
|
already
|
||||||
|
also
|
||||||
|
although
|
||||||
|
always
|
||||||
|
am
|
||||||
|
among
|
||||||
|
amongst
|
||||||
|
an
|
||||||
|
and
|
||||||
|
another
|
||||||
|
any
|
||||||
|
anybody
|
||||||
|
anyhow
|
||||||
|
anyone
|
||||||
|
anything
|
||||||
|
anyway
|
||||||
|
anyways
|
||||||
|
anywhere
|
||||||
|
apart
|
||||||
|
appear
|
||||||
|
appreciate
|
||||||
|
appropriate
|
||||||
|
are
|
||||||
|
aren't
|
||||||
|
around
|
||||||
|
as
|
||||||
|
aside
|
||||||
|
ask
|
||||||
|
asking
|
||||||
|
associated
|
||||||
|
at
|
||||||
|
available
|
||||||
|
away
|
||||||
|
awfully
|
||||||
|
be
|
||||||
|
became
|
||||||
|
because
|
||||||
|
become
|
||||||
|
becomes
|
||||||
|
becoming
|
||||||
|
been
|
||||||
|
before
|
||||||
|
beforehand
|
||||||
|
behind
|
||||||
|
being
|
||||||
|
believe
|
||||||
|
below
|
||||||
|
beside
|
||||||
|
besides
|
||||||
|
best
|
||||||
|
better
|
||||||
|
between
|
||||||
|
beyond
|
||||||
|
both
|
||||||
|
brief
|
||||||
|
but
|
||||||
|
by
|
||||||
|
c'mon
|
||||||
|
c's
|
||||||
|
came
|
||||||
|
can
|
||||||
|
can't
|
||||||
|
cannot
|
||||||
|
cant
|
||||||
|
cause
|
||||||
|
causes
|
||||||
|
certain
|
||||||
|
certainly
|
||||||
|
changes
|
||||||
|
clearly
|
||||||
|
co
|
||||||
|
com
|
||||||
|
come
|
||||||
|
comes
|
||||||
|
concerning
|
||||||
|
consequently
|
||||||
|
consider
|
||||||
|
considering
|
||||||
|
contain
|
||||||
|
containing
|
||||||
|
contains
|
||||||
|
corresponding
|
||||||
|
could
|
||||||
|
couldn't
|
||||||
|
course
|
||||||
|
currently
|
||||||
|
definitely
|
||||||
|
described
|
||||||
|
despite
|
||||||
|
did
|
||||||
|
didn't
|
||||||
|
different
|
||||||
|
do
|
||||||
|
does
|
||||||
|
doesn't
|
||||||
|
doing
|
||||||
|
don't
|
||||||
|
done
|
||||||
|
down
|
||||||
|
downwards
|
||||||
|
during
|
||||||
|
each
|
||||||
|
edu
|
||||||
|
eg
|
||||||
|
eight
|
||||||
|
either
|
||||||
|
else
|
||||||
|
elsewhere
|
||||||
|
enough
|
||||||
|
entirely
|
||||||
|
especially
|
||||||
|
et
|
||||||
|
etc
|
||||||
|
even
|
||||||
|
ever
|
||||||
|
every
|
||||||
|
everybody
|
||||||
|
everyone
|
||||||
|
everything
|
||||||
|
everywhere
|
||||||
|
ex
|
||||||
|
exactly
|
||||||
|
example
|
||||||
|
except
|
||||||
|
far
|
||||||
|
few
|
||||||
|
fifth
|
||||||
|
first
|
||||||
|
five
|
||||||
|
followed
|
||||||
|
following
|
||||||
|
follows
|
||||||
|
for
|
||||||
|
former
|
||||||
|
formerly
|
||||||
|
forth
|
||||||
|
four
|
||||||
|
from
|
||||||
|
further
|
||||||
|
furthermore
|
||||||
|
get
|
||||||
|
gets
|
||||||
|
getting
|
||||||
|
given
|
||||||
|
gives
|
||||||
|
go
|
||||||
|
goes
|
||||||
|
going
|
||||||
|
gone
|
||||||
|
got
|
||||||
|
gotten
|
||||||
|
greetings
|
||||||
|
had
|
||||||
|
hadn't
|
||||||
|
happens
|
||||||
|
hardly
|
||||||
|
has
|
||||||
|
hasn't
|
||||||
|
have
|
||||||
|
haven't
|
||||||
|
having
|
||||||
|
he
|
||||||
|
he's
|
||||||
|
hello
|
||||||
|
help
|
||||||
|
hence
|
||||||
|
her
|
||||||
|
here
|
||||||
|
here's
|
||||||
|
hereafter
|
||||||
|
hereby
|
||||||
|
herein
|
||||||
|
hereupon
|
||||||
|
hers
|
||||||
|
herself
|
||||||
|
hi
|
||||||
|
him
|
||||||
|
himself
|
||||||
|
his
|
||||||
|
hither
|
||||||
|
hopefully
|
||||||
|
how
|
||||||
|
howbeit
|
||||||
|
however
|
||||||
|
i'd
|
||||||
|
i'll
|
||||||
|
i'm
|
||||||
|
i've
|
||||||
|
ie
|
||||||
|
if
|
||||||
|
ignored
|
||||||
|
immediate
|
||||||
|
in
|
||||||
|
inasmuch
|
||||||
|
inc
|
||||||
|
indeed
|
||||||
|
indicate
|
||||||
|
indicated
|
||||||
|
indicates
|
||||||
|
inner
|
||||||
|
insofar
|
||||||
|
instead
|
||||||
|
into
|
||||||
|
inward
|
||||||
|
is
|
||||||
|
isn't
|
||||||
|
it
|
||||||
|
it'd
|
||||||
|
it'll
|
||||||
|
it's
|
||||||
|
its
|
||||||
|
itself
|
||||||
|
just
|
||||||
|
keep
|
||||||
|
keeps
|
||||||
|
kept
|
||||||
|
know
|
||||||
|
known
|
||||||
|
knows
|
||||||
|
last
|
||||||
|
lately
|
||||||
|
later
|
||||||
|
latter
|
||||||
|
latterly
|
||||||
|
least
|
||||||
|
less
|
||||||
|
lest
|
||||||
|
let
|
||||||
|
let's
|
||||||
|
like
|
||||||
|
liked
|
||||||
|
likely
|
||||||
|
little
|
||||||
|
look
|
||||||
|
looking
|
||||||
|
looks
|
||||||
|
ltd
|
||||||
|
mainly
|
||||||
|
many
|
||||||
|
may
|
||||||
|
maybe
|
||||||
|
me
|
||||||
|
mean
|
||||||
|
meanwhile
|
||||||
|
merely
|
||||||
|
might
|
||||||
|
more
|
||||||
|
moreover
|
||||||
|
most
|
||||||
|
mostly
|
||||||
|
much
|
||||||
|
must
|
||||||
|
my
|
||||||
|
myself
|
||||||
|
name
|
||||||
|
namely
|
||||||
|
nd
|
||||||
|
near
|
||||||
|
nearly
|
||||||
|
necessary
|
||||||
|
need
|
||||||
|
needs
|
||||||
|
neither
|
||||||
|
never
|
||||||
|
nevertheless
|
||||||
|
new
|
||||||
|
next
|
||||||
|
nine
|
||||||
|
no
|
||||||
|
nobody
|
||||||
|
non
|
||||||
|
none
|
||||||
|
noone
|
||||||
|
nor
|
||||||
|
normally
|
||||||
|
not
|
||||||
|
nothing
|
||||||
|
novel
|
||||||
|
now
|
||||||
|
nowhere
|
||||||
|
obviously
|
||||||
|
of
|
||||||
|
off
|
||||||
|
often
|
||||||
|
oh
|
||||||
|
ok
|
||||||
|
okay
|
||||||
|
old
|
||||||
|
on
|
||||||
|
once
|
||||||
|
one
|
||||||
|
ones
|
||||||
|
only
|
||||||
|
onto
|
||||||
|
or
|
||||||
|
other
|
||||||
|
others
|
||||||
|
otherwise
|
||||||
|
ought
|
||||||
|
our
|
||||||
|
ours
|
||||||
|
ourselves
|
||||||
|
out
|
||||||
|
outside
|
||||||
|
over
|
||||||
|
overall
|
||||||
|
own
|
||||||
|
particular
|
||||||
|
particularly
|
||||||
|
per
|
||||||
|
perhaps
|
||||||
|
placed
|
||||||
|
please
|
||||||
|
plus
|
||||||
|
possible
|
||||||
|
presumably
|
||||||
|
probably
|
||||||
|
provides
|
||||||
|
que
|
||||||
|
quite
|
||||||
|
qv
|
||||||
|
rather
|
||||||
|
rd
|
||||||
|
re
|
||||||
|
really
|
||||||
|
reasonably
|
||||||
|
regarding
|
||||||
|
regardless
|
||||||
|
regards
|
||||||
|
relatively
|
||||||
|
respectively
|
||||||
|
right
|
||||||
|
said
|
||||||
|
same
|
||||||
|
saw
|
||||||
|
say
|
||||||
|
saying
|
||||||
|
says
|
||||||
|
second
|
||||||
|
secondly
|
||||||
|
see
|
||||||
|
seeing
|
||||||
|
seem
|
||||||
|
seemed
|
||||||
|
seeming
|
||||||
|
seems
|
||||||
|
seen
|
||||||
|
self
|
||||||
|
selves
|
||||||
|
sensible
|
||||||
|
sent
|
||||||
|
serious
|
||||||
|
seriously
|
||||||
|
seven
|
||||||
|
several
|
||||||
|
shall
|
||||||
|
she
|
||||||
|
should
|
||||||
|
shouldn't
|
||||||
|
since
|
||||||
|
six
|
||||||
|
so
|
||||||
|
some
|
||||||
|
somebody
|
||||||
|
somehow
|
||||||
|
someone
|
||||||
|
something
|
||||||
|
sometime
|
||||||
|
sometimes
|
||||||
|
somewhat
|
||||||
|
somewhere
|
||||||
|
soon
|
||||||
|
sorry
|
||||||
|
specified
|
||||||
|
specify
|
||||||
|
specifying
|
||||||
|
still
|
||||||
|
sub
|
||||||
|
such
|
||||||
|
sup
|
||||||
|
sure
|
||||||
|
t's
|
||||||
|
take
|
||||||
|
taken
|
||||||
|
tell
|
||||||
|
tends
|
||||||
|
th
|
||||||
|
than
|
||||||
|
thank
|
||||||
|
thanks
|
||||||
|
thanx
|
||||||
|
that
|
||||||
|
that's
|
||||||
|
thats
|
||||||
|
the
|
||||||
|
their
|
||||||
|
theirs
|
||||||
|
them
|
||||||
|
themselves
|
||||||
|
then
|
||||||
|
thence
|
||||||
|
there
|
||||||
|
there's
|
||||||
|
thereafter
|
||||||
|
thereby
|
||||||
|
therefore
|
||||||
|
therein
|
||||||
|
theres
|
||||||
|
thereupon
|
||||||
|
these
|
||||||
|
they
|
||||||
|
they'd
|
||||||
|
they'll
|
||||||
|
they're
|
||||||
|
they've
|
||||||
|
think
|
||||||
|
third
|
||||||
|
this
|
||||||
|
thorough
|
||||||
|
thoroughly
|
||||||
|
those
|
||||||
|
though
|
||||||
|
three
|
||||||
|
through
|
||||||
|
throughout
|
||||||
|
thru
|
||||||
|
thus
|
||||||
|
to
|
||||||
|
together
|
||||||
|
too
|
||||||
|
took
|
||||||
|
toward
|
||||||
|
towards
|
||||||
|
tried
|
||||||
|
tries
|
||||||
|
truly
|
||||||
|
try
|
||||||
|
trying
|
||||||
|
twice
|
||||||
|
two
|
||||||
|
un
|
||||||
|
under
|
||||||
|
unfortunately
|
||||||
|
unless
|
||||||
|
unlikely
|
||||||
|
until
|
||||||
|
unto
|
||||||
|
up
|
||||||
|
upon
|
||||||
|
us
|
||||||
|
use
|
||||||
|
used
|
||||||
|
useful
|
||||||
|
uses
|
||||||
|
using
|
||||||
|
usually
|
||||||
|
value
|
||||||
|
various
|
||||||
|
very
|
||||||
|
via
|
||||||
|
viz
|
||||||
|
vs
|
||||||
|
want
|
||||||
|
wants
|
||||||
|
was
|
||||||
|
wasn't
|
||||||
|
way
|
||||||
|
we
|
||||||
|
we'd
|
||||||
|
we'll
|
||||||
|
we're
|
||||||
|
we've
|
||||||
|
welcome
|
||||||
|
well
|
||||||
|
went
|
||||||
|
were
|
||||||
|
weren't
|
||||||
|
what
|
||||||
|
what's
|
||||||
|
whatever
|
||||||
|
when
|
||||||
|
whence
|
||||||
|
whenever
|
||||||
|
where
|
||||||
|
where's
|
||||||
|
whereafter
|
||||||
|
whereas
|
||||||
|
whereby
|
||||||
|
wherein
|
||||||
|
whereupon
|
||||||
|
wherever
|
||||||
|
whether
|
||||||
|
which
|
||||||
|
while
|
||||||
|
whither
|
||||||
|
who
|
||||||
|
who's
|
||||||
|
whoever
|
||||||
|
whole
|
||||||
|
whom
|
||||||
|
whose
|
||||||
|
why
|
||||||
|
will
|
||||||
|
willing
|
||||||
|
wish
|
||||||
|
with
|
||||||
|
within
|
||||||
|
without
|
||||||
|
won't
|
||||||
|
wonder
|
||||||
|
would
|
||||||
|
wouldn't
|
||||||
|
yes
|
||||||
|
yet
|
||||||
|
you
|
||||||
|
you'd
|
||||||
|
you'll
|
||||||
|
you're
|
||||||
|
you've
|
||||||
|
your
|
||||||
|
yours
|
||||||
|
yourself
|
||||||
|
yourselves
|
||||||
|
zero
|
@@ -205,9 +205,8 @@ abstract class AphrontApplicationConfiguration extends Phobject {
|
|||||||
DarkConsoleXHProfPluginAPI::saveProfilerSample($access_log);
|
DarkConsoleXHProfPluginAPI::saveProfilerSample($access_log);
|
||||||
|
|
||||||
// Add points to the rate limits for this request.
|
// Add points to the rate limits for this request.
|
||||||
if (isset($_SERVER['REMOTE_ADDR'])) {
|
$rate_token = PhabricatorStartup::getRateLimitToken();
|
||||||
$user_ip = $_SERVER['REMOTE_ADDR'];
|
if ($rate_token !== null) {
|
||||||
|
|
||||||
// The base score for a request allows users to make 30 requests per
|
// The base score for a request allows users to make 30 requests per
|
||||||
// minute.
|
// minute.
|
||||||
$score = (1000 / 30);
|
$score = (1000 / 30);
|
||||||
@@ -217,7 +216,7 @@ abstract class AphrontApplicationConfiguration extends Phobject {
|
|||||||
$score = $score / 5;
|
$score = $score / 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
PhabricatorStartup::addRateLimitScore($user_ip, $score);
|
PhabricatorStartup::addRateLimitScore($rate_token, $score);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($processing_exception) {
|
if ($processing_exception) {
|
||||||
|
@@ -94,10 +94,15 @@ final class AphrontFileResponse extends AphrontResponse {
|
|||||||
array('Accept-Ranges', 'bytes'),
|
array('Accept-Ranges', 'bytes'),
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($this->rangeMin || $this->rangeMax) {
|
if ($this->rangeMin !== null || $this->rangeMax !== null) {
|
||||||
$len = $this->getContentLength();
|
$len = $this->getContentLength();
|
||||||
$min = $this->rangeMin;
|
$min = $this->rangeMin;
|
||||||
|
|
||||||
$max = $this->rangeMax;
|
$max = $this->rangeMax;
|
||||||
|
if ($max === null) {
|
||||||
|
$max = ($len - 1);
|
||||||
|
}
|
||||||
|
|
||||||
$headers[] = array('Content-Range', "bytes {$min}-{$max}/{$len}");
|
$headers[] = array('Content-Range', "bytes {$min}-{$max}/{$len}");
|
||||||
$content_len = ($max - $min) + 1;
|
$content_len = ($max - $min) + 1;
|
||||||
} else {
|
} else {
|
||||||
@@ -105,7 +110,7 @@ final class AphrontFileResponse extends AphrontResponse {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!$this->shouldCompressResponse()) {
|
if (!$this->shouldCompressResponse()) {
|
||||||
$headers[] = array('Content-Length', $this->getContentLength());
|
$headers[] = array('Content-Length', $content_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen($this->getDownload())) {
|
if (strlen($this->getDownload())) {
|
||||||
@@ -134,4 +139,29 @@ final class AphrontFileResponse extends AphrontResponse {
|
|||||||
return $this->getCompressResponse();
|
return $this->getCompressResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function parseHTTPRange($range) {
|
||||||
|
$begin = null;
|
||||||
|
$end = null;
|
||||||
|
|
||||||
|
$matches = null;
|
||||||
|
if (preg_match('/^bytes=(\d+)-(\d*)$/', $range, $matches)) {
|
||||||
|
// Note that the "Range" header specifies bytes differently than
|
||||||
|
// we do internally: the range 0-1 has 2 bytes (byte 0 and byte 1).
|
||||||
|
$begin = (int)$matches[1];
|
||||||
|
|
||||||
|
// The "Range" may be "200-299" or "200-", meaning "until end of file".
|
||||||
|
if (strlen($matches[2])) {
|
||||||
|
$range_end = (int)$matches[2];
|
||||||
|
$end = $range_end + 1;
|
||||||
|
} else {
|
||||||
|
$range_end = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->setHTTPResponseCode(206);
|
||||||
|
$this->setRange($begin, $range_end);
|
||||||
|
}
|
||||||
|
|
||||||
|
return array($begin, $end);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -178,10 +178,13 @@ final class PhabricatorCommitSearchEngine
|
|||||||
$groups = $bucket->newResultGroups($query, $commits);
|
$groups = $bucket->newResultGroups($query, $commits);
|
||||||
|
|
||||||
foreach ($groups as $group) {
|
foreach ($groups as $group) {
|
||||||
$views[] = id(clone $template)
|
// Don't show groups in Dashboard Panels
|
||||||
->setHeader($group->getName())
|
if ($group->getObjects() || !$this->isPanelContext()) {
|
||||||
->setNoDataString($group->getNoDataString())
|
$views[] = id(clone $template)
|
||||||
->setCommits($group->getObjects());
|
->setHeader($group->getName())
|
||||||
|
->setNoDataString($group->getNoDataString())
|
||||||
|
->setCommits($group->getObjects());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (Exception $ex) {
|
} catch (Exception $ex) {
|
||||||
$this->addError($ex->getMessage());
|
$this->addError($ex->getMessage());
|
||||||
@@ -189,7 +192,13 @@ final class PhabricatorCommitSearchEngine
|
|||||||
} else {
|
} else {
|
||||||
$views[] = id(clone $template)
|
$views[] = id(clone $template)
|
||||||
->setCommits($commits)
|
->setCommits($commits)
|
||||||
->setNoDataString(pht('No matching commits.'));
|
->setNoDataString(pht('No commits found.'));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$views) {
|
||||||
|
$views[] = id(new PhabricatorAuditListView())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setNoDataString(pht('No commits found.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (count($views) == 1) {
|
if (count($views) == 1) {
|
||||||
|
@@ -194,7 +194,7 @@ abstract class PhabricatorAuthController extends PhabricatorController {
|
|||||||
// hijacking registration sessions.
|
// hijacking registration sessions.
|
||||||
|
|
||||||
$actual = $account->getProperty('registrationKey');
|
$actual = $account->getProperty('registrationKey');
|
||||||
$expect = PhabricatorHash::digest($registration_key);
|
$expect = PhabricatorHash::weakDigest($registration_key);
|
||||||
if (!phutil_hashes_are_identical($actual, $expect)) {
|
if (!phutil_hashes_are_identical($actual, $expect)) {
|
||||||
$response = $this->renderError(
|
$response = $this->renderError(
|
||||||
pht(
|
pht(
|
||||||
|
@@ -194,7 +194,7 @@ final class PhabricatorAuthLoginController
|
|||||||
$registration_key = Filesystem::readRandomCharacters(32);
|
$registration_key = Filesystem::readRandomCharacters(32);
|
||||||
$account->setProperty(
|
$account->setProperty(
|
||||||
'registrationKey',
|
'registrationKey',
|
||||||
PhabricatorHash::digest($registration_key));
|
PhabricatorHash::weakDigest($registration_key));
|
||||||
|
|
||||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||||
$account->save();
|
$account->save();
|
||||||
|
@@ -135,7 +135,7 @@ final class PhabricatorAuthOneTimeLoginController
|
|||||||
->setTokenResource($target_user->getPHID())
|
->setTokenResource($target_user->getPHID())
|
||||||
->setTokenType($password_type)
|
->setTokenType($password_type)
|
||||||
->setTokenExpires(time() + phutil_units('1 hour in seconds'))
|
->setTokenExpires(time() + phutil_units('1 hour in seconds'))
|
||||||
->setTokenCode(PhabricatorHash::digest($key))
|
->setTokenCode(PhabricatorHash::weakDigest($key))
|
||||||
->save();
|
->save();
|
||||||
unset($unguarded);
|
unset($unguarded);
|
||||||
|
|
||||||
|
@@ -24,11 +24,11 @@ final class PhabricatorAuthSSHKeyGenerateController
|
|||||||
$keys = PhabricatorSSHKeyGenerator::generateKeypair();
|
$keys = PhabricatorSSHKeyGenerator::generateKeypair();
|
||||||
list($public_key, $private_key) = $keys;
|
list($public_key, $private_key) = $keys;
|
||||||
|
|
||||||
$file = PhabricatorFile::buildFromFileDataOrHash(
|
$file = PhabricatorFile::newFromFileData(
|
||||||
$private_key,
|
$private_key,
|
||||||
array(
|
array(
|
||||||
'name' => $default_name.'.key',
|
'name' => $default_name.'.key',
|
||||||
'ttl' => time() + (60 * 10),
|
'ttl.relative' => phutil_units('10 minutes in seconds'),
|
||||||
'viewPolicy' => $viewer->getPHID(),
|
'viewPolicy' => $viewer->getPHID(),
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@@ -16,7 +16,7 @@ final class PhabricatorAuthTerminateSessionController
|
|||||||
$query->withIDs(array($id));
|
$query->withIDs(array($id));
|
||||||
}
|
}
|
||||||
|
|
||||||
$current_key = PhabricatorHash::digest(
|
$current_key = PhabricatorHash::weakDigest(
|
||||||
$request->getCookie(PhabricatorCookies::COOKIE_SESSION));
|
$request->getCookie(PhabricatorCookies::COOKIE_SESSION));
|
||||||
|
|
||||||
$sessions = $query->execute();
|
$sessions = $query->execute();
|
||||||
|
@@ -197,9 +197,7 @@ final class PhabricatorAuthSSHKeyEditor
|
|||||||
|
|
||||||
// After making any change to an SSH key, drop the authfile cache so it
|
// After making any change to an SSH key, drop the authfile cache so it
|
||||||
// is regenerated the next time anyone authenticates.
|
// is regenerated the next time anyone authenticates.
|
||||||
$cache = PhabricatorCaches::getMutableCache();
|
PhabricatorAuthSSHKeyQuery::deleteSSHKeyCache();
|
||||||
$authfile_key = PhabricatorAuthSSHKeyQuery::AUTHFILE_CACHEKEY;
|
|
||||||
$cache->deleteKey($authfile_key);
|
|
||||||
|
|
||||||
return $xactions;
|
return $xactions;
|
||||||
}
|
}
|
||||||
|
@@ -110,7 +110,7 @@ final class PhabricatorAuthSessionEngine extends Phobject {
|
|||||||
$session_table = new PhabricatorAuthSession();
|
$session_table = new PhabricatorAuthSession();
|
||||||
$user_table = new PhabricatorUser();
|
$user_table = new PhabricatorUser();
|
||||||
$conn_r = $session_table->establishConnection('r');
|
$conn_r = $session_table->establishConnection('r');
|
||||||
$session_key = PhabricatorHash::digest($session_token);
|
$session_key = PhabricatorHash::weakDigest($session_token);
|
||||||
|
|
||||||
$cache_parts = $this->getUserCacheQueryParts($conn_r);
|
$cache_parts = $this->getUserCacheQueryParts($conn_r);
|
||||||
list($cache_selects, $cache_joins, $cache_map, $types_map) = $cache_parts;
|
list($cache_selects, $cache_joins, $cache_map, $types_map) = $cache_parts;
|
||||||
@@ -240,7 +240,7 @@ final class PhabricatorAuthSessionEngine extends Phobject {
|
|||||||
// This has a side effect of validating the session type.
|
// This has a side effect of validating the session type.
|
||||||
$session_ttl = PhabricatorAuthSession::getSessionTypeTTL($session_type);
|
$session_ttl = PhabricatorAuthSession::getSessionTypeTTL($session_type);
|
||||||
|
|
||||||
$digest_key = PhabricatorHash::digest($session_key);
|
$digest_key = PhabricatorHash::weakDigest($session_key);
|
||||||
|
|
||||||
// Logging-in users don't have CSRF stuff yet, so we have to unguard this
|
// Logging-in users don't have CSRF stuff yet, so we have to unguard this
|
||||||
// write.
|
// write.
|
||||||
@@ -306,7 +306,7 @@ final class PhabricatorAuthSessionEngine extends Phobject {
|
|||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
if ($except_session !== null) {
|
if ($except_session !== null) {
|
||||||
$except_session = PhabricatorHash::digest($except_session);
|
$except_session = PhabricatorHash::weakDigest($except_session);
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($sessions as $key => $session) {
|
foreach ($sessions as $key => $session) {
|
||||||
@@ -755,7 +755,7 @@ final class PhabricatorAuthSessionEngine extends Phobject {
|
|||||||
$parts[] = $email->getVerificationCode();
|
$parts[] = $email->getVerificationCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
return PhabricatorHash::digest(implode(':', $parts));
|
return PhabricatorHash::weakDigest(implode(':', $parts));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -39,7 +39,7 @@ final class PhabricatorTOTPAuthFactor extends PhabricatorAuthFactor {
|
|||||||
->withTokenResources(array($user->getPHID()))
|
->withTokenResources(array($user->getPHID()))
|
||||||
->withTokenTypes(array($totp_token_type))
|
->withTokenTypes(array($totp_token_type))
|
||||||
->withExpired(false)
|
->withExpired(false)
|
||||||
->withTokenCodes(array(PhabricatorHash::digest($key)))
|
->withTokenCodes(array(PhabricatorHash::weakDigest($key)))
|
||||||
->executeOne();
|
->executeOne();
|
||||||
if (!$temporary_token) {
|
if (!$temporary_token) {
|
||||||
// If we don't have a matching token, regenerate the key below.
|
// If we don't have a matching token, regenerate the key below.
|
||||||
@@ -58,7 +58,7 @@ final class PhabricatorTOTPAuthFactor extends PhabricatorAuthFactor {
|
|||||||
->setTokenResource($user->getPHID())
|
->setTokenResource($user->getPHID())
|
||||||
->setTokenType($totp_token_type)
|
->setTokenType($totp_token_type)
|
||||||
->setTokenExpires(time() + phutil_units('1 hour in seconds'))
|
->setTokenExpires(time() + phutil_units('1 hour in seconds'))
|
||||||
->setTokenCode(PhabricatorHash::digest($key))
|
->setTokenCode(PhabricatorHash::weakDigest($key))
|
||||||
->save();
|
->save();
|
||||||
unset($unguarded);
|
unset($unguarded);
|
||||||
}
|
}
|
||||||
|
@@ -474,7 +474,7 @@ abstract class PhabricatorAuthProvider extends Phobject {
|
|||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return PhabricatorHash::digest($phcid);
|
return PhabricatorHash::weakDigest($phcid);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function verifyAuthCSRFCode(AphrontRequest $request, $actual) {
|
protected function verifyAuthCSRFCode(AphrontRequest $request, $actual) {
|
||||||
|
@@ -11,6 +11,12 @@ final class PhabricatorAuthSSHKeyQuery
|
|||||||
private $keys;
|
private $keys;
|
||||||
private $isActive;
|
private $isActive;
|
||||||
|
|
||||||
|
public static function deleteSSHKeyCache() {
|
||||||
|
$cache = PhabricatorCaches::getMutableCache();
|
||||||
|
$authfile_key = self::AUTHFILE_CACHEKEY;
|
||||||
|
$cache->deleteKey($authfile_key);
|
||||||
|
}
|
||||||
|
|
||||||
public function withIDs(array $ids) {
|
public function withIDs(array $ids) {
|
||||||
$this->ids = $ids;
|
$this->ids = $ids;
|
||||||
return $this;
|
return $this;
|
||||||
|
@@ -85,7 +85,7 @@ final class PhabricatorAuthSessionQuery
|
|||||||
if ($this->sessionKeys) {
|
if ($this->sessionKeys) {
|
||||||
$hashes = array();
|
$hashes = array();
|
||||||
foreach ($this->sessionKeys as $session_key) {
|
foreach ($this->sessionKeys as $session_key) {
|
||||||
$hashes[] = PhabricatorHash::digest($session_key);
|
$hashes[] = PhabricatorHash::weakDigest($session_key);
|
||||||
}
|
}
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn_r,
|
||||||
|
24
src/applications/auth/storage/PhabricatorAuthHMACKey.php
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorAuthHMACKey
|
||||||
|
extends PhabricatorAuthDAO {
|
||||||
|
|
||||||
|
protected $keyName;
|
||||||
|
protected $keyValue;
|
||||||
|
|
||||||
|
protected function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
|
'keyName' => 'text64',
|
||||||
|
'keyValue' => 'text128',
|
||||||
|
),
|
||||||
|
self::CONFIG_KEY_SCHEMA => array(
|
||||||
|
'key_name' => array(
|
||||||
|
'columns' => array('keyName'),
|
||||||
|
'unique' => true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -11,7 +11,7 @@ final class PhabricatorBadgesApplication extends PhabricatorApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getShortDescription() {
|
public function getShortDescription() {
|
||||||
return pht('Achievements and Notority');
|
return pht('Achievements and Notoriety');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getIcon() {
|
public function getIcon() {
|
||||||
@@ -26,10 +26,6 @@ final class PhabricatorBadgesApplication extends PhabricatorApplication {
|
|||||||
return self::GROUP_UTILITIES;
|
return self::GROUP_UTILITIES;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isPrototype() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getRoutes() {
|
public function getRoutes() {
|
||||||
return array(
|
return array(
|
||||||
'/badges/' => array(
|
'/badges/' => array(
|
||||||
|
@@ -1,103 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
final class PhabricatorBadgeHasRecipientEdgeType
|
|
||||||
extends PhabricatorEdgeType {
|
|
||||||
|
|
||||||
const EDGECONST = 59;
|
|
||||||
|
|
||||||
public function getInverseEdgeConstant() {
|
|
||||||
return PhabricatorRecipientHasBadgeEdgeType::EDGECONST;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function shouldWriteInverseTransactions() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTransactionAddString(
|
|
||||||
$actor,
|
|
||||||
$add_count,
|
|
||||||
$add_edges) {
|
|
||||||
|
|
||||||
return pht(
|
|
||||||
'%s awarded %s recipients(s): %s.',
|
|
||||||
$actor,
|
|
||||||
$add_count,
|
|
||||||
$add_edges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTransactionRemoveString(
|
|
||||||
$actor,
|
|
||||||
$rem_count,
|
|
||||||
$rem_edges) {
|
|
||||||
|
|
||||||
return pht(
|
|
||||||
'%s revoked %s recipients(s): %s.',
|
|
||||||
$actor,
|
|
||||||
$rem_count,
|
|
||||||
$rem_edges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTransactionEditString(
|
|
||||||
$actor,
|
|
||||||
$total_count,
|
|
||||||
$add_count,
|
|
||||||
$add_edges,
|
|
||||||
$rem_count,
|
|
||||||
$rem_edges) {
|
|
||||||
|
|
||||||
return pht(
|
|
||||||
'%s edited recipient(s), awarded %s: %s; revoked %s: %s.',
|
|
||||||
$actor,
|
|
||||||
$add_count,
|
|
||||||
$add_edges,
|
|
||||||
$rem_count,
|
|
||||||
$rem_edges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFeedAddString(
|
|
||||||
$actor,
|
|
||||||
$object,
|
|
||||||
$add_count,
|
|
||||||
$add_edges) {
|
|
||||||
|
|
||||||
return pht(
|
|
||||||
'%s awarded %s recipient(s) for %s: %s.',
|
|
||||||
$actor,
|
|
||||||
$add_count,
|
|
||||||
$object,
|
|
||||||
$add_edges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFeedRemoveString(
|
|
||||||
$actor,
|
|
||||||
$object,
|
|
||||||
$rem_count,
|
|
||||||
$rem_edges) {
|
|
||||||
|
|
||||||
return pht(
|
|
||||||
'%s revoked %s recipient(s) for %s: %s.',
|
|
||||||
$actor,
|
|
||||||
$rem_count,
|
|
||||||
$object,
|
|
||||||
$rem_edges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFeedEditString(
|
|
||||||
$actor,
|
|
||||||
$object,
|
|
||||||
$total_count,
|
|
||||||
$add_count,
|
|
||||||
$add_edges,
|
|
||||||
$rem_count,
|
|
||||||
$rem_edges) {
|
|
||||||
|
|
||||||
return pht(
|
|
||||||
'%s edited recipient(s) for %s, awarded %s: %s; revoked %s: %s.',
|
|
||||||
$actor,
|
|
||||||
$object,
|
|
||||||
$add_count,
|
|
||||||
$add_edges,
|
|
||||||
$rem_count,
|
|
||||||
$rem_edges);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -1,103 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
final class PhabricatorRecipientHasBadgeEdgeType
|
|
||||||
extends PhabricatorEdgeType {
|
|
||||||
|
|
||||||
const EDGECONST = 58;
|
|
||||||
|
|
||||||
public function getInverseEdgeConstant() {
|
|
||||||
return PhabricatorBadgeHasRecipientEdgeType::EDGECONST;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function shouldWriteInverseTransactions() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTransactionAddString(
|
|
||||||
$actor,
|
|
||||||
$add_count,
|
|
||||||
$add_edges) {
|
|
||||||
|
|
||||||
return pht(
|
|
||||||
'%s added %s badge(s): %s.',
|
|
||||||
$actor,
|
|
||||||
$add_count,
|
|
||||||
$add_edges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTransactionRemoveString(
|
|
||||||
$actor,
|
|
||||||
$rem_count,
|
|
||||||
$rem_edges) {
|
|
||||||
|
|
||||||
return pht(
|
|
||||||
'%s revoked %s badge(s): %s.',
|
|
||||||
$actor,
|
|
||||||
$rem_count,
|
|
||||||
$rem_edges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getTransactionEditString(
|
|
||||||
$actor,
|
|
||||||
$total_count,
|
|
||||||
$add_count,
|
|
||||||
$add_edges,
|
|
||||||
$rem_count,
|
|
||||||
$rem_edges) {
|
|
||||||
|
|
||||||
return pht(
|
|
||||||
'%s edited badge(s), added %s: %s; revoked %s: %s.',
|
|
||||||
$actor,
|
|
||||||
$add_count,
|
|
||||||
$add_edges,
|
|
||||||
$rem_count,
|
|
||||||
$rem_edges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFeedAddString(
|
|
||||||
$actor,
|
|
||||||
$object,
|
|
||||||
$add_count,
|
|
||||||
$add_edges) {
|
|
||||||
|
|
||||||
return pht(
|
|
||||||
'%s added %s badge(s) for %s: %s.',
|
|
||||||
$actor,
|
|
||||||
$add_count,
|
|
||||||
$object,
|
|
||||||
$add_edges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFeedRemoveString(
|
|
||||||
$actor,
|
|
||||||
$object,
|
|
||||||
$rem_count,
|
|
||||||
$rem_edges) {
|
|
||||||
|
|
||||||
return pht(
|
|
||||||
'%s revoked %s badge(s) for %s: %s.',
|
|
||||||
$actor,
|
|
||||||
$rem_count,
|
|
||||||
$object,
|
|
||||||
$rem_edges);
|
|
||||||
}
|
|
||||||
|
|
||||||
public function getFeedEditString(
|
|
||||||
$actor,
|
|
||||||
$object,
|
|
||||||
$total_count,
|
|
||||||
$add_count,
|
|
||||||
$add_edges,
|
|
||||||
$rem_count,
|
|
||||||
$rem_edges) {
|
|
||||||
|
|
||||||
return pht(
|
|
||||||
'%s edited badge(s) for %s, added %s: %s; revoked %s: %s.',
|
|
||||||
$actor,
|
|
||||||
$object,
|
|
||||||
$add_count,
|
|
||||||
$add_edges,
|
|
||||||
$rem_count,
|
|
||||||
$rem_edges);
|
|
||||||
}
|
|
||||||
}
|
|
@@ -43,7 +43,7 @@ final class PhabricatorBadgesBadgeNameTransaction
|
|||||||
$new_value = $xaction->getNewValue();
|
$new_value = $xaction->getNewValue();
|
||||||
$new_length = strlen($new_value);
|
$new_length = strlen($new_value);
|
||||||
if ($new_length > $max_length) {
|
if ($new_length > $max_length) {
|
||||||
$errors[] = $this->newRequiredError(
|
$errors[] = $this->newInvalidError(
|
||||||
pht('The name can be no longer than %s characters.',
|
pht('The name can be no longer than %s characters.',
|
||||||
new PhutilNumber($max_length)));
|
new PhutilNumber($max_length)));
|
||||||
}
|
}
|
||||||
|
@@ -9,8 +9,10 @@
|
|||||||
* @task meta Application Management
|
* @task meta Application Management
|
||||||
*/
|
*/
|
||||||
abstract class PhabricatorApplication
|
abstract class PhabricatorApplication
|
||||||
extends Phobject
|
extends PhabricatorLiskDAO
|
||||||
implements PhabricatorPolicyInterface {
|
implements
|
||||||
|
PhabricatorPolicyInterface,
|
||||||
|
PhabricatorApplicationTransactionInterface {
|
||||||
|
|
||||||
const GROUP_CORE = 'core';
|
const GROUP_CORE = 'core';
|
||||||
const GROUP_UTILITIES = 'util';
|
const GROUP_UTILITIES = 'util';
|
||||||
@@ -26,6 +28,30 @@ abstract class PhabricatorApplication
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final public function getApplicationName() {
|
||||||
|
return 'application';
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function getTableName() {
|
||||||
|
return 'application_application';
|
||||||
|
}
|
||||||
|
|
||||||
|
final protected function getConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::CONFIG_AUX_PHID => true,
|
||||||
|
) + parent::getConfiguration();
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function generatePHID() {
|
||||||
|
return $this->getPHID();
|
||||||
|
}
|
||||||
|
|
||||||
|
final public function save() {
|
||||||
|
// When "save()" is called on applications, we just return without
|
||||||
|
// actually writing anything to the database.
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* -( Application Information )-------------------------------------------- */
|
/* -( Application Information )-------------------------------------------- */
|
||||||
|
|
||||||
@@ -613,4 +639,25 @@ abstract class PhabricatorApplication
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -( PhabricatorApplicationTransactionInterface )------------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
public function getApplicationTransactionEditor() {
|
||||||
|
return new PhutilMethodNotImplementedException(pht('Coming Soon!'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionObject() {
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getApplicationTransactionTemplate() {
|
||||||
|
return new PhabricatorApplicationApplicationTransaction();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function willRenderTimeline(
|
||||||
|
PhabricatorApplicationTransactionView $timeline,
|
||||||
|
AphrontRequest $request) {
|
||||||
|
|
||||||
|
return $timeline;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -98,7 +98,7 @@ abstract class PhabricatorController extends AphrontController {
|
|||||||
|
|
||||||
|
|
||||||
if (!$user->isLoggedIn()) {
|
if (!$user->isLoggedIn()) {
|
||||||
$user->attachAlternateCSRFString(PhabricatorHash::digest($phsid));
|
$user->attachAlternateCSRFString(PhabricatorHash::weakDigest($phsid));
|
||||||
}
|
}
|
||||||
|
|
||||||
$request->setUser($user);
|
$request->setUser($user);
|
||||||
|
@@ -58,4 +58,12 @@ final class PhabricatorCalendarEventNotificationView
|
|||||||
return phabricator_datetime($epoch, $viewer);
|
return phabricator_datetime($epoch, $viewer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDisplayTimeWithTimezone() {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$epoch = $this->getEpoch();
|
||||||
|
return phabricator_datetimezone($epoch, $viewer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -268,7 +268,7 @@ final class PhabricatorCalendarNotificationEngine
|
|||||||
'%s is starting in %s minute(s), at %s.',
|
'%s is starting in %s minute(s), at %s.',
|
||||||
$event->getEvent()->getName(),
|
$event->getEvent()->getName(),
|
||||||
$event->getDisplayMinutes(),
|
$event->getDisplayMinutes(),
|
||||||
$event->getDisplayTime()));
|
$event->getDisplayTimeWithTimezone()));
|
||||||
|
|
||||||
$body->addLinkSection(
|
$body->addLinkSection(
|
||||||
pht('EVENT DETAIL'),
|
pht('EVENT DETAIL'),
|
||||||
|
@@ -226,7 +226,7 @@ final class PhabricatorCalendarEventQuery
|
|||||||
$set = $event->newRecurrenceSet();
|
$set = $event->newRecurrenceSet();
|
||||||
|
|
||||||
$recurrences = $set->getEventsBetween(
|
$recurrences = $set->getEventsBetween(
|
||||||
null,
|
$start_date,
|
||||||
$end_date,
|
$end_date,
|
||||||
$limit + 1);
|
$limit + 1);
|
||||||
|
|
||||||
|
@@ -391,6 +391,10 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||||||
return ($epoch - $window);
|
return ($epoch - $window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getEndDateTimeEpochForCache() {
|
||||||
|
return $this->getEndDateTimeEpoch();
|
||||||
|
}
|
||||||
|
|
||||||
protected function getConfiguration() {
|
protected function getConfiguration() {
|
||||||
return array(
|
return array(
|
||||||
self::CONFIG_AUX_PHID => true,
|
self::CONFIG_AUX_PHID => true,
|
||||||
@@ -1182,9 +1186,8 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||||||
* @task markup
|
* @task markup
|
||||||
*/
|
*/
|
||||||
public function getMarkupFieldKey($field) {
|
public function getMarkupFieldKey($field) {
|
||||||
$hash = PhabricatorHash::digest($this->getMarkupText($field));
|
$content = $this->getMarkupText($field);
|
||||||
$id = $this->getID();
|
return PhabricatorMarkupEngine::digestRemarkupContent($this, $content);
|
||||||
return "calendar:T{$id}:{$field}:{$hash}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -1343,7 +1346,21 @@ final class PhabricatorCalendarEvent extends PhabricatorCalendarDAO
|
|||||||
PhabricatorDestructionEngine $engine) {
|
PhabricatorDestructionEngine $engine) {
|
||||||
|
|
||||||
$this->openTransaction();
|
$this->openTransaction();
|
||||||
$this->delete();
|
$invitees = id(new PhabricatorCalendarEventInvitee())->loadAllWhere(
|
||||||
|
'eventPHID = %s',
|
||||||
|
$this->getPHID());
|
||||||
|
foreach ($invitees as $invitee) {
|
||||||
|
$invitee->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
$notifications = id(new PhabricatorCalendarNotification())->loadAllWhere(
|
||||||
|
'eventPHID = %s',
|
||||||
|
$this->getPHID());
|
||||||
|
foreach ($notifications as $notification) {
|
||||||
|
$notification->delete();
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->delete();
|
||||||
$this->saveTransaction();
|
$this->saveTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -104,9 +104,30 @@ abstract class CelerityResourceController extends PhabricatorController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
$response = id(new AphrontFileResponse())
|
$response = id(new AphrontFileResponse())
|
||||||
->setContent($data)
|
->setMimeType($type_map[$type]);
|
||||||
->setMimeType($type_map[$type])
|
|
||||||
->setCompressResponse(true);
|
$range = AphrontRequest::getHTTPHeader('Range');
|
||||||
|
|
||||||
|
if (strlen($range)) {
|
||||||
|
$response->setContentLength(strlen($data));
|
||||||
|
|
||||||
|
list($range_begin, $range_end) = $response->parseHTTPRange($range);
|
||||||
|
|
||||||
|
if ($range_begin !== null) {
|
||||||
|
if ($range_end !== null) {
|
||||||
|
$data = substr($data, $range_begin, ($range_end - $range_begin));
|
||||||
|
} else {
|
||||||
|
$data = substr($data, $range_begin);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->setContentIterator(array($data));
|
||||||
|
} else {
|
||||||
|
$response
|
||||||
|
->setContent($data)
|
||||||
|
->setCompressResponse(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// NOTE: This is a piece of magic required to make WOFF fonts work in
|
// NOTE: This is a piece of magic required to make WOFF fonts work in
|
||||||
// Firefox and IE. Possibly we should generalize this more.
|
// Firefox and IE. Possibly we should generalize this more.
|
||||||
|
@@ -14,7 +14,7 @@ abstract class CelerityResources extends Phobject {
|
|||||||
|
|
||||||
public function getCelerityHash($data) {
|
public function getCelerityHash($data) {
|
||||||
$tail = PhabricatorEnv::getEnvConfig('celerity.resource-hash');
|
$tail = PhabricatorEnv::getEnvConfig('celerity.resource-hash');
|
||||||
$hash = PhabricatorHash::digest($data, $tail);
|
$hash = PhabricatorHash::weakDigest($data, $tail);
|
||||||
return substr($hash, 0, 8);
|
return substr($hash, 0, 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -56,6 +56,12 @@ abstract class PhabricatorConduitController extends PhabricatorController {
|
|||||||
$panel_link),
|
$panel_link),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if ($params === null) {
|
||||||
|
$messages[] = pht(
|
||||||
|
'If you submit parameters, these examples will update to show '.
|
||||||
|
'exactly how to encode the parameters you submit.');
|
||||||
|
}
|
||||||
|
|
||||||
$info_view = id(new PHUIInfoView())
|
$info_view = id(new PHUIInfoView())
|
||||||
->setErrors($messages)
|
->setErrors($messages)
|
||||||
->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
|
->setSeverity(PHUIInfoView::SEVERITY_NOTICE);
|
||||||
|
@@ -27,7 +27,7 @@ final class PhabricatorConfigApplication extends PhabricatorApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function getName() {
|
public function getName() {
|
||||||
return 'Config';
|
return pht('Config');
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getShortDescription() {
|
public function getShortDescription() {
|
||||||
@@ -69,6 +69,7 @@ final class PhabricatorConfigApplication extends PhabricatorApplication {
|
|||||||
'databases/' => 'PhabricatorConfigClusterDatabasesController',
|
'databases/' => 'PhabricatorConfigClusterDatabasesController',
|
||||||
'notifications/' => 'PhabricatorConfigClusterNotificationsController',
|
'notifications/' => 'PhabricatorConfigClusterNotificationsController',
|
||||||
'repositories/' => 'PhabricatorConfigClusterRepositoriesController',
|
'repositories/' => 'PhabricatorConfigClusterRepositoriesController',
|
||||||
|
'search/' => 'PhabricatorConfigClusterSearchController',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@@ -1,77 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
final class PhabricatorElasticSearchSetupCheck extends PhabricatorSetupCheck {
|
|
||||||
|
|
||||||
public function getDefaultGroup() {
|
|
||||||
return self::GROUP_OTHER;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function executeChecks() {
|
|
||||||
if (!$this->shouldUseElasticSearchEngine()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
$engine = new PhabricatorElasticFulltextStorageEngine();
|
|
||||||
|
|
||||||
$index_exists = null;
|
|
||||||
$index_sane = null;
|
|
||||||
try {
|
|
||||||
$index_exists = $engine->indexExists();
|
|
||||||
if ($index_exists) {
|
|
||||||
$index_sane = $engine->indexIsSane();
|
|
||||||
}
|
|
||||||
} catch (Exception $ex) {
|
|
||||||
$summary = pht('Elasticsearch is not reachable as configured.');
|
|
||||||
$message = pht(
|
|
||||||
'Elasticsearch is configured (with the %s setting) but Phabricator '.
|
|
||||||
'encountered an exception when trying to test the index.'.
|
|
||||||
"\n\n".
|
|
||||||
'%s',
|
|
||||||
phutil_tag('tt', array(), 'search.elastic.host'),
|
|
||||||
phutil_tag('pre', array(), $ex->getMessage()));
|
|
||||||
|
|
||||||
$this->newIssue('elastic.misconfigured')
|
|
||||||
->setName(pht('Elasticsearch Misconfigured'))
|
|
||||||
->setSummary($summary)
|
|
||||||
->setMessage($message)
|
|
||||||
->addRelatedPhabricatorConfig('search.elastic.host');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$index_exists) {
|
|
||||||
$summary = pht(
|
|
||||||
'You enabled Elasticsearch but the index does not exist.');
|
|
||||||
|
|
||||||
$message = pht(
|
|
||||||
'You likely enabled search.elastic.host without creating the '.
|
|
||||||
'index. Run `./bin/search init` to correct the index.');
|
|
||||||
|
|
||||||
$this
|
|
||||||
->newIssue('elastic.missing-index')
|
|
||||||
->setName(pht('Elasticsearch index Not Found'))
|
|
||||||
->setSummary($summary)
|
|
||||||
->setMessage($message)
|
|
||||||
->addRelatedPhabricatorConfig('search.elastic.host');
|
|
||||||
} else if (!$index_sane) {
|
|
||||||
$summary = pht(
|
|
||||||
'Elasticsearch index exists but needs correction.');
|
|
||||||
|
|
||||||
$message = pht(
|
|
||||||
'Either the Phabricator schema for Elasticsearch has changed '.
|
|
||||||
'or Elasticsearch created the index automatically. Run '.
|
|
||||||
'`./bin/search init` to correct the index.');
|
|
||||||
|
|
||||||
$this
|
|
||||||
->newIssue('elastic.broken-index')
|
|
||||||
->setName(pht('Elasticsearch index Incorrect'))
|
|
||||||
->setSummary($summary)
|
|
||||||
->setMessage($message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function shouldUseElasticSearchEngine() {
|
|
||||||
$search_engine = PhabricatorFulltextStorageEngine::loadEngine();
|
|
||||||
return ($search_engine instanceof PhabricatorElasticFulltextStorageEngine);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -0,0 +1,82 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorElasticsearchSetupCheck extends PhabricatorSetupCheck {
|
||||||
|
|
||||||
|
public function getDefaultGroup() {
|
||||||
|
return self::GROUP_OTHER;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function executeChecks() {
|
||||||
|
$services = PhabricatorSearchService::getAllServices();
|
||||||
|
|
||||||
|
foreach ($services as $service) {
|
||||||
|
try {
|
||||||
|
$host = $service->getAnyHostForRole('read');
|
||||||
|
} catch (PhabricatorClusterNoHostForRoleException $e) {
|
||||||
|
// ignore the error
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if ($host instanceof PhabricatorElasticsearchHost) {
|
||||||
|
$index_exists = null;
|
||||||
|
$index_sane = null;
|
||||||
|
try {
|
||||||
|
$engine = $host->getEngine();
|
||||||
|
$index_exists = $engine->indexExists();
|
||||||
|
if ($index_exists) {
|
||||||
|
$index_sane = $engine->indexIsSane();
|
||||||
|
}
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$summary = pht('Elasticsearch is not reachable as configured.');
|
||||||
|
$message = pht(
|
||||||
|
'Elasticsearch is configured (with the %s setting) but Phabricator'.
|
||||||
|
' encountered an exception when trying to test the index.'.
|
||||||
|
"\n\n".
|
||||||
|
'%s',
|
||||||
|
phutil_tag('tt', array(), 'cluster.search'),
|
||||||
|
phutil_tag('pre', array(), $ex->getMessage()));
|
||||||
|
|
||||||
|
$this->newIssue('elastic.misconfigured')
|
||||||
|
->setName(pht('Elasticsearch Misconfigured'))
|
||||||
|
->setSummary($summary)
|
||||||
|
->setMessage($message)
|
||||||
|
->addRelatedPhabricatorConfig('cluster.search');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$index_exists) {
|
||||||
|
$summary = pht(
|
||||||
|
'You enabled Elasticsearch but the index does not exist.');
|
||||||
|
|
||||||
|
$message = pht(
|
||||||
|
'You likely enabled cluster.search without creating the '.
|
||||||
|
'index. Use the following command to create a new index.');
|
||||||
|
|
||||||
|
$this
|
||||||
|
->newIssue('elastic.missing-index')
|
||||||
|
->setName(pht('Elasticsearch Index Not Found'))
|
||||||
|
->addCommand('./bin/search init')
|
||||||
|
->setSummary($summary)
|
||||||
|
->setMessage($message);
|
||||||
|
|
||||||
|
} else if (!$index_sane) {
|
||||||
|
$summary = pht(
|
||||||
|
'Elasticsearch index exists but needs correction.');
|
||||||
|
|
||||||
|
$message = pht(
|
||||||
|
'Either the Phabricator schema for Elasticsearch has changed '.
|
||||||
|
'or Elasticsearch created the index automatically. '.
|
||||||
|
'Use the following command to rebuild the index.');
|
||||||
|
|
||||||
|
$this
|
||||||
|
->newIssue('elastic.broken-index')
|
||||||
|
->setName(pht('Elasticsearch Index Schema Mismatch'))
|
||||||
|
->addCommand('./bin/search init')
|
||||||
|
->setSummary($summary)
|
||||||
|
->setMessage($message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -198,6 +198,10 @@ final class PhabricatorExtraConfigSetupCheck extends PhabricatorSetupCheck {
|
|||||||
'This option has been removed, you can use Dashboards to provide '.
|
'This option has been removed, you can use Dashboards to provide '.
|
||||||
'homepage customization. See T11533 for more details.');
|
'homepage customization. See T11533 for more details.');
|
||||||
|
|
||||||
|
$elastic_reason = pht(
|
||||||
|
'Elasticsearch is now configured with "%s".',
|
||||||
|
'cluster.search');
|
||||||
|
|
||||||
$ancient_config += array(
|
$ancient_config += array(
|
||||||
'phid.external-loaders' =>
|
'phid.external-loaders' =>
|
||||||
pht(
|
pht(
|
||||||
@@ -348,6 +352,10 @@ final class PhabricatorExtraConfigSetupCheck extends PhabricatorSetupCheck {
|
|||||||
'mysql.configuration-provider' => pht(
|
'mysql.configuration-provider' => pht(
|
||||||
'Phabricator now has application-level management of partitioning '.
|
'Phabricator now has application-level management of partitioning '.
|
||||||
'and replicas.'),
|
'and replicas.'),
|
||||||
|
|
||||||
|
'search.elastic.host' => $elastic_reason,
|
||||||
|
'search.elastic.namespace' => $elastic_reason,
|
||||||
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return $ancient_config;
|
return $ancient_config;
|
||||||
|
@@ -145,7 +145,7 @@ final class PhabricatorMySQLSetupCheck extends PhabricatorSetupCheck {
|
|||||||
"be able to find search results for common words. You can gain ".
|
"be able to find search results for common words. You can gain ".
|
||||||
"access to this option by upgrading MySQL to a more recent ".
|
"access to this option by upgrading MySQL to a more recent ".
|
||||||
"version.\n\n".
|
"version.\n\n".
|
||||||
"You can ignore this warning if you plan to configure ElasticSearch ".
|
"You can ignore this warning if you plan to configure Elasticsearch ".
|
||||||
"later, or aren't concerned about searching for common words.",
|
"later, or aren't concerned about searching for common words.",
|
||||||
$host_name,
|
$host_name,
|
||||||
phutil_tag('tt', array(), 'ft_stopword_file'));
|
phutil_tag('tt', array(), 'ft_stopword_file'));
|
||||||
@@ -180,7 +180,7 @@ final class PhabricatorMySQLSetupCheck extends PhabricatorSetupCheck {
|
|||||||
"To make search more useful, you can use an alternate stopword ".
|
"To make search more useful, you can use an alternate stopword ".
|
||||||
"file with fewer words. Alternatively, if you aren't concerned ".
|
"file with fewer words. Alternatively, if you aren't concerned ".
|
||||||
"about searching for common words, you can ignore this warning. ".
|
"about searching for common words, you can ignore this warning. ".
|
||||||
"If you later plan to configure ElasticSearch, you can also ignore ".
|
"If you later plan to configure Elasticsearch, you can also ignore ".
|
||||||
"this warning: this stopword file only affects MySQL fulltext ".
|
"this warning: this stopword file only affects MySQL fulltext ".
|
||||||
"indexes.\n\n".
|
"indexes.\n\n".
|
||||||
"To choose a different stopword file, add this to your %s file ".
|
"To choose a different stopword file, add this to your %s file ".
|
||||||
@@ -231,7 +231,7 @@ final class PhabricatorMySQLSetupCheck extends PhabricatorSetupCheck {
|
|||||||
"You can change this setting to 3 to allow these words to be ".
|
"You can change this setting to 3 to allow these words to be ".
|
||||||
"indexed. Alternatively, you can ignore this warning if you are ".
|
"indexed. Alternatively, you can ignore this warning if you are ".
|
||||||
"not concerned about searching for 3-letter words. If you later ".
|
"not concerned about searching for 3-letter words. If you later ".
|
||||||
"plan to configure ElasticSearch, you can also ignore this warning: ".
|
"plan to configure Elasticsearch, you can also ignore this warning: ".
|
||||||
"only MySQL fulltext search is affected.\n\n".
|
"only MySQL fulltext search is affected.\n\n".
|
||||||
"To reduce the minimum word length to 3, add this to your %s file ".
|
"To reduce the minimum word length to 3, add this to your %s file ".
|
||||||
"(in the %s section) and then restart %s:\n\n".
|
"(in the %s section) and then restart %s:\n\n".
|
||||||
@@ -379,8 +379,13 @@ final class PhabricatorMySQLSetupCheck extends PhabricatorSetupCheck {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function shouldUseMySQLSearchEngine() {
|
protected function shouldUseMySQLSearchEngine() {
|
||||||
$search_engine = PhabricatorFulltextStorageEngine::loadEngine();
|
$services = PhabricatorSearchService::getAllServices();
|
||||||
return ($search_engine instanceof PhabricatorMySQLFulltextStorageEngine);
|
foreach ($services as $service) {
|
||||||
|
if ($service instanceof PhabricatorMySQLSearchHost) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -107,7 +107,7 @@ final class PhabricatorPathSetupCheck extends PhabricatorSetupCheck {
|
|||||||
|
|
||||||
if ($bad_paths) {
|
if ($bad_paths) {
|
||||||
foreach ($bad_paths as $path_part => $message) {
|
foreach ($bad_paths as $path_part => $message) {
|
||||||
$digest = substr(PhabricatorHash::digest($path_part), 0, 8);
|
$digest = substr(PhabricatorHash::weakDigest($path_part), 0, 8);
|
||||||
|
|
||||||
$this
|
$this
|
||||||
->newIssue('config.PATH.'.$digest)
|
->newIssue('config.PATH.'.$digest)
|
||||||
|
@@ -103,10 +103,20 @@ final class PhabricatorConfigClusterNotificationsController
|
|||||||
new PhutilNumber(idx($details, 'messages.in')),
|
new PhutilNumber(idx($details, 'messages.in')),
|
||||||
new PhutilNumber(idx($details, 'messages.out')));
|
new PhutilNumber(idx($details, 'messages.out')));
|
||||||
|
|
||||||
|
if (idx($details, 'history.size')) {
|
||||||
|
$history = pht(
|
||||||
|
'%s Held / %sms',
|
||||||
|
new PhutilNumber(idx($details, 'history.size')),
|
||||||
|
new PhutilNumber(idx($details, 'history.age')));
|
||||||
|
} else {
|
||||||
|
$history = pht('No Messages');
|
||||||
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
$uptime = null;
|
$uptime = null;
|
||||||
$clients = null;
|
$clients = null;
|
||||||
$stats = null;
|
$stats = null;
|
||||||
|
$history = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
$status_view = array(
|
$status_view = array(
|
||||||
@@ -126,6 +136,7 @@ final class PhabricatorConfigClusterNotificationsController
|
|||||||
$uptime,
|
$uptime,
|
||||||
$clients,
|
$clients,
|
||||||
$stats,
|
$stats,
|
||||||
|
$history,
|
||||||
$messages,
|
$messages,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -143,6 +154,7 @@ final class PhabricatorConfigClusterNotificationsController
|
|||||||
pht('Uptime'),
|
pht('Uptime'),
|
||||||
pht('Clients'),
|
pht('Clients'),
|
||||||
pht('Messages'),
|
pht('Messages'),
|
||||||
|
pht('History'),
|
||||||
null,
|
null,
|
||||||
))
|
))
|
||||||
->setColumnClasses(
|
->setColumnClasses(
|
||||||
@@ -155,6 +167,7 @@ final class PhabricatorConfigClusterNotificationsController
|
|||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
|
null,
|
||||||
'wide',
|
'wide',
|
||||||
));
|
));
|
||||||
|
|
||||||
|
@@ -0,0 +1,129 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorConfigClusterSearchController
|
||||||
|
extends PhabricatorConfigController {
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$nav = $this->buildSideNavView();
|
||||||
|
$nav->selectFilter('cluster/search/');
|
||||||
|
|
||||||
|
$title = pht('Cluster Search');
|
||||||
|
$doc_href = PhabricatorEnv::getDoclink('Cluster: Search');
|
||||||
|
|
||||||
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setHeader($title)
|
||||||
|
->setProfileHeader(true)
|
||||||
|
->addActionLink(
|
||||||
|
id(new PHUIButtonView())
|
||||||
|
->setIcon('fa-book')
|
||||||
|
->setHref($doc_href)
|
||||||
|
->setTag('a')
|
||||||
|
->setText(pht('Documentation')));
|
||||||
|
|
||||||
|
$crumbs = $this
|
||||||
|
->buildApplicationCrumbs($nav)
|
||||||
|
->addTextCrumb($title)
|
||||||
|
->setBorder(true);
|
||||||
|
|
||||||
|
$search_status = $this->buildClusterSearchStatus();
|
||||||
|
|
||||||
|
$content = id(new PhabricatorConfigPageView())
|
||||||
|
->setHeader($header)
|
||||||
|
->setContent($search_status);
|
||||||
|
|
||||||
|
return $this->newPage()
|
||||||
|
->setTitle($title)
|
||||||
|
->setCrumbs($crumbs)
|
||||||
|
->setNavigation($nav)
|
||||||
|
->appendChild($content)
|
||||||
|
->addClass('white-background');
|
||||||
|
}
|
||||||
|
|
||||||
|
private function buildClusterSearchStatus() {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$services = PhabricatorSearchService::getAllServices();
|
||||||
|
Javelin::initBehavior('phabricator-tooltips');
|
||||||
|
|
||||||
|
$view = array();
|
||||||
|
foreach ($services as $service) {
|
||||||
|
$view[] = $this->renderStatusView($service);
|
||||||
|
}
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function renderStatusView($service) {
|
||||||
|
$head = array_merge(
|
||||||
|
array(pht('Type')),
|
||||||
|
array_keys($service->getStatusViewColumns()),
|
||||||
|
array(pht('Status')));
|
||||||
|
|
||||||
|
$rows = array();
|
||||||
|
|
||||||
|
$status_map = PhabricatorSearchService::getConnectionStatusMap();
|
||||||
|
$stats = false;
|
||||||
|
$stats_view = false;
|
||||||
|
|
||||||
|
foreach ($service->getHosts() as $host) {
|
||||||
|
try {
|
||||||
|
$status = $host->getConnectionStatus();
|
||||||
|
$status = idx($status_map, $status, array());
|
||||||
|
} catch (Exception $ex) {
|
||||||
|
$status['icon'] = 'fa-times';
|
||||||
|
$status['label'] = pht('Connection Error');
|
||||||
|
$status['color'] = 'red';
|
||||||
|
$host->didHealthCheck(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$stats_view) {
|
||||||
|
try {
|
||||||
|
$stats = $host->getEngine()->getIndexStats($host);
|
||||||
|
$stats_view = $this->renderIndexStats($stats);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$stats_view = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$type_icon = 'fa-search sky';
|
||||||
|
$type_tip = $host->getDisplayName();
|
||||||
|
|
||||||
|
$type_icon = id(new PHUIIconView())
|
||||||
|
->setIcon($type_icon);
|
||||||
|
$status_view = array(
|
||||||
|
id(new PHUIIconView())->setIcon($status['icon'].' '.$status['color']),
|
||||||
|
' ',
|
||||||
|
$status['label'],
|
||||||
|
);
|
||||||
|
$row = array(array($type_icon, ' ', $type_tip));
|
||||||
|
$row = array_merge($row, array_values(
|
||||||
|
$host->getStatusViewColumns()));
|
||||||
|
$row[] = $status_view;
|
||||||
|
$rows[] = $row;
|
||||||
|
}
|
||||||
|
|
||||||
|
$table = id(new AphrontTableView($rows))
|
||||||
|
->setNoDataString(pht('No search servers are configured.'))
|
||||||
|
->setHeaders($head);
|
||||||
|
|
||||||
|
$view = id(new PHUIObjectBoxView())
|
||||||
|
->setHeaderText($service->getDisplayName())
|
||||||
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||||
|
->setTable($table);
|
||||||
|
|
||||||
|
if ($stats_view) {
|
||||||
|
$view->addPropertyList($stats_view);
|
||||||
|
}
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function renderIndexStats($stats) {
|
||||||
|
$view = id(new PHUIPropertyListView());
|
||||||
|
if ($stats !== false) {
|
||||||
|
foreach ($stats as $label => $val) {
|
||||||
|
$view->addProperty($label, $val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $view;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -42,8 +42,11 @@ abstract class PhabricatorConfigController extends PhabricatorController {
|
|||||||
pht('Notification Servers'), null, 'fa-bell-o');
|
pht('Notification Servers'), null, 'fa-bell-o');
|
||||||
$nav->addFilter('cluster/repositories/',
|
$nav->addFilter('cluster/repositories/',
|
||||||
pht('Repository Servers'), null, 'fa-code');
|
pht('Repository Servers'), null, 'fa-code');
|
||||||
|
$nav->addFilter('cluster/search/',
|
||||||
|
pht('Search Servers'), null, 'fa-search');
|
||||||
$nav->addLabel(pht('Modules'));
|
$nav->addLabel(pht('Modules'));
|
||||||
|
|
||||||
|
|
||||||
$modules = PhabricatorConfigModule::getAllModules();
|
$modules = PhabricatorConfigModule::getAllModules();
|
||||||
foreach ($modules as $key => $module) {
|
foreach ($modules as $key => $module) {
|
||||||
$nav->addFilter('module/'.$key.'/',
|
$nav->addFilter('module/'.$key.'/',
|
||||||
|
@@ -0,0 +1,18 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class PhabricatorConfigRegexOptionType
|
||||||
|
extends PhabricatorConfigJSONOptionType {
|
||||||
|
|
||||||
|
public function validateOption(PhabricatorConfigOption $option, $value) {
|
||||||
|
foreach ($value as $pattern => $spec) {
|
||||||
|
$ok = preg_match($pattern, '');
|
||||||
|
if ($ok === false) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'The following regex is malformed and cannot be used: %s',
|
||||||
|
$pattern));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -35,6 +35,7 @@ final class PhabricatorAccessLogConfigOptions
|
|||||||
'P' => pht('The logged-in user PHID, if one is logged in.'),
|
'P' => pht('The logged-in user PHID, if one is logged in.'),
|
||||||
'i' => pht('Request input, in bytes.'),
|
'i' => pht('Request input, in bytes.'),
|
||||||
'o' => pht('Request output, in bytes.'),
|
'o' => pht('Request output, in bytes.'),
|
||||||
|
'I' => pht('Cluster instance name, if configured.'),
|
||||||
);
|
);
|
||||||
|
|
||||||
$http_map = $common_map + array(
|
$http_map = $common_map + array(
|
||||||
|
@@ -38,6 +38,17 @@ EOTEXT
|
|||||||
$intro_href = PhabricatorEnv::getDoclink('Clustering Introduction');
|
$intro_href = PhabricatorEnv::getDoclink('Clustering Introduction');
|
||||||
$intro_name = pht('Clustering Introduction');
|
$intro_name = pht('Clustering Introduction');
|
||||||
|
|
||||||
|
$search_type = 'custom:PhabricatorClusterSearchConfigOptionType';
|
||||||
|
$search_help = $this->deformat(pht(<<<EOTEXT
|
||||||
|
Define one or more fulltext storage services. Here you can configure which
|
||||||
|
hosts will handle fulltext search queries and indexing. For help with
|
||||||
|
configuring fulltext search clusters, see **[[ %s | %s ]]** in the
|
||||||
|
documentation.
|
||||||
|
EOTEXT
|
||||||
|
,
|
||||||
|
PhabricatorEnv::getDoclink('Cluster: Search'),
|
||||||
|
pht('Cluster: Search')));
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
$this->newOption('cluster.addresses', 'list<string>', array())
|
$this->newOption('cluster.addresses', 'list<string>', array())
|
||||||
->setLocked(true)
|
->setLocked(true)
|
||||||
@@ -114,6 +125,21 @@ EOTEXT
|
|||||||
->setSummary(
|
->setSummary(
|
||||||
pht('Configure database read replicas.'))
|
pht('Configure database read replicas.'))
|
||||||
->setDescription($databases_help),
|
->setDescription($databases_help),
|
||||||
|
$this->newOption('cluster.search', $search_type, array())
|
||||||
|
->setLocked(true)
|
||||||
|
->setSummary(
|
||||||
|
pht('Configure full-text search services.'))
|
||||||
|
->setDescription($search_help)
|
||||||
|
->setDefault(
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'type' => 'mysql',
|
||||||
|
'roles' => array(
|
||||||
|
'read' => true,
|
||||||
|
'write' => true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -109,7 +109,8 @@ EOTEXT
|
|||||||
'Default key for HMAC digests where the key is not important '.
|
'Default key for HMAC digests where the key is not important '.
|
||||||
'(i.e., the hash itself is secret). You can change this if you '.
|
'(i.e., the hash itself is secret). You can change this if you '.
|
||||||
'want (to any other string), but doing so will break existing '.
|
'want (to any other string), but doing so will break existing '.
|
||||||
'sessions and CSRF tokens.')),
|
'sessions and CSRF tokens. This option is deprecated. Newer '.
|
||||||
|
'code automatically manages HMAC keys.')),
|
||||||
$this->newOption('security.require-https', 'bool', false)
|
$this->newOption('security.require-https', 'bool', false)
|
||||||
->setLocked(true)
|
->setLocked(true)
|
||||||
->setSummary(
|
->setSummary(
|
||||||
|
@@ -120,11 +120,11 @@ final class PhabricatorSyntaxHighlightingConfigOptions
|
|||||||
'this is where that list is defined.')),
|
'this is where that list is defined.')),
|
||||||
$this->newOption(
|
$this->newOption(
|
||||||
'syntax.filemap',
|
'syntax.filemap',
|
||||||
'wild',
|
'custom:PhabricatorConfigRegexOptionType',
|
||||||
array(
|
array(
|
||||||
'@\.arcconfig$@' => 'js',
|
'@\.arcconfig$@' => 'json',
|
||||||
'@\.arclint$@' => 'js',
|
'@\.arclint$@' => 'json',
|
||||||
'@\.divinerconfig$@' => 'js',
|
'@\.divinerconfig$@' => 'json',
|
||||||
))
|
))
|
||||||
->setSummary(
|
->setSummary(
|
||||||
pht('Override what language files (based on filename) highlight as.'))
|
pht('Override what language files (based on filename) highlight as.'))
|
||||||
@@ -138,12 +138,14 @@ final class PhabricatorSyntaxHighlightingConfigOptions
|
|||||||
'be tested against the filename. They should map to either an '.
|
'be tested against the filename. They should map to either an '.
|
||||||
'explicit language as a string value, or a numeric index into '.
|
'explicit language as a string value, or a numeric index into '.
|
||||||
'the captured groups as an integer.'))
|
'the captured groups as an integer.'))
|
||||||
->addExample('{"@\\.xyz$@": "php"}', pht('Highlight %s as PHP.', '*.xyz'))
|
|
||||||
->addExample(
|
->addExample(
|
||||||
'{"@/httpd\\.conf@": "apacheconf"}',
|
'{"@\\\.xyz$@": "php"}',
|
||||||
|
pht('Highlight %s as PHP.', '*.xyz'))
|
||||||
|
->addExample(
|
||||||
|
'{"@/httpd\\\.conf@": "apacheconf"}',
|
||||||
pht('Highlight httpd.conf as "apacheconf".'))
|
pht('Highlight httpd.conf as "apacheconf".'))
|
||||||
->addExample(
|
->addExample(
|
||||||
'{"@\\.([^.]+)\\.bak$@": 1}',
|
'{"@\\\.([^.]+)\\\.bak$@": 1}',
|
||||||
pht(
|
pht(
|
||||||
"Treat all '*.x.bak' file as '.x'. NOTE: We map to capturing group ".
|
"Treat all '*.x.bak' file as '.x'. NOTE: We map to capturing group ".
|
||||||
"1 by specifying the mapping as '1'")),
|
"1 by specifying the mapping as '1'")),
|
||||||
|
@@ -11,6 +11,13 @@ final class PhabricatorConfigDatabaseSchema
|
|||||||
public function addTable(PhabricatorConfigTableSchema $table) {
|
public function addTable(PhabricatorConfigTableSchema $table) {
|
||||||
$key = $table->getName();
|
$key = $table->getName();
|
||||||
if (isset($this->tables[$key])) {
|
if (isset($this->tables[$key])) {
|
||||||
|
|
||||||
|
if ($key == 'application_application') {
|
||||||
|
// NOTE: This is a terrible hack to allow Application subclasses to
|
||||||
|
// extend LiskDAO so we can apply transactions to them.
|
||||||
|
return $this;
|
||||||
|
}
|
||||||
|
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
pht('Trying to add duplicate table "%s"!', $key));
|
pht('Trying to add duplicate table "%s"!', $key));
|
||||||
}
|
}
|
||||||
|
@@ -60,7 +60,8 @@ final class ConpherenceTransactionRenderer extends Phobject {
|
|||||||
// between days. some setup required!
|
// between days. some setup required!
|
||||||
$previous_transaction = null;
|
$previous_transaction = null;
|
||||||
$date_marker_transaction = id(new ConpherenceTransaction())
|
$date_marker_transaction = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransaction::TYPE_DATE_MARKER)
|
->setTransactionType(
|
||||||
|
ConpherenceThreadDateMarkerTransaction::TRANSACTIONTYPE)
|
||||||
->makeEphemeral();
|
->makeEphemeral();
|
||||||
$date_marker_transaction_view = id(new ConpherenceTransactionView())
|
$date_marker_transaction_view = id(new ConpherenceTransactionView())
|
||||||
->setUser($user)
|
->setUser($user)
|
||||||
|
@@ -16,9 +16,6 @@ final class ConpherenceRoomTestCase extends ConpherenceTestCase {
|
|||||||
|
|
||||||
$this->assertTrue((bool)$conpherence->getID());
|
$this->assertTrue((bool)$conpherence->getID());
|
||||||
$this->assertEqual(1, count($conpherence->getParticipants()));
|
$this->assertEqual(1, count($conpherence->getParticipants()));
|
||||||
$this->assertEqual(
|
|
||||||
$participant_phids,
|
|
||||||
$conpherence->getRecentParticipantPHIDs());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testNUserRoomCreate() {
|
public function testNUserRoomCreate() {
|
||||||
@@ -38,9 +35,6 @@ final class ConpherenceRoomTestCase extends ConpherenceTestCase {
|
|||||||
|
|
||||||
$this->assertTrue((bool)$conpherence->getID());
|
$this->assertTrue((bool)$conpherence->getID());
|
||||||
$this->assertEqual(4, count($conpherence->getParticipants()));
|
$this->assertEqual(4, count($conpherence->getParticipants()));
|
||||||
$this->assertEqual(
|
|
||||||
$participant_phids,
|
|
||||||
$conpherence->getRecentParticipantPHIDs());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRoomParticipantAddition() {
|
public function testRoomParticipantAddition() {
|
||||||
@@ -58,16 +52,11 @@ final class ConpherenceRoomTestCase extends ConpherenceTestCase {
|
|||||||
|
|
||||||
$this->assertTrue((bool)$conpherence->getID());
|
$this->assertTrue((bool)$conpherence->getID());
|
||||||
$this->assertEqual(2, count($conpherence->getParticipants()));
|
$this->assertEqual(2, count($conpherence->getParticipants()));
|
||||||
$this->assertEqual(
|
|
||||||
$participant_phids,
|
|
||||||
$conpherence->getRecentParticipantPHIDs());
|
|
||||||
|
|
||||||
// test add by creator
|
// test add by creator
|
||||||
$participant_phids[] = $friend_2->getPHID();
|
$participant_phids[] = $friend_2->getPHID();
|
||||||
$this->addParticipants($creator, $conpherence, array($friend_2->getPHID()));
|
$this->addParticipants($creator, $conpherence, array($friend_2->getPHID()));
|
||||||
$this->assertEqual(
|
$this->assertEqual(3, count($conpherence->getParticipants()));
|
||||||
$participant_phids,
|
|
||||||
$conpherence->getRecentParticipantPHIDs());
|
|
||||||
|
|
||||||
// test add by other participant, so recent participation should
|
// test add by other participant, so recent participation should
|
||||||
// meaningfully change
|
// meaningfully change
|
||||||
@@ -81,9 +70,7 @@ final class ConpherenceRoomTestCase extends ConpherenceTestCase {
|
|||||||
$friend_2,
|
$friend_2,
|
||||||
$conpherence,
|
$conpherence,
|
||||||
array($friend_3->getPHID()));
|
array($friend_3->getPHID()));
|
||||||
$this->assertEqual(
|
$this->assertEqual(4, count($conpherence->getParticipants()));
|
||||||
$participant_phids,
|
|
||||||
$conpherence->getRecentParticipantPHIDs());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testRoomParticipantDeletion() {
|
public function testRoomParticipantDeletion() {
|
||||||
@@ -120,10 +107,12 @@ final class ConpherenceRoomTestCase extends ConpherenceTestCase {
|
|||||||
|
|
||||||
$xactions = array();
|
$xactions = array();
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransaction::TYPE_PARTICIPANTS)
|
->setTransactionType(
|
||||||
|
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue(array('+' => $participant_phids));
|
->setNewValue(array('+' => $participant_phids));
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransaction::TYPE_TITLE)
|
->setTransactionType(
|
||||||
|
ConpherenceThreadTitleTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue(pht('Test'));
|
->setNewValue(pht('Test'));
|
||||||
|
|
||||||
id(new ConpherenceEditor())
|
id(new ConpherenceEditor())
|
||||||
|
@@ -9,7 +9,8 @@ abstract class ConpherenceTestCase extends PhabricatorTestCase {
|
|||||||
|
|
||||||
$xactions = array(
|
$xactions = array(
|
||||||
id(new ConpherenceTransaction())
|
id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransaction::TYPE_PARTICIPANTS)
|
->setTransactionType(
|
||||||
|
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue(array('+' => $participant_phids)),
|
->setNewValue(array('+' => $participant_phids)),
|
||||||
);
|
);
|
||||||
$editor = id(new ConpherenceEditor())
|
$editor = id(new ConpherenceEditor())
|
||||||
@@ -26,7 +27,8 @@ abstract class ConpherenceTestCase extends PhabricatorTestCase {
|
|||||||
|
|
||||||
$xactions = array(
|
$xactions = array(
|
||||||
id(new ConpherenceTransaction())
|
id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransaction::TYPE_PARTICIPANTS)
|
->setTransactionType(
|
||||||
|
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue(array('-' => $participant_phids)),
|
->setNewValue(array('-' => $participant_phids)),
|
||||||
);
|
);
|
||||||
$editor = id(new ConpherenceEditor())
|
$editor = id(new ConpherenceEditor())
|
||||||
|
@@ -55,6 +55,8 @@ final class PhabricatorConpherenceApplication extends PhabricatorApplication {
|
|||||||
=> 'ConpherenceNotificationPanelController',
|
=> 'ConpherenceNotificationPanelController',
|
||||||
'participant/(?P<id>[1-9]\d*)/'
|
'participant/(?P<id>[1-9]\d*)/'
|
||||||
=> 'ConpherenceParticipantController',
|
=> 'ConpherenceParticipantController',
|
||||||
|
'preferences/(?P<id>[1-9]\d*)/'
|
||||||
|
=> 'ConpherenceRoomPreferencesController',
|
||||||
'update/(?P<id>[1-9]\d*)/'
|
'update/(?P<id>[1-9]\d*)/'
|
||||||
=> 'ConpherenceUpdateController',
|
=> 'ConpherenceUpdateController',
|
||||||
),
|
),
|
||||||
|
@@ -36,8 +36,7 @@ final class ConpherenceQueryThreadConduitAPIMethod
|
|||||||
$offset = $request->getValue('offset');
|
$offset = $request->getValue('offset');
|
||||||
|
|
||||||
$query = id(new ConpherenceThreadQuery())
|
$query = id(new ConpherenceThreadQuery())
|
||||||
->setViewer($user)
|
->setViewer($user);
|
||||||
->needParticipantCache(true);
|
|
||||||
|
|
||||||
if ($ids) {
|
if ($ids) {
|
||||||
$conpherences = $query
|
$conpherences = $query
|
||||||
@@ -57,7 +56,7 @@ final class ConpherenceQueryThreadConduitAPIMethod
|
|||||||
->setLimit($limit)
|
->setLimit($limit)
|
||||||
->setOffset($offset)
|
->setOffset($offset)
|
||||||
->execute();
|
->execute();
|
||||||
$conpherence_phids = array_keys($participation);
|
$conpherence_phids = mpull($participation, 'getConpherencePHID');
|
||||||
$query->withPHIDs($conpherence_phids);
|
$query->withPHIDs($conpherence_phids);
|
||||||
$conpherences = $query->execute();
|
$conpherences = $query->execute();
|
||||||
$conpherences = array_select_keys($conpherences, $conpherence_phids);
|
$conpherences = array_select_keys($conpherences, $conpherence_phids);
|
||||||
@@ -71,7 +70,6 @@ final class ConpherenceQueryThreadConduitAPIMethod
|
|||||||
'conpherencePHID' => $conpherence->getPHID(),
|
'conpherencePHID' => $conpherence->getPHID(),
|
||||||
'conpherenceTitle' => $conpherence->getTitle(),
|
'conpherenceTitle' => $conpherence->getTitle(),
|
||||||
'messageCount' => $conpherence->getMessageCount(),
|
'messageCount' => $conpherence->getMessageCount(),
|
||||||
'recentParticipantPHIDs' => $conpherence->getRecentParticipantPHIDs(),
|
|
||||||
'conpherenceURI' => $this->getConpherenceURI($conpherence),
|
'conpherenceURI' => $this->getConpherenceURI($conpherence),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -69,7 +69,7 @@ final class ConpherenceUpdateThreadConduitAPIMethod
|
|||||||
if ($add_participant_phids) {
|
if ($add_participant_phids) {
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(
|
->setTransactionType(
|
||||||
ConpherenceTransaction::TYPE_PARTICIPANTS)
|
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue(array('+' => $add_participant_phids));
|
->setNewValue(array('+' => $add_participant_phids));
|
||||||
}
|
}
|
||||||
if ($remove_participant_phid) {
|
if ($remove_participant_phid) {
|
||||||
@@ -78,12 +78,13 @@ final class ConpherenceUpdateThreadConduitAPIMethod
|
|||||||
}
|
}
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(
|
->setTransactionType(
|
||||||
ConpherenceTransaction::TYPE_PARTICIPANTS)
|
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue(array('-' => array($remove_participant_phid)));
|
->setNewValue(array('-' => array($remove_participant_phid)));
|
||||||
}
|
}
|
||||||
if ($title) {
|
if ($title) {
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransaction::TYPE_TITLE)
|
->setTransactionType(
|
||||||
|
ConpherenceThreadTitleTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue($title);
|
->setNewValue($title);
|
||||||
}
|
}
|
||||||
if ($message) {
|
if ($message) {
|
||||||
|
@@ -1,8 +0,0 @@
|
|||||||
<?php
|
|
||||||
|
|
||||||
final class ConpherenceParticipationStatus extends ConpherenceConstants {
|
|
||||||
|
|
||||||
const UP_TO_DATE = 0;
|
|
||||||
const BEHIND = 1;
|
|
||||||
|
|
||||||
}
|
|
@@ -0,0 +1,69 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class ConpherenceRoomSettings extends ConpherenceConstants {
|
||||||
|
|
||||||
|
const SOUND_RECEIVE = 'receive';
|
||||||
|
const SOUND_MENTION = 'mention';
|
||||||
|
|
||||||
|
const DEFAULT_RECEIVE_SOUND = 'tap';
|
||||||
|
const DEFAULT_MENTION_SOUND = 'alert';
|
||||||
|
const DEFAULT_NO_SOUND = 'none';
|
||||||
|
|
||||||
|
const COLOR_LIGHT = 'light';
|
||||||
|
const COLOR_BLUE = 'blue';
|
||||||
|
const COLOR_INDIGO = 'indigo';
|
||||||
|
const COLOR_PEACH = 'peach';
|
||||||
|
const COLOR_GREEN = 'green';
|
||||||
|
const COLOR_PINK = 'pink';
|
||||||
|
|
||||||
|
public static function getSoundMap() {
|
||||||
|
return array(
|
||||||
|
'none' => array(
|
||||||
|
'name' => pht('No Sound'),
|
||||||
|
'rsrc' => '',
|
||||||
|
),
|
||||||
|
'alert' => array(
|
||||||
|
'name' => pht('Alert'),
|
||||||
|
'rsrc' => celerity_get_resource_uri('/rsrc/audio/basic/alert.mp3'),
|
||||||
|
),
|
||||||
|
'bing' => array(
|
||||||
|
'name' => pht('Bing'),
|
||||||
|
'rsrc' => celerity_get_resource_uri('/rsrc/audio/basic/bing.mp3'),
|
||||||
|
),
|
||||||
|
'pock' => array(
|
||||||
|
'name' => pht('Pock'),
|
||||||
|
'rsrc' => celerity_get_resource_uri('/rsrc/audio/basic/pock.mp3'),
|
||||||
|
),
|
||||||
|
'tap' => array(
|
||||||
|
'name' => pht('Tap'),
|
||||||
|
'rsrc' => celerity_get_resource_uri('/rsrc/audio/basic/tap.mp3'),
|
||||||
|
),
|
||||||
|
'ting' => array(
|
||||||
|
'name' => pht('Ting'),
|
||||||
|
'rsrc' => celerity_get_resource_uri('/rsrc/audio/basic/ting.mp3'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getDropdownSoundMap() {
|
||||||
|
$map = self::getSoundMap();
|
||||||
|
return ipull($map, 'name');
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getThemeMap() {
|
||||||
|
return array(
|
||||||
|
self::COLOR_LIGHT => pht('Light'),
|
||||||
|
self::COLOR_BLUE => pht('Blue'),
|
||||||
|
self::COLOR_INDIGO => pht('Indigo'),
|
||||||
|
self::COLOR_PEACH => pht('Peach'),
|
||||||
|
self::COLOR_GREEN => pht('Green'),
|
||||||
|
self::COLOR_PINK => pht('Pink'),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function getThemeClass($theme) {
|
||||||
|
return 'conpherence-theme-'.$theme;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
@@ -8,7 +8,6 @@ final class ConpherenceUpdateActions extends ConpherenceConstants {
|
|||||||
const JOIN_ROOM = 'join_room';
|
const JOIN_ROOM = 'join_room';
|
||||||
const ADD_PERSON = 'add_person';
|
const ADD_PERSON = 'add_person';
|
||||||
const REMOVE_PERSON = 'remove_person';
|
const REMOVE_PERSON = 'remove_person';
|
||||||
const NOTIFICATIONS = 'notifications';
|
|
||||||
const ADD_STATUS = 'add_status';
|
const ADD_STATUS = 'add_status';
|
||||||
const LOAD = 'load';
|
const LOAD = 'load';
|
||||||
}
|
}
|
||||||
|
@@ -17,7 +17,6 @@ final class ConpherenceColumnViewController extends
|
|||||||
->setViewer($user)
|
->setViewer($user)
|
||||||
->withPHIDs($conpherence_phids)
|
->withPHIDs($conpherence_phids)
|
||||||
->needProfileImage(true)
|
->needProfileImage(true)
|
||||||
->needParticipantCache(true)
|
|
||||||
->execute();
|
->execute();
|
||||||
$latest_conpherences = mpull($latest_conpherences, null, 'getPHID');
|
$latest_conpherences = mpull($latest_conpherences, null, 'getPHID');
|
||||||
$latest_conpherences = array_select_keys(
|
$latest_conpherences = array_select_keys(
|
||||||
@@ -68,7 +67,7 @@ final class ConpherenceColumnViewController extends
|
|||||||
$transactions = $conpherence->getTransactions();
|
$transactions = $conpherence->getTransactions();
|
||||||
$latest_transaction = head($transactions);
|
$latest_transaction = head($transactions);
|
||||||
$write_guard = AphrontWriteGuard::beginScopedUnguardedWrites();
|
$write_guard = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||||
$participant->markUpToDate($conpherence, $latest_transaction);
|
$participant->markUpToDate($conpherence);
|
||||||
unset($write_guard);
|
unset($write_guard);
|
||||||
|
|
||||||
$draft = PhabricatorDraft::newFromUserAndKey(
|
$draft = PhabricatorDraft::newFromUserAndKey(
|
||||||
|
@@ -54,19 +54,29 @@ abstract class ConpherenceController extends PhabricatorController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected function buildHeaderPaneContent(
|
protected function buildHeaderPaneContent(
|
||||||
ConpherenceThread $conpherence,
|
ConpherenceThread $conpherence) {
|
||||||
array $policy_objects) {
|
|
||||||
assert_instances_of($policy_objects, 'PhabricatorPolicy');
|
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
$header = null;
|
$header = null;
|
||||||
|
$id = $conpherence->getID();
|
||||||
|
|
||||||
if ($conpherence->getID()) {
|
if ($id) {
|
||||||
$data = $conpherence->getDisplayData($this->getViewer());
|
$data = $conpherence->getDisplayData($this->getViewer());
|
||||||
|
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
|
->setViewer($viewer)
|
||||||
->setHeader($data['title'])
|
->setHeader($data['title'])
|
||||||
->setSubheader($data['topic'])
|
->setPolicyObject($conpherence)
|
||||||
->setImage($data['image']);
|
->setImage($data['image']);
|
||||||
|
|
||||||
|
if (strlen($data['topic'])) {
|
||||||
|
$topic = id(new PHUITagView())
|
||||||
|
->setName($data['topic'])
|
||||||
|
->setShade(PHUITagView::COLOR_VIOLET)
|
||||||
|
->setType(PHUITagView::TYPE_SHADE)
|
||||||
|
->addClass('conpherence-header-topic');
|
||||||
|
$header->addTag($topic);
|
||||||
|
}
|
||||||
|
|
||||||
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
$can_edit = PhabricatorPolicyFilter::hasCapability(
|
||||||
$viewer,
|
$viewer,
|
||||||
$conpherence,
|
$conpherence,
|
||||||
@@ -74,19 +84,14 @@ abstract class ConpherenceController extends PhabricatorController {
|
|||||||
|
|
||||||
if ($can_edit) {
|
if ($can_edit) {
|
||||||
$header->setImageURL(
|
$header->setImageURL(
|
||||||
$this->getApplicationURI('picture/'.$conpherence->getID().'/'));
|
$this->getApplicationURI("picture/{$id}/"));
|
||||||
}
|
}
|
||||||
|
|
||||||
$participating = $conpherence->getParticipantIfExists($viewer->getPHID());
|
$participating = $conpherence->getParticipantIfExists($viewer->getPHID());
|
||||||
$can_join = PhabricatorPolicyFilter::hasCapability(
|
|
||||||
$viewer,
|
|
||||||
$conpherence,
|
|
||||||
PhabricatorPolicyCapability::CAN_JOIN);
|
|
||||||
|
|
||||||
$header->addActionItem(
|
$header->addActionItem(
|
||||||
id(new PHUIIconCircleView())
|
id(new PHUIIconCircleView())
|
||||||
->setHref(
|
->setHref($this->getApplicationURI("update/{$id}/"))
|
||||||
$this->getApplicationURI('update/'.$conpherence->getID()).'/')
|
|
||||||
->setIcon('fa-pencil')
|
->setIcon('fa-pencil')
|
||||||
->addClass('hide-on-device')
|
->addClass('hide-on-device')
|
||||||
->setColor('violet')
|
->setColor('violet')
|
||||||
@@ -94,9 +99,7 @@ abstract class ConpherenceController extends PhabricatorController {
|
|||||||
|
|
||||||
$header->addActionItem(
|
$header->addActionItem(
|
||||||
id(new PHUIIconCircleView())
|
id(new PHUIIconCircleView())
|
||||||
->setHref(
|
->setHref($this->getApplicationURI("preferences/{$id}/"))
|
||||||
$this->getApplicationURI('update/'.$conpherence->getID()).'/'.
|
|
||||||
'?action='.ConpherenceUpdateActions::NOTIFICATIONS)
|
|
||||||
->setIcon('fa-gear')
|
->setIcon('fa-gear')
|
||||||
->addClass('hide-on-device')
|
->addClass('hide-on-device')
|
||||||
->setColor('pink')
|
->setColor('pink')
|
||||||
@@ -129,9 +132,9 @@ abstract class ConpherenceController extends PhabricatorController {
|
|||||||
->setColor('green')
|
->setColor('green')
|
||||||
->addClass('conpherence-search-toggle'));
|
->addClass('conpherence-search-toggle'));
|
||||||
|
|
||||||
if ($can_join && !$participating) {
|
if (!$participating) {
|
||||||
$action = ConpherenceUpdateActions::JOIN_ROOM;
|
$action = ConpherenceUpdateActions::JOIN_ROOM;
|
||||||
$uri = $this->getApplicationURI('update/'.$conpherence->getID().'/');
|
$uri = $this->getApplicationURI("update/{$id}/");
|
||||||
$button = phutil_tag(
|
$button = phutil_tag(
|
||||||
'button',
|
'button',
|
||||||
array(
|
array(
|
||||||
|
@@ -34,7 +34,7 @@ final class ConpherenceListController extends ConpherenceController {
|
|||||||
$title = pht('Conpherence');
|
$title = pht('Conpherence');
|
||||||
$conpherence = null;
|
$conpherence = null;
|
||||||
|
|
||||||
$limit = (ConpherenceThreadListView::SEE_MORE_LIMIT * 2) + 1;
|
$limit = ConpherenceThreadListView::SEE_ALL_LIMIT + 1;
|
||||||
$all_participation = array();
|
$all_participation = array();
|
||||||
|
|
||||||
$mode = $this->determineMode();
|
$mode = $this->determineMode();
|
||||||
@@ -64,7 +64,7 @@ final class ConpherenceListController extends ConpherenceController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check to see if the loaded conpherence is going to show up
|
// check to see if the loaded conpherence is going to show up
|
||||||
// within the SEE_MORE_LIMIT amount of conpherences.
|
// within the SEE_ALL_LIMIT amount of conpherences.
|
||||||
// If its not there, then we just pre-pend it as the "first"
|
// If its not there, then we just pre-pend it as the "first"
|
||||||
// conpherence so folks have a navigation item in the menu.
|
// conpherence so folks have a navigation item in the menu.
|
||||||
$count = 0;
|
$count = 0;
|
||||||
@@ -75,7 +75,7 @@ final class ConpherenceListController extends ConpherenceController {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
$count++;
|
$count++;
|
||||||
if ($count > ConpherenceThreadListView::SEE_MORE_LIMIT) {
|
if ($count > ConpherenceThreadListView::SEE_ALL_LIMIT) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,11 +89,19 @@ final class ConpherenceListController extends ConpherenceController {
|
|||||||
default:
|
default:
|
||||||
$data = $this->loadDefaultParticipation($limit);
|
$data = $this->loadDefaultParticipation($limit);
|
||||||
$all_participation = $data['all_participation'];
|
$all_participation = $data['all_participation'];
|
||||||
|
if ($all_participation) {
|
||||||
|
$conpherence_id = head($all_participation)->getConpherencePHID();
|
||||||
|
$conpherence = id(new ConpherenceThreadQuery())
|
||||||
|
->setViewer($user)
|
||||||
|
->withPHIDs(array($conpherence_id))
|
||||||
|
->needProfileImage(true)
|
||||||
|
->executeOne();
|
||||||
|
}
|
||||||
|
// If $conpherence is null, NUX state will render
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
$threads = $this->loadConpherenceThreadData(
|
$threads = $this->loadConpherenceThreadData($all_participation);
|
||||||
$all_participation);
|
|
||||||
|
|
||||||
$thread_view = id(new ConpherenceThreadListView())
|
$thread_view = id(new ConpherenceThreadListView())
|
||||||
->setUser($user)
|
->setUser($user)
|
||||||
@@ -144,6 +152,7 @@ final class ConpherenceListController extends ConpherenceController {
|
|||||||
->withParticipantPHIDs(array($viewer->getPHID()))
|
->withParticipantPHIDs(array($viewer->getPHID()))
|
||||||
->setLimit($limit)
|
->setLimit($limit)
|
||||||
->execute();
|
->execute();
|
||||||
|
$all_participation = mpull($all_participation, null, 'getConpherencePHID');
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
'all_participation' => $all_participation,
|
'all_participation' => $all_participation,
|
||||||
@@ -159,7 +168,6 @@ final class ConpherenceListController extends ConpherenceController {
|
|||||||
->setViewer($user)
|
->setViewer($user)
|
||||||
->withPHIDs($conpherence_phids)
|
->withPHIDs($conpherence_phids)
|
||||||
->needProfileImage(true)
|
->needProfileImage(true)
|
||||||
->needParticipantCache(true)
|
|
||||||
->execute();
|
->execute();
|
||||||
|
|
||||||
// this will re-sort by participation data
|
// this will re-sort by participation data
|
||||||
|
@@ -7,7 +7,6 @@ final class ConpherenceNewRoomController extends ConpherenceController {
|
|||||||
|
|
||||||
$title = pht('New Room');
|
$title = pht('New Room');
|
||||||
$e_title = true;
|
$e_title = true;
|
||||||
$v_message = null;
|
|
||||||
$validation_exception = null;
|
$validation_exception = null;
|
||||||
|
|
||||||
$conpherence = ConpherenceThread::initializeNewRoom($user);
|
$conpherence = ConpherenceThread::initializeNewRoom($user);
|
||||||
@@ -17,17 +16,18 @@ final class ConpherenceNewRoomController extends ConpherenceController {
|
|||||||
$xactions = array();
|
$xactions = array();
|
||||||
|
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransaction::TYPE_TITLE)
|
->setTransactionType(ConpherenceThreadTitleTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue($request->getStr('title'));
|
->setNewValue($request->getStr('title'));
|
||||||
|
|
||||||
$participants = $request->getArr('participants');
|
$participants = $request->getArr('participants');
|
||||||
$participants[] = $user->getPHID();
|
$participants[] = $user->getPHID();
|
||||||
$participants = array_unique($participants);
|
$participants = array_unique($participants);
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransaction::TYPE_PARTICIPANTS)
|
->setTransactionType(
|
||||||
|
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue(array('+' => $participants));
|
->setNewValue(array('+' => $participants));
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransaction::TYPE_TOPIC)
|
->setTransactionType(ConpherenceThreadTopicTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue($request->getStr('topic'));
|
->setNewValue($request->getStr('topic'));
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
|
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
|
||||||
@@ -35,18 +35,6 @@ final class ConpherenceNewRoomController extends ConpherenceController {
|
|||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
|
->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
|
||||||
->setNewValue($request->getStr('editPolicy'));
|
->setNewValue($request->getStr('editPolicy'));
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
|
||||||
->setTransactionType(PhabricatorTransactions::TYPE_JOIN_POLICY)
|
|
||||||
->setNewValue($request->getStr('joinPolicy'));
|
|
||||||
|
|
||||||
$v_message = $request->getStr('message');
|
|
||||||
if (strlen($v_message)) {
|
|
||||||
$message_xactions = $editor->generateTransactionsFromText(
|
|
||||||
$user,
|
|
||||||
$conpherence,
|
|
||||||
$v_message);
|
|
||||||
$xactions = array_merge($xactions, $message_xactions);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$editor
|
$editor
|
||||||
@@ -60,11 +48,11 @@ final class ConpherenceNewRoomController extends ConpherenceController {
|
|||||||
} catch (PhabricatorApplicationTransactionValidationException $ex) {
|
} catch (PhabricatorApplicationTransactionValidationException $ex) {
|
||||||
$validation_exception = $ex;
|
$validation_exception = $ex;
|
||||||
|
|
||||||
$e_title = $ex->getShortMessage(ConpherenceTransaction::TYPE_TITLE);
|
$e_title = $ex->getShortMessage(
|
||||||
|
ConpherenceThreadTitleTransaction::TRANSACTIONTYPE);
|
||||||
|
|
||||||
$conpherence->setViewPolicy($request->getStr('viewPolicy'));
|
$conpherence->setViewPolicy($request->getStr('viewPolicy'));
|
||||||
$conpherence->setEditPolicy($request->getStr('editPolicy'));
|
$conpherence->setEditPolicy($request->getStr('editPolicy'));
|
||||||
$conpherence->setJoinPolicy($request->getStr('joinPolicy'));
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($request->getStr('participant')) {
|
if ($request->getStr('participant')) {
|
||||||
@@ -119,19 +107,7 @@ final class ConpherenceNewRoomController extends ConpherenceController {
|
|||||||
->setName('editPolicy')
|
->setName('editPolicy')
|
||||||
->setPolicyObject($conpherence)
|
->setPolicyObject($conpherence)
|
||||||
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
|
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
|
||||||
->setPolicies($policies))
|
->setPolicies($policies));
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormPolicyControl())
|
|
||||||
->setName('joinPolicy')
|
|
||||||
->setPolicyObject($conpherence)
|
|
||||||
->setCapability(PhabricatorPolicyCapability::CAN_JOIN)
|
|
||||||
->setPolicies($policies))
|
|
||||||
->appendChild(
|
|
||||||
id(new PhabricatorRemarkupControl())
|
|
||||||
->setUser($user)
|
|
||||||
->setName('message')
|
|
||||||
->setLabel(pht('First Message'))
|
|
||||||
->setValue($v_message));
|
|
||||||
|
|
||||||
$dialog->appendChild($form);
|
$dialog->appendChild($form);
|
||||||
|
|
||||||
|
@@ -7,12 +7,12 @@ final class ConpherenceNotificationPanelController
|
|||||||
$user = $request->getUser();
|
$user = $request->getUser();
|
||||||
$conpherences = array();
|
$conpherences = array();
|
||||||
require_celerity_resource('conpherence-notification-css');
|
require_celerity_resource('conpherence-notification-css');
|
||||||
$unread_status = ConpherenceParticipationStatus::BEHIND;
|
|
||||||
|
|
||||||
$participant_data = id(new ConpherenceParticipantQuery())
|
$participant_data = id(new ConpherenceParticipantQuery())
|
||||||
->withParticipantPHIDs(array($user->getPHID()))
|
->withParticipantPHIDs(array($user->getPHID()))
|
||||||
->setLimit(5)
|
->setLimit(5)
|
||||||
->execute();
|
->execute();
|
||||||
|
$participant_data = mpull($participant_data, null, 'getConpherencePHID');
|
||||||
|
|
||||||
if ($participant_data) {
|
if ($participant_data) {
|
||||||
$conpherences = id(new ConpherenceThreadQuery())
|
$conpherences = id(new ConpherenceThreadQuery())
|
||||||
@@ -20,8 +20,7 @@ final class ConpherenceNotificationPanelController
|
|||||||
->withPHIDs(array_keys($participant_data))
|
->withPHIDs(array_keys($participant_data))
|
||||||
->needProfileImage(true)
|
->needProfileImage(true)
|
||||||
->needTransactions(true)
|
->needTransactions(true)
|
||||||
->setTransactionLimit(50)
|
->setTransactionLimit(100)
|
||||||
->needParticipantCache(true)
|
|
||||||
->execute();
|
->execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,7 +37,7 @@ final class ConpherenceNotificationPanelController
|
|||||||
'conpherence-notification',
|
'conpherence-notification',
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($p_data->getParticipationStatus() == $unread_status) {
|
if (!$p_data->isUpToDate($conpherence)) {
|
||||||
$classes[] = 'phabricator-notification-unread';
|
$classes[] = 'phabricator-notification-unread';
|
||||||
}
|
}
|
||||||
$uri = $this->getApplicationURI($conpherence->getID().'/');
|
$uri = $this->getApplicationURI($conpherence->getID().'/');
|
||||||
@@ -96,7 +95,7 @@ final class ConpherenceNotificationPanelController
|
|||||||
|
|
||||||
$unread = id(new ConpherenceParticipantCountQuery())
|
$unread = id(new ConpherenceParticipantCountQuery())
|
||||||
->withParticipantPHIDs(array($user->getPHID()))
|
->withParticipantPHIDs(array($user->getPHID()))
|
||||||
->withParticipationStatus($unread_status)
|
->withUnread(true)
|
||||||
->execute();
|
->execute();
|
||||||
$unread_count = idx($unread, $user->getPHID(), 0);
|
$unread_count = idx($unread, $user->getPHID(), 0);
|
||||||
|
|
||||||
|
@@ -76,7 +76,8 @@ final class ConpherenceRoomPictureController
|
|||||||
|
|
||||||
$xactions = array();
|
$xactions = array();
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransaction::TYPE_PICTURE)
|
->setTransactionType(
|
||||||
|
ConpherenceThreadPictureTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue($new_value);
|
->setNewValue($new_value);
|
||||||
|
|
||||||
$editor = id(new ConpherenceEditor())
|
$editor = id(new ConpherenceEditor())
|
||||||
|
@@ -0,0 +1,113 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
final class ConpherenceRoomPreferencesController
|
||||||
|
extends ConpherenceController {
|
||||||
|
|
||||||
|
public function shouldAllowPublic() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function handleRequest(AphrontRequest $request) {
|
||||||
|
$viewer = $request->getViewer();
|
||||||
|
$conpherence_id = $request->getURIData('id');
|
||||||
|
|
||||||
|
$conpherence = id(new ConpherenceThreadQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($conpherence_id))
|
||||||
|
->executeOne();
|
||||||
|
if (!$conpherence) {
|
||||||
|
return new Aphront404Response();
|
||||||
|
}
|
||||||
|
|
||||||
|
$view_uri = $conpherence->getURI();
|
||||||
|
|
||||||
|
$participant = $conpherence->getParticipantIfExists($viewer->getPHID());
|
||||||
|
if (!$participant) {
|
||||||
|
if ($viewer->isLoggedIn()) {
|
||||||
|
$text = pht(
|
||||||
|
'Notification settings are available after joining the room.');
|
||||||
|
} else {
|
||||||
|
$text = pht(
|
||||||
|
'Notification settings are available after logging in and joining '.
|
||||||
|
'the room.');
|
||||||
|
}
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Room Preferences'))
|
||||||
|
->addCancelButton($view_uri)
|
||||||
|
->appendParagraph($text);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Save the data and redirect
|
||||||
|
if ($request->isFormPost()) {
|
||||||
|
$notifications = $request->getStr('notifications');
|
||||||
|
$sounds = $request->getArr('sounds');
|
||||||
|
$theme = $request->getStr('theme');
|
||||||
|
|
||||||
|
$participant->setSettings(array(
|
||||||
|
'notifications' => $notifications,
|
||||||
|
'sounds' => $sounds,
|
||||||
|
'theme' => $theme,
|
||||||
|
));
|
||||||
|
$participant->save();
|
||||||
|
|
||||||
|
return id(new AphrontRedirectResponse())
|
||||||
|
->setURI($view_uri);
|
||||||
|
}
|
||||||
|
|
||||||
|
$notification_key = PhabricatorConpherenceNotificationsSetting::SETTINGKEY;
|
||||||
|
$notification_default = $viewer->getUserSetting($notification_key);
|
||||||
|
|
||||||
|
$sound_key = PhabricatorConpherenceSoundSetting::SETTINGKEY;
|
||||||
|
$sound_default = $viewer->getUserSetting($sound_key);
|
||||||
|
|
||||||
|
$settings = $participant->getSettings();
|
||||||
|
$notifications = idx($settings, 'notifications', $notification_default);
|
||||||
|
$theme = idx($settings, 'theme', ConpherenceRoomSettings::COLOR_LIGHT);
|
||||||
|
|
||||||
|
$sounds = idx($settings, 'sounds', array());
|
||||||
|
$map = PhabricatorConpherenceSoundSetting::getDefaultSound($sound_default);
|
||||||
|
$receive = idx($sounds,
|
||||||
|
ConpherenceRoomSettings::SOUND_RECEIVE,
|
||||||
|
$map[ConpherenceRoomSettings::SOUND_RECEIVE]);
|
||||||
|
$mention = idx($sounds,
|
||||||
|
ConpherenceRoomSettings::SOUND_MENTION,
|
||||||
|
$map[ConpherenceRoomSettings::SOUND_MENTION]);
|
||||||
|
|
||||||
|
$form = id(new AphrontFormView())
|
||||||
|
->setUser($viewer)
|
||||||
|
->appendControl(
|
||||||
|
id(new AphrontFormRadioButtonControl())
|
||||||
|
->setLabel(pht('Notify'))
|
||||||
|
->addButton(
|
||||||
|
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL,
|
||||||
|
PhabricatorConpherenceNotificationsSetting::getSettingLabel(
|
||||||
|
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL),
|
||||||
|
'')
|
||||||
|
->addButton(
|
||||||
|
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_NOTIFY,
|
||||||
|
PhabricatorConpherenceNotificationsSetting::getSettingLabel(
|
||||||
|
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_NOTIFY),
|
||||||
|
'')
|
||||||
|
->setName('notifications')
|
||||||
|
->setValue($notifications))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormSelectControl())
|
||||||
|
->setLabel(pht('New Message'))
|
||||||
|
->setName('sounds['.ConpherenceRoomSettings::SOUND_RECEIVE.']')
|
||||||
|
->setOptions(ConpherenceRoomSettings::getDropdownSoundMap())
|
||||||
|
->setValue($receive))
|
||||||
|
->appendChild(
|
||||||
|
id(new AphrontFormSelectControl())
|
||||||
|
->setLabel(pht('Theme'))
|
||||||
|
->setName('theme')
|
||||||
|
->setOptions(ConpherenceRoomSettings::getThemeMap())
|
||||||
|
->setValue($theme));
|
||||||
|
|
||||||
|
return $this->newDialog()
|
||||||
|
->setTitle(pht('Room Preferences'))
|
||||||
|
->appendForm($form)
|
||||||
|
->addCancelButton($view_uri)
|
||||||
|
->addSubmitButton(pht('Save'));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@@ -24,12 +24,6 @@ final class ConpherenceUpdateController
|
|||||||
case ConpherenceUpdateActions::METADATA:
|
case ConpherenceUpdateActions::METADATA:
|
||||||
$needed_capabilities[] = PhabricatorPolicyCapability::CAN_EDIT;
|
$needed_capabilities[] = PhabricatorPolicyCapability::CAN_EDIT;
|
||||||
break;
|
break;
|
||||||
case ConpherenceUpdateActions::JOIN_ROOM:
|
|
||||||
$needed_capabilities[] = PhabricatorPolicyCapability::CAN_JOIN;
|
|
||||||
break;
|
|
||||||
case ConpherenceUpdateActions::NOTIFICATIONS:
|
|
||||||
$need_participants = true;
|
|
||||||
break;
|
|
||||||
case ConpherenceUpdateActions::LOAD:
|
case ConpherenceUpdateActions::LOAD:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -64,7 +58,7 @@ final class ConpherenceUpdateController
|
|||||||
case ConpherenceUpdateActions::JOIN_ROOM:
|
case ConpherenceUpdateActions::JOIN_ROOM:
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(
|
->setTransactionType(
|
||||||
ConpherenceTransaction::TYPE_PARTICIPANTS)
|
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue(array('+' => array($user->getPHID())));
|
->setNewValue(array('+' => array($user->getPHID())));
|
||||||
$delete_draft = true;
|
$delete_draft = true;
|
||||||
$message = $request->getStr('text');
|
$message = $request->getStr('text');
|
||||||
@@ -98,7 +92,7 @@ final class ConpherenceUpdateController
|
|||||||
if (!empty($person_phids)) {
|
if (!empty($person_phids)) {
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(
|
->setTransactionType(
|
||||||
ConpherenceTransaction::TYPE_PARTICIPANTS)
|
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue(array('+' => $person_phids));
|
->setNewValue(array('+' => $person_phids));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -111,22 +105,10 @@ final class ConpherenceUpdateController
|
|||||||
if ($person_phid) {
|
if ($person_phid) {
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(
|
->setTransactionType(
|
||||||
ConpherenceTransaction::TYPE_PARTICIPANTS)
|
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue(array('-' => array($person_phid)));
|
->setNewValue(array('-' => array($person_phid)));
|
||||||
$response_mode = 'go-home';
|
$response_mode = 'go-home';
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
case ConpherenceUpdateActions::NOTIFICATIONS:
|
|
||||||
$notifications = $request->getStr('notifications');
|
|
||||||
$participant = $conpherence->getParticipantIfExists($user->getPHID());
|
|
||||||
if (!$participant) {
|
|
||||||
return id(new Aphront404Response());
|
|
||||||
}
|
|
||||||
$participant->setSettings(array('notifications' => $notifications));
|
|
||||||
$participant->save();
|
|
||||||
return id(new AphrontRedirectResponse())
|
|
||||||
->setURI('/'.$conpherence->getMonogram());
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case ConpherenceUpdateActions::METADATA:
|
case ConpherenceUpdateActions::METADATA:
|
||||||
$title = $request->getStr('title');
|
$title = $request->getStr('title');
|
||||||
@@ -140,10 +122,12 @@ final class ConpherenceUpdateController
|
|||||||
$title = $request->getStr('title');
|
$title = $request->getStr('title');
|
||||||
$topic = $request->getStr('topic');
|
$topic = $request->getStr('topic');
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransaction::TYPE_TITLE)
|
->setTransactionType(
|
||||||
|
ConpherenceThreadTitleTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue($title);
|
->setNewValue($title);
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransaction::TYPE_TOPIC)
|
->setTransactionType(
|
||||||
|
ConpherenceThreadTopicTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue($topic);
|
->setNewValue($topic);
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
|
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
|
||||||
@@ -151,9 +135,6 @@ final class ConpherenceUpdateController
|
|||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
|
->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
|
||||||
->setNewValue($request->getStr('editPolicy'));
|
->setNewValue($request->getStr('editPolicy'));
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
|
||||||
->setTransactionType(PhabricatorTransactions::TYPE_JOIN_POLICY)
|
|
||||||
->setNewValue($request->getStr('joinPolicy'));
|
|
||||||
if (!$request->getExists('force_ajax')) {
|
if (!$request->getExists('force_ajax')) {
|
||||||
$response_mode = 'redirect';
|
$response_mode = 'redirect';
|
||||||
}
|
}
|
||||||
@@ -221,9 +202,6 @@ final class ConpherenceUpdateController
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch ($action) {
|
switch ($action) {
|
||||||
case ConpherenceUpdateActions::NOTIFICATIONS:
|
|
||||||
$dialog = $this->renderPreferencesDialog($conpherence);
|
|
||||||
break;
|
|
||||||
case ConpherenceUpdateActions::ADD_PERSON:
|
case ConpherenceUpdateActions::ADD_PERSON:
|
||||||
$dialog = $this->renderAddPersonDialog($conpherence);
|
$dialog = $this->renderAddPersonDialog($conpherence);
|
||||||
break;
|
break;
|
||||||
@@ -246,71 +224,6 @@ final class ConpherenceUpdateController
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private function renderPreferencesDialog(
|
|
||||||
ConpherenceThread $conpherence) {
|
|
||||||
|
|
||||||
$request = $this->getRequest();
|
|
||||||
$user = $request->getUser();
|
|
||||||
|
|
||||||
$participant = $conpherence->getParticipantIfExists($user->getPHID());
|
|
||||||
if (!$participant) {
|
|
||||||
$can_join = PhabricatorPolicyFilter::hasCapability(
|
|
||||||
$user,
|
|
||||||
$conpherence,
|
|
||||||
PhabricatorPolicyCapability::CAN_JOIN);
|
|
||||||
if ($can_join) {
|
|
||||||
$text = pht(
|
|
||||||
'Notification settings are available after joining the room.');
|
|
||||||
} else if ($user->isLoggedIn()) {
|
|
||||||
$text = pht(
|
|
||||||
'Notification settings not applicable to rooms you can not join.');
|
|
||||||
} else {
|
|
||||||
$text = pht(
|
|
||||||
'Notification settings are available after logging in and joining '.
|
|
||||||
'the room.');
|
|
||||||
}
|
|
||||||
return id(new AphrontDialogView())
|
|
||||||
->setTitle(pht('Room Preferences'))
|
|
||||||
->appendParagraph($text);
|
|
||||||
}
|
|
||||||
|
|
||||||
$notification_key = PhabricatorConpherenceNotificationsSetting::SETTINGKEY;
|
|
||||||
$notification_default = $user->getUserSetting($notification_key);
|
|
||||||
|
|
||||||
$settings = $participant->getSettings();
|
|
||||||
$notifications = idx(
|
|
||||||
$settings,
|
|
||||||
'notifications',
|
|
||||||
$notification_default);
|
|
||||||
|
|
||||||
$form = id(new AphrontFormView())
|
|
||||||
->setUser($user)
|
|
||||||
->setFullWidth(true)
|
|
||||||
->appendControl(
|
|
||||||
id(new AphrontFormRadioButtonControl())
|
|
||||||
->addButton(
|
|
||||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL,
|
|
||||||
PhabricatorConpherenceNotificationsSetting::getSettingLabel(
|
|
||||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_EMAIL),
|
|
||||||
'')
|
|
||||||
->addButton(
|
|
||||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_NOTIFY,
|
|
||||||
PhabricatorConpherenceNotificationsSetting::getSettingLabel(
|
|
||||||
PhabricatorConpherenceNotificationsSetting::VALUE_CONPHERENCE_NOTIFY),
|
|
||||||
'')
|
|
||||||
->setName('notifications')
|
|
||||||
->setValue($notifications));
|
|
||||||
|
|
||||||
return id(new AphrontDialogView())
|
|
||||||
->setTitle(pht('Room Preferences'))
|
|
||||||
->addHiddenInput('action', 'notifications')
|
|
||||||
->addHiddenInput(
|
|
||||||
'latest_transaction_id',
|
|
||||||
$request->getInt('latest_transaction_id'))
|
|
||||||
->appendForm($form);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private function renderAddPersonDialog(
|
private function renderAddPersonDialog(
|
||||||
ConpherenceThread $conpherence) {
|
ConpherenceThread $conpherence) {
|
||||||
|
|
||||||
@@ -371,9 +284,9 @@ final class ConpherenceUpdateController
|
|||||||
$body[] = pht(
|
$body[] = pht(
|
||||||
'Are you sure you want to leave this room?');
|
'Are you sure you want to leave this room?');
|
||||||
} else {
|
} else {
|
||||||
$title = pht('Banish User');
|
$title = pht('Remove Participant');
|
||||||
$body[] = pht(
|
$body[] = pht(
|
||||||
'Banish %s from the realm?',
|
'Remove %s from this room?',
|
||||||
phutil_tag('strong', array(), $removed_user->getUsername()));
|
phutil_tag('strong', array(), $removed_user->getUsername()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,7 +296,7 @@ final class ConpherenceUpdateController
|
|||||||
'You will be able to rejoin the room later.');
|
'You will be able to rejoin the room later.');
|
||||||
} else {
|
} else {
|
||||||
$body[] = pht(
|
$body[] = pht(
|
||||||
'This user will be able to rejoin the room later.');
|
'They will be able to rejoin the room later.');
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if ($is_self) {
|
if ($is_self) {
|
||||||
@@ -398,7 +311,7 @@ final class ConpherenceUpdateController
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
$body[] = pht(
|
$body[] = pht(
|
||||||
'This user will not be able to rejoin the room unless invited '.
|
'They will not be able to rejoin the room unless invited '.
|
||||||
'again.');
|
'again.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -457,12 +370,6 @@ final class ConpherenceUpdateController
|
|||||||
->setName('editPolicy')
|
->setName('editPolicy')
|
||||||
->setPolicyObject($conpherence)
|
->setPolicyObject($conpherence)
|
||||||
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
|
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
|
||||||
->setPolicies($policies))
|
|
||||||
->appendChild(
|
|
||||||
id(new AphrontFormPolicyControl())
|
|
||||||
->setName('joinPolicy')
|
|
||||||
->setPolicyObject($conpherence)
|
|
||||||
->setCapability(PhabricatorPolicyCapability::CAN_JOIN)
|
|
||||||
->setPolicies($policies));
|
->setPolicies($policies));
|
||||||
|
|
||||||
$view = id(new AphrontDialogView())
|
$view = id(new AphrontDialogView())
|
||||||
@@ -487,7 +394,6 @@ final class ConpherenceUpdateController
|
|||||||
$latest_transaction_id) {
|
$latest_transaction_id) {
|
||||||
|
|
||||||
$need_transactions = false;
|
$need_transactions = false;
|
||||||
$need_participant_cache = true;
|
|
||||||
switch ($action) {
|
switch ($action) {
|
||||||
case ConpherenceUpdateActions::METADATA:
|
case ConpherenceUpdateActions::METADATA:
|
||||||
case ConpherenceUpdateActions::LOAD:
|
case ConpherenceUpdateActions::LOAD:
|
||||||
@@ -498,7 +404,6 @@ final class ConpherenceUpdateController
|
|||||||
$need_transactions = true;
|
$need_transactions = true;
|
||||||
break;
|
break;
|
||||||
case ConpherenceUpdateActions::REMOVE_PERSON:
|
case ConpherenceUpdateActions::REMOVE_PERSON:
|
||||||
case ConpherenceUpdateActions::NOTIFICATIONS:
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -508,13 +413,14 @@ final class ConpherenceUpdateController
|
|||||||
->setViewer($user)
|
->setViewer($user)
|
||||||
->setAfterTransactionID($latest_transaction_id)
|
->setAfterTransactionID($latest_transaction_id)
|
||||||
->needProfileImage(true)
|
->needProfileImage(true)
|
||||||
->needParticipantCache($need_participant_cache)
|
|
||||||
->needParticipants(true)
|
->needParticipants(true)
|
||||||
->needTransactions($need_transactions)
|
->needTransactions($need_transactions)
|
||||||
->withIDs(array($conpherence_id))
|
->withIDs(array($conpherence_id))
|
||||||
->executeOne();
|
->executeOne();
|
||||||
|
|
||||||
$non_update = false;
|
$non_update = false;
|
||||||
|
$participant = $conpherence->getParticipant($user->getPHID());
|
||||||
|
|
||||||
if ($need_transactions && $conpherence->getTransactions()) {
|
if ($need_transactions && $conpherence->getTransactions()) {
|
||||||
$data = ConpherenceTransactionRenderer::renderTransactions(
|
$data = ConpherenceTransactionRenderer::renderTransactions(
|
||||||
$user,
|
$user,
|
||||||
@@ -522,9 +428,7 @@ final class ConpherenceUpdateController
|
|||||||
$key = PhabricatorConpherenceColumnMinimizeSetting::SETTINGKEY;
|
$key = PhabricatorConpherenceColumnMinimizeSetting::SETTINGKEY;
|
||||||
$minimized = $user->getUserSetting($key);
|
$minimized = $user->getUserSetting($key);
|
||||||
if (!$minimized) {
|
if (!$minimized) {
|
||||||
$participant_obj = $conpherence->getParticipant($user->getPHID());
|
$participant->markUpToDate($conpherence);
|
||||||
$participant_obj
|
|
||||||
->markUpToDate($conpherence, $data['latest_transaction']);
|
|
||||||
}
|
}
|
||||||
} else if ($need_transactions) {
|
} else if ($need_transactions) {
|
||||||
$non_update = true;
|
$non_update = true;
|
||||||
@@ -541,18 +445,12 @@ final class ConpherenceUpdateController
|
|||||||
$people_widget = null;
|
$people_widget = null;
|
||||||
switch ($action) {
|
switch ($action) {
|
||||||
case ConpherenceUpdateActions::METADATA:
|
case ConpherenceUpdateActions::METADATA:
|
||||||
$policy_objects = id(new PhabricatorPolicyQuery())
|
$header = $this->buildHeaderPaneContent($conpherence);
|
||||||
->setViewer($user)
|
|
||||||
->setObject($conpherence)
|
|
||||||
->execute();
|
|
||||||
$header = $this->buildHeaderPaneContent(
|
|
||||||
$conpherence,
|
|
||||||
$policy_objects);
|
|
||||||
$header = hsprintf('%s', $header);
|
$header = hsprintf('%s', $header);
|
||||||
$nav_item = id(new ConpherenceThreadListView())
|
$nav_item = id(new ConpherenceThreadListView())
|
||||||
->setUser($user)
|
->setUser($user)
|
||||||
->setBaseURI($this->getApplicationURI())
|
->setBaseURI($this->getApplicationURI())
|
||||||
->renderSingleThread($conpherence, $policy_objects);
|
->renderThreadItem($conpherence);
|
||||||
$nav_item = hsprintf('%s', $nav_item);
|
$nav_item = hsprintf('%s', $nav_item);
|
||||||
break;
|
break;
|
||||||
case ConpherenceUpdateActions::ADD_PERSON:
|
case ConpherenceUpdateActions::ADD_PERSON:
|
||||||
@@ -563,7 +461,6 @@ final class ConpherenceUpdateController
|
|||||||
$people_widget = hsprintf('%s', $people_widget->render());
|
$people_widget = hsprintf('%s', $people_widget->render());
|
||||||
break;
|
break;
|
||||||
case ConpherenceUpdateActions::REMOVE_PERSON:
|
case ConpherenceUpdateActions::REMOVE_PERSON:
|
||||||
case ConpherenceUpdateActions::NOTIFICATIONS:
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -571,6 +468,11 @@ final class ConpherenceUpdateController
|
|||||||
$dropdown_query = id(new AphlictDropdownDataQuery())
|
$dropdown_query = id(new AphlictDropdownDataQuery())
|
||||||
->setViewer($user);
|
->setViewer($user);
|
||||||
$dropdown_query->execute();
|
$dropdown_query->execute();
|
||||||
|
|
||||||
|
$sounds = $this->getSoundForParticipant($user, $participant);
|
||||||
|
$receive_sound = $sounds[ConpherenceRoomSettings::SOUND_RECEIVE];
|
||||||
|
$mention_sound = $sounds[ConpherenceRoomSettings::SOUND_MENTION];
|
||||||
|
|
||||||
$content = array(
|
$content = array(
|
||||||
'non_update' => $non_update,
|
'non_update' => $non_update,
|
||||||
'transactions' => hsprintf('%s', $rendered_transactions),
|
'transactions' => hsprintf('%s', $rendered_transactions),
|
||||||
@@ -584,9 +486,40 @@ final class ConpherenceUpdateController
|
|||||||
$dropdown_query->getNotificationData(),
|
$dropdown_query->getNotificationData(),
|
||||||
$dropdown_query->getConpherenceData(),
|
$dropdown_query->getConpherenceData(),
|
||||||
),
|
),
|
||||||
|
'sound' => array(
|
||||||
|
'receive' => $receive_sound,
|
||||||
|
'mention' => $mention_sound,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return $content;
|
return $content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected function getSoundForParticipant(
|
||||||
|
PhabricatorUser $user,
|
||||||
|
ConpherenceParticipant $participant) {
|
||||||
|
|
||||||
|
$sound_key = PhabricatorConpherenceSoundSetting::SETTINGKEY;
|
||||||
|
$sound_default = $user->getUserSetting($sound_key);
|
||||||
|
|
||||||
|
$settings = $participant->getSettings();
|
||||||
|
$sounds = idx($settings, 'sounds', array());
|
||||||
|
$map = PhabricatorConpherenceSoundSetting::getDefaultSound($sound_default);
|
||||||
|
|
||||||
|
$receive = idx($sounds,
|
||||||
|
ConpherenceRoomSettings::SOUND_RECEIVE,
|
||||||
|
$map[ConpherenceRoomSettings::SOUND_RECEIVE]);
|
||||||
|
$mention = idx($sounds,
|
||||||
|
ConpherenceRoomSettings::SOUND_MENTION,
|
||||||
|
$map[ConpherenceRoomSettings::SOUND_MENTION]);
|
||||||
|
|
||||||
|
$sound_map = ConpherenceRoomSettings::getSoundMap();
|
||||||
|
|
||||||
|
return array(
|
||||||
|
ConpherenceRoomSettings::SOUND_RECEIVE => $sound_map[$receive]['rsrc'],
|
||||||
|
ConpherenceRoomSettings::SOUND_MENTION => $sound_map[$mention]['rsrc'],
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,6 @@ final class ConpherenceViewController extends
|
|||||||
->setViewer($user)
|
->setViewer($user)
|
||||||
->withIDs(array($conpherence_id))
|
->withIDs(array($conpherence_id))
|
||||||
->needProfileImage(true)
|
->needProfileImage(true)
|
||||||
->needParticipantCache(true)
|
|
||||||
->needTransactions(true)
|
->needTransactions(true)
|
||||||
->setTransactionLimit($this->getMainQueryLimit());
|
->setTransactionLimit($this->getMainQueryLimit());
|
||||||
|
|
||||||
@@ -56,15 +55,15 @@ final class ConpherenceViewController extends
|
|||||||
}
|
}
|
||||||
$this->setConpherence($conpherence);
|
$this->setConpherence($conpherence);
|
||||||
|
|
||||||
$transactions = $this->getNeededTransactions(
|
|
||||||
$conpherence,
|
|
||||||
$old_message_id);
|
|
||||||
$latest_transaction = head($transactions);
|
|
||||||
$participant = $conpherence->getParticipantIfExists($user->getPHID());
|
$participant = $conpherence->getParticipantIfExists($user->getPHID());
|
||||||
|
$theme = ConpherenceRoomSettings::COLOR_LIGHT;
|
||||||
|
|
||||||
if ($participant) {
|
if ($participant) {
|
||||||
|
$settings = $participant->getSettings();
|
||||||
|
$theme = idx($settings, 'theme', ConpherenceRoomSettings::COLOR_LIGHT);
|
||||||
if (!$participant->isUpToDate($conpherence)) {
|
if (!$participant->isUpToDate($conpherence)) {
|
||||||
$write_guard = AphrontWriteGuard::beginScopedUnguardedWrites();
|
$write_guard = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||||
$participant->markUpToDate($conpherence, $latest_transaction);
|
$participant->markUpToDate($conpherence);
|
||||||
$user->clearCacheData(PhabricatorUserMessageCountCacheType::KEY_COUNT);
|
$user->clearCacheData(PhabricatorUserMessageCountCacheType::KEY_COUNT);
|
||||||
unset($write_guard);
|
unset($write_guard);
|
||||||
}
|
}
|
||||||
@@ -83,11 +82,7 @@ final class ConpherenceViewController extends
|
|||||||
$form = null;
|
$form = null;
|
||||||
$content = array('transactions' => $messages);
|
$content = array('transactions' => $messages);
|
||||||
} else {
|
} else {
|
||||||
$policy_objects = id(new PhabricatorPolicyQuery())
|
$header = $this->buildHeaderPaneContent($conpherence);
|
||||||
->setViewer($user)
|
|
||||||
->setObject($conpherence)
|
|
||||||
->execute();
|
|
||||||
$header = $this->buildHeaderPaneContent($conpherence, $policy_objects);
|
|
||||||
$search = $this->buildSearchForm();
|
$search = $this->buildSearchForm();
|
||||||
$form = $this->renderFormContent();
|
$form = $this->renderFormContent();
|
||||||
$content = array(
|
$content = array(
|
||||||
@@ -119,11 +114,6 @@ final class ConpherenceViewController extends
|
|||||||
return id(new AphrontAjaxResponse())->setContent($content);
|
return id(new AphrontAjaxResponse())->setContent($content);
|
||||||
}
|
}
|
||||||
|
|
||||||
$can_join = PhabricatorPolicyFilter::hasCapability(
|
|
||||||
$user,
|
|
||||||
$conpherence,
|
|
||||||
PhabricatorPolicyCapability::CAN_JOIN);
|
|
||||||
|
|
||||||
$layout = id(new ConpherenceLayoutView())
|
$layout = id(new ConpherenceLayoutView())
|
||||||
->setUser($user)
|
->setUser($user)
|
||||||
->setBaseURI($this->getApplicationURI())
|
->setBaseURI($this->getApplicationURI())
|
||||||
@@ -132,6 +122,7 @@ final class ConpherenceViewController extends
|
|||||||
->setSearch($search)
|
->setSearch($search)
|
||||||
->setMessages($messages)
|
->setMessages($messages)
|
||||||
->setReplyForm($form)
|
->setReplyForm($form)
|
||||||
|
->setTheme($theme)
|
||||||
->setLatestTransactionID($data['latest_transaction_id'])
|
->setLatestTransactionID($data['latest_transaction_id'])
|
||||||
->setRole('thread');
|
->setRole('thread');
|
||||||
|
|
||||||
@@ -151,14 +142,8 @@ final class ConpherenceViewController extends
|
|||||||
|
|
||||||
$conpherence = $this->getConpherence();
|
$conpherence = $this->getConpherence();
|
||||||
$user = $this->getRequest()->getUser();
|
$user = $this->getRequest()->getUser();
|
||||||
$can_join = PhabricatorPolicyFilter::hasCapability(
|
|
||||||
$user,
|
|
||||||
$conpherence,
|
|
||||||
PhabricatorPolicyCapability::CAN_JOIN);
|
|
||||||
$participating = $conpherence->getParticipantIfExists($user->getPHID());
|
$participating = $conpherence->getParticipantIfExists($user->getPHID());
|
||||||
if (!$can_join && !$participating && $user->isLoggedIn()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
$draft = PhabricatorDraft::newFromUserAndKey(
|
$draft = PhabricatorDraft::newFromUserAndKey(
|
||||||
$user,
|
$user,
|
||||||
$conpherence->getPHID());
|
$conpherence->getPHID());
|
||||||
@@ -184,6 +169,7 @@ final class ConpherenceViewController extends
|
|||||||
id(new PhabricatorRemarkupControl())
|
id(new PhabricatorRemarkupControl())
|
||||||
->setUser($user)
|
->setUser($user)
|
||||||
->setName('text')
|
->setName('text')
|
||||||
|
->setSendOnEnter(true)
|
||||||
->setValue($draft->getDraft()));
|
->setValue($draft->getDraft()));
|
||||||
|
|
||||||
$status_view = phutil_tag(
|
$status_view = phutil_tag(
|
||||||
@@ -214,33 +200,6 @@ final class ConpherenceViewController extends
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private function getNeededTransactions(
|
|
||||||
ConpherenceThread $conpherence,
|
|
||||||
$message_id) {
|
|
||||||
|
|
||||||
if ($message_id) {
|
|
||||||
$newer_transactions = $conpherence->getTransactions();
|
|
||||||
$query = id(new ConpherenceTransactionQuery())
|
|
||||||
->setViewer($this->getRequest()->getUser())
|
|
||||||
->withObjectPHIDs(array($conpherence->getPHID()))
|
|
||||||
->setAfterID($message_id)
|
|
||||||
->needHandles(true)
|
|
||||||
->setLimit(self::OLDER_FETCH_LIMIT);
|
|
||||||
$older_transactions = $query->execute();
|
|
||||||
$handles = array();
|
|
||||||
foreach ($older_transactions as $transaction) {
|
|
||||||
$handles += $transaction->getHandles();
|
|
||||||
}
|
|
||||||
$conpherence->attachHandles($conpherence->getHandles() + $handles);
|
|
||||||
$transactions = array_merge($newer_transactions, $older_transactions);
|
|
||||||
$conpherence->attachTransactions($transactions);
|
|
||||||
} else {
|
|
||||||
$transactions = $conpherence->getTransactions();
|
|
||||||
}
|
|
||||||
|
|
||||||
return $transactions;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function getMainQueryLimit() {
|
private function getMainQueryLimit() {
|
||||||
$request = $this->getRequest();
|
$request = $this->getRequest();
|
||||||
$base_limit = ConpherenceThreadQuery::TRANSACTION_LIMIT;
|
$base_limit = ConpherenceThreadQuery::TRANSACTION_LIMIT;
|
||||||
|
@@ -37,16 +37,19 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||||||
if (!$errors) {
|
if (!$errors) {
|
||||||
$xactions = array();
|
$xactions = array();
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransaction::TYPE_PARTICIPANTS)
|
->setTransactionType(
|
||||||
|
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue(array('+' => $participant_phids));
|
->setNewValue(array('+' => $participant_phids));
|
||||||
if ($title) {
|
if ($title) {
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransaction::TYPE_TITLE)
|
->setTransactionType(
|
||||||
|
ConpherenceThreadTitleTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue($title);
|
->setNewValue($title);
|
||||||
}
|
}
|
||||||
if (strlen($topic)) {
|
if (strlen($topic)) {
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransaction::TYPE_TOPIC)
|
->setTransactionType(
|
||||||
|
ConpherenceThreadTopicTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue($topic);
|
->setNewValue($topic);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,49 +89,14 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||||||
$types = parent::getTransactionTypes();
|
$types = parent::getTransactionTypes();
|
||||||
|
|
||||||
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
$types[] = PhabricatorTransactions::TYPE_COMMENT;
|
||||||
|
|
||||||
$types[] = ConpherenceTransaction::TYPE_TITLE;
|
|
||||||
$types[] = ConpherenceTransaction::TYPE_TOPIC;
|
|
||||||
$types[] = ConpherenceTransaction::TYPE_PARTICIPANTS;
|
|
||||||
$types[] = ConpherenceTransaction::TYPE_PICTURE;
|
|
||||||
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||||
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
$types[] = PhabricatorTransactions::TYPE_EDIT_POLICY;
|
||||||
$types[] = PhabricatorTransactions::TYPE_JOIN_POLICY;
|
|
||||||
|
|
||||||
return $types;
|
return $types;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function getCustomTransactionOldValue(
|
public function getCreateObjectTitle($author, $object) {
|
||||||
PhabricatorLiskDAO $object,
|
return pht('%s created this room.', $author);
|
||||||
PhabricatorApplicationTransaction $xaction) {
|
|
||||||
|
|
||||||
switch ($xaction->getTransactionType()) {
|
|
||||||
case ConpherenceTransaction::TYPE_TITLE:
|
|
||||||
return $object->getTitle();
|
|
||||||
case ConpherenceTransaction::TYPE_TOPIC:
|
|
||||||
return $object->getTopic();
|
|
||||||
case ConpherenceTransaction::TYPE_PICTURE:
|
|
||||||
return $object->getProfileImagePHID();
|
|
||||||
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
|
||||||
if ($this->getIsNewObject()) {
|
|
||||||
return array();
|
|
||||||
}
|
|
||||||
return $object->getParticipantPHIDs();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function getCustomTransactionNewValue(
|
|
||||||
PhabricatorLiskDAO $object,
|
|
||||||
PhabricatorApplicationTransaction $xaction) {
|
|
||||||
|
|
||||||
switch ($xaction->getTransactionType()) {
|
|
||||||
case ConpherenceTransaction::TYPE_TITLE:
|
|
||||||
case ConpherenceTransaction::TYPE_TOPIC:
|
|
||||||
case ConpherenceTransaction::TYPE_PICTURE:
|
|
||||||
return $xaction->getNewValue();
|
|
||||||
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
|
||||||
return $this->getPHIDTransactionNewValue($xaction);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -150,109 +118,6 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||||||
return $lock;
|
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_TOPIC:
|
|
||||||
$object->setTopic($xaction->getNewValue());
|
|
||||||
break;
|
|
||||||
case ConpherenceTransaction::TYPE_PICTURE:
|
|
||||||
$object->setProfileImagePHID($xaction->getNewValue());
|
|
||||||
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(
|
protected function applyBuiltinInternalTransaction(
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
PhabricatorApplicationTransaction $xaction) {
|
PhabricatorApplicationTransaction $xaction) {
|
||||||
@@ -266,108 +131,24 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||||||
return parent::applyBuiltinInternalTransaction($object, $xaction);
|
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_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(
|
protected function applyFinalEffects(
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
array $xactions) {
|
array $xactions) {
|
||||||
|
|
||||||
if (!$xactions) {
|
$acting_phid = $this->getActingAsPHID();
|
||||||
return $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();
|
$participants = $object->getParticipants();
|
||||||
$user = $this->getActor();
|
foreach ($participants as $participant) {
|
||||||
$time = time();
|
if ($participant->getParticipantPHID() == $acting_phid) {
|
||||||
foreach ($participants as $phid => $participant) {
|
$participant->markUpToDate($object);
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PhabricatorUserCache::clearCaches(
|
if ($participants) {
|
||||||
PhabricatorUserMessageCountCacheType::KEY_COUNT,
|
PhabricatorUserCache::clearCaches(
|
||||||
array_keys($participants));
|
PhabricatorUserMessageCountCacheType::KEY_COUNT,
|
||||||
|
array_keys($participants));
|
||||||
|
}
|
||||||
|
|
||||||
if ($xactions) {
|
if ($xactions) {
|
||||||
$data = array(
|
$data = array(
|
||||||
@@ -390,36 +171,34 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||||||
parent::requireCapabilities($object, $xaction);
|
parent::requireCapabilities($object, $xaction);
|
||||||
|
|
||||||
switch ($xaction->getTransactionType()) {
|
switch ($xaction->getTransactionType()) {
|
||||||
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
case ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE:
|
||||||
$old_map = array_fuse($xaction->getOldValue());
|
$old_map = array_fuse($xaction->getOldValue());
|
||||||
$new_map = array_fuse($xaction->getNewValue());
|
$new_map = array_fuse($xaction->getNewValue());
|
||||||
|
|
||||||
$add = array_keys(array_diff_key($new_map, $old_map));
|
$add = array_keys(array_diff_key($new_map, $old_map));
|
||||||
$rem = array_keys(array_diff_key($old_map, $new_map));
|
$rem = array_keys(array_diff_key($old_map, $new_map));
|
||||||
|
|
||||||
$actor_phid = $this->requireActor()->getPHID();
|
$actor_phid = $this->getActingAsPHID();
|
||||||
|
|
||||||
$is_join = (($add === array($actor_phid)) && !$rem);
|
$is_join = (($add === array($actor_phid)) && !$rem);
|
||||||
$is_leave = (($rem === array($actor_phid)) && !$add);
|
$is_leave = (($rem === array($actor_phid)) && !$add);
|
||||||
|
|
||||||
if ($is_join) {
|
if ($is_join) {
|
||||||
// You need CAN_JOIN to join a room.
|
// Anyone can join a thread they can see.
|
||||||
PhabricatorPolicyFilter::requireCapability(
|
|
||||||
$this->requireActor(),
|
|
||||||
$object,
|
|
||||||
PhabricatorPolicyCapability::CAN_JOIN);
|
|
||||||
} else if ($is_leave) {
|
} else if ($is_leave) {
|
||||||
// You don't need any capabilities to leave a conpherence thread.
|
// Anyone can leave a thread.
|
||||||
} else {
|
} else {
|
||||||
// You need CAN_EDIT to change participants other than yourself.
|
// You need CAN_EDIT to add or remove participants. For additional
|
||||||
|
// discussion, see D17696 and T4411.
|
||||||
PhabricatorPolicyFilter::requireCapability(
|
PhabricatorPolicyFilter::requireCapability(
|
||||||
$this->requireActor(),
|
$this->requireActor(),
|
||||||
$object,
|
$object,
|
||||||
PhabricatorPolicyCapability::CAN_EDIT);
|
PhabricatorPolicyCapability::CAN_EDIT);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ConpherenceTransaction::TYPE_TITLE:
|
|
||||||
case ConpherenceTransaction::TYPE_TOPIC:
|
case ConpherenceThreadTitleTransaction::TRANSACTIONTYPE:
|
||||||
|
case ConpherenceThreadTopicTransaction::TRANSACTIONTYPE:
|
||||||
PhabricatorPolicyFilter::requireCapability(
|
PhabricatorPolicyFilter::requireCapability(
|
||||||
$this->requireActor(),
|
$this->requireActor(),
|
||||||
$object,
|
$object,
|
||||||
@@ -428,21 +207,6 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function mergeTransactions(
|
|
||||||
PhabricatorApplicationTransaction $u,
|
|
||||||
PhabricatorApplicationTransaction $v) {
|
|
||||||
|
|
||||||
$type = $u->getTransactionType();
|
|
||||||
switch ($type) {
|
|
||||||
case ConpherenceTransaction::TYPE_TITLE:
|
|
||||||
return $v;
|
|
||||||
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
|
||||||
return $this->mergePHIDOrEdgeTransactions($u, $v);
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent::mergeTransactions($u, $v);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function shouldSendMail(
|
protected function shouldSendMail(
|
||||||
PhabricatorLiskDAO $object,
|
PhabricatorLiskDAO $object,
|
||||||
array $xactions) {
|
array $xactions) {
|
||||||
@@ -541,84 +305,8 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||||||
return PhabricatorEnv::getEnvConfig('metamta.conpherence.subject-prefix');
|
return PhabricatorEnv::getEnvConfig('metamta.conpherence.subject-prefix');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function shouldPublishFeedStory(
|
|
||||||
PhabricatorLiskDAO $object,
|
|
||||||
array $xactions) {
|
|
||||||
|
|
||||||
foreach ($xactions as $xaction) {
|
|
||||||
switch ($xaction->getTransactionType()) {
|
|
||||||
case ConpherenceTransaction::TYPE_TITLE:
|
|
||||||
case ConpherenceTransaction::TYPE_TOPIC:
|
|
||||||
case ConpherenceTransaction::TYPE_PICTURE:
|
|
||||||
return true;
|
|
||||||
default:
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected function supportsSearch() {
|
protected function supportsSearch() {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
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_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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -55,7 +55,8 @@ final class ConpherenceReplyHandler extends PhabricatorMailReplyHandler {
|
|||||||
$xactions = array();
|
$xactions = array();
|
||||||
if ($this->getMailAddedParticipantPHIDs()) {
|
if ($this->getMailAddedParticipantPHIDs()) {
|
||||||
$xactions[] = id(new ConpherenceTransaction())
|
$xactions[] = id(new ConpherenceTransaction())
|
||||||
->setTransactionType(ConpherenceTransaction::TYPE_PARTICIPANTS)
|
->setTransactionType(
|
||||||
|
ConpherenceThreadParticipantsTransaction::TRANSACTIONTYPE)
|
||||||
->setNewValue(array('+' => $this->getMailAddedParticipantPHIDs()));
|
->setNewValue(array('+' => $this->getMailAddedParticipantPHIDs()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -56,9 +56,9 @@ final class ConpherenceFulltextQuery
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (strlen($this->fulltext)) {
|
if (strlen($this->fulltext)) {
|
||||||
$compiled_query = PhabricatorSearchDocument::newQueryCompiler()
|
$compiler = PhabricatorSearchDocument::newQueryCompiler();
|
||||||
->setQuery($this->fulltext)
|
$tokens = $compiler->newTokens($this->fulltext);
|
||||||
->compileQuery();
|
$compiled_query = $compiler->compileQuery($tokens);
|
||||||
|
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn_r,
|
||||||
|
@@ -1,73 +1,69 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
|
||||||
* Query class that answers the question:
|
|
||||||
*
|
|
||||||
* - Q: How many unread conpherences am I participating in?
|
|
||||||
* - A:
|
|
||||||
* id(new ConpherenceParticipantCountQuery())
|
|
||||||
* ->withParticipantPHIDs(array($my_phid))
|
|
||||||
* ->withParticipationStatus(ConpherenceParticipationStatus::BEHIND)
|
|
||||||
* ->execute();
|
|
||||||
*/
|
|
||||||
final class ConpherenceParticipantCountQuery
|
final class ConpherenceParticipantCountQuery
|
||||||
extends PhabricatorOffsetPagedQuery {
|
extends PhabricatorOffsetPagedQuery {
|
||||||
|
|
||||||
private $participantPHIDs;
|
private $participantPHIDs;
|
||||||
private $participationStatus;
|
private $unread;
|
||||||
|
|
||||||
public function withParticipantPHIDs(array $phids) {
|
public function withParticipantPHIDs(array $phids) {
|
||||||
$this->participantPHIDs = $phids;
|
$this->participantPHIDs = $phids;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function withParticipationStatus($participation_status) {
|
public function withUnread($unread) {
|
||||||
$this->participationStatus = $participation_status;
|
$this->unread = $unread;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function execute() {
|
public function execute() {
|
||||||
|
$thread = new ConpherenceThread();
|
||||||
$table = new ConpherenceParticipant();
|
$table = new ConpherenceParticipant();
|
||||||
$conn_r = $table->establishConnection('r');
|
$conn = $table->establishConnection('r');
|
||||||
|
|
||||||
$rows = queryfx_all(
|
$rows = queryfx_all(
|
||||||
$conn_r,
|
$conn,
|
||||||
'SELECT COUNT(*) as count, participantPHID '.
|
'SELECT COUNT(*) as count, participantPHID
|
||||||
'FROM %T participant %Q %Q %Q',
|
FROM %T participant JOIN %T thread
|
||||||
|
ON participant.conpherencePHID = thread.phid %Q %Q %Q',
|
||||||
$table->getTableName(),
|
$table->getTableName(),
|
||||||
$this->buildWhereClause($conn_r),
|
$thread->getTableName(),
|
||||||
$this->buildGroupByClause($conn_r),
|
$this->buildWhereClause($conn),
|
||||||
$this->buildLimitClause($conn_r));
|
$this->buildGroupByClause($conn),
|
||||||
|
$this->buildLimitClause($conn));
|
||||||
|
|
||||||
return ipull($rows, 'count', 'participantPHID');
|
return ipull($rows, 'count', 'participantPHID');
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
protected function buildWhereClause(AphrontDatabaseConnection $conn) {
|
||||||
$where = array();
|
$where = array();
|
||||||
|
|
||||||
if ($this->participantPHIDs) {
|
if ($this->participantPHIDs !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'participantPHID IN (%Ls)',
|
'participant.participantPHID IN (%Ls)',
|
||||||
$this->participantPHIDs);
|
$this->participantPHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->participationStatus !== null) {
|
if ($this->unread !== null) {
|
||||||
$where[] = qsprintf(
|
if ($this->unread) {
|
||||||
$conn_r,
|
$where[] = qsprintf(
|
||||||
'participationStatus = %d',
|
$conn,
|
||||||
$this->participationStatus);
|
'participant.seenMessageCount < thread.messageCount');
|
||||||
|
} else {
|
||||||
|
$where[] = qsprintf(
|
||||||
|
$conn,
|
||||||
|
'participant.seenMessageCount >= thread.messageCount');
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->formatWhereClause($where);
|
return $this->formatWhereClause($where);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildGroupByClause(AphrontDatabaseConnection $conn_r) {
|
private function buildGroupByClause(AphrontDatabaseConnection $conn) {
|
||||||
$group_by = qsprintf(
|
return qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'GROUP BY participantPHID');
|
'GROUP BY participantPHID');
|
||||||
|
|
||||||
return $group_by;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,128 +1,50 @@
|
|||||||
<?php
|
<?php
|
||||||
|
|
||||||
/**
|
|
||||||
* Query class that answers these questions:
|
|
||||||
*
|
|
||||||
* - Q: What are the conpherences to show when I land on /conpherence/ ?
|
|
||||||
* - A:
|
|
||||||
*
|
|
||||||
* id(new ConpherenceParticipantQuery())
|
|
||||||
* ->withParticipantPHIDs(array($my_phid))
|
|
||||||
* ->execute();
|
|
||||||
*
|
|
||||||
* - Q: What are the next set of conpherences as I scroll up (more recent) or
|
|
||||||
* down (less recent) this list of conpherences?
|
|
||||||
* - A:
|
|
||||||
*
|
|
||||||
* id(new ConpherenceParticipantQuery())
|
|
||||||
* ->withParticipantPHIDs(array($my_phid))
|
|
||||||
* ->withParticipantCursor($top_participant)
|
|
||||||
* ->setOrder(ConpherenceParticipantQuery::ORDER_NEWER)
|
|
||||||
* ->execute();
|
|
||||||
*
|
|
||||||
* -or-
|
|
||||||
*
|
|
||||||
* id(new ConpherenceParticipantQuery())
|
|
||||||
* ->withParticipantPHIDs(array($my_phid))
|
|
||||||
* ->withParticipantCursor($bottom_participant)
|
|
||||||
* ->setOrder(ConpherenceParticipantQuery::ORDER_OLDER)
|
|
||||||
* ->execute();
|
|
||||||
*
|
|
||||||
* For counts of read, un-read, or all conpherences by participant, see
|
|
||||||
* @{class:ConpherenceParticipantCountQuery}.
|
|
||||||
*/
|
|
||||||
final class ConpherenceParticipantQuery extends PhabricatorOffsetPagedQuery {
|
final class ConpherenceParticipantQuery extends PhabricatorOffsetPagedQuery {
|
||||||
|
|
||||||
const LIMIT = 100;
|
|
||||||
const ORDER_NEWER = 'newer';
|
|
||||||
const ORDER_OLDER = 'older';
|
|
||||||
|
|
||||||
private $participantPHIDs;
|
private $participantPHIDs;
|
||||||
private $participantCursor;
|
|
||||||
private $order = self::ORDER_OLDER;
|
|
||||||
|
|
||||||
public function withParticipantPHIDs(array $phids) {
|
public function withParticipantPHIDs(array $phids) {
|
||||||
$this->participantPHIDs = $phids;
|
$this->participantPHIDs = $phids;
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function withParticipantCursor(ConpherenceParticipant $participant) {
|
|
||||||
$this->participantCursor = $participant;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function setOrder($order) {
|
|
||||||
$this->order = $order;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function execute() {
|
public function execute() {
|
||||||
$table = new ConpherenceParticipant();
|
$table = new ConpherenceParticipant();
|
||||||
$conn_r = $table->establishConnection('r');
|
$thread = new ConpherenceThread();
|
||||||
|
|
||||||
|
$conn = $table->establishConnection('r');
|
||||||
|
|
||||||
$data = queryfx_all(
|
$data = queryfx_all(
|
||||||
$conn_r,
|
$conn,
|
||||||
'SELECT * FROM %T participant %Q %Q %Q',
|
'SELECT * FROM %T participant JOIN %T thread
|
||||||
|
ON participant.conpherencePHID = thread.phid %Q %Q %Q',
|
||||||
$table->getTableName(),
|
$table->getTableName(),
|
||||||
$this->buildWhereClause($conn_r),
|
$thread->getTableName(),
|
||||||
$this->buildOrderClause($conn_r),
|
$this->buildWhereClause($conn),
|
||||||
$this->buildLimitClause($conn_r));
|
$this->buildOrderClause($conn),
|
||||||
|
$this->buildLimitClause($conn));
|
||||||
|
|
||||||
$participants = $table->loadAllFromArray($data);
|
return $table->loadAllFromArray($data);
|
||||||
|
|
||||||
$participants = mpull($participants, null, 'getConpherencePHID');
|
|
||||||
|
|
||||||
if ($this->order == self::ORDER_NEWER) {
|
|
||||||
$participants = array_reverse($participants);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $participants;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function buildWhereClause(AphrontDatabaseConnection $conn_r) {
|
protected function buildWhereClause(AphrontDatabaseConnection $conn) {
|
||||||
$where = array();
|
$where = array();
|
||||||
|
|
||||||
if ($this->participantPHIDs) {
|
if ($this->participantPHIDs !== null) {
|
||||||
$where[] = qsprintf(
|
$where[] = qsprintf(
|
||||||
$conn_r,
|
$conn,
|
||||||
'participantPHID IN (%Ls)',
|
'participantPHID IN (%Ls)',
|
||||||
$this->participantPHIDs);
|
$this->participantPHIDs);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->participantCursor) {
|
|
||||||
$date_touched = $this->participantCursor->getDateTouched();
|
|
||||||
$id = $this->participantCursor->getID();
|
|
||||||
if ($this->order == self::ORDER_OLDER) {
|
|
||||||
$compare_date = '<';
|
|
||||||
$compare_id = '<=';
|
|
||||||
} else {
|
|
||||||
$compare_date = '>';
|
|
||||||
$compare_id = '>=';
|
|
||||||
}
|
|
||||||
$where[] = qsprintf(
|
|
||||||
$conn_r,
|
|
||||||
'(dateTouched %Q %d OR (dateTouched = %d AND id %Q %d))',
|
|
||||||
$compare_date,
|
|
||||||
$date_touched,
|
|
||||||
$date_touched,
|
|
||||||
$compare_id,
|
|
||||||
$id);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $this->formatWhereClause($where);
|
return $this->formatWhereClause($where);
|
||||||
}
|
}
|
||||||
|
|
||||||
private function buildOrderClause(AphrontDatabaseConnection $conn_r) {
|
private function buildOrderClause(AphrontDatabaseConnection $conn) {
|
||||||
$order_word = ($this->order == self::ORDER_OLDER) ? 'DESC' : 'ASC';
|
return qsprintf(
|
||||||
// if these are different direction we won't get as efficient a query
|
$conn,
|
||||||
// see http://dev.mysql.com/doc/refman/5.5/en/order-by-optimization.html
|
'ORDER BY thread.dateModified DESC, thread.id DESC, participant.id DESC');
|
||||||
$order = qsprintf(
|
|
||||||
$conn_r,
|
|
||||||
'ORDER BY dateTouched %Q, id %Q',
|
|
||||||
$order_word,
|
|
||||||
$order_word);
|
|
||||||
|
|
||||||
return $order;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -10,18 +10,12 @@ final class ConpherenceThreadQuery
|
|||||||
private $participantPHIDs;
|
private $participantPHIDs;
|
||||||
private $needParticipants;
|
private $needParticipants;
|
||||||
private $needTransactions;
|
private $needTransactions;
|
||||||
private $needParticipantCache;
|
|
||||||
private $afterTransactionID;
|
private $afterTransactionID;
|
||||||
private $beforeTransactionID;
|
private $beforeTransactionID;
|
||||||
private $transactionLimit;
|
private $transactionLimit;
|
||||||
private $fulltext;
|
private $fulltext;
|
||||||
private $needProfileImage;
|
private $needProfileImage;
|
||||||
|
|
||||||
public function needParticipantCache($participant_cache) {
|
|
||||||
$this->needParticipantCache = $participant_cache;
|
|
||||||
return $this;
|
|
||||||
}
|
|
||||||
|
|
||||||
public function needParticipants($need) {
|
public function needParticipants($need) {
|
||||||
$this->needParticipants = $need;
|
$this->needParticipants = $need;
|
||||||
return $this;
|
return $this;
|
||||||
@@ -101,9 +95,6 @@ final class ConpherenceThreadQuery
|
|||||||
if ($conpherences) {
|
if ($conpherences) {
|
||||||
$conpherences = mpull($conpherences, null, 'getPHID');
|
$conpherences = mpull($conpherences, null, 'getPHID');
|
||||||
$this->loadParticipantsAndInitHandles($conpherences);
|
$this->loadParticipantsAndInitHandles($conpherences);
|
||||||
if ($this->needParticipantCache) {
|
|
||||||
$this->loadCoreHandles($conpherences, 'getRecentParticipantPHIDs');
|
|
||||||
}
|
|
||||||
if ($this->needParticipants) {
|
if ($this->needParticipants) {
|
||||||
$this->loadCoreHandles($conpherences, 'getParticipantPHIDs');
|
$this->loadCoreHandles($conpherences, 'getParticipantPHIDs');
|
||||||
}
|
}
|
||||||
|