mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-28 01:32:42 +01:00
(stable) Promote 2016 Week 39
This commit is contained in:
commit
27006fedcc
38 changed files with 507 additions and 545 deletions
102
externals/mimemailparser/MimeMailParser.class.php
vendored
102
externals/mimemailparser/MimeMailParser.class.php
vendored
|
@ -111,13 +111,13 @@ class MimeMailParser {
|
|||
* @param $data String
|
||||
*/
|
||||
public function setText($data) {
|
||||
// NOTE: This has been modified for Phabricator. If the input data does not
|
||||
// end in a newline, Mailparse fails to include the last line in the mail
|
||||
// body. This happens somewhere deep, deep inside the mailparse extension,
|
||||
// so adding a newline here seems like the most straightforward fix.
|
||||
if (!preg_match('/\n\z/', $data)) {
|
||||
$data = $data."\n";
|
||||
}
|
||||
// NOTE: This has been modified for Phabricator. If the input data does not
|
||||
// end in a newline, Mailparse fails to include the last line in the mail
|
||||
// body. This happens somewhere deep, deep inside the mailparse extension,
|
||||
// so adding a newline here seems like the most straightforward fix.
|
||||
if (!preg_match('/\n\z/', $data)) {
|
||||
$data = $data."\n";
|
||||
}
|
||||
|
||||
$this->resource = mailparse_msg_create();
|
||||
// does not parse incrementally, fast memory hog might explode
|
||||
|
@ -203,23 +203,23 @@ class MimeMailParser {
|
|||
);
|
||||
if (in_array($type, array_keys($mime_types))) {
|
||||
foreach($this->parts as $part) {
|
||||
$disposition = $this->getPartContentDisposition($part);
|
||||
if ($disposition == 'attachment') {
|
||||
// text/plain parts with "Content-Disposition: attachment" are
|
||||
// attachments, not part of the text body.
|
||||
continue;
|
||||
}
|
||||
$disposition = $this->getPartContentDisposition($part);
|
||||
if ($disposition == 'attachment') {
|
||||
// text/plain parts with "Content-Disposition: attachment" are
|
||||
// attachments, not part of the text body.
|
||||
continue;
|
||||
}
|
||||
if ($this->getPartContentType($part) == $mime_types[$type]) {
|
||||
$headers = $this->getPartHeaders($part);
|
||||
// Concatenate all the matching parts into the body text. For example,
|
||||
// if a user sends a message with some text, then an image, and then
|
||||
// some more text, the text body of the email gets split over several
|
||||
// attachments.
|
||||
$headers = $this->getPartHeaders($part);
|
||||
// Concatenate all the matching parts into the body text. For example,
|
||||
// if a user sends a message with some text, then an image, and then
|
||||
// some more text, the text body of the email gets split over several
|
||||
// attachments.
|
||||
$body .= $this->decode(
|
||||
$this->getPartBody($part),
|
||||
array_key_exists('content-transfer-encoding', $headers)
|
||||
? $headers['content-transfer-encoding']
|
||||
: '');
|
||||
? $headers['content-transfer-encoding']
|
||||
: '');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
@ -251,20 +251,42 @@ class MimeMailParser {
|
|||
return $headers;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the attachments contents in order of appearance
|
||||
* @return Array
|
||||
* @param $type Object[optional]
|
||||
*/
|
||||
public function getAttachments() {
|
||||
// NOTE: This has been modified for Phabricator. Some mail clients do not
|
||||
// send attachments with "Content-Disposition" headers.
|
||||
$attachments = array();
|
||||
$dispositions = array("attachment","inline");
|
||||
foreach($this->parts as $part) {
|
||||
$non_attachment_types = array("text/plain", "text/html");
|
||||
$nonameIter = 0;
|
||||
foreach ($this->parts as $part) {
|
||||
$disposition = $this->getPartContentDisposition($part);
|
||||
if (in_array($disposition, $dispositions)) {
|
||||
$filename = 'noname';
|
||||
if (isset($part['disposition-filename'])) {
|
||||
$filename = $part['disposition-filename'];
|
||||
} elseif (isset($part['content-name'])) {
|
||||
// if we have no disposition but we have a content-name, it's a valid attachment.
|
||||
// we simulate the presence of an attachment disposition with a disposition filename
|
||||
$filename = $part['content-name'];
|
||||
$disposition = 'attachment';
|
||||
} elseif (!in_array($part['content-type'], $non_attachment_types, true)
|
||||
&& substr($part['content-type'], 0, 10) !== 'multipart/'
|
||||
) {
|
||||
// if we cannot get it with getMessageBody, we assume it is an attachment
|
||||
$disposition = 'attachment';
|
||||
}
|
||||
|
||||
if (in_array($disposition, $dispositions) && isset($filename) === true) {
|
||||
if ($filename == 'noname') {
|
||||
$nonameIter++;
|
||||
$filename = 'noname'.$nonameIter;
|
||||
}
|
||||
$attachments[] = new MimeMailParser_attachment(
|
||||
$part['disposition-filename'],
|
||||
$filename,
|
||||
$this->getPartContentType($part),
|
||||
$this->getAttachmentStream($part),
|
||||
$disposition,
|
||||
|
@ -413,7 +435,7 @@ class MimeMailParser {
|
|||
private function getAttachmentStream(&$part) {
|
||||
$temp_fp = tmpfile();
|
||||
|
||||
array_key_exists('content-transfer-encoding', $part['headers']) ? $encoding = $part['headers']['content-transfer-encoding'] : $encoding = '';
|
||||
array_key_exists('content-transfer-encoding', $part['headers']) ? $encoding = $part['headers']['content-transfer-encoding'] : $encoding = '';
|
||||
|
||||
if ($temp_fp) {
|
||||
if ($this->stream) {
|
||||
|
@ -445,21 +467,21 @@ class MimeMailParser {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Decode the string depending on encoding type.
|
||||
* @return String the decoded string.
|
||||
* @param $encodedString The string in its original encoded state.
|
||||
* @param $encodingType The encoding type from the Content-Transfer-Encoding header of the part.
|
||||
*/
|
||||
private function decode($encodedString, $encodingType) {
|
||||
if (strtolower($encodingType) == 'base64') {
|
||||
return base64_decode($encodedString);
|
||||
} else if (strtolower($encodingType) == 'quoted-printable') {
|
||||
return quoted_printable_decode($encodedString);
|
||||
} else {
|
||||
return $encodedString;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Decode the string depending on encoding type.
|
||||
* @return String the decoded string.
|
||||
* @param $encodedString The string in its original encoded state.
|
||||
* @param $encodingType The encoding type from the Content-Transfer-Encoding header of the part.
|
||||
*/
|
||||
private function decode($encodedString, $encodingType) {
|
||||
if (strtolower($encodingType) == 'base64') {
|
||||
return base64_decode($encodedString);
|
||||
} else if (strtolower($encodingType) == 'quoted-printable') {
|
||||
return quoted_printable_decode($encodedString);
|
||||
} else {
|
||||
return $encodedString;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ return array(
|
|||
'names' => array(
|
||||
'conpherence.pkg.css' => '80a3fcb3',
|
||||
'conpherence.pkg.js' => '89b4837e',
|
||||
'core.pkg.css' => '476e9330',
|
||||
'core.pkg.css' => 'f7b03076',
|
||||
'core.pkg.js' => '1d376fa9',
|
||||
'darkconsole.pkg.js' => 'e7393ebb',
|
||||
'differential.pkg.css' => '3fb7f532',
|
||||
|
@ -27,7 +27,7 @@ return array(
|
|||
'rsrc/css/aphront/notification.css' => '3f6c89c9',
|
||||
'rsrc/css/aphront/panel-view.css' => '8427b78d',
|
||||
'rsrc/css/aphront/phabricator-nav-view.css' => 'b29426e9',
|
||||
'rsrc/css/aphront/table-view.css' => '832656fd',
|
||||
'rsrc/css/aphront/table-view.css' => '3225137a',
|
||||
'rsrc/css/aphront/tokenizer.css' => '056da01b',
|
||||
'rsrc/css/aphront/tooltip.css' => '1a07aea8',
|
||||
'rsrc/css/aphront/typeahead-browse.css' => '8904346a',
|
||||
|
@ -38,7 +38,7 @@ return array(
|
|||
'rsrc/css/application/base/notification-menu.css' => 'b3ab500d',
|
||||
'rsrc/css/application/base/phabricator-application-launch-view.css' => '95351601',
|
||||
'rsrc/css/application/base/phui-theme.css' => '027ba77e',
|
||||
'rsrc/css/application/base/standard-page-view.css' => '2b592894',
|
||||
'rsrc/css/application/base/standard-page-view.css' => '3026770e',
|
||||
'rsrc/css/application/chatlog/chatlog.css' => 'd295b020',
|
||||
'rsrc/css/application/conduit/conduit-api.css' => '7bc725c4',
|
||||
'rsrc/css/application/config/config-options.css' => '0ede4c9b',
|
||||
|
@ -607,7 +607,7 @@ return array(
|
|||
'aphront-list-filter-view-css' => '5d6f0526',
|
||||
'aphront-multi-column-view-css' => 'fd18389d',
|
||||
'aphront-panel-view-css' => '8427b78d',
|
||||
'aphront-table-view-css' => '832656fd',
|
||||
'aphront-table-view-css' => '3225137a',
|
||||
'aphront-tokenizer-control-css' => '056da01b',
|
||||
'aphront-tooltip-css' => '1a07aea8',
|
||||
'aphront-typeahead-control-css' => 'd4f16145',
|
||||
|
@ -869,7 +869,7 @@ return array(
|
|||
'phabricator-shaped-request' => '7cbe244b',
|
||||
'phabricator-slowvote-css' => 'a94b7230',
|
||||
'phabricator-source-code-view-css' => 'cbeef983',
|
||||
'phabricator-standard-page-view' => '2b592894',
|
||||
'phabricator-standard-page-view' => '3026770e',
|
||||
'phabricator-textareautils' => '320810c8',
|
||||
'phabricator-title' => 'df5e11d2',
|
||||
'phabricator-tooltip' => '6323f942',
|
||||
|
|
14
resources/sql/autopatches/20160921.fileexternalrequest.sql
Normal file
14
resources/sql/autopatches/20160921.fileexternalrequest.sql
Normal file
|
@ -0,0 +1,14 @@
|
|||
CREATE TABLE {$NAMESPACE}_file.file_externalrequest (
|
||||
id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
|
||||
filePHID VARBINARY(64),
|
||||
ttl INT UNSIGNED NOT NULL,
|
||||
uri LONGTEXT NOT NULL,
|
||||
uriIndex BINARY(12) NOT NULL,
|
||||
isSuccessful BOOL NOT NULL,
|
||||
responseMessage LONGTEXT,
|
||||
dateCreated INT UNSIGNED NOT NULL,
|
||||
dateModified INT UNSIGNED NOT NULL,
|
||||
UNIQUE KEY `key_uriindex` (uriIndex),
|
||||
KEY `key_ttl` (ttl),
|
||||
KEY `key_file` (filePHID)
|
||||
) ENGINE=InnoDB, COLLATE {$COLLATE_TEXT};
|
|
@ -2553,10 +2553,13 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFileDropUploadController' => 'applications/files/controller/PhabricatorFileDropUploadController.php',
|
||||
'PhabricatorFileEditController' => 'applications/files/controller/PhabricatorFileEditController.php',
|
||||
'PhabricatorFileEditor' => 'applications/files/editor/PhabricatorFileEditor.php',
|
||||
'PhabricatorFileExternalRequest' => 'applications/files/storage/PhabricatorFileExternalRequest.php',
|
||||
'PhabricatorFileExternalRequestGarbageCollector' => 'applications/files/garbagecollector/PhabricatorFileExternalRequestGarbageCollector.php',
|
||||
'PhabricatorFileFilePHIDType' => 'applications/files/phid/PhabricatorFileFilePHIDType.php',
|
||||
'PhabricatorFileHasObjectEdgeType' => 'applications/files/edge/PhabricatorFileHasObjectEdgeType.php',
|
||||
'PhabricatorFileIconSetSelectController' => 'applications/files/controller/PhabricatorFileIconSetSelectController.php',
|
||||
'PhabricatorFileImageMacro' => 'applications/macro/storage/PhabricatorFileImageMacro.php',
|
||||
'PhabricatorFileImageProxyController' => 'applications/files/controller/PhabricatorFileImageProxyController.php',
|
||||
'PhabricatorFileImageTransform' => 'applications/files/transform/PhabricatorFileImageTransform.php',
|
||||
'PhabricatorFileInfoController' => 'applications/files/controller/PhabricatorFileInfoController.php',
|
||||
'PhabricatorFileLinkView' => 'view/layout/PhabricatorFileLinkView.php',
|
||||
|
@ -3184,6 +3187,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPhurlURLCommentController' => 'applications/phurl/controller/PhabricatorPhurlURLCommentController.php',
|
||||
'PhabricatorPhurlURLCreateCapability' => 'applications/phurl/capability/PhabricatorPhurlURLCreateCapability.php',
|
||||
'PhabricatorPhurlURLEditController' => 'applications/phurl/controller/PhabricatorPhurlURLEditController.php',
|
||||
'PhabricatorPhurlURLEditEngine' => 'applications/phurl/editor/PhabricatorPhurlURLEditEngine.php',
|
||||
'PhabricatorPhurlURLEditor' => 'applications/phurl/editor/PhabricatorPhurlURLEditor.php',
|
||||
'PhabricatorPhurlURLListController' => 'applications/phurl/controller/PhabricatorPhurlURLListController.php',
|
||||
'PhabricatorPhurlURLMailReceiver' => 'applications/phurl/mail/PhabricatorPhurlURLMailReceiver.php',
|
||||
|
@ -7367,6 +7371,11 @@ phutil_register_library_map(array(
|
|||
'PhabricatorFileDropUploadController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileEditController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorFileExternalRequest' => array(
|
||||
'PhabricatorFileDAO',
|
||||
'PhabricatorDestructibleInterface',
|
||||
),
|
||||
'PhabricatorFileExternalRequestGarbageCollector' => 'PhabricatorGarbageCollector',
|
||||
'PhabricatorFileFilePHIDType' => 'PhabricatorPHIDType',
|
||||
'PhabricatorFileHasObjectEdgeType' => 'PhabricatorEdgeType',
|
||||
'PhabricatorFileIconSetSelectController' => 'PhabricatorFileController',
|
||||
|
@ -7378,6 +7387,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorTokenReceiverInterface',
|
||||
'PhabricatorPolicyInterface',
|
||||
),
|
||||
'PhabricatorFileImageProxyController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileImageTransform' => 'PhabricatorFileTransform',
|
||||
'PhabricatorFileInfoController' => 'PhabricatorFileController',
|
||||
'PhabricatorFileLinkView' => 'AphrontView',
|
||||
|
@ -8097,6 +8107,7 @@ phutil_register_library_map(array(
|
|||
'PhabricatorPhurlURLCommentController' => 'PhabricatorPhurlController',
|
||||
'PhabricatorPhurlURLCreateCapability' => 'PhabricatorPolicyCapability',
|
||||
'PhabricatorPhurlURLEditController' => 'PhabricatorPhurlController',
|
||||
'PhabricatorPhurlURLEditEngine' => 'PhabricatorEditEngine',
|
||||
'PhabricatorPhurlURLEditor' => 'PhabricatorApplicationTransactionEditor',
|
||||
'PhabricatorPhurlURLListController' => 'PhabricatorPhurlController',
|
||||
'PhabricatorPhurlURLMailReceiver' => 'PhabricatorObjectMailReceiver',
|
||||
|
|
|
@ -2,9 +2,6 @@
|
|||
|
||||
final class PhabricatorRedirectController extends PhabricatorController {
|
||||
|
||||
private $uri;
|
||||
private $allowExternal;
|
||||
|
||||
public function shouldRequireLogin() {
|
||||
return false;
|
||||
}
|
||||
|
@ -13,15 +10,12 @@ final class PhabricatorRedirectController extends PhabricatorController {
|
|||
return false;
|
||||
}
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->uri = $data['uri'];
|
||||
$this->allowExternal = idx($data, 'external', false);
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$uri = $request->getURIData('uri');
|
||||
$external = $request->getURIData('external', false);
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($this->uri)
|
||||
->setIsExternal($this->allowExternal);
|
||||
->setURI($uri)
|
||||
->setIsExternal($external);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -143,9 +143,6 @@ final class PhabricatorExtraConfigSetupCheck extends PhabricatorSetupCheck {
|
|||
'phabricator.auth-permanent',
|
||||
'phabricator.application-id',
|
||||
'phabricator.application-secret',
|
||||
'maniphest.priorities.unbreak-now',
|
||||
'maniphest.priorities.needs-triage',
|
||||
'welcome.html',
|
||||
);
|
||||
|
||||
$ancient_config = array_fill_keys($auth_config, $reason_auth);
|
||||
|
@ -197,6 +194,10 @@ final class PhabricatorExtraConfigSetupCheck extends PhabricatorSetupCheck {
|
|||
'The "Re: Prefix" and "Vary Subjects" settings are now configured '.
|
||||
'in global settings.');
|
||||
|
||||
$dashboard_reason = pht(
|
||||
'This option has been removed, you can use Dashboards to provide '.
|
||||
'homepage customization. See T11533 for more details.');
|
||||
|
||||
$ancient_config += array(
|
||||
'phid.external-loaders' =>
|
||||
pht(
|
||||
|
@ -336,17 +337,9 @@ final class PhabricatorExtraConfigSetupCheck extends PhabricatorSetupCheck {
|
|||
'This option has been replaced with `ui.logo`, which provides more '.
|
||||
'flexible configuration options.'),
|
||||
|
||||
'welcome.html' => pht(
|
||||
'This option has been removed, you can use Dashboards to provide '.
|
||||
'homepage customization. See T11533 for more details.'),
|
||||
|
||||
'maniphest.priorities.unbreak-now' => pht(
|
||||
'This option has been removed, you can use Dashboards to provide '.
|
||||
'homepage customization. See T11533 for more details.'),
|
||||
|
||||
'maniphest.priorities.needs-triage' => pht(
|
||||
'This option has been removed, you can use Dashboards to provide '.
|
||||
'homepage customization. See T11533 for more details.'),
|
||||
'welcome.html' => $dashboard_reason,
|
||||
'maniphest.priorities.unbreak-now' => $dashboard_reason,
|
||||
'maniphest.priorities.needs-triage' => $dashboard_reason,
|
||||
|
||||
);
|
||||
|
||||
|
|
|
@ -112,25 +112,6 @@ final class ConpherenceRoomTestCase extends ConpherenceTestCase {
|
|||
}
|
||||
}
|
||||
|
||||
public function testAddMessageWithFileAttachments() {
|
||||
$creator = $this->generateNewTestUser();
|
||||
$friend_1 = $this->generateNewTestUser();
|
||||
|
||||
$participant_map = array(
|
||||
$creator->getPHID() => $creator,
|
||||
$friend_1->getPHID() => $friend_1,
|
||||
);
|
||||
|
||||
$conpherence = $this->createRoom(
|
||||
$creator,
|
||||
array_keys($participant_map));
|
||||
|
||||
foreach ($participant_map as $phid => $user) {
|
||||
$xactions = $this->addMessageWithFile($user, $conpherence);
|
||||
$this->assertEqual(2, count($xactions));
|
||||
}
|
||||
}
|
||||
|
||||
private function createRoom(
|
||||
PhabricatorUser $creator,
|
||||
array $participant_phids) {
|
||||
|
|
|
@ -37,8 +37,7 @@ final class ConpherenceQueryThreadConduitAPIMethod
|
|||
|
||||
$query = id(new ConpherenceThreadQuery())
|
||||
->setViewer($user)
|
||||
->needParticipantCache(true)
|
||||
->needFilePHIDs(true);
|
||||
->needParticipantCache(true);
|
||||
|
||||
if ($ids) {
|
||||
$conpherences = $query
|
||||
|
@ -73,7 +72,6 @@ final class ConpherenceQueryThreadConduitAPIMethod
|
|||
'conpherenceTitle' => $conpherence->getTitle(),
|
||||
'messageCount' => $conpherence->getMessageCount(),
|
||||
'recentParticipantPHIDs' => $conpherence->getRecentParticipantPHIDs(),
|
||||
'filePHIDs' => $conpherence->getFilePHIDs(),
|
||||
'conpherenceURI' => $this->getConpherenceURI($conpherence),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -44,8 +44,7 @@ final class ConpherenceUpdateThreadConduitAPIMethod
|
|||
$id = $request->getValue('id');
|
||||
$phid = $request->getValue('phid');
|
||||
$query = id(new ConpherenceThreadQuery())
|
||||
->setViewer($user)
|
||||
->needFilePHIDs(true);
|
||||
->setViewer($user);
|
||||
if ($id) {
|
||||
$query->withIDs(array($id));
|
||||
} else if ($phid) {
|
||||
|
|
|
@ -36,7 +36,6 @@ final class ConpherenceUpdateController
|
|||
$conpherence = id(new ConpherenceThreadQuery())
|
||||
->setViewer($user)
|
||||
->withIDs(array($conpherence_id))
|
||||
->needFilePHIDs(true)
|
||||
->needOrigPics(true)
|
||||
->needCropPics(true)
|
||||
->needParticipants($need_participants)
|
||||
|
|
|
@ -22,7 +22,6 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
$topic) {
|
||||
|
||||
$conpherence = ConpherenceThread::initializeNewRoom($creator);
|
||||
$files = array();
|
||||
$errors = array();
|
||||
if (empty($participant_phids)) {
|
||||
$errors[] = self::ERROR_EMPTY_PARTICIPANTS;
|
||||
|
@ -35,26 +34,11 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
$errors[] = self::ERROR_EMPTY_MESSAGE;
|
||||
}
|
||||
|
||||
$file_phids = PhabricatorMarkupEngine::extractFilePHIDsFromEmbeddedFiles(
|
||||
$creator,
|
||||
array($message));
|
||||
if ($file_phids) {
|
||||
$files = id(new PhabricatorFileQuery())
|
||||
->setViewer($creator)
|
||||
->withPHIDs($file_phids)
|
||||
->execute();
|
||||
}
|
||||
|
||||
if (!$errors) {
|
||||
$xactions = array();
|
||||
$xactions[] = id(new ConpherenceTransaction())
|
||||
->setTransactionType(ConpherenceTransaction::TYPE_PARTICIPANTS)
|
||||
->setNewValue(array('+' => $participant_phids));
|
||||
if ($files) {
|
||||
$xactions[] = id(new ConpherenceTransaction())
|
||||
->setTransactionType(ConpherenceTransaction::TYPE_FILES)
|
||||
->setNewValue(array('+' => mpull($files, 'getPHID')));
|
||||
}
|
||||
if ($title) {
|
||||
$xactions[] = id(new ConpherenceTransaction())
|
||||
->setTransactionType(ConpherenceTransaction::TYPE_TITLE)
|
||||
|
@ -88,27 +72,7 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
ConpherenceThread $conpherence,
|
||||
$text) {
|
||||
|
||||
$files = array();
|
||||
$file_phids = PhabricatorMarkupEngine::extractFilePHIDsFromEmbeddedFiles(
|
||||
$viewer,
|
||||
array($text));
|
||||
// Since these are extracted from text, we might be re-including the
|
||||
// same file -- e.g. a mock under discussion. Filter files we
|
||||
// already have.
|
||||
$existing_file_phids = $conpherence->getFilePHIDs();
|
||||
$file_phids = array_diff($file_phids, $existing_file_phids);
|
||||
if ($file_phids) {
|
||||
$files = id(new PhabricatorFileQuery())
|
||||
->setViewer($this->getActor())
|
||||
->withPHIDs($file_phids)
|
||||
->execute();
|
||||
}
|
||||
$xactions = array();
|
||||
if ($files) {
|
||||
$xactions[] = id(new ConpherenceTransaction())
|
||||
->setTransactionType(ConpherenceTransaction::TYPE_FILES)
|
||||
->setNewValue(array('+' => mpull($files, 'getPHID')));
|
||||
}
|
||||
$xactions[] = id(new ConpherenceTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_COMMENT)
|
||||
->attachComment(
|
||||
|
@ -126,7 +90,6 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
$types[] = ConpherenceTransaction::TYPE_TITLE;
|
||||
$types[] = ConpherenceTransaction::TYPE_TOPIC;
|
||||
$types[] = ConpherenceTransaction::TYPE_PARTICIPANTS;
|
||||
$types[] = ConpherenceTransaction::TYPE_FILES;
|
||||
$types[] = ConpherenceTransaction::TYPE_PICTURE;
|
||||
$types[] = ConpherenceTransaction::TYPE_PICTURE_CROP;
|
||||
$types[] = PhabricatorTransactions::TYPE_VIEW_POLICY;
|
||||
|
@ -154,8 +117,6 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
return array();
|
||||
}
|
||||
return $object->getParticipantPHIDs();
|
||||
case ConpherenceTransaction::TYPE_FILES:
|
||||
return $object->getFilePHIDs();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -172,7 +133,6 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
$file = $xaction->getNewValue();
|
||||
return $file->getPHID();
|
||||
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
||||
case ConpherenceTransaction::TYPE_FILES:
|
||||
return $this->getPHIDTransactionNewValue($xaction);
|
||||
}
|
||||
}
|
||||
|
@ -335,27 +295,6 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
PhabricatorApplicationTransaction $xaction) {
|
||||
|
||||
switch ($xaction->getTransactionType()) {
|
||||
case ConpherenceTransaction::TYPE_FILES:
|
||||
$editor = new PhabricatorEdgeEditor();
|
||||
$edge_type = PhabricatorObjectHasFileEdgeType::EDGECONST;
|
||||
$old = array_fill_keys($xaction->getOldValue(), true);
|
||||
$new = array_fill_keys($xaction->getNewValue(), true);
|
||||
$add_edges = array_keys(array_diff_key($new, $old));
|
||||
$remove_edges = array_keys(array_diff_key($old, $new));
|
||||
foreach ($add_edges as $file_phid) {
|
||||
$editor->addEdge(
|
||||
$object->getPHID(),
|
||||
$edge_type,
|
||||
$file_phid);
|
||||
}
|
||||
foreach ($remove_edges as $file_phid) {
|
||||
$editor->removeEdge(
|
||||
$object->getPHID(),
|
||||
$edge_type,
|
||||
$file_phid);
|
||||
}
|
||||
$editor->save();
|
||||
break;
|
||||
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
||||
if ($this->getIsNewObject()) {
|
||||
continue;
|
||||
|
@ -488,14 +427,6 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
PhabricatorPolicyCapability::CAN_EDIT);
|
||||
}
|
||||
break;
|
||||
// This is similar to PhabricatorTransactions::TYPE_COMMENT so
|
||||
// use CAN_VIEW
|
||||
case ConpherenceTransaction::TYPE_FILES:
|
||||
PhabricatorPolicyFilter::requireCapability(
|
||||
$this->requireActor(),
|
||||
$object,
|
||||
PhabricatorPolicyCapability::CAN_VIEW);
|
||||
break;
|
||||
case ConpherenceTransaction::TYPE_TITLE:
|
||||
case ConpherenceTransaction::TYPE_TOPIC:
|
||||
PhabricatorPolicyFilter::requireCapability(
|
||||
|
@ -514,7 +445,6 @@ final class ConpherenceEditor extends PhabricatorApplicationTransactionEditor {
|
|||
switch ($type) {
|
||||
case ConpherenceTransaction::TYPE_TITLE:
|
||||
return $v;
|
||||
case ConpherenceTransaction::TYPE_FILES:
|
||||
case ConpherenceTransaction::TYPE_PARTICIPANTS:
|
||||
return $this->mergePHIDOrEdgeTransactions($u, $v);
|
||||
}
|
||||
|
|
|
@ -13,17 +13,11 @@ final class ConpherenceThreadQuery
|
|||
private $needOrigPics;
|
||||
private $needTransactions;
|
||||
private $needParticipantCache;
|
||||
private $needFilePHIDs;
|
||||
private $afterTransactionID;
|
||||
private $beforeTransactionID;
|
||||
private $transactionLimit;
|
||||
private $fulltext;
|
||||
|
||||
public function needFilePHIDs($need_file_phids) {
|
||||
$this->needFilePHIDs = $need_file_phids;
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function needParticipantCache($participant_cache) {
|
||||
$this->needParticipantCache = $participant_cache;
|
||||
return $this;
|
||||
|
@ -116,9 +110,6 @@ final class ConpherenceThreadQuery
|
|||
if ($this->needTransactions) {
|
||||
$this->loadTransactionsAndHandles($conpherences);
|
||||
}
|
||||
if ($this->needFilePHIDs) {
|
||||
$this->loadFilePHIDs($conpherences);
|
||||
}
|
||||
if ($this->needOrigPics || $this->needCropPics) {
|
||||
$this->initImages($conpherences);
|
||||
}
|
||||
|
@ -275,19 +266,6 @@ final class ConpherenceThreadQuery
|
|||
return $this;
|
||||
}
|
||||
|
||||
private function loadFilePHIDs(array $conpherences) {
|
||||
$edge_type = PhabricatorObjectHasFileEdgeType::EDGECONST;
|
||||
$file_edges = id(new PhabricatorEdgeQuery())
|
||||
->withSourcePHIDs(array_keys($conpherences))
|
||||
->withEdgeTypes(array($edge_type))
|
||||
->execute();
|
||||
foreach ($file_edges as $conpherence_phid => $data) {
|
||||
$conpherence = $conpherences[$conpherence_phid];
|
||||
$conpherence->attachFilePHIDs(array_keys($data[$edge_type]));
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
private function loadOrigPics(array $conpherences) {
|
||||
return $this->loadPics(
|
||||
$conpherences,
|
||||
|
|
|
@ -20,7 +20,6 @@ final class ConpherenceThread extends ConpherenceDAO
|
|||
private $participants = self::ATTACHABLE;
|
||||
private $transactions = self::ATTACHABLE;
|
||||
private $handles = self::ATTACHABLE;
|
||||
private $filePHIDs = self::ATTACHABLE;
|
||||
private $images = self::ATTACHABLE;
|
||||
|
||||
public static function initializeNewRoom(PhabricatorUser $sender) {
|
||||
|
@ -31,7 +30,6 @@ final class ConpherenceThread extends ConpherenceDAO
|
|||
->setTitle('')
|
||||
->setTopic('')
|
||||
->attachParticipants(array())
|
||||
->attachFilePHIDs(array())
|
||||
->attachImages(array())
|
||||
->setViewPolicy($default_policy)
|
||||
->setEditPolicy($default_policy)
|
||||
|
@ -158,14 +156,6 @@ final class ConpherenceThread extends ConpherenceDAO
|
|||
$amount);
|
||||
}
|
||||
|
||||
public function attachFilePHIDs(array $file_phids) {
|
||||
$this->filePHIDs = $file_phids;
|
||||
return $this;
|
||||
}
|
||||
public function getFilePHIDs() {
|
||||
return $this->assertAttached($this->filePHIDs);
|
||||
}
|
||||
|
||||
public function loadImageURI($size) {
|
||||
$file = $this->getImage($size);
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
final class ConpherenceTransaction extends PhabricatorApplicationTransaction {
|
||||
|
||||
const TYPE_FILES = 'files';
|
||||
const TYPE_TITLE = 'title';
|
||||
const TYPE_TOPIC = 'topic';
|
||||
const TYPE_PARTICIPANTS = 'participants';
|
||||
|
@ -44,8 +43,6 @@ final class ConpherenceTransaction extends PhabricatorApplicationTransaction {
|
|||
case self::TYPE_PICTURE:
|
||||
case self::TYPE_DATE_MARKER:
|
||||
return false;
|
||||
case self::TYPE_FILES:
|
||||
return true;
|
||||
case self::TYPE_PICTURE_CROP:
|
||||
return true;
|
||||
}
|
||||
|
@ -68,29 +65,6 @@ final class ConpherenceTransaction extends PhabricatorApplicationTransaction {
|
|||
case self::TYPE_PICTURE:
|
||||
return $this->getRoomTitle();
|
||||
break;
|
||||
case self::TYPE_FILES:
|
||||
$add = array_diff($new, $old);
|
||||
$rem = array_diff($old, $new);
|
||||
|
||||
if ($add && $rem) {
|
||||
$title = pht(
|
||||
'%s edited files(s), added %d and removed %d.',
|
||||
$this->renderHandleLink($author_phid),
|
||||
count($add),
|
||||
count($rem));
|
||||
} else if ($add) {
|
||||
$title = pht(
|
||||
'%s added %s files(s).',
|
||||
$this->renderHandleLink($author_phid),
|
||||
phutil_count($add));
|
||||
} else {
|
||||
$title = pht(
|
||||
'%s removed %s file(s).',
|
||||
$this->renderHandleLink($author_phid),
|
||||
phutil_count($rem));
|
||||
}
|
||||
return $title;
|
||||
break;
|
||||
case self::TYPE_PARTICIPANTS:
|
||||
$add = array_diff($new, $old);
|
||||
$rem = array_diff($old, $new);
|
||||
|
@ -252,7 +226,6 @@ final class ConpherenceTransaction extends PhabricatorApplicationTransaction {
|
|||
switch ($this->getTransactionType()) {
|
||||
case self::TYPE_TITLE:
|
||||
case self::TYPE_PICTURE:
|
||||
case self::TYPE_FILES:
|
||||
case self::TYPE_DATE_MARKER:
|
||||
break;
|
||||
case self::TYPE_PARTICIPANTS:
|
||||
|
|
|
@ -227,9 +227,6 @@ final class ConpherenceTransactionView extends AphrontView {
|
|||
$content = null;
|
||||
$handles = $this->getHandles();
|
||||
switch ($transaction->getTransactionType()) {
|
||||
case ConpherenceTransaction::TYPE_FILES:
|
||||
$content = $transaction->getTitle();
|
||||
break;
|
||||
case ConpherenceTransaction::TYPE_TITLE:
|
||||
case ConpherenceTransaction::TYPE_TOPIC:
|
||||
case ConpherenceTransaction::TYPE_PICTURE:
|
||||
|
|
|
@ -2,8 +2,6 @@
|
|||
|
||||
final class DarkConsoleDataController extends PhabricatorController {
|
||||
|
||||
private $key;
|
||||
|
||||
public function shouldRequireLogin() {
|
||||
return !PhabricatorEnv::getEnvConfig('darkconsole.always-on');
|
||||
}
|
||||
|
@ -16,19 +14,15 @@ final class DarkConsoleDataController extends PhabricatorController {
|
|||
return true;
|
||||
}
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->key = $data['key'];
|
||||
}
|
||||
|
||||
public function processRequest() {
|
||||
$request = $this->getRequest();
|
||||
$user = $request->getUser();
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $request->getViewer();
|
||||
$key = $request->getURIData('key');
|
||||
|
||||
$cache = new PhabricatorKeyValueDatabaseCache();
|
||||
$cache = new PhutilKeyValueCacheProfiler($cache);
|
||||
$cache->setProfiler(PhutilServiceProfiler::getInstance());
|
||||
|
||||
$result = $cache->getKey('darkconsole:'.$this->key);
|
||||
$result = $cache->getKey('darkconsole:'.$key);
|
||||
if (!$result) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
@ -43,7 +37,7 @@ final class DarkConsoleDataController extends PhabricatorController {
|
|||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
if ($result['user'] != $user->getPHID()) {
|
||||
if ($result['user'] != $viewer->getPHID()) {
|
||||
return new Aphront400Response();
|
||||
}
|
||||
|
||||
|
|
|
@ -2,19 +2,12 @@
|
|||
|
||||
final class DifferentialRevisionLandController extends DifferentialController {
|
||||
|
||||
private $revisionID;
|
||||
private $strategyClass;
|
||||
private $pushStrategy;
|
||||
|
||||
public function willProcessRequest(array $data) {
|
||||
$this->revisionID = $data['id'];
|
||||
$this->strategyClass = $data['strategy'];
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$viewer = $this->getViewer();
|
||||
|
||||
$revision_id = $this->revisionID;
|
||||
$revision_id = $request->getURIData('id');
|
||||
$strategy_class = $request->getURIData('strategy');
|
||||
|
||||
$revision = id(new DifferentialRevisionQuery())
|
||||
->withIDs(array($revision_id))
|
||||
|
@ -24,15 +17,15 @@ final class DifferentialRevisionLandController extends DifferentialController {
|
|||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
if (is_subclass_of($this->strategyClass, 'DifferentialLandingStrategy')) {
|
||||
$this->pushStrategy = newv($this->strategyClass, array());
|
||||
if (is_subclass_of($strategy_class, 'DifferentialLandingStrategy')) {
|
||||
$this->pushStrategy = newv($strategy_class, array());
|
||||
} else {
|
||||
throw new Exception(
|
||||
pht(
|
||||
"Strategy type must be a valid class name and must subclass ".
|
||||
"%s. '%s' is not a subclass of %s",
|
||||
'DifferentialLandingStrategy',
|
||||
$this->strategyClass,
|
||||
$strategy_class,
|
||||
'DifferentialLandingStrategy'));
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ final class PhabricatorFilesApplication extends PhabricatorApplication {
|
|||
'delete/(?P<id>[1-9]\d*)/' => 'PhabricatorFileDeleteController',
|
||||
'edit/(?P<id>[1-9]\d*)/' => 'PhabricatorFileEditController',
|
||||
'info/(?P<phid>[^/]+)/' => 'PhabricatorFileInfoController',
|
||||
'proxy/' => 'PhabricatorFileProxyController',
|
||||
'imageproxy/' => 'PhabricatorFileImageProxyController',
|
||||
'transforms/(?P<id>[1-9]\d*)/' =>
|
||||
'PhabricatorFileTransformListController',
|
||||
'uploaddialog/(?P<single>single/)?'
|
||||
|
|
|
@ -0,0 +1,118 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorFileImageProxyController
|
||||
extends PhabricatorFileController {
|
||||
|
||||
public function shouldAllowPublic() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
|
||||
$show_prototypes = PhabricatorEnv::getEnvConfig(
|
||||
'phabricator.show-prototypes');
|
||||
if (!$show_prototypes) {
|
||||
throw new Exception(
|
||||
pht('Show prototypes is disabled.
|
||||
Set `phabricator.show-prototypes` to `true` to use the image proxy'));
|
||||
}
|
||||
|
||||
$viewer = $request->getViewer();
|
||||
$img_uri = $request->getStr('uri');
|
||||
|
||||
// Validate the URI before doing anything
|
||||
PhabricatorEnv::requireValidRemoteURIForLink($img_uri);
|
||||
$uri = new PhutilURI($img_uri);
|
||||
$proto = $uri->getProtocol();
|
||||
if (!in_array($proto, array('http', 'https'))) {
|
||||
throw new Exception(
|
||||
pht('The provided image URI must be either http or https'));
|
||||
}
|
||||
|
||||
// Check if we already have the specified image URI downloaded
|
||||
$cached_request = id(new PhabricatorFileExternalRequest())->loadOneWhere(
|
||||
'uriIndex = %s',
|
||||
PhabricatorHash::digestForIndex($img_uri));
|
||||
|
||||
if ($cached_request) {
|
||||
return $this->getExternalResponse($cached_request);
|
||||
}
|
||||
|
||||
$ttl = PhabricatorTime::getNow() + phutil_units('7 days in seconds');
|
||||
$external_request = id(new PhabricatorFileExternalRequest())
|
||||
->setURI($img_uri)
|
||||
->setTTL($ttl);
|
||||
|
||||
$unguarded = AphrontWriteGuard::beginScopedUnguardedWrites();
|
||||
// Cache missed so we'll need to validate and download the image
|
||||
try {
|
||||
// Rate limit outbound fetches to make this mechanism less useful for
|
||||
// scanning networks and ports.
|
||||
PhabricatorSystemActionEngine::willTakeAction(
|
||||
array($viewer->getPHID()),
|
||||
new PhabricatorFilesOutboundRequestAction(),
|
||||
1);
|
||||
|
||||
$file = PhabricatorFile::newFromFileDownload(
|
||||
$uri,
|
||||
array(
|
||||
'viewPolicy' => PhabricatorPolicies::POLICY_NOONE,
|
||||
'canCDN' => true,
|
||||
));
|
||||
if (!$file->isViewableImage()) {
|
||||
$mime_type = $file->getMimeType();
|
||||
$engine = new PhabricatorDestructionEngine();
|
||||
$engine->destroyObject($file);
|
||||
$file = null;
|
||||
throw new Exception(
|
||||
pht(
|
||||
'The URI "%s" does not correspond to a valid image file, got '.
|
||||
'a file with MIME type "%s". You must specify the URI of a '.
|
||||
'valid image file.',
|
||||
$uri,
|
||||
$mime_type));
|
||||
} else {
|
||||
$file->save();
|
||||
}
|
||||
|
||||
$external_request->setIsSuccessful(true)
|
||||
->setFilePHID($file->getPHID())
|
||||
->save();
|
||||
unset($unguarded);
|
||||
return $this->getExternalResponse($external_request);
|
||||
} catch (HTTPFutureHTTPResponseStatus $status) {
|
||||
$external_request->setIsSuccessful(false)
|
||||
->setResponseMessage($status->getMessage())
|
||||
->save();
|
||||
return $this->getExternalResponse($external_request);
|
||||
} catch (Exception $ex) {
|
||||
// Not actually saving the request in this case
|
||||
$external_request->setResponseMessage($ex->getMessage());
|
||||
return $this->getExternalResponse($external_request);
|
||||
}
|
||||
}
|
||||
|
||||
private function getExternalResponse(
|
||||
PhabricatorFileExternalRequest $request) {
|
||||
if ($request->getIsSuccessful()) {
|
||||
$file = id(new PhabricatorFileQuery())
|
||||
->setViewer(PhabricatorUser::getOmnipotentUser())
|
||||
->withPHIDs(array($request->getFilePHID()))
|
||||
->executeOne();
|
||||
if (!file) {
|
||||
throw new Exception(pht(
|
||||
'The underlying file does not exist, but the cached request was '.
|
||||
'successful. This likely means the file record was manually deleted '.
|
||||
'by an administrator.'));
|
||||
}
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setIsExternal(true)
|
||||
->setURI($file->getViewURI());
|
||||
} else {
|
||||
throw new Exception(pht(
|
||||
"The request to get the external file from '%s' was unsuccessful:\n %s",
|
||||
$request->getURI(),
|
||||
$request->getResponseMessage()));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorFileExternalRequestGarbageCollector
|
||||
extends PhabricatorGarbageCollector {
|
||||
|
||||
const COLLECTORCONST = 'files.externalttl';
|
||||
|
||||
public function getCollectorName() {
|
||||
return pht('External Requests (TTL)');
|
||||
}
|
||||
|
||||
public function hasAutomaticPolicy() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function collectGarbage() {
|
||||
$file_requests = id(new PhabricatorFileExternalRequest())->loadAllWhere(
|
||||
'ttl < %d LIMIT 100',
|
||||
PhabricatorTime::getNow());
|
||||
$engine = new PhabricatorDestructionEngine();
|
||||
foreach ($file_requests as $request) {
|
||||
$engine->destroyObject($request);
|
||||
}
|
||||
|
||||
return (count($file_requests) == 100);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorFileExternalRequest extends PhabricatorFileDAO
|
||||
implements
|
||||
PhabricatorDestructibleInterface {
|
||||
|
||||
protected $uri;
|
||||
protected $uriIndex;
|
||||
protected $ttl;
|
||||
protected $filePHID;
|
||||
protected $isSuccessful;
|
||||
protected $responseMessage;
|
||||
|
||||
protected function getConfiguration() {
|
||||
return array(
|
||||
self::CONFIG_COLUMN_SCHEMA => array(
|
||||
'uri' => 'text',
|
||||
'uriIndex' => 'bytes12',
|
||||
'ttl' => 'epoch',
|
||||
'filePHID' => 'phid?',
|
||||
'isSuccessful' => 'bool',
|
||||
'responseMessage' => 'text?',
|
||||
),
|
||||
self::CONFIG_KEY_SCHEMA => array(
|
||||
'key_uriindex' => array(
|
||||
'columns' => array('uriIndex'),
|
||||
'unique' => true,
|
||||
),
|
||||
'key_ttl' => array(
|
||||
'columns' => array('ttl'),
|
||||
),
|
||||
'key_file' => array(
|
||||
'columns' => array('filePHID'),
|
||||
),
|
||||
),
|
||||
) + parent::getConfiguration();
|
||||
}
|
||||
|
||||
public function save() {
|
||||
$hash = PhabricatorHash::digestForIndex($this->getURI());
|
||||
$this->setURIIndex($hash);
|
||||
return parent::save();
|
||||
}
|
||||
|
||||
/* -( PhabricatorDestructibleInterface )----------------------------------- */
|
||||
|
||||
public function destroyObjectPermanently(
|
||||
PhabricatorDestructionEngine $engine) {
|
||||
|
||||
$file_phid = $this->getFilePHID();
|
||||
if ($file_phid) {
|
||||
$file = id(new PhabricatorFileQuery())
|
||||
->setViewer($engine->getViewer())
|
||||
->withPHIDs(array($file_phid))
|
||||
->executeOne();
|
||||
if ($file) {
|
||||
$engine->destroyObject($file);
|
||||
}
|
||||
}
|
||||
$this->delete();
|
||||
}
|
||||
|
||||
}
|
|
@ -420,6 +420,10 @@ final class HarbormasterBuild extends HarbormasterDAO
|
|||
->setKey('initiatorPHID')
|
||||
->setType('phid')
|
||||
->setDescription(pht('The person (or thing) that started this build.')),
|
||||
id(new PhabricatorConduitSearchFieldSpecification())
|
||||
->setKey('name')
|
||||
->setType('string')
|
||||
->setDescription(pht('The name of this build.')),
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -433,6 +437,7 @@ final class HarbormasterBuild extends HarbormasterDAO
|
|||
'name' => HarbormasterBuildStatus::getBuildStatusName($status),
|
||||
),
|
||||
'initiatorPHID' => nonempty($this->getInitiatorPHID(), null),
|
||||
'name' => $this->getName(),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -38,7 +38,6 @@ final class PhabricatorPasteApplication extends PhabricatorApplication {
|
|||
=> 'PhabricatorPasteViewController',
|
||||
'/paste/' => array(
|
||||
'(query/(?P<queryKey>[^/]+)/)?' => 'PhabricatorPasteListController',
|
||||
'create/' => 'PhabricatorPasteEditController',
|
||||
$this->getEditRoutePattern('edit/') => 'PhabricatorPasteEditController',
|
||||
'raw/(?P<id>[1-9]\d*)/' => 'PhabricatorPasteRawController',
|
||||
'archive/(?P<id>[1-9]\d*)/' => 'PhabricatorPasteArchiveController',
|
||||
|
|
|
@ -361,7 +361,7 @@ final class PhameBlog extends PhameDAO
|
|||
|
||||
|
||||
public function isAutomaticallySubscribed($phid) {
|
||||
return ($this->creatorPHID == $phid);
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ final class PhabricatorPhragmentApplication extends PhabricatorApplication {
|
|||
}
|
||||
|
||||
public function getTitleGlyph() {
|
||||
return "\xE2\x26\xB6";
|
||||
return "\xE2\x96\x9B";
|
||||
}
|
||||
|
||||
public function getApplicationGroup() {
|
||||
|
|
|
@ -46,9 +46,7 @@ final class PhabricatorPhurlApplication extends PhabricatorApplication {
|
|||
'(?:query/(?P<queryKey>[^/]+)/)?'
|
||||
=> 'PhabricatorPhurlURLListController',
|
||||
'url/' => array(
|
||||
'create/'
|
||||
=> 'PhabricatorPhurlURLEditController',
|
||||
'edit/(?P<id>[1-9]\d*)/'
|
||||
$this->getEditRoutePattern('edit/')
|
||||
=> 'PhabricatorPhurlURLEditController',
|
||||
'comment/(?P<id>[1-9]\d*)/'
|
||||
=> 'PhabricatorPhurlURLCommentController',
|
||||
|
|
|
@ -3,17 +3,10 @@
|
|||
abstract class PhabricatorPhurlController extends PhabricatorController {
|
||||
|
||||
protected function buildApplicationCrumbs() {
|
||||
$can_create = $this->hasApplicationCapability(
|
||||
PhabricatorPhurlURLCreateCapability::CAPABILITY);
|
||||
|
||||
$crumbs = parent::buildApplicationCrumbs();
|
||||
$crumbs->addAction(
|
||||
id(new PHUIListItemView())
|
||||
->setName(pht('Shorten URL'))
|
||||
->setHref($this->getApplicationURI().'url/create/')
|
||||
->setIcon('fa-plus-square')
|
||||
->setDisabled(!$can_create)
|
||||
->setWorkflow(!$can_create));
|
||||
id(new PhabricatorPhurlURLEditEngine())
|
||||
->setViewer($this->getViewer())
|
||||
->addActionToCrumbs($crumbs);
|
||||
|
||||
return $crumbs;
|
||||
}
|
||||
|
|
|
@ -4,263 +4,8 @@ final class PhabricatorPhurlURLEditController
|
|||
extends PhabricatorPhurlController {
|
||||
|
||||
public function handleRequest(AphrontRequest $request) {
|
||||
$id = $request->getURIData('id');
|
||||
$is_create = !$id;
|
||||
|
||||
$viewer = $this->getViewer();
|
||||
$user_phid = $viewer->getPHID();
|
||||
$error_long_url = true;
|
||||
$error_alias = null;
|
||||
$validation_exception = null;
|
||||
|
||||
$next_workflow = $request->getStr('next');
|
||||
$uri_query = $request->getStr('query');
|
||||
|
||||
if ($is_create) {
|
||||
$this->requireApplicationCapability(
|
||||
PhabricatorPhurlURLCreateCapability::CAPABILITY);
|
||||
|
||||
$url = PhabricatorPhurlURL::initializeNewPhurlURL(
|
||||
$viewer);
|
||||
$submit_label = pht('Create');
|
||||
$page_title = pht('Shorten URL');
|
||||
$header_icon = 'fa-plus-square';
|
||||
$subscribers = array();
|
||||
$cancel_uri = $this->getApplicationURI();
|
||||
} else {
|
||||
$url = id(new PhabricatorPhurlURLQuery())
|
||||
->setViewer($viewer)
|
||||
->withIDs(array($id))
|
||||
->requireCapabilities(
|
||||
array(
|
||||
PhabricatorPolicyCapability::CAN_VIEW,
|
||||
PhabricatorPolicyCapability::CAN_EDIT,
|
||||
))
|
||||
->executeOne();
|
||||
|
||||
if (!$url) {
|
||||
return new Aphront404Response();
|
||||
}
|
||||
|
||||
$submit_label = pht('Update');
|
||||
$page_title = pht('Edit URL: %s', $url->getName());
|
||||
$header_icon = 'fa-pencil';
|
||||
|
||||
$subscribers = PhabricatorSubscribersQuery::loadSubscribersForPHID(
|
||||
$url->getPHID());
|
||||
|
||||
$cancel_uri = '/U'.$url->getID();
|
||||
}
|
||||
|
||||
if ($is_create) {
|
||||
$projects = array();
|
||||
} else {
|
||||
$projects = PhabricatorEdgeQuery::loadDestinationPHIDs(
|
||||
$url->getPHID(),
|
||||
PhabricatorProjectObjectHasProjectEdgeType::EDGECONST);
|
||||
$projects = array_reverse($projects);
|
||||
}
|
||||
|
||||
$name = $url->getName();
|
||||
$long_url = $url->getLongURL();
|
||||
$alias = $url->getAlias();
|
||||
$description = $url->getDescription();
|
||||
$edit_policy = $url->getEditPolicy();
|
||||
$view_policy = $url->getViewPolicy();
|
||||
$space = $url->getSpacePHID();
|
||||
|
||||
if ($request->isFormPost()) {
|
||||
$xactions = array();
|
||||
$name = $request->getStr('name');
|
||||
$long_url = $request->getStr('longURL');
|
||||
$alias = $request->getStr('alias');
|
||||
$projects = $request->getArr('projects');
|
||||
$description = $request->getStr('description');
|
||||
$subscribers = $request->getArr('subscribers');
|
||||
$edit_policy = $request->getStr('editPolicy');
|
||||
$view_policy = $request->getStr('viewPolicy');
|
||||
$space = $request->getStr('spacePHID');
|
||||
|
||||
$xactions[] = id(new PhabricatorPhurlURLTransaction())
|
||||
->setTransactionType(
|
||||
PhabricatorPhurlURLTransaction::TYPE_NAME)
|
||||
->setNewValue($name);
|
||||
|
||||
$xactions[] = id(new PhabricatorPhurlURLTransaction())
|
||||
->setTransactionType(
|
||||
PhabricatorPhurlURLTransaction::TYPE_URL)
|
||||
->setNewValue($long_url);
|
||||
|
||||
$xactions[] = id(new PhabricatorPhurlURLTransaction())
|
||||
->setTransactionType(
|
||||
PhabricatorPhurlURLTransaction::TYPE_ALIAS)
|
||||
->setNewValue($alias);
|
||||
|
||||
$xactions[] = id(new PhabricatorPhurlURLTransaction())
|
||||
->setTransactionType(
|
||||
PhabricatorTransactions::TYPE_SUBSCRIBERS)
|
||||
->setNewValue(array('=' => array_fuse($subscribers)));
|
||||
|
||||
$xactions[] = id(new PhabricatorPhurlURLTransaction())
|
||||
->setTransactionType(
|
||||
PhabricatorPhurlURLTransaction::TYPE_DESCRIPTION)
|
||||
->setNewValue($description);
|
||||
|
||||
$xactions[] = id(new PhabricatorPhurlURLTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_VIEW_POLICY)
|
||||
->setNewValue($view_policy);
|
||||
|
||||
$xactions[] = id(new PhabricatorPhurlURLTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_EDIT_POLICY)
|
||||
->setNewValue($edit_policy);
|
||||
|
||||
$xactions[] = id(new PhabricatorPhurlURLTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_SPACE)
|
||||
->setNewValue($space);
|
||||
|
||||
$editor = id(new PhabricatorPhurlURLEditor())
|
||||
->setActor($viewer)
|
||||
->setContentSourceFromRequest($request)
|
||||
->setContinueOnNoEffect(true);
|
||||
|
||||
try {
|
||||
$proj_edge_type = PhabricatorProjectObjectHasProjectEdgeType::EDGECONST;
|
||||
$xactions[] = id(new PhabricatorPhurlURLTransaction())
|
||||
->setTransactionType(PhabricatorTransactions::TYPE_EDGE)
|
||||
->setMetadataValue('edge:type', $proj_edge_type)
|
||||
->setNewValue(array('=' => array_fuse($projects)));
|
||||
|
||||
$xactions = $editor->applyTransactions($url, $xactions);
|
||||
return id(new AphrontRedirectResponse())
|
||||
->setURI($url->getURI());
|
||||
} catch (PhabricatorApplicationTransactionValidationException $ex) {
|
||||
$validation_exception = $ex;
|
||||
$error_long_url = $ex->getShortMessage(
|
||||
PhabricatorPhurlURLTransaction::TYPE_URL);
|
||||
$error_alias = $ex->getShortMessage(
|
||||
PhabricatorPhurlURLTransaction::TYPE_ALIAS);
|
||||
}
|
||||
}
|
||||
|
||||
$current_policies = id(new PhabricatorPolicyQuery())
|
||||
->setViewer($viewer)
|
||||
->setObject($url)
|
||||
->execute();
|
||||
|
||||
$name = id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Name'))
|
||||
->setName('name')
|
||||
->setValue($name);
|
||||
|
||||
$long_url = id(new AphrontFormTextControl())
|
||||
->setLabel(pht('URL'))
|
||||
->setName('longURL')
|
||||
->setValue($long_url)
|
||||
->setError($error_long_url);
|
||||
|
||||
$alias = id(new AphrontFormTextControl())
|
||||
->setLabel(pht('Alias'))
|
||||
->setName('alias')
|
||||
->setValue($alias)
|
||||
->setError($error_alias);
|
||||
|
||||
$projects = id(new AphrontFormTokenizerControl())
|
||||
->setLabel(pht('Tags'))
|
||||
->setName('projects')
|
||||
->setValue($projects)
|
||||
->setUser($viewer)
|
||||
->setDatasource(new PhabricatorProjectDatasource());
|
||||
|
||||
$description = id(new PhabricatorRemarkupControl())
|
||||
->setLabel(pht('Description'))
|
||||
->setName('description')
|
||||
->setValue($description)
|
||||
->setUser($viewer);
|
||||
|
||||
$view_policies = id(new AphrontFormPolicyControl())
|
||||
->setUser($viewer)
|
||||
->setValue($view_policy)
|
||||
->setCapability(PhabricatorPolicyCapability::CAN_VIEW)
|
||||
->setPolicyObject($url)
|
||||
->setPolicies($current_policies)
|
||||
->setSpacePHID($space)
|
||||
->setName('viewPolicy');
|
||||
$edit_policies = id(new AphrontFormPolicyControl())
|
||||
->setUser($viewer)
|
||||
->setValue($edit_policy)
|
||||
->setCapability(PhabricatorPolicyCapability::CAN_EDIT)
|
||||
->setPolicyObject($url)
|
||||
->setPolicies($current_policies)
|
||||
->setName('editPolicy');
|
||||
|
||||
$subscribers = id(new AphrontFormTokenizerControl())
|
||||
->setLabel(pht('Subscribers'))
|
||||
->setName('subscribers')
|
||||
->setValue($subscribers)
|
||||
->setUser($viewer)
|
||||
->setDatasource(new PhabricatorMetaMTAMailableDatasource());
|
||||
|
||||
$form = id(new AphrontFormView())
|
||||
->setUser($viewer)
|
||||
->appendChild($name)
|
||||
->appendChild($long_url)
|
||||
->appendChild($alias)
|
||||
->appendControl($view_policies)
|
||||
->appendControl($edit_policies)
|
||||
->appendControl($subscribers)
|
||||
->appendChild($projects)
|
||||
->appendChild($description);
|
||||
|
||||
|
||||
if ($request->isAjax()) {
|
||||
return $this->newDialog()
|
||||
->setTitle($page_title)
|
||||
->setWidth(AphrontDialogView::WIDTH_FULL)
|
||||
->appendForm($form)
|
||||
->addCancelButton($cancel_uri)
|
||||
->addSubmitButton($submit_label);
|
||||
}
|
||||
|
||||
$submit = id(new AphrontFormSubmitControl())
|
||||
->addCancelButton($cancel_uri)
|
||||
->setValue($submit_label);
|
||||
|
||||
$form->appendChild($submit);
|
||||
|
||||
$form_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText($page_title)
|
||||
->setForm($form);
|
||||
|
||||
$crumbs = $this->buildApplicationCrumbs();
|
||||
|
||||
if (!$is_create) {
|
||||
$crumbs->addTextCrumb($url->getMonogram(), $url->getURI());
|
||||
} else {
|
||||
$crumbs->addTextCrumb(pht('Create URL'));
|
||||
}
|
||||
|
||||
$crumbs->addTextCrumb($page_title);
|
||||
$crumbs->setBorder(true);
|
||||
|
||||
$object_box = id(new PHUIObjectBoxView())
|
||||
->setHeaderText(pht('URL'))
|
||||
->setValidationException($validation_exception)
|
||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||
->appendChild($form);
|
||||
|
||||
$header = id(new PHUIHeaderView())
|
||||
->setHeader($page_title)
|
||||
->setHeaderIcon($header_icon);
|
||||
|
||||
$view = id(new PHUITwoColumnView())
|
||||
->setHeader($header)
|
||||
->setFooter(array(
|
||||
$object_box,
|
||||
));
|
||||
|
||||
return $this->newPage()
|
||||
->setTitle($page_title)
|
||||
->setCrumbs($crumbs)
|
||||
->appendChild($view);
|
||||
return id(new PhabricatorPhurlURLEditEngine())
|
||||
->setController($this)
|
||||
->buildResponse();
|
||||
}
|
||||
}
|
||||
|
|
104
src/applications/phurl/editor/PhabricatorPhurlURLEditEngine.php
Normal file
104
src/applications/phurl/editor/PhabricatorPhurlURLEditEngine.php
Normal file
|
@ -0,0 +1,104 @@
|
|||
<?php
|
||||
|
||||
final class PhabricatorPhurlURLEditEngine
|
||||
extends PhabricatorEditEngine {
|
||||
|
||||
const ENGINECONST = 'phurl.url';
|
||||
|
||||
public function getEngineName() {
|
||||
return pht('Phurl');
|
||||
}
|
||||
|
||||
public function getEngineApplicationClass() {
|
||||
return 'PhabricatorPhurlApplication';
|
||||
}
|
||||
|
||||
public function getSummaryHeader() {
|
||||
return pht('Configure Phurl Forms');
|
||||
}
|
||||
|
||||
public function getSummaryText() {
|
||||
return pht('Configure creation and editing forms in Phurl.');
|
||||
}
|
||||
|
||||
protected function newEditableObject() {
|
||||
return PhabricatorPhurlURL::initializeNewPhurlURL($this->getViewer());
|
||||
}
|
||||
|
||||
protected function newObjectQuery() {
|
||||
return new PhabricatorPhurlURLQuery();
|
||||
}
|
||||
|
||||
protected function getObjectCreateTitleText($object) {
|
||||
return pht('Create New URL');
|
||||
}
|
||||
|
||||
protected function getObjectEditTitleText($object) {
|
||||
return pht('Edit URL: %s', $object->getName());
|
||||
}
|
||||
|
||||
protected function getObjectEditShortText($object) {
|
||||
return $object->getName();
|
||||
}
|
||||
|
||||
protected function getObjectCreateShortText() {
|
||||
return pht('Create URL');
|
||||
}
|
||||
|
||||
protected function getObjectName() {
|
||||
return pht('URL');
|
||||
}
|
||||
|
||||
protected function getObjectCreateCancelURI($object) {
|
||||
return $this->getApplication()->getApplicationURI('/');
|
||||
}
|
||||
|
||||
protected function getEditorURI() {
|
||||
return $this->getApplication()->getApplicationURI('url/edit/');
|
||||
}
|
||||
|
||||
protected function getObjectViewURI($object) {
|
||||
return $object->getURI();
|
||||
}
|
||||
|
||||
protected function getCreateNewObjectPolicy() {
|
||||
return $this->getApplication()->getPolicy(
|
||||
PhabricatorPhurlURLCreateCapability::CAPABILITY);
|
||||
}
|
||||
|
||||
protected function buildCustomEditFields($object) {
|
||||
|
||||
return array(
|
||||
id(new PhabricatorTextEditField())
|
||||
->setKey('name')
|
||||
->setLabel(pht('Name'))
|
||||
->setDescription(pht('URL name.'))
|
||||
->setConduitTypeDescription(pht('New URL name.'))
|
||||
->setTransactionType(PhabricatorPhurlURLTransaction::TYPE_NAME)
|
||||
->setValue($object->getName()),
|
||||
id(new PhabricatorTextEditField())
|
||||
->setKey('url')
|
||||
->setLabel(pht('URL'))
|
||||
->setDescription(pht('The URL to shorten.'))
|
||||
->setConduitTypeDescription(pht('New URL.'))
|
||||
->setValue($object->getLongURL())
|
||||
->setIsRequired(true)
|
||||
->setTransactionType(PhabricatorPhurlURLTransaction::TYPE_URL),
|
||||
id(new PhabricatorTextEditField())
|
||||
->setKey('alias')
|
||||
->setLabel(pht('Alias'))
|
||||
->setTransactionType(PhabricatorPhurlURLTransaction::TYPE_ALIAS)
|
||||
->setDescription(pht('The alias to give the URL.'))
|
||||
->setConduitTypeDescription(pht('New alias.'))
|
||||
->setValue($object->getAlias()),
|
||||
id(new PhabricatorRemarkupEditField())
|
||||
->setKey('description')
|
||||
->setLabel(pht('Description'))
|
||||
->setDescription(pht('URL long description.'))
|
||||
->setConduitTypeDescription(pht('New URL description.'))
|
||||
->setTransactionType(PhabricatorPhurlURLTransaction::TYPE_DESCRIPTION)
|
||||
->setValue($object->getDescription()),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
|
@ -99,10 +99,13 @@ final class PhabricatorPhurlURLSearchEngine
|
|||
}
|
||||
|
||||
protected function getNewUserBody() {
|
||||
$create_uri = id(new PhabricatorPhurlURLEditEngine())
|
||||
->getEditURI();
|
||||
|
||||
$create_button = id(new PHUIButtonView())
|
||||
->setTag('a')
|
||||
->setText(pht('Shorten a URL'))
|
||||
->setHref('/phurl/url/create/')
|
||||
->setHref($create_uri)
|
||||
->setColor(PHUIButtonView::GREEN);
|
||||
|
||||
$icon = $this->getApplication()->getIcon();
|
||||
|
|
|
@ -682,7 +682,32 @@ final class PhabricatorRepositoryDiscoveryEngine
|
|||
|
||||
$data['commitID'] = $commit->getID();
|
||||
|
||||
PhabricatorWorker::scheduleTask($class, $data);
|
||||
// If the repository is importing for the first time, we schedule tasks
|
||||
// at IMPORT priority, which is very low. Making progress on importing a
|
||||
// new repository for the first time is less important than any other
|
||||
// daemon task.
|
||||
|
||||
// If the repostitory has finished importing and we're just catching up
|
||||
// on recent commits, we schedule discovery at COMMIT priority, which is
|
||||
// slightly below the default priority.
|
||||
|
||||
// Note that followup tasks and triggered tasks (like those generated by
|
||||
// Herald or Harbormaster) will queue at DEFAULT priority, so that each
|
||||
// commit tends to fully import before we start the next one. This tends
|
||||
// to give imports fairly predictable progress. See T11677 for some
|
||||
// discussion.
|
||||
|
||||
if ($repository->isImporting()) {
|
||||
$task_priority = PhabricatorWorker::PRIORITY_IMPORT;
|
||||
} else {
|
||||
$task_priority = PhabricatorWorker::PRIORITY_COMMIT;
|
||||
}
|
||||
|
||||
$options = array(
|
||||
'priority' => $task_priority,
|
||||
);
|
||||
|
||||
PhabricatorWorker::scheduleTask($class, $data, $options);
|
||||
}
|
||||
|
||||
private function isInitialImport(array $refs) {
|
||||
|
|
|
@ -47,6 +47,14 @@ abstract class PhabricatorRepositoryCommitMessageParserWorker
|
|||
$this->getFollowupTaskClass(),
|
||||
array(
|
||||
'commitID' => $commit->getID(),
|
||||
),
|
||||
array(
|
||||
// We queue followup tasks at default priority so that the queue
|
||||
// finishes work it has started before starting more work. If
|
||||
// followups are queued at the same priority level, we do all
|
||||
// message parses first, then all change parses, etc. This makes
|
||||
// progress uneven. See T11677 for discussion.
|
||||
'priority' => PhabricatorWorker::PRIORITY_DEFAULT,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,10 +72,6 @@ final class PhabricatorStandardCustomFieldText
|
|||
return new AphrontStringHTTPParameterType();
|
||||
}
|
||||
|
||||
public function shouldAppearInApplicationSearch() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public function getConduitEditParameterType() {
|
||||
return new ConduitStringParameterType();
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ abstract class PhabricatorWorker extends Phobject {
|
|||
|
||||
const PRIORITY_ALERTS = 1000;
|
||||
const PRIORITY_DEFAULT = 2000;
|
||||
const PRIORITY_COMMIT = 2500;
|
||||
const PRIORITY_BULK = 3000;
|
||||
const PRIORITY_IMPORT = 4000;
|
||||
|
||||
|
|
|
@ -51,12 +51,19 @@ final class ManiphestTaskGraph
|
|||
$assigned = phutil_tag('em', array(), pht('None'));
|
||||
}
|
||||
|
||||
$full_title = $object->getTitle();
|
||||
|
||||
$title = id(new PhutilUTF8StringTruncator())
|
||||
->setMaximumGlyphs(80)
|
||||
->truncateString($full_title);
|
||||
|
||||
$link = phutil_tag(
|
||||
'a',
|
||||
array(
|
||||
'href' => $object->getURI(),
|
||||
'title' => $full_title,
|
||||
),
|
||||
$object->getTitle());
|
||||
$title);
|
||||
|
||||
$link = array(
|
||||
phutil_tag(
|
||||
|
@ -95,8 +102,6 @@ final class ManiphestTaskGraph
|
|||
));
|
||||
}
|
||||
|
||||
$link = AphrontTableView::renderSingleDisplayLine($link);
|
||||
|
||||
return array(
|
||||
$marker,
|
||||
$trace,
|
||||
|
|
|
@ -75,10 +75,19 @@ abstract class PhabricatorLiskDAO extends LiskDAO {
|
|||
$connection->setReadOnly(true);
|
||||
}
|
||||
|
||||
// Unless this is a script running from the CLI, prevent any query from
|
||||
// running for more than 30 seconds. See T10849 for discussion.
|
||||
// Unless this is a script running from the CLI:
|
||||
// - (T10849) Prevent any query from running for more than 30 seconds.
|
||||
// - (T11672) Use persistent connections.
|
||||
if (php_sapi_name() != 'cli') {
|
||||
$connection->setQueryTimeout(30);
|
||||
|
||||
// TODO: For now, disable this until after T11044: it's better at high
|
||||
// load, but causes us to use slightly more connections at low load and
|
||||
// is pushing users over limits like MySQL "max_connections".
|
||||
$use_persistent = false;
|
||||
|
||||
$connection
|
||||
->setQueryTimeout(30)
|
||||
->setPersistent($use_persistent);
|
||||
}
|
||||
|
||||
return $connection;
|
||||
|
|
|
@ -228,6 +228,10 @@ span.single-display-line-content {
|
|||
position: static;
|
||||
}
|
||||
|
||||
.aphront-table-view td.object-link {
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.aphront-table-view tr.closed td.object-link .object-name,
|
||||
.aphront-table-view tr.alt-closed td.object-link .object-name {
|
||||
text-decoration: line-through;
|
||||
|
|
|
@ -56,14 +56,6 @@ body.white-background {
|
|||
color: {$greytext};
|
||||
}
|
||||
|
||||
.keyboard-shortcut-help kbd {
|
||||
background: #222222;
|
||||
padding: 6px;
|
||||
color: #ffffff;
|
||||
font-weight: bold;
|
||||
border: 1px solid #555555;
|
||||
}
|
||||
|
||||
.keyboard-focus-focus-reticle {
|
||||
background: #ffffd3;
|
||||
position: absolute;
|
||||
|
|
Loading…
Reference in a new issue