mirror of
https://we.phorge.it/source/phorge.git
synced 2024-12-16 02:20:54 +01:00
(stable) Promote 2017 Week 17
This commit is contained in:
commit
53bc57ecef
31 changed files with 919 additions and 192 deletions
|
@ -9,8 +9,8 @@ return array(
|
||||||
'names' => array(
|
'names' => array(
|
||||||
'conpherence.pkg.css' => 'ff161f2d',
|
'conpherence.pkg.css' => 'ff161f2d',
|
||||||
'conpherence.pkg.js' => 'b5b51108',
|
'conpherence.pkg.js' => 'b5b51108',
|
||||||
'core.pkg.css' => '005d943f',
|
'core.pkg.css' => '84ce260a',
|
||||||
'core.pkg.js' => '47a69358',
|
'core.pkg.js' => 'fffe0122',
|
||||||
'darkconsole.pkg.js' => '1f9a31bc',
|
'darkconsole.pkg.js' => '1f9a31bc',
|
||||||
'differential.pkg.css' => '90b30783',
|
'differential.pkg.css' => '90b30783',
|
||||||
'differential.pkg.js' => 'ddfeb49b',
|
'differential.pkg.js' => 'ddfeb49b',
|
||||||
|
@ -32,7 +32,7 @@ return array(
|
||||||
'rsrc/css/aphront/notification.css' => '3f6c89c9',
|
'rsrc/css/aphront/notification.css' => '3f6c89c9',
|
||||||
'rsrc/css/aphront/panel-view.css' => '8427b78d',
|
'rsrc/css/aphront/panel-view.css' => '8427b78d',
|
||||||
'rsrc/css/aphront/phabricator-nav-view.css' => 'faf6a6fc',
|
'rsrc/css/aphront/phabricator-nav-view.css' => 'faf6a6fc',
|
||||||
'rsrc/css/aphront/table-view.css' => '6ca8e057',
|
'rsrc/css/aphront/table-view.css' => '34cf86b4',
|
||||||
'rsrc/css/aphront/tokenizer.css' => '9a8cb501',
|
'rsrc/css/aphront/tokenizer.css' => '9a8cb501',
|
||||||
'rsrc/css/aphront/tooltip.css' => '173b9431',
|
'rsrc/css/aphront/tooltip.css' => '173b9431',
|
||||||
'rsrc/css/aphront/typeahead-browse.css' => '8904346a',
|
'rsrc/css/aphront/typeahead-browse.css' => '8904346a',
|
||||||
|
@ -42,7 +42,7 @@ return array(
|
||||||
'rsrc/css/application/base/main-menu-view.css' => '5294060f',
|
'rsrc/css/application/base/main-menu-view.css' => '5294060f',
|
||||||
'rsrc/css/application/base/notification-menu.css' => '6a697e43',
|
'rsrc/css/application/base/notification-menu.css' => '6a697e43',
|
||||||
'rsrc/css/application/base/phui-theme.css' => '9f261c6b',
|
'rsrc/css/application/base/phui-theme.css' => '9f261c6b',
|
||||||
'rsrc/css/application/base/standard-page-view.css' => '89da5a9c',
|
'rsrc/css/application/base/standard-page-view.css' => 'eb5b80c5',
|
||||||
'rsrc/css/application/chatlog/chatlog.css' => 'd295b020',
|
'rsrc/css/application/chatlog/chatlog.css' => 'd295b020',
|
||||||
'rsrc/css/application/conduit/conduit-api.css' => '7bc725c4',
|
'rsrc/css/application/conduit/conduit-api.css' => '7bc725c4',
|
||||||
'rsrc/css/application/config/config-options.css' => '0ede4c9b',
|
'rsrc/css/application/config/config-options.css' => '0ede4c9b',
|
||||||
|
@ -116,7 +116,7 @@ return array(
|
||||||
'rsrc/css/core/core.css' => '9f4cb463',
|
'rsrc/css/core/core.css' => '9f4cb463',
|
||||||
'rsrc/css/core/remarkup.css' => '17c0fb37',
|
'rsrc/css/core/remarkup.css' => '17c0fb37',
|
||||||
'rsrc/css/core/syntax.css' => 'cae95e89',
|
'rsrc/css/core/syntax.css' => 'cae95e89',
|
||||||
'rsrc/css/core/z-index.css' => '5e72c4e0',
|
'rsrc/css/core/z-index.css' => '0233d039',
|
||||||
'rsrc/css/diviner/diviner-shared.css' => '896f1d43',
|
'rsrc/css/diviner/diviner-shared.css' => '896f1d43',
|
||||||
'rsrc/css/font/font-awesome.css' => 'e838e088',
|
'rsrc/css/font/font-awesome.css' => 'e838e088',
|
||||||
'rsrc/css/font/font-lato.css' => 'c7ccd872',
|
'rsrc/css/font/font-lato.css' => 'c7ccd872',
|
||||||
|
@ -131,7 +131,7 @@ return array(
|
||||||
'rsrc/css/phui/object-item/phui-oi-color.css' => 'cd2b9b77',
|
'rsrc/css/phui/object-item/phui-oi-color.css' => 'cd2b9b77',
|
||||||
'rsrc/css/phui/object-item/phui-oi-drag-ui.css' => 'f12cbc9f',
|
'rsrc/css/phui/object-item/phui-oi-drag-ui.css' => 'f12cbc9f',
|
||||||
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '9d9685d6',
|
'rsrc/css/phui/object-item/phui-oi-flush-ui.css' => '9d9685d6',
|
||||||
'rsrc/css/phui/object-item/phui-oi-list-view.css' => '5c383524',
|
'rsrc/css/phui/object-item/phui-oi-list-view.css' => '7c8ec27a',
|
||||||
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea',
|
'rsrc/css/phui/object-item/phui-oi-simple-ui.css' => 'a8beebea',
|
||||||
'rsrc/css/phui/phui-action-list.css' => 'c01858f4',
|
'rsrc/css/phui/phui-action-list.css' => 'c01858f4',
|
||||||
'rsrc/css/phui/phui-action-panel.css' => '91c7b835',
|
'rsrc/css/phui/phui-action-panel.css' => '91c7b835',
|
||||||
|
@ -146,7 +146,7 @@ return array(
|
||||||
'rsrc/css/phui/phui-comment-panel.css' => 'f50152ad',
|
'rsrc/css/phui/phui-comment-panel.css' => 'f50152ad',
|
||||||
'rsrc/css/phui/phui-crumbs-view.css' => '6ece3bbb',
|
'rsrc/css/phui/phui-crumbs-view.css' => '6ece3bbb',
|
||||||
'rsrc/css/phui/phui-curtain-view.css' => '679743bb',
|
'rsrc/css/phui/phui-curtain-view.css' => '679743bb',
|
||||||
'rsrc/css/phui/phui-document-pro.css' => 'f56738ed',
|
'rsrc/css/phui/phui-document-pro.css' => '62c4dcbf',
|
||||||
'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf',
|
'rsrc/css/phui/phui-document-summary.css' => '9ca48bdf',
|
||||||
'rsrc/css/phui/phui-document.css' => 'c32e8dec',
|
'rsrc/css/phui/phui-document.css' => 'c32e8dec',
|
||||||
'rsrc/css/phui/phui-feed-story.css' => '44a9c8e9',
|
'rsrc/css/phui/phui-feed-story.css' => '44a9c8e9',
|
||||||
|
@ -155,7 +155,7 @@ return array(
|
||||||
'rsrc/css/phui/phui-form.css' => 'a5570f70',
|
'rsrc/css/phui/phui-form.css' => 'a5570f70',
|
||||||
'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
|
'rsrc/css/phui/phui-head-thing.css' => 'fd311e5f',
|
||||||
'rsrc/css/phui/phui-header-view.css' => 'e082678d',
|
'rsrc/css/phui/phui-header-view.css' => 'e082678d',
|
||||||
'rsrc/css/phui/phui-hovercard.css' => 'ae091fc5',
|
'rsrc/css/phui/phui-hovercard.css' => 'f0592bcf',
|
||||||
'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee',
|
'rsrc/css/phui/phui-icon-set-selector.css' => '87db8fee',
|
||||||
'rsrc/css/phui/phui-icon.css' => '12b387a1',
|
'rsrc/css/phui/phui-icon.css' => '12b387a1',
|
||||||
'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c',
|
'rsrc/css/phui/phui-image-mask.css' => 'a8498f9c',
|
||||||
|
@ -508,7 +508,7 @@ return array(
|
||||||
'rsrc/js/core/behavior-object-selector.js' => 'e0ec7f2f',
|
'rsrc/js/core/behavior-object-selector.js' => 'e0ec7f2f',
|
||||||
'rsrc/js/core/behavior-oncopy.js' => '2926fff2',
|
'rsrc/js/core/behavior-oncopy.js' => '2926fff2',
|
||||||
'rsrc/js/core/behavior-phabricator-nav.js' => '08675c6d',
|
'rsrc/js/core/behavior-phabricator-nav.js' => '08675c6d',
|
||||||
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => '0ca788bd',
|
'rsrc/js/core/behavior-phabricator-remarkup-assist.js' => 'acd29eee',
|
||||||
'rsrc/js/core/behavior-read-only-warning.js' => 'ba158207',
|
'rsrc/js/core/behavior-read-only-warning.js' => 'ba158207',
|
||||||
'rsrc/js/core/behavior-refresh-csrf.js' => 'ab2f381b',
|
'rsrc/js/core/behavior-refresh-csrf.js' => 'ab2f381b',
|
||||||
'rsrc/js/core/behavior-remarkup-preview.js' => '4b700e9e',
|
'rsrc/js/core/behavior-remarkup-preview.js' => '4b700e9e',
|
||||||
|
@ -536,7 +536,7 @@ return array(
|
||||||
'rsrc/js/phui/behavior-phui-tab-group.js' => '0a0b10e9',
|
'rsrc/js/phui/behavior-phui-tab-group.js' => '0a0b10e9',
|
||||||
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
|
'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8',
|
||||||
'rsrc/js/phuix/PHUIXActionView.js' => 'b3465b9b',
|
'rsrc/js/phuix/PHUIXActionView.js' => 'b3465b9b',
|
||||||
'rsrc/js/phuix/PHUIXAutocomplete.js' => 'd713a2c5',
|
'rsrc/js/phuix/PHUIXAutocomplete.js' => 'f6699267',
|
||||||
'rsrc/js/phuix/PHUIXDropdownMenu.js' => '8018ee50',
|
'rsrc/js/phuix/PHUIXDropdownMenu.js' => '8018ee50',
|
||||||
'rsrc/js/phuix/PHUIXFormControl.js' => '83e03671',
|
'rsrc/js/phuix/PHUIXFormControl.js' => '83e03671',
|
||||||
'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b',
|
'rsrc/js/phuix/PHUIXIconView.js' => 'bff6884b',
|
||||||
|
@ -549,7 +549,7 @@ return array(
|
||||||
'aphront-list-filter-view-css' => '5d6f0526',
|
'aphront-list-filter-view-css' => '5d6f0526',
|
||||||
'aphront-multi-column-view-css' => '84cc6640',
|
'aphront-multi-column-view-css' => '84cc6640',
|
||||||
'aphront-panel-view-css' => '8427b78d',
|
'aphront-panel-view-css' => '8427b78d',
|
||||||
'aphront-table-view-css' => '6ca8e057',
|
'aphront-table-view-css' => '34cf86b4',
|
||||||
'aphront-tokenizer-control-css' => '9a8cb501',
|
'aphront-tokenizer-control-css' => '9a8cb501',
|
||||||
'aphront-tooltip-css' => '173b9431',
|
'aphront-tooltip-css' => '173b9431',
|
||||||
'aphront-typeahead-control-css' => '8a84cc7d',
|
'aphront-typeahead-control-css' => '8a84cc7d',
|
||||||
|
@ -673,7 +673,7 @@ return array(
|
||||||
'javelin-behavior-phabricator-notification-example' => '8ce821c5',
|
'javelin-behavior-phabricator-notification-example' => '8ce821c5',
|
||||||
'javelin-behavior-phabricator-object-selector' => 'e0ec7f2f',
|
'javelin-behavior-phabricator-object-selector' => 'e0ec7f2f',
|
||||||
'javelin-behavior-phabricator-oncopy' => '2926fff2',
|
'javelin-behavior-phabricator-oncopy' => '2926fff2',
|
||||||
'javelin-behavior-phabricator-remarkup-assist' => '0ca788bd',
|
'javelin-behavior-phabricator-remarkup-assist' => 'acd29eee',
|
||||||
'javelin-behavior-phabricator-reveal-content' => '60821bc7',
|
'javelin-behavior-phabricator-reveal-content' => '60821bc7',
|
||||||
'javelin-behavior-phabricator-search-typeahead' => 'eded9ee8',
|
'javelin-behavior-phabricator-search-typeahead' => 'eded9ee8',
|
||||||
'javelin-behavior-phabricator-show-older-transactions' => '94c65b72',
|
'javelin-behavior-phabricator-show-older-transactions' => '94c65b72',
|
||||||
|
@ -809,7 +809,7 @@ return array(
|
||||||
'phabricator-shaped-request' => '7cbe244b',
|
'phabricator-shaped-request' => '7cbe244b',
|
||||||
'phabricator-slowvote-css' => 'a94b7230',
|
'phabricator-slowvote-css' => 'a94b7230',
|
||||||
'phabricator-source-code-view-css' => '4383192f',
|
'phabricator-source-code-view-css' => '4383192f',
|
||||||
'phabricator-standard-page-view' => '89da5a9c',
|
'phabricator-standard-page-view' => 'eb5b80c5',
|
||||||
'phabricator-textareautils' => '320810c8',
|
'phabricator-textareautils' => '320810c8',
|
||||||
'phabricator-title' => '485aaa6c',
|
'phabricator-title' => '485aaa6c',
|
||||||
'phabricator-tooltip' => '8fadb715',
|
'phabricator-tooltip' => '8fadb715',
|
||||||
|
@ -824,7 +824,7 @@ return array(
|
||||||
'phabricator-uiexample-reactor-select' => 'a155550f',
|
'phabricator-uiexample-reactor-select' => 'a155550f',
|
||||||
'phabricator-uiexample-reactor-sendclass' => '1def2711',
|
'phabricator-uiexample-reactor-sendclass' => '1def2711',
|
||||||
'phabricator-uiexample-reactor-sendproperties' => 'b1f0ccee',
|
'phabricator-uiexample-reactor-sendproperties' => 'b1f0ccee',
|
||||||
'phabricator-zindex-css' => '5e72c4e0',
|
'phabricator-zindex-css' => '0233d039',
|
||||||
'phame-css' => 'b3a0b3a3',
|
'phame-css' => 'b3a0b3a3',
|
||||||
'pholio-css' => 'ca89d380',
|
'pholio-css' => 'ca89d380',
|
||||||
'pholio-edit-css' => '07676f51',
|
'pholio-edit-css' => '07676f51',
|
||||||
|
@ -853,7 +853,7 @@ return array(
|
||||||
'phui-curtain-view-css' => '679743bb',
|
'phui-curtain-view-css' => '679743bb',
|
||||||
'phui-document-summary-view-css' => '9ca48bdf',
|
'phui-document-summary-view-css' => '9ca48bdf',
|
||||||
'phui-document-view-css' => 'c32e8dec',
|
'phui-document-view-css' => 'c32e8dec',
|
||||||
'phui-document-view-pro-css' => 'f56738ed',
|
'phui-document-view-pro-css' => '62c4dcbf',
|
||||||
'phui-feed-story-css' => '44a9c8e9',
|
'phui-feed-story-css' => '44a9c8e9',
|
||||||
'phui-font-icon-base-css' => '870a7360',
|
'phui-font-icon-base-css' => '870a7360',
|
||||||
'phui-fontkit-css' => '1320ed01',
|
'phui-fontkit-css' => '1320ed01',
|
||||||
|
@ -862,7 +862,7 @@ return array(
|
||||||
'phui-head-thing-view-css' => 'fd311e5f',
|
'phui-head-thing-view-css' => 'fd311e5f',
|
||||||
'phui-header-view-css' => 'e082678d',
|
'phui-header-view-css' => 'e082678d',
|
||||||
'phui-hovercard' => '1bd28176',
|
'phui-hovercard' => '1bd28176',
|
||||||
'phui-hovercard-view-css' => 'ae091fc5',
|
'phui-hovercard-view-css' => 'f0592bcf',
|
||||||
'phui-icon-set-selector-css' => '87db8fee',
|
'phui-icon-set-selector-css' => '87db8fee',
|
||||||
'phui-icon-view-css' => '12b387a1',
|
'phui-icon-view-css' => '12b387a1',
|
||||||
'phui-image-mask-css' => 'a8498f9c',
|
'phui-image-mask-css' => 'a8498f9c',
|
||||||
|
@ -877,7 +877,7 @@ return array(
|
||||||
'phui-oi-color-css' => 'cd2b9b77',
|
'phui-oi-color-css' => 'cd2b9b77',
|
||||||
'phui-oi-drag-ui-css' => 'f12cbc9f',
|
'phui-oi-drag-ui-css' => 'f12cbc9f',
|
||||||
'phui-oi-flush-ui-css' => '9d9685d6',
|
'phui-oi-flush-ui-css' => '9d9685d6',
|
||||||
'phui-oi-list-view-css' => '5c383524',
|
'phui-oi-list-view-css' => '7c8ec27a',
|
||||||
'phui-oi-simple-ui-css' => 'a8beebea',
|
'phui-oi-simple-ui-css' => 'a8beebea',
|
||||||
'phui-pager-css' => '77d8a794',
|
'phui-pager-css' => '77d8a794',
|
||||||
'phui-pinboard-view-css' => '2495140e',
|
'phui-pinboard-view-css' => '2495140e',
|
||||||
|
@ -896,7 +896,7 @@ return array(
|
||||||
'phui-workpanel-view-css' => 'a3a63478',
|
'phui-workpanel-view-css' => 'a3a63478',
|
||||||
'phuix-action-list-view' => 'b5c256b8',
|
'phuix-action-list-view' => 'b5c256b8',
|
||||||
'phuix-action-view' => 'b3465b9b',
|
'phuix-action-view' => 'b3465b9b',
|
||||||
'phuix-autocomplete' => 'd713a2c5',
|
'phuix-autocomplete' => 'f6699267',
|
||||||
'phuix-dropdown-menu' => '8018ee50',
|
'phuix-dropdown-menu' => '8018ee50',
|
||||||
'phuix-form-control-view' => '83e03671',
|
'phuix-form-control-view' => '83e03671',
|
||||||
'phuix-icon-view' => 'bff6884b',
|
'phuix-icon-view' => 'bff6884b',
|
||||||
|
@ -988,17 +988,6 @@ return array(
|
||||||
'javelin-dom',
|
'javelin-dom',
|
||||||
'javelin-router',
|
'javelin-router',
|
||||||
),
|
),
|
||||||
'0ca788bd' => array(
|
|
||||||
'javelin-behavior',
|
|
||||||
'javelin-stratcom',
|
|
||||||
'javelin-dom',
|
|
||||||
'phabricator-phtize',
|
|
||||||
'phabricator-textareautils',
|
|
||||||
'javelin-workflow',
|
|
||||||
'javelin-vector',
|
|
||||||
'phuix-autocomplete',
|
|
||||||
'javelin-mask',
|
|
||||||
),
|
|
||||||
'0f764c35' => array(
|
'0f764c35' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
'javelin-util',
|
'javelin-util',
|
||||||
|
@ -1822,6 +1811,17 @@ return array(
|
||||||
'javelin-util',
|
'javelin-util',
|
||||||
'phabricator-busy',
|
'phabricator-busy',
|
||||||
),
|
),
|
||||||
|
'acd29eee' => array(
|
||||||
|
'javelin-behavior',
|
||||||
|
'javelin-stratcom',
|
||||||
|
'javelin-dom',
|
||||||
|
'phabricator-phtize',
|
||||||
|
'phabricator-textareautils',
|
||||||
|
'javelin-workflow',
|
||||||
|
'javelin-vector',
|
||||||
|
'phuix-autocomplete',
|
||||||
|
'javelin-mask',
|
||||||
|
),
|
||||||
'b003d4fb' => array(
|
'b003d4fb' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
'javelin-stratcom',
|
'javelin-stratcom',
|
||||||
|
@ -2087,12 +2087,6 @@ return array(
|
||||||
'javelin-json',
|
'javelin-json',
|
||||||
'phabricator-prefab',
|
'phabricator-prefab',
|
||||||
),
|
),
|
||||||
'd713a2c5' => array(
|
|
||||||
'javelin-install',
|
|
||||||
'javelin-dom',
|
|
||||||
'phuix-icon-view',
|
|
||||||
'phabricator-prefab',
|
|
||||||
),
|
|
||||||
'd7a74243' => array(
|
'd7a74243' => array(
|
||||||
'javelin-behavior',
|
'javelin-behavior',
|
||||||
'javelin-stratcom',
|
'javelin-stratcom',
|
||||||
|
@ -2220,6 +2214,12 @@ return array(
|
||||||
'javelin-util',
|
'javelin-util',
|
||||||
'javelin-reactor',
|
'javelin-reactor',
|
||||||
),
|
),
|
||||||
|
'f6699267' => array(
|
||||||
|
'javelin-install',
|
||||||
|
'javelin-dom',
|
||||||
|
'phuix-icon-view',
|
||||||
|
'phabricator-prefab',
|
||||||
|
),
|
||||||
'f7fc67ec' => array(
|
'f7fc67ec' => array(
|
||||||
'javelin-install',
|
'javelin-install',
|
||||||
'javelin-typeahead',
|
'javelin-typeahead',
|
||||||
|
|
|
@ -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']);
|
|
||||||
}
|
|
||||||
|
|
34
resources/sql/autopatches/20170424.user.01.verify.php
Normal file
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()));
|
||||||
|
}
|
2
resources/sql/autopatches/20170427.owners.01.long.sql
Normal file
2
resources/sql/autopatches/20170427.owners.01.long.sql
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
ALTER TABLE {$NAMESPACE}_owners.owners_package
|
||||||
|
DROP originalName;
|
File diff suppressed because one or more lines are too long
|
@ -3204,6 +3204,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorOwnersDefaultViewCapability' => 'applications/owners/capability/PhabricatorOwnersDefaultViewCapability.php',
|
'PhabricatorOwnersDefaultViewCapability' => 'applications/owners/capability/PhabricatorOwnersDefaultViewCapability.php',
|
||||||
'PhabricatorOwnersDetailController' => 'applications/owners/controller/PhabricatorOwnersDetailController.php',
|
'PhabricatorOwnersDetailController' => 'applications/owners/controller/PhabricatorOwnersDetailController.php',
|
||||||
'PhabricatorOwnersEditController' => 'applications/owners/controller/PhabricatorOwnersEditController.php',
|
'PhabricatorOwnersEditController' => 'applications/owners/controller/PhabricatorOwnersEditController.php',
|
||||||
|
'PhabricatorOwnersHovercardEngineExtension' => 'applications/owners/engineextension/PhabricatorOwnersHovercardEngineExtension.php',
|
||||||
'PhabricatorOwnersListController' => 'applications/owners/controller/PhabricatorOwnersListController.php',
|
'PhabricatorOwnersListController' => 'applications/owners/controller/PhabricatorOwnersListController.php',
|
||||||
'PhabricatorOwnersOwner' => 'applications/owners/storage/PhabricatorOwnersOwner.php',
|
'PhabricatorOwnersOwner' => 'applications/owners/storage/PhabricatorOwnersOwner.php',
|
||||||
'PhabricatorOwnersPackage' => 'applications/owners/storage/PhabricatorOwnersPackage.php',
|
'PhabricatorOwnersPackage' => 'applications/owners/storage/PhabricatorOwnersPackage.php',
|
||||||
|
@ -8406,6 +8407,7 @@ phutil_register_library_map(array(
|
||||||
'PhabricatorOwnersDefaultViewCapability' => 'PhabricatorPolicyCapability',
|
'PhabricatorOwnersDefaultViewCapability' => 'PhabricatorPolicyCapability',
|
||||||
'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController',
|
'PhabricatorOwnersDetailController' => 'PhabricatorOwnersController',
|
||||||
'PhabricatorOwnersEditController' => 'PhabricatorOwnersController',
|
'PhabricatorOwnersEditController' => 'PhabricatorOwnersController',
|
||||||
|
'PhabricatorOwnersHovercardEngineExtension' => 'PhabricatorHovercardEngineExtension',
|
||||||
'PhabricatorOwnersListController' => 'PhabricatorOwnersController',
|
'PhabricatorOwnersListController' => 'PhabricatorOwnersController',
|
||||||
'PhabricatorOwnersOwner' => 'PhabricatorOwnersDAO',
|
'PhabricatorOwnersOwner' => 'PhabricatorOwnersDAO',
|
||||||
'PhabricatorOwnersPackage' => array(
|
'PhabricatorOwnersPackage' => array(
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
|
@ -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(
|
||||||
|
|
|
@ -559,8 +559,7 @@ final class DiffusionRepositoryClusterEngine extends Phobject {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: For now, this is only supported for Git.
|
if (!$repository->supportsSynchronization()) {
|
||||||
if (!$repository->isGit()) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,9 +2,33 @@
|
||||||
|
|
||||||
final class PhabricatorFileTransformTestCase extends PhabricatorTestCase {
|
final class PhabricatorFileTransformTestCase extends PhabricatorTestCase {
|
||||||
|
|
||||||
|
protected function getPhabricatorTestCaseConfiguration() {
|
||||||
|
return array(
|
||||||
|
self::PHABRICATOR_TESTCONFIG_BUILD_STORAGE_FIXTURES => true,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
public function testGetAllTransforms() {
|
public function testGetAllTransforms() {
|
||||||
PhabricatorFileTransform::getAllTransforms();
|
PhabricatorFileTransform::getAllTransforms();
|
||||||
$this->assertTrue(true);
|
$this->assertTrue(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testThumbTransformDefaults() {
|
||||||
|
$xforms = PhabricatorFileTransform::getAllTransforms();
|
||||||
|
$file = new PhabricatorFile();
|
||||||
|
|
||||||
|
foreach ($xforms as $xform) {
|
||||||
|
if (!($xform instanceof PhabricatorFileThumbnailTransform)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For thumbnails, generate the default thumbnail. This should be able
|
||||||
|
// to generate something rather than throwing an exception because we
|
||||||
|
// forgot to add a default file to the builtin resources. See T12614.
|
||||||
|
$xform->getDefaultTransform($file);
|
||||||
|
|
||||||
|
$this->assertTrue(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -320,13 +320,16 @@ final class LegalpadDocumentSignController extends LegalpadController {
|
||||||
$crumbs->setBorder(true);
|
$crumbs->setBorder(true);
|
||||||
$crumbs->addTextCrumb($document->getMonogram());
|
$crumbs->addTextCrumb($document->getMonogram());
|
||||||
|
|
||||||
|
$box = id(new PHUITwoColumnView())
|
||||||
|
->setFooter($signature_box);
|
||||||
|
|
||||||
return $this->newPage()
|
return $this->newPage()
|
||||||
->setTitle($title)
|
->setTitle($title)
|
||||||
->setCrumbs($crumbs)
|
->setCrumbs($crumbs)
|
||||||
->setPageObjectPHIDs(array($document->getPHID()))
|
->setPageObjectPHIDs(array($document->getPHID()))
|
||||||
->appendChild(array(
|
->appendChild(array(
|
||||||
$content,
|
$content,
|
||||||
$signature_box,
|
$box,
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,24 +24,52 @@ final class ManiphestHovercardEngineExtension
|
||||||
$task,
|
$task,
|
||||||
$data) {
|
$data) {
|
||||||
$viewer = $this->getViewer();
|
$viewer = $this->getViewer();
|
||||||
|
require_celerity_resource('phui-workcard-view-css');
|
||||||
|
|
||||||
$hovercard
|
$id = $task->getID();
|
||||||
->setTitle($task->getMonogram())
|
$task = id(new ManiphestTaskQuery())
|
||||||
->setDetail($task->getTitle());
|
->setViewer($viewer)
|
||||||
|
->withIDs(array($id))
|
||||||
|
->needProjectPHIDs(true)
|
||||||
|
->executeOne();
|
||||||
|
|
||||||
|
$phids = array();
|
||||||
|
$owner_phid = $task->getOwnerPHID();
|
||||||
|
if ($owner_phid) {
|
||||||
|
$phids[$owner_phid] = $owner_phid;
|
||||||
|
}
|
||||||
|
foreach ($task->getProjectPHIDs() as $phid) {
|
||||||
|
$phids[$phid] = $phid;
|
||||||
|
}
|
||||||
|
|
||||||
|
$handles = $viewer->loadHandles($phids);
|
||||||
|
$handles = iterator_to_array($handles);
|
||||||
|
|
||||||
|
$card = id(new ProjectBoardTaskCard())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->setTask($task)
|
||||||
|
->setCanEdit(false);
|
||||||
|
|
||||||
$owner_phid = $task->getOwnerPHID();
|
$owner_phid = $task->getOwnerPHID();
|
||||||
if ($owner_phid) {
|
if ($owner_phid) {
|
||||||
$owner = $viewer->renderHandle($owner_phid);
|
$owner_handle = $handles[$owner_phid];
|
||||||
} else {
|
$card->setOwner($owner_handle);
|
||||||
$owner = phutil_tag('em', array(), pht('None'));
|
|
||||||
}
|
}
|
||||||
$hovercard->addField(pht('Assigned To'), $owner);
|
|
||||||
|
|
||||||
$hovercard->addField(
|
$project_phids = $task->getProjectPHIDs();
|
||||||
pht('Priority'),
|
$project_handles = array_select_keys($handles, $project_phids);
|
||||||
ManiphestTaskPriority::getTaskPriorityName($task->getPriority()));
|
if ($project_handles) {
|
||||||
|
$card->setProjectHandles($project_handles);
|
||||||
|
}
|
||||||
|
|
||||||
|
$item = $card->getItem();
|
||||||
|
$card = id(new PHUIObjectItemListView())
|
||||||
|
->setFlush(true)
|
||||||
|
->setItemClass('phui-workcard')
|
||||||
|
->addClass('hovercard-task-view')
|
||||||
|
->addItem($item);
|
||||||
|
$hovercard->appendChild($card);
|
||||||
|
|
||||||
$hovercard->addTag(ManiphestView::renderTagForTask($task));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -323,6 +323,10 @@ final class PhabricatorOwnersDetailController
|
||||||
'wide',
|
'wide',
|
||||||
));
|
));
|
||||||
|
|
||||||
|
if ($info) {
|
||||||
|
$table->setNotice($info);
|
||||||
|
}
|
||||||
|
|
||||||
$header = id(new PHUIHeaderView())
|
$header = id(new PHUIHeaderView())
|
||||||
->setHeader(pht('Paths'))
|
->setHeader(pht('Paths'))
|
||||||
->setHeaderIcon('fa-folder-open');
|
->setHeaderIcon('fa-folder-open');
|
||||||
|
@ -332,10 +336,6 @@ final class PhabricatorOwnersDetailController
|
||||||
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
->setBackground(PHUIObjectBoxView::BLUE_PROPERTY)
|
||||||
->setTable($table);
|
->setTable($table);
|
||||||
|
|
||||||
if ($info) {
|
|
||||||
$box->setInfoView($info);
|
|
||||||
}
|
|
||||||
|
|
||||||
return $box;
|
return $box;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,89 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
final class PhabricatorOwnersHovercardEngineExtension
|
||||||
|
extends PhabricatorHovercardEngineExtension {
|
||||||
|
|
||||||
|
const EXTENSIONKEY = 'owners';
|
||||||
|
|
||||||
|
public function isExtensionEnabled() {
|
||||||
|
return PhabricatorApplication::isClassInstalled(
|
||||||
|
'PhabricatorOwnersApplication');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExtensionName() {
|
||||||
|
return pht('Owner Packages');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function canRenderObjectHovercard($object) {
|
||||||
|
return ($object instanceof PhabricatorOwnersPackage);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function willRenderHovercards(array $objects) {
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
$phids = mpull($objects, 'getPHID');
|
||||||
|
|
||||||
|
$packages = id(new PhabricatorOwnersPackageQuery())
|
||||||
|
->setViewer($viewer)
|
||||||
|
->withPHIDs($phids)
|
||||||
|
->execute();
|
||||||
|
$packages = mpull($packages, null, 'getPHID');
|
||||||
|
|
||||||
|
return array(
|
||||||
|
'packages' => $packages,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function renderHovercard(
|
||||||
|
PHUIHovercardView $hovercard,
|
||||||
|
PhabricatorObjectHandle $handle,
|
||||||
|
$object,
|
||||||
|
$data) {
|
||||||
|
|
||||||
|
$viewer = $this->getViewer();
|
||||||
|
|
||||||
|
$package = idx($data['packages'], $object->getPHID());
|
||||||
|
if (!$package) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$title = pht('%s: %s', 'O'.$package->getID(), $package->getName());
|
||||||
|
$hovercard->setTitle($title);
|
||||||
|
|
||||||
|
$dominion = $package->getDominion();
|
||||||
|
$dominion_map = PhabricatorOwnersPackage::getDominionOptionsMap();
|
||||||
|
$spec = idx($dominion_map, $dominion, array());
|
||||||
|
$name = idx($spec, 'short', $dominion);
|
||||||
|
$hovercard->addField(pht('Dominion'), $name);
|
||||||
|
|
||||||
|
$auto = $package->getAutoReview();
|
||||||
|
$autoreview_map = PhabricatorOwnersPackage::getAutoreviewOptionsMap();
|
||||||
|
$spec = idx($autoreview_map, $auto, array());
|
||||||
|
$name = idx($spec, 'name', $auto);
|
||||||
|
$hovercard->addField(pht('Auto Review'), $name);
|
||||||
|
|
||||||
|
if ($package->isArchived()) {
|
||||||
|
$tag = id(new PHUITagView())
|
||||||
|
->setName(pht('Archived'))
|
||||||
|
->setShade(PHUITagView::COLOR_INDIGO)
|
||||||
|
->setType(PHUITagView::TYPE_OBJECT);
|
||||||
|
$hovercard->addTag($tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
$owner_phids = $package->getOwnerPHIDs();
|
||||||
|
|
||||||
|
$hovercard->addField(
|
||||||
|
pht('Owners'),
|
||||||
|
$viewer->renderHandleList($owner_phids)->setAsInline(true));
|
||||||
|
|
||||||
|
$description = $package->getDescription();
|
||||||
|
if (strlen($description)) {
|
||||||
|
$description = id(new PhutilUTF8StringTruncator())
|
||||||
|
->setMaximumGlyphs(120)
|
||||||
|
->truncateString($description);
|
||||||
|
|
||||||
|
$hovercard->addField(pht('Description'), $description);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -12,7 +12,6 @@ final class PhabricatorOwnersPackage
|
||||||
PhabricatorNgramsInterface {
|
PhabricatorNgramsInterface {
|
||||||
|
|
||||||
protected $name;
|
protected $name;
|
||||||
protected $originalName;
|
|
||||||
protected $auditingEnabled;
|
protected $auditingEnabled;
|
||||||
protected $autoReview;
|
protected $autoReview;
|
||||||
protected $description;
|
protected $description;
|
||||||
|
@ -105,8 +104,7 @@ final class PhabricatorOwnersPackage
|
||||||
self::CONFIG_TIMESTAMPS => false,
|
self::CONFIG_TIMESTAMPS => false,
|
||||||
self::CONFIG_AUX_PHID => true,
|
self::CONFIG_AUX_PHID => true,
|
||||||
self::CONFIG_COLUMN_SCHEMA => array(
|
self::CONFIG_COLUMN_SCHEMA => array(
|
||||||
'name' => 'sort128',
|
'name' => 'sort',
|
||||||
'originalName' => 'text255',
|
|
||||||
'description' => 'text',
|
'description' => 'text',
|
||||||
'primaryOwnerPHID' => 'phid?',
|
'primaryOwnerPHID' => 'phid?',
|
||||||
'auditingEnabled' => 'bool',
|
'auditingEnabled' => 'bool',
|
||||||
|
@ -137,9 +135,6 @@ final class PhabricatorOwnersPackage
|
||||||
|
|
||||||
public function setName($name) {
|
public function setName($name) {
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
if (!$this->getID()) {
|
|
||||||
$this->originalName = $name;
|
|
||||||
}
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -540,6 +540,14 @@ final class PhabricatorUserEditor extends PhabricatorEditor {
|
||||||
$email->setIsPrimary(1);
|
$email->setIsPrimary(1);
|
||||||
$email->save();
|
$email->save();
|
||||||
|
|
||||||
|
// If the user doesn't have the verified flag set on their account
|
||||||
|
// yet, set it. We've made sure the email is verified above. See
|
||||||
|
// T12635 for discussion.
|
||||||
|
if (!$user->getIsEmailVerified()) {
|
||||||
|
$user->setIsEmailVerified(1);
|
||||||
|
$user->save();
|
||||||
|
}
|
||||||
|
|
||||||
$log = PhabricatorUserLog::initializeNewLog(
|
$log = PhabricatorUserLog::initializeNewLog(
|
||||||
$actor,
|
$actor,
|
||||||
$user->getPHID(),
|
$user->getPHID(),
|
||||||
|
|
|
@ -1929,10 +1929,31 @@ final class PhabricatorRepository extends PhabricatorRepositoryDAO
|
||||||
'Cluster hosts must correctly route their intracluster requests.'));
|
'Cluster hosts must correctly route their intracluster requests.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (count($results) > 1) {
|
||||||
|
if (!$this->supportsSynchronization()) {
|
||||||
|
throw new Exception(
|
||||||
|
pht(
|
||||||
|
'Repository "%s" is bound to multiple active repository hosts, '.
|
||||||
|
'but this repository does not support cluster synchronization. '.
|
||||||
|
'Declusterize this repository or move it to a service with only '.
|
||||||
|
'one host.',
|
||||||
|
$this->getDisplayName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
shuffle($results);
|
shuffle($results);
|
||||||
return head($results);
|
return head($results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function supportsSynchronization() {
|
||||||
|
// TODO: For now, this is only supported for Git.
|
||||||
|
if (!$this->isGit()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public function getAlmanacServiceCacheKey() {
|
public function getAlmanacServiceCacheKey() {
|
||||||
$service_phid = $this->getAlmanacServicePHID();
|
$service_phid = $this->getAlmanacServicePHID();
|
||||||
if (!$service_phid) {
|
if (!$service_phid) {
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
@title Configuring a Preamble Script
|
@title Configuring a Preamble Script
|
||||||
@group config
|
@group config
|
||||||
|
|
||||||
Adjust environmental settings (SSL, remote IP, rate limiting) using a preamble
|
Adjust environmental settings (SSL, remote IPs) using a preamble script.
|
||||||
script.
|
|
||||||
|
|
||||||
Overview
|
Overview
|
||||||
========
|
========
|
||||||
|
|
|
@ -30,6 +30,7 @@ final class PhabricatorAccessLog extends Phobject {
|
||||||
'h' => php_uname('n'),
|
'h' => php_uname('n'),
|
||||||
'p' => getmypid(),
|
'p' => getmypid(),
|
||||||
'e' => time(),
|
'e' => time(),
|
||||||
|
'I' => PhabricatorEnv::getEnvConfig('cluster.instance'),
|
||||||
));
|
));
|
||||||
|
|
||||||
self::$log = $log;
|
self::$log = $log;
|
||||||
|
|
|
@ -20,6 +20,7 @@ final class PhabricatorSSHLog extends Phobject {
|
||||||
'h' => php_uname('n'),
|
'h' => php_uname('n'),
|
||||||
'p' => getmypid(),
|
'p' => getmypid(),
|
||||||
'e' => time(),
|
'e' => time(),
|
||||||
|
'I' => PhabricatorEnv::getEnvConfig('cluster.instance'),
|
||||||
);
|
);
|
||||||
|
|
||||||
$sudo_user = PhabricatorEnv::getEnvConfig('phd.user');
|
$sudo_user = PhabricatorEnv::getEnvConfig('phd.user');
|
||||||
|
|
|
@ -112,14 +112,17 @@ final class PHUIHovercardView extends AphrontTagView {
|
||||||
|
|
||||||
$body = array();
|
$body = array();
|
||||||
|
|
||||||
|
$body_title = null;
|
||||||
if ($this->detail) {
|
if ($this->detail) {
|
||||||
$body_title = $this->detail;
|
$body_title = $this->detail;
|
||||||
} else {
|
} else if (!$this->fields) {
|
||||||
// Fallback for object handles
|
// Fallback for object handles
|
||||||
$body_title = $handle->getFullName();
|
$body_title = $handle->getFullName();
|
||||||
}
|
}
|
||||||
|
|
||||||
$body[] = phutil_tag_div('phui-hovercard-body-header', $body_title);
|
if ($body_title) {
|
||||||
|
$body[] = phutil_tag_div('phui-hovercard-body-header', $body_title);
|
||||||
|
}
|
||||||
|
|
||||||
foreach ($this->fields as $field) {
|
foreach ($this->fields as $field) {
|
||||||
$item = array(
|
$item = array(
|
||||||
|
|
|
@ -50,6 +50,7 @@ final class PhabricatorStartup {
|
||||||
// iterate on it a bit for Conduit, some of the specific score levels, and
|
// iterate on it a bit for Conduit, some of the specific score levels, and
|
||||||
// to deal with NAT'd offices.
|
// to deal with NAT'd offices.
|
||||||
private static $maximumRate = 0;
|
private static $maximumRate = 0;
|
||||||
|
private static $rateLimitToken;
|
||||||
|
|
||||||
|
|
||||||
/* -( Accessing Request Information )-------------------------------------- */
|
/* -( Accessing Request Information )-------------------------------------- */
|
||||||
|
@ -137,8 +138,9 @@ final class PhabricatorStartup {
|
||||||
// we can switch over to relying on our own exception recovery mechanisms.
|
// we can switch over to relying on our own exception recovery mechanisms.
|
||||||
ini_set('display_errors', 0);
|
ini_set('display_errors', 0);
|
||||||
|
|
||||||
if (isset($_SERVER['REMOTE_ADDR'])) {
|
$rate_token = self::getRateLimitToken();
|
||||||
self::rateLimitRequest($_SERVER['REMOTE_ADDR']);
|
if ($rate_token !== null) {
|
||||||
|
self::rateLimitRequest($rate_token);
|
||||||
}
|
}
|
||||||
|
|
||||||
self::normalizeInput();
|
self::normalizeInput();
|
||||||
|
@ -680,6 +682,36 @@ final class PhabricatorStartup {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set a token to identify the client for purposes of rate limiting.
|
||||||
|
*
|
||||||
|
* By default, the `REMOTE_ADDR` is used. If your install is behind a load
|
||||||
|
* balancer, you may want to parse `X-Forwarded-For` and use that address
|
||||||
|
* instead.
|
||||||
|
*
|
||||||
|
* @param string Client identity for rate limiting.
|
||||||
|
*/
|
||||||
|
public static function setRateLimitToken($token) {
|
||||||
|
self::$rateLimitToken = $token;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the current client identity for rate limiting.
|
||||||
|
*/
|
||||||
|
public static function getRateLimitToken() {
|
||||||
|
if (self::$rateLimitToken !== null) {
|
||||||
|
return self::$rateLimitToken;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isset($_SERVER['REMOTE_ADDR'])) {
|
||||||
|
return $_SERVER['REMOTE_ADDR'];
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the user (identified by `$user_identity`) has issued too many
|
* Check if the user (identified by `$user_identity`) has issued too many
|
||||||
* requests recently. If they have, end the request with a 429 error code.
|
* requests recently. If they have, end the request with a 429 error code.
|
||||||
|
@ -699,13 +731,18 @@ final class PhabricatorStartup {
|
||||||
}
|
}
|
||||||
|
|
||||||
$score = self::getRateLimitScore($user_identity);
|
$score = self::getRateLimitScore($user_identity);
|
||||||
if ($score > (self::$maximumRate * self::getRateLimitBucketCount())) {
|
$limit = self::$maximumRate * self::getRateLimitBucketCount();
|
||||||
|
if ($score > $limit) {
|
||||||
// Give the user some bonus points for getting rate limited. This keeps
|
// Give the user some bonus points for getting rate limited. This keeps
|
||||||
// bad actors who keep slamming the 429 page locked out completely,
|
// bad actors who keep slamming the 429 page locked out completely,
|
||||||
// instead of letting them get a burst of requests through every minute
|
// instead of letting them get a burst of requests through every minute
|
||||||
// after a bucket expires.
|
// after a bucket expires.
|
||||||
self::addRateLimitScore($user_identity, 50);
|
$penalty = 50;
|
||||||
self::didRateLimit($user_identity);
|
|
||||||
|
self::addRateLimitScore($user_identity, $penalty);
|
||||||
|
$score += $penalty;
|
||||||
|
|
||||||
|
self::didRateLimit($user_identity, $score, $limit);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -729,15 +766,21 @@ final class PhabricatorStartup {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$is_apcu = (bool)function_exists('apcu_fetch');
|
||||||
$current = self::getRateLimitBucket();
|
$current = self::getRateLimitBucket();
|
||||||
|
|
||||||
// There's a bit of a race here, if a second process reads the bucket before
|
// There's a bit of a race here, if a second process reads the bucket
|
||||||
// this one writes it, but it's fine if we occasionally fail to record a
|
// before this one writes it, but it's fine if we occasionally fail to
|
||||||
// user's score. If they're making requests fast enough to hit rate
|
// record a user's score. If they're making requests fast enough to hit
|
||||||
// limiting, we'll get them soon.
|
// rate limiting, we'll get them soon enough.
|
||||||
|
|
||||||
$bucket_key = self::getRateLimitBucketKey($current);
|
$bucket_key = self::getRateLimitBucketKey($current);
|
||||||
$bucket = apc_fetch($bucket_key);
|
if ($is_apcu) {
|
||||||
|
$bucket = apcu_fetch($bucket_key);
|
||||||
|
} else {
|
||||||
|
$bucket = apc_fetch($bucket_key);
|
||||||
|
}
|
||||||
|
|
||||||
if (!is_array($bucket)) {
|
if (!is_array($bucket)) {
|
||||||
$bucket = array();
|
$bucket = array();
|
||||||
}
|
}
|
||||||
|
@ -747,7 +790,12 @@ final class PhabricatorStartup {
|
||||||
}
|
}
|
||||||
|
|
||||||
$bucket[$user_identity] += $score;
|
$bucket[$user_identity] += $score;
|
||||||
apc_store($bucket_key, $bucket);
|
|
||||||
|
if ($is_apcu) {
|
||||||
|
apcu_store($bucket_key, $bucket);
|
||||||
|
} else {
|
||||||
|
apc_store($bucket_key, $bucket);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -761,11 +809,12 @@ final class PhabricatorStartup {
|
||||||
* @task ratelimit
|
* @task ratelimit
|
||||||
*/
|
*/
|
||||||
private static function canRateLimit() {
|
private static function canRateLimit() {
|
||||||
|
|
||||||
if (!self::$maximumRate) {
|
if (!self::$maximumRate) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!function_exists('apc_fetch')) {
|
if (!function_exists('apc_fetch') && !function_exists('apcu_fetch')) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -826,16 +875,26 @@ final class PhabricatorStartup {
|
||||||
* @task ratelimit
|
* @task ratelimit
|
||||||
*/
|
*/
|
||||||
private static function getRateLimitScore($user_identity) {
|
private static function getRateLimitScore($user_identity) {
|
||||||
|
$is_apcu = (bool)function_exists('apcu_fetch');
|
||||||
|
|
||||||
$min_key = self::getRateLimitMinKey();
|
$min_key = self::getRateLimitMinKey();
|
||||||
|
|
||||||
// Identify the oldest bucket stored in APC.
|
// Identify the oldest bucket stored in APC.
|
||||||
$cur = self::getRateLimitBucket();
|
$cur = self::getRateLimitBucket();
|
||||||
$min = apc_fetch($min_key);
|
if ($is_apcu) {
|
||||||
|
$min = apcu_fetch($min_key);
|
||||||
|
} else {
|
||||||
|
$min = apc_fetch($min_key);
|
||||||
|
}
|
||||||
|
|
||||||
// If we don't have any buckets stored yet, store the current bucket as
|
// If we don't have any buckets stored yet, store the current bucket as
|
||||||
// the oldest bucket.
|
// the oldest bucket.
|
||||||
if (!$min) {
|
if (!$min) {
|
||||||
apc_store($min_key, $cur);
|
if ($is_apcu) {
|
||||||
|
apcu_store($min_key, $cur);
|
||||||
|
} else {
|
||||||
|
apc_store($min_key, $cur);
|
||||||
|
}
|
||||||
$min = $cur;
|
$min = $cur;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -844,14 +903,25 @@ final class PhabricatorStartup {
|
||||||
// up an old bucket once per minute.
|
// up an old bucket once per minute.
|
||||||
$count = self::getRateLimitBucketCount();
|
$count = self::getRateLimitBucketCount();
|
||||||
for ($cursor = $min; $cursor < ($cur - $count); $cursor++) {
|
for ($cursor = $min; $cursor < ($cur - $count); $cursor++) {
|
||||||
apc_delete(self::getRateLimitBucketKey($cursor));
|
$bucket_key = self::getRateLimitBucketKey($cursor);
|
||||||
apc_store($min_key, $cursor + 1);
|
if ($is_apcu) {
|
||||||
|
apcu_delete($bucket_key);
|
||||||
|
apcu_store($min_key, $cursor + 1);
|
||||||
|
} else {
|
||||||
|
apc_delete($bucket_key);
|
||||||
|
apc_store($min_key, $cursor + 1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now, sum up the user's scores in all of the active buckets.
|
// Now, sum up the user's scores in all of the active buckets.
|
||||||
$score = 0;
|
$score = 0;
|
||||||
for (; $cursor <= $cur; $cursor++) {
|
for (; $cursor <= $cur; $cursor++) {
|
||||||
$bucket = apc_fetch(self::getRateLimitBucketKey($cursor));
|
$bucket_key = self::getRateLimitBucketKey($cursor);
|
||||||
|
if ($is_apcu) {
|
||||||
|
$bucket = apcu_fetch($bucket_key);
|
||||||
|
} else {
|
||||||
|
$bucket = apc_fetch($bucket_key);
|
||||||
|
}
|
||||||
if (isset($bucket[$user_identity])) {
|
if (isset($bucket[$user_identity])) {
|
||||||
$score += $bucket[$user_identity];
|
$score += $bucket[$user_identity];
|
||||||
}
|
}
|
||||||
|
@ -868,12 +938,11 @@ final class PhabricatorStartup {
|
||||||
* @return exit This method **does not return**.
|
* @return exit This method **does not return**.
|
||||||
* @task ratelimit
|
* @task ratelimit
|
||||||
*/
|
*/
|
||||||
private static function didRateLimit() {
|
private static function didRateLimit($user_identity, $score, $limit) {
|
||||||
$message =
|
$message =
|
||||||
"TOO MANY REQUESTS\n".
|
"TOO MANY REQUESTS\n".
|
||||||
"You are issuing too many requests too quickly.\n".
|
"You (\"{$user_identity}\") are issuing too many requests ".
|
||||||
"To adjust limits, see \"Configuring a Preamble Script\" in the ".
|
"too quickly.\n";
|
||||||
"documentation.";
|
|
||||||
|
|
||||||
header(
|
header(
|
||||||
'Content-Type: text/plain; charset=utf-8',
|
'Content-Type: text/plain; charset=utf-8',
|
||||||
|
|
|
@ -29,6 +29,10 @@
|
||||||
border-bottom: 1px solid {$thinblueborder};
|
border-bottom: 1px solid {$thinblueborder};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.phui-two-column-view .aphront-table-notice .phui-info-view {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
.aphront-table-view tr.alt {
|
.aphront-table-view tr.alt {
|
||||||
background: {$lightgreybackground};
|
background: {$lightgreybackground};
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,9 +61,10 @@ body.white-background {
|
||||||
}
|
}
|
||||||
|
|
||||||
.keyboard-focus-focus-reticle {
|
.keyboard-focus-focus-reticle {
|
||||||
background: #ffffd3;
|
background: rgba(255, 255, 211, 0.15);
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border: 1px solid #999900;
|
border: 1px solid {$yellow};
|
||||||
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
a.handle-status-closed {
|
a.handle-status-closed {
|
||||||
|
|
|
@ -2,16 +2,16 @@
|
||||||
* @provides phabricator-zindex-css
|
* @provides phabricator-zindex-css
|
||||||
*/
|
*/
|
||||||
|
|
||||||
.keyboard-focus-focus-reticle {
|
|
||||||
z-index: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.device .phabricator-action-list-view.phabricator-action-list-toggle,
|
.device .phabricator-action-list-view.phabricator-action-list-toggle,
|
||||||
.device-desktop .phui-document-content
|
.device-desktop .phui-document-content
|
||||||
.phabricator-action-list-view.phabricator-action-list-toggle {
|
.phabricator-action-list-view.phabricator-action-list-toggle {
|
||||||
z-index: 1;
|
z-index: 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.keyboard-focus-focus-reticle {
|
||||||
|
z-index: 2;
|
||||||
|
}
|
||||||
|
|
||||||
.device-desktop .phui-timeline-minor-event .phui-timeline-image {
|
.device-desktop .phui-timeline-minor-event .phui-timeline-image {
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
}
|
}
|
||||||
|
|
|
@ -302,6 +302,7 @@ ul.phui-oi-list-view {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
color: {$greytext};
|
color: {$greytext};
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
|
margin-right: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.phui-oi-attribute-spacer {
|
.phui-oi-attribute-spacer {
|
||||||
|
|
|
@ -74,7 +74,7 @@ body.printable {
|
||||||
a.button.phui-document-toc {
|
a.button.phui-document-toc {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
height: 16px;
|
height: 16px;
|
||||||
width: 16px;
|
width: 20px;
|
||||||
padding: 3px 8px 4px 8px;
|
padding: 3px 8px 4px 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +88,7 @@ a.button.phui-document-toc {
|
||||||
z-index: 30;
|
z-index: 30;
|
||||||
background-color: #fff;
|
background-color: #fff;
|
||||||
top: 52px;
|
top: 52px;
|
||||||
left: -44px;
|
left: -40px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.device .phui-document-view-pro .phui-document-toc {
|
.device .phui-document-view-pro .phui-document-toc {
|
||||||
|
|
|
@ -105,3 +105,11 @@
|
||||||
.phui-hovercard-tail a.button {
|
.phui-hovercard-tail a.button {
|
||||||
margin: 3px;
|
margin: 3px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.phui-hovercard-wrapper .hovercard-task-view {
|
||||||
|
box-shadow: 0px 4px 16px rgba(0,0,0,.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hovercard-task-view .phui-oi-disabled.phui-workcard {
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
|
@ -393,6 +393,12 @@ JX.behavior('phabricator-remarkup-assist', function(config) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Let other listeners (particularly the inline autocomplete) have a
|
||||||
|
// chance to handle this event.
|
||||||
|
if (JX.Stratcom.pass()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
var raw = e.getRawEvent();
|
var raw = e.getRawEvent();
|
||||||
if (raw.shiftKey) {
|
if (raw.shiftKey) {
|
||||||
// If the shift key is pressed, let the browser write a newline into
|
// If the shift key is pressed, let the browser write a newline into
|
||||||
|
@ -412,8 +418,7 @@ JX.behavior('phabricator-remarkup-assist', function(config) {
|
||||||
// This allows 'workflow' and similar actions to take effect.
|
// This allows 'workflow' and similar actions to take effect.
|
||||||
// Such as pontificate in Conpherence
|
// Such as pontificate in Conpherence
|
||||||
var form = e.getNode('tag:form');
|
var form = e.getNode('tag:form');
|
||||||
var r = JX.DOM.invoke(form, 'didSyntheticSubmit');
|
JX.DOM.invoke(form, 'didSyntheticSubmit');
|
||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -127,7 +127,7 @@ JX.install('PHUIXAutocomplete', {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get all the text on the current line. If the line only contains
|
// Get all the text on the current line. If the line only contains
|
||||||
// whitespace, don't actiavte: the user is probably typing code or a
|
// whitespace, don't activate: the user is probably typing code or a
|
||||||
// numbered list.
|
// numbered list.
|
||||||
var line = area.value.substring(0, head - 1);
|
var line = area.value.substring(0, head - 1);
|
||||||
line = line.split('\n');
|
line = line.split('\n');
|
||||||
|
@ -454,7 +454,7 @@ JX.install('PHUIXAutocomplete', {
|
||||||
|
|
||||||
// If the user hasn't typed any text yet after typing the character
|
// If the user hasn't typed any text yet after typing the character
|
||||||
// which can summon the autocomplete, deactivate and let the keystroke
|
// which can summon the autocomplete, deactivate and let the keystroke
|
||||||
// through. For example, We hit this when a line ends with an
|
// through. For example, we hit this when a line ends with an
|
||||||
// autocomplete character and the user is trying to type a newline.
|
// autocomplete character and the user is trying to type a newline.
|
||||||
if (range.start == this._cursorHead) {
|
if (range.start == this._cursorHead) {
|
||||||
this._deactivate();
|
this._deactivate();
|
||||||
|
@ -529,9 +529,13 @@ JX.install('PHUIXAutocomplete', {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deactivate immediately if the user types an ignored token like ":)",
|
||||||
|
// the smiley face emoticon. Note that we test against "text", not
|
||||||
|
// "trim", because the ignore list and suffix list can otherwise
|
||||||
|
// interact destructively.
|
||||||
var ignore = this._getIgnoreList();
|
var ignore = this._getIgnoreList();
|
||||||
for (ii = 0; ii < ignore.length; ii++) {
|
for (ii = 0; ii < ignore.length; ii++) {
|
||||||
if (trim.indexOf(ignore[ii]) === 0) {
|
if (text.indexOf(ignore[ii]) === 0) {
|
||||||
this._deactivate();
|
this._deactivate();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue