diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index ce345f6e52..c8c97ed5ec 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1,325 +1,327 @@ array( 'Aphront400Response' => 'aphront/response/400', 'Aphront404Response' => 'aphront/response/404', 'AphrontAjaxResponse' => 'aphront/response/ajax', 'AphrontApplicationConfiguration' => 'aphront/applicationconfiguration', 'AphrontController' => 'aphront/controller', 'AphrontDatabaseConnection' => 'storage/connection/base', 'AphrontDefaultApplicationConfiguration' => 'aphront/default/configuration', 'AphrontDefaultApplicationController' => 'aphront/default/controller', 'AphrontDialogResponse' => 'aphront/response/dialog', 'AphrontDialogView' => 'view/dialog', 'AphrontErrorView' => 'view/form/error', 'AphrontException' => 'aphront/exception/base', 'AphrontFileResponse' => 'aphront/response/file', 'AphrontFormCheckboxControl' => 'view/form/control/checkbox', 'AphrontFormControl' => 'view/form/control/base', 'AphrontFormFileControl' => 'view/form/control/file', 'AphrontFormMarkupControl' => 'view/form/control/markup', 'AphrontFormSelectControl' => 'view/form/control/select', 'AphrontFormStaticControl' => 'view/form/control/static', 'AphrontFormSubmitControl' => 'view/form/control/submit', 'AphrontFormTextAreaControl' => 'view/form/control/textarea', 'AphrontFormTextControl' => 'view/form/control/text', 'AphrontFormTokenizerControl' => 'view/form/control/tokenizer', 'AphrontFormView' => 'view/form/base', 'AphrontMySQLDatabaseConnection' => 'storage/connection/mysql', 'AphrontNullView' => 'view/null', 'AphrontPageView' => 'view/page/base', 'AphrontPanelView' => 'view/layout/panel', 'AphrontQueryConnectionException' => 'storage/exception/connection', 'AphrontQueryConnectionLostException' => 'storage/exception/connectionlost', 'AphrontQueryCountException' => 'storage/exception/count', 'AphrontQueryException' => 'storage/exception/base', 'AphrontQueryObjectMissingException' => 'storage/exception/objectmissing', 'AphrontQueryParameterException' => 'storage/exception/parameter', 'AphrontQueryRecoverableException' => 'storage/exception/recoverable', 'AphrontRedirectException' => 'aphront/exception/redirect', 'AphrontRedirectResponse' => 'aphront/response/redirect', 'AphrontRequest' => 'aphront/request', 'AphrontRequestFailureView' => 'view/page/failure', 'AphrontResponse' => 'aphront/response/base', 'AphrontSideNavView' => 'view/layout/sidenav', 'AphrontTableView' => 'view/control/table', 'AphrontURIMapper' => 'aphront/mapper', 'AphrontView' => 'view/base', 'AphrontWebpageResponse' => 'aphront/response/webpage', 'CelerityAPI' => 'infratructure/celerity/api', 'CelerityResourceController' => 'infratructure/celerity/controller', 'CelerityResourceMap' => 'infratructure/celerity/map', 'CelerityStaticResourceResponse' => 'infratructure/celerity/response', 'ConduitAPIMethod' => 'applications/conduit/method/base', 'ConduitAPIRequest' => 'applications/conduit/protocol/request', 'ConduitAPI_conduit_connect_Method' => 'applications/conduit/method/conduit/connect', 'ConduitAPI_differential_creatediff_Method' => 'applications/conduit/method/differential/creatediff', 'ConduitAPI_differential_setdiffproperty_Method' => 'applications/conduit/method/differential/setdiffproperty', 'ConduitAPI_file_upload_Method' => 'applications/conduit/method/file/upload', 'ConduitAPI_user_find_Method' => 'applications/conduit/method/user/find', 'ConduitException' => 'applications/conduit/protocol/exception', 'DifferentialAction' => 'applications/differential/constants/action', 'DifferentialAddCommentView' => 'applications/differential/view/addcomment', 'DifferentialCCWelcomeMail' => 'applications/differential/mail/ccwelcome', 'DifferentialChangeType' => 'applications/differential/constants/changetype', 'DifferentialChangeset' => 'applications/differential/storage/changeset', 'DifferentialChangesetDetailView' => 'applications/differential/view/changesetdetailview', 'DifferentialChangesetListView' => 'applications/differential/view/changesetlistview', 'DifferentialChangesetParser' => 'applications/differential/parser/changeset', 'DifferentialChangesetViewController' => 'applications/differential/controller/changesetview', 'DifferentialComment' => 'applications/differential/storage/comment', 'DifferentialCommentEditor' => 'applications/differential/editor/comment', 'DifferentialCommentMail' => 'applications/differential/mail/comment', 'DifferentialCommentSaveController' => 'applications/differential/controller/commentsave', 'DifferentialController' => 'applications/differential/controller/base', 'DifferentialDAO' => 'applications/differential/storage/base', 'DifferentialDiff' => 'applications/differential/storage/diff', 'DifferentialDiffContentMail' => 'applications/differential/mail/diffcontent', 'DifferentialDiffProperty' => 'applications/differential/storage/diffproperty', 'DifferentialDiffTableOfContentsView' => 'applications/differential/view/difftableofcontents', 'DifferentialDiffViewController' => 'applications/differential/controller/diffview', 'DifferentialHunk' => 'applications/differential/storage/hunk', 'DifferentialLintStatus' => 'applications/differential/constants/lintstatus', 'DifferentialMail' => 'applications/differential/mail/base', 'DifferentialMarkupEngineFactory' => 'applications/differential/parser/markup', 'DifferentialNewDiffMail' => 'applications/differential/mail/newdiff', 'DifferentialReviewRequestMail' => 'applications/differential/mail/reviewrequest', 'DifferentialRevision' => 'applications/differential/storage/revision', 'DifferentialRevisionCommentListView' => 'applications/differential/view/revisioncommentlist', 'DifferentialRevisionCommentView' => 'applications/differential/view/revisioncomment', 'DifferentialRevisionControlSystem' => 'applications/differential/constants/revisioncontrolsystem', 'DifferentialRevisionDetailView' => 'applications/differential/view/revisiondetail', 'DifferentialRevisionEditController' => 'applications/differential/controller/revisionedit', 'DifferentialRevisionEditor' => 'applications/differential/editor/revision', 'DifferentialRevisionListController' => 'applications/differential/controller/revisionlist', 'DifferentialRevisionListData' => 'applications/differential/data/revisionlist', 'DifferentialRevisionStatus' => 'applications/differential/constants/revisionstatus', 'DifferentialRevisionUpdateHistoryView' => 'applications/differential/view/revisionupdatehistory', 'DifferentialRevisionViewController' => 'applications/differential/controller/revisionview', 'DifferentialUnitStatus' => 'applications/differential/constants/unitstatus', 'Javelin' => 'infratructure/javelin/api', 'LiskDAO' => 'storage/lisk/dao', 'Phabricator404Controller' => 'applications/base/controller/404', 'PhabricatorAuthController' => 'applications/auth/controlller/base', 'PhabricatorConduitAPIController' => 'applications/conduit/controller/api', 'PhabricatorConduitConnectionLog' => 'applications/conduit/storage/connectionlog', 'PhabricatorConduitConsoleController' => 'applications/conduit/controller/console', 'PhabricatorConduitController' => 'applications/conduit/controller/base', 'PhabricatorConduitDAO' => 'applications/conduit/storage/base', 'PhabricatorConduitLogController' => 'applications/conduit/controller/log', 'PhabricatorConduitMethodCallLog' => 'applications/conduit/storage/methodcalllog', 'PhabricatorController' => 'applications/base/controller/base', 'PhabricatorDirectoryCategory' => 'applications/directory/storage/category', 'PhabricatorDirectoryCategoryDeleteController' => 'applications/directory/controller/categorydelete', 'PhabricatorDirectoryCategoryEditController' => 'applications/directory/controller/categoryedit', 'PhabricatorDirectoryCategoryListController' => 'applications/directory/controller/categorylist', 'PhabricatorDirectoryController' => 'applications/directory/controller/base', 'PhabricatorDirectoryDAO' => 'applications/directory/storage/base', 'PhabricatorDirectoryItem' => 'applications/directory/storage/item', 'PhabricatorDirectoryItemDeleteController' => 'applications/directory/controller/itemdelete', 'PhabricatorDirectoryItemEditController' => 'applications/directory/controller/itemedit', 'PhabricatorDirectoryItemListController' => 'applications/directory/controller/itemlist', 'PhabricatorDirectoryMainController' => 'applications/directory/controller/main', 'PhabricatorFile' => 'applications/files/storage/file', 'PhabricatorFileController' => 'applications/files/controller/base', 'PhabricatorFileDAO' => 'applications/files/storage/base', 'PhabricatorFileListController' => 'applications/files/controller/list', 'PhabricatorFileStorageBlob' => 'applications/files/storage/storageblob', 'PhabricatorFileURI' => 'applications/files/uri', 'PhabricatorFileUploadController' => 'applications/files/controller/upload', 'PhabricatorFileViewController' => 'applications/files/controller/view', 'PhabricatorLiskDAO' => 'applications/base/storage/lisk', 'PhabricatorLoginController' => 'applications/auth/controlller/login', + 'PhabricatorLogoutController' => 'applications/auth/controlller/logout', 'PhabricatorMailImplementationAdapter' => 'applications/metamta/adapter/base', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'applications/metamta/adapter/phpmailerlite', 'PhabricatorMetaMTAController' => 'applications/metamta/controller/base', 'PhabricatorMetaMTADAO' => 'applications/metamta/storage/base', 'PhabricatorMetaMTAListController' => 'applications/metamta/controller/list', 'PhabricatorMetaMTAMail' => 'applications/metamta/storage/mail', 'PhabricatorMetaMTAMailingList' => 'applications/metamta/storage/mailinglist', 'PhabricatorMetaMTAMailingListEditController' => 'applications/metamta/controller/mailinglistedit', 'PhabricatorMetaMTAMailingListsController' => 'applications/metamta/controller/mailinglists', 'PhabricatorMetaMTASendController' => 'applications/metamta/controller/send', 'PhabricatorMetaMTAViewController' => 'applications/metamta/controller/view', 'PhabricatorObjectHandle' => 'applications/phid/handle', 'PhabricatorObjectHandleData' => 'applications/phid/handle/data', 'PhabricatorPHID' => 'applications/phid/storage/phid', 'PhabricatorPHIDAllocateController' => 'applications/phid/controller/allocate', 'PhabricatorPHIDController' => 'applications/phid/controller/base', 'PhabricatorPHIDDAO' => 'applications/phid/storage/base', 'PhabricatorPHIDListController' => 'applications/phid/controller/list', 'PhabricatorPHIDLookupController' => 'applications/phid/controller/lookup', 'PhabricatorPHIDType' => 'applications/phid/storage/type', 'PhabricatorPHIDTypeEditController' => 'applications/phid/controller/typeedit', 'PhabricatorPHIDTypeListController' => 'applications/phid/controller/typelist', 'PhabricatorPeopleController' => 'applications/people/controller/base', 'PhabricatorPeopleEditController' => 'applications/people/controller/edit', 'PhabricatorPeopleListController' => 'applications/people/controller/list', 'PhabricatorPeopleProfileController' => 'applications/people/controller/profile', 'PhabricatorStandardPageView' => 'view/page/standard', 'PhabricatorTypeaheadCommonDatasourceController' => 'applications/typeahead/controller/common', 'PhabricatorTypeaheadDatasourceController' => 'applications/typeahead/controller/base', 'PhabricatorUser' => 'applications/people/storage/user', 'PhabricatorUserDAO' => 'applications/people/storage/base', ), 'function' => array( '_qsprintf_check_scalar_type' => 'storage/qsprintf', '_qsprintf_check_type' => 'storage/qsprintf', 'celerity_generate_unique_node_id' => 'infratructure/celerity/api', 'celerity_register_resource_map' => 'infratructure/celerity/map', 'javelin_render_tag' => 'infratructure/javelin/markup', 'phabricator_format_relative_time' => 'view/utils', 'phabricator_format_timestamp' => 'view/utils', 'phabricator_format_units_generic' => 'view/utils', 'qsprintf' => 'storage/qsprintf', 'queryfx' => 'storage/queryfx', 'queryfx_all' => 'storage/queryfx', 'queryfx_one' => 'storage/queryfx', 'require_celerity_resource' => 'infratructure/celerity/api', 'vqsprintf' => 'storage/qsprintf', 'vqueryfx' => 'storage/queryfx', 'vqueryfx_all' => 'storage/queryfx', 'xsprintf_query' => 'storage/qsprintf', ), 'requires_class' => array( 'Aphront400Response' => 'AphrontResponse', 'Aphront404Response' => 'AphrontResponse', 'AphrontAjaxResponse' => 'AphrontResponse', 'AphrontDefaultApplicationConfiguration' => 'AphrontApplicationConfiguration', 'AphrontDefaultApplicationController' => 'AphrontController', 'AphrontDialogResponse' => 'AphrontResponse', 'AphrontDialogView' => 'AphrontView', 'AphrontErrorView' => 'AphrontView', 'AphrontFileResponse' => 'AphrontResponse', 'AphrontFormCheckboxControl' => 'AphrontFormControl', 'AphrontFormControl' => 'AphrontView', 'AphrontFormFileControl' => 'AphrontFormControl', 'AphrontFormMarkupControl' => 'AphrontFormControl', 'AphrontFormSelectControl' => 'AphrontFormControl', 'AphrontFormStaticControl' => 'AphrontFormControl', 'AphrontFormSubmitControl' => 'AphrontFormControl', 'AphrontFormTextAreaControl' => 'AphrontFormControl', 'AphrontFormTextControl' => 'AphrontFormControl', 'AphrontFormTokenizerControl' => 'AphrontFormControl', 'AphrontFormView' => 'AphrontView', 'AphrontMySQLDatabaseConnection' => 'AphrontDatabaseConnection', 'AphrontNullView' => 'AphrontView', 'AphrontPageView' => 'AphrontView', 'AphrontPanelView' => 'AphrontView', 'AphrontQueryConnectionException' => 'AphrontQueryException', 'AphrontQueryConnectionLostException' => 'AphrontQueryRecoverableException', 'AphrontQueryCountException' => 'AphrontQueryException', 'AphrontQueryObjectMissingException' => 'AphrontQueryException', 'AphrontQueryParameterException' => 'AphrontQueryException', 'AphrontQueryRecoverableException' => 'AphrontQueryException', 'AphrontRedirectException' => 'AphrontException', 'AphrontRedirectResponse' => 'AphrontResponse', 'AphrontRequestFailureView' => 'AphrontView', 'AphrontSideNavView' => 'AphrontView', 'AphrontTableView' => 'AphrontView', 'AphrontWebpageResponse' => 'AphrontResponse', 'CelerityResourceController' => 'AphrontController', 'ConduitAPI_conduit_connect_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_creatediff_Method' => 'ConduitAPIMethod', 'ConduitAPI_differential_setdiffproperty_Method' => 'ConduitAPIMethod', 'ConduitAPI_file_upload_Method' => 'ConduitAPIMethod', 'ConduitAPI_user_find_Method' => 'ConduitAPIMethod', 'DifferentialAddCommentView' => 'AphrontView', 'DifferentialCCWelcomeMail' => 'DifferentialReviewRequestMail', 'DifferentialChangeset' => 'DifferentialDAO', 'DifferentialChangesetDetailView' => 'AphrontView', 'DifferentialChangesetListView' => 'AphrontView', 'DifferentialChangesetViewController' => 'DifferentialController', 'DifferentialComment' => 'DifferentialDAO', 'DifferentialCommentMail' => 'DifferentialMail', 'DifferentialCommentSaveController' => 'DifferentialController', 'DifferentialController' => 'PhabricatorController', 'DifferentialDAO' => 'PhabricatorLiskDAO', 'DifferentialDiff' => 'DifferentialDAO', 'DifferentialDiffContentMail' => 'DifferentialMail', 'DifferentialDiffProperty' => 'DifferentialDAO', 'DifferentialDiffTableOfContentsView' => 'AphrontView', 'DifferentialDiffViewController' => 'DifferentialController', 'DifferentialHunk' => 'DifferentialDAO', 'DifferentialNewDiffMail' => 'DifferentialReviewRequestMail', 'DifferentialReviewRequestMail' => 'DifferentialMail', 'DifferentialRevision' => 'DifferentialDAO', 'DifferentialRevisionCommentListView' => 'AphrontView', 'DifferentialRevisionCommentView' => 'AphrontView', 'DifferentialRevisionDetailView' => 'AphrontView', 'DifferentialRevisionEditController' => 'DifferentialController', 'DifferentialRevisionListController' => 'DifferentialController', 'DifferentialRevisionUpdateHistoryView' => 'AphrontView', 'DifferentialRevisionViewController' => 'DifferentialController', 'Phabricator404Controller' => 'PhabricatorController', 'PhabricatorAuthController' => 'PhabricatorController', 'PhabricatorConduitAPIController' => 'PhabricatorConduitController', 'PhabricatorConduitConnectionLog' => 'PhabricatorConduitDAO', 'PhabricatorConduitConsoleController' => 'PhabricatorConduitController', 'PhabricatorConduitController' => 'PhabricatorController', 'PhabricatorConduitDAO' => 'PhabricatorLiskDAO', 'PhabricatorConduitLogController' => 'PhabricatorConduitController', 'PhabricatorConduitMethodCallLog' => 'PhabricatorConduitDAO', 'PhabricatorController' => 'AphrontController', 'PhabricatorDirectoryCategory' => 'PhabricatorDirectoryDAO', 'PhabricatorDirectoryCategoryDeleteController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryCategoryEditController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryCategoryListController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryController' => 'PhabricatorController', 'PhabricatorDirectoryDAO' => 'PhabricatorLiskDAO', 'PhabricatorDirectoryItem' => 'PhabricatorDirectoryDAO', 'PhabricatorDirectoryItemDeleteController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryItemEditController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryItemListController' => 'PhabricatorDirectoryController', 'PhabricatorDirectoryMainController' => 'PhabricatorDirectoryController', 'PhabricatorFile' => 'PhabricatorFileDAO', 'PhabricatorFileController' => 'PhabricatorController', 'PhabricatorFileDAO' => 'PhabricatorLiskDAO', 'PhabricatorFileListController' => 'PhabricatorFileController', 'PhabricatorFileStorageBlob' => 'PhabricatorFileDAO', 'PhabricatorFileUploadController' => 'PhabricatorFileController', 'PhabricatorFileViewController' => 'PhabricatorFileController', 'PhabricatorLiskDAO' => 'LiskDAO', 'PhabricatorLoginController' => 'PhabricatorAuthController', + 'PhabricatorLogoutController' => 'PhabricatorAuthController', 'PhabricatorMailImplementationPHPMailerLiteAdapter' => 'PhabricatorMailImplementationAdapter', 'PhabricatorMetaMTAController' => 'PhabricatorController', 'PhabricatorMetaMTADAO' => 'PhabricatorLiskDAO', 'PhabricatorMetaMTAListController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAMail' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTAMailingList' => 'PhabricatorMetaMTADAO', 'PhabricatorMetaMTAMailingListEditController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAMailingListsController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTASendController' => 'PhabricatorMetaMTAController', 'PhabricatorMetaMTAViewController' => 'PhabricatorMetaMTAController', 'PhabricatorPHID' => 'PhabricatorPHIDDAO', 'PhabricatorPHIDAllocateController' => 'PhabricatorPHIDController', 'PhabricatorPHIDController' => 'PhabricatorController', 'PhabricatorPHIDDAO' => 'PhabricatorLiskDAO', 'PhabricatorPHIDListController' => 'PhabricatorPHIDController', 'PhabricatorPHIDLookupController' => 'PhabricatorPHIDController', 'PhabricatorPHIDType' => 'PhabricatorPHIDDAO', 'PhabricatorPHIDTypeEditController' => 'PhabricatorPHIDController', 'PhabricatorPHIDTypeListController' => 'PhabricatorPHIDController', 'PhabricatorPeopleController' => 'PhabricatorController', 'PhabricatorPeopleEditController' => 'PhabricatorPeopleController', 'PhabricatorPeopleListController' => 'PhabricatorPeopleController', 'PhabricatorPeopleProfileController' => 'PhabricatorPeopleController', 'PhabricatorStandardPageView' => 'AphrontPageView', 'PhabricatorTypeaheadCommonDatasourceController' => 'PhabricatorTypeaheadDatasourceController', 'PhabricatorTypeaheadDatasourceController' => 'PhabricatorController', 'PhabricatorUser' => 'PhabricatorUserDAO', 'PhabricatorUserDAO' => 'PhabricatorLiskDAO', ), 'requires_interface' => array( ), )); diff --git a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php index 4344d37c7e..5082398cd4 100644 --- a/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php +++ b/src/aphront/default/configuration/AphrontDefaultApplicationConfiguration.php @@ -1,186 +1,187 @@ array( '$' => 'RepositoryListController', 'new/$' => 'RepositoryEditController', 'edit/(?\d+)/$' => 'RepositoryEditController', 'delete/(?\d+)/$' => 'RepositoryDeleteController', ), '/' => array( '$' => 'PhabricatorDirectoryMainController', ), '/directory/' => array( 'item/$' => 'PhabricatorDirectoryItemListController', 'item/edit/(?:(?\d+)/)?$' => 'PhabricatorDirectoryItemEditController', 'item/delete/(?\d+)/' => 'PhabricatorDirectoryItemDeleteController', 'category/$' => 'PhabricatorDirectoryCategoryListController', 'category/edit/(?:(?\d+)/)?$' => 'PhabricatorDirectoryCategoryEditController', 'category/delete/(?\d+)/' => 'PhabricatorDirectoryCategoryDeleteController', ), '/file/' => array( '$' => 'PhabricatorFileListController', 'upload/$' => 'PhabricatorFileUploadController', '(?info)/(?[^/]+)/' => 'PhabricatorFileViewController', '(?view)/(?[^/]+)/' => 'PhabricatorFileViewController', '(?download)/(?[^/]+)/' => 'PhabricatorFileViewController', ), '/phid/' => array( '$' => 'PhabricatorPHIDLookupController', 'list/$' => 'PhabricatorPHIDListController', 'type/$' => 'PhabricatorPHIDTypeListController', 'type/edit/(?:(?\d+)/)?$' => 'PhabricatorPHIDTypeEditController', 'new/$' => 'PhabricatorPHIDAllocateController', ), '/people/' => array( '$' => 'PhabricatorPeopleListController', 'edit/(?:(?\w+)/)?$' => 'PhabricatorPeopleEditController', ), '/p/(?\w+)/$' => 'PhabricatorPeopleProfileController', '/conduit/' => array( '$' => 'PhabricatorConduitConsoleController', 'method/(?[^/]+)$' => 'PhabricatorConduitConsoleController', 'log/$' => 'PhabricatorConduitLogController', ), '/api/(?[^/]+)$' => 'PhabricatorConduitAPIController', '/D(?\d+)' => 'DifferentialRevisionViewController', '/differential/' => array( '$' => 'DifferentialRevisionListController', 'filter/(?\w+)/$' => 'DifferentialRevisionListController', 'diff/(?\d+)/$' => 'DifferentialDiffViewController', 'changeset/(?\d+)/$' => 'DifferentialChangesetViewController', 'revision/edit/(?:(?\d+)/)?$' => 'DifferentialRevisionEditController', 'comment/' => array( 'preview/$' => 'DifferentialCommentPreviewController', 'save/$' => 'DifferentialCommentSaveController', 'inline/' => array( 'preview/$' => 'DifferentialInlineCommentPreviewController', 'edit/$' => 'DifferentialInlineCommentEditController', ), ), ), '/res/' => array( '(?pkg/)?(?[a-f0-9]{8})/(?.+\.(?:css|js))$' => 'CelerityResourceController', ), '/typeahead/' => array( 'common/(?\w+)/$' => 'PhabricatorTypeaheadCommonDatasourceController', ), '/mail/' => array( '$' => 'PhabricatorMetaMTAListController', 'send/$' => 'PhabricatorMetaMTASendController', 'view/(?\d+)/$' => 'PhabricatorMetaMTAViewController', 'lists/$' => 'PhabricatorMetaMTAMailingListsController', 'lists/edit/(?:(?\d+)/)?$' => 'PhabricatorMetaMTAMailingListEditController', ), '/login/' => 'PhabricatorLoginController', + '/logout/' => 'PhabricatorLogoutController', ); } public function buildRequest() { $request = new AphrontRequest($this->getHost(), $this->getPath()); $request->setRequestData($_GET + $_POST); return $request; } public function handleException(Exception $ex) { $class = phutil_escape_html(get_class($ex)); $message = phutil_escape_html($ex->getMessage()); $content = '
'. '

Unhandled Exception "'.$class.'": '.$message.'

'. ''.phutil_escape_html((string)$ex).''. '
'; $view = new PhabricatorStandardPageView(); $view->appendChild($content); $response = new AphrontWebpageResponse(); $response->setContent($view->render()); return $response; } public function willSendResponse(AphrontResponse $response) { $request = $this->getRequest(); if ($response instanceof AphrontDialogResponse) { if (!$request->isAjax()) { $view = new PhabricatorStandardPageView(); $view->appendChild( '
'. $response->buildResponseString(). '
'); $response = new AphrontWebpageResponse(); $response->setContent($view->render()); return $response; } } else if ($response instanceof Aphront404Response) { $failure = new AphrontRequestFailureView(); $failure->setHeader('404 Not Found'); $failure->appendChild( '

The page you requested was not found.

'); $view = new PhabricatorStandardPageView(); $view->setTitle('404 Not Found'); $view->appendChild($failure); $response = new AphrontWebpageResponse(); $response->setContent($view->render()); $response->setHTTPResponseCode(404); return $response; } return $response; } public function build404Controller() { return array(new Phabricator404Controller($this->getRequest()), array()); } } diff --git a/src/aphront/request/AphrontRequest.php b/src/aphront/request/AphrontRequest.php index 4ea9114b8e..6cc50fa2f5 100644 --- a/src/aphront/request/AphrontRequest.php +++ b/src/aphront/request/AphrontRequest.php @@ -1,125 +1,127 @@ host = $host; $this->path = $path; } final public function setRequestData(array $request_data) { $this->requestData = $request_data; return $this; } final public function getPath() { return $this->path; } final public function getHost() { return $this->host; } final public function getInt($name, $default = null) { if (isset($this->requestData[$name])) { return (int)$this->requestData[$name]; } else { return $default; } } final public function getStr($name, $default = null) { if (isset($this->requestData[$name])) { return (string)$this->requestData[$name]; } else { return $default; } } final public function getArr($name, $default = array()) { if (isset($this->requestData[$name]) && is_array($this->requestData[$name])) { return $this->requestData[$name]; } else { return $default; } } final public function getExists($name) { return array_key_exists($name, $this->requestData); } final public function isHTTPPost() { return ($_SERVER['REQUEST_METHOD'] == 'POST'); } final public function isAjax() { return $this->getExists(self::TYPE_AJAX); } final public function isFormPost() { - return $this->getExists(self::TYPE_FORM) && $this->isHTTPPost(); + return $this->getExists(self::TYPE_FORM) && + $this->isHTTPPost() && + $this->getUser()->validateCSRFToken($this->getStr('__csrf__')); } final public function getCookie($name, $default = null) { return idx($_COOKIE, $name, $default); } final public function clearCookie($name) { $this->setCookie($name, '', time() - (60 * 60 * 24 * 30)); } final public function setCookie($name, $value, $expire = null) { if ($expire === null) { $expire = time() + (60 * 60 * 24 * 365 * 5); } setcookie( $name, $value, $expire, $path = '/', $domain = '', $secure = false, $http_only = true); } final public function setUser($user) { $this->user = $user; return $this; } final public function getUser() { return $this->user; } } diff --git a/src/applications/auth/controlller/login/PhabricatorLoginController.php b/src/applications/auth/controlller/login/PhabricatorLoginController.php index 914531230c..3d8536e8d3 100644 --- a/src/applications/auth/controlller/login/PhabricatorLoginController.php +++ b/src/applications/auth/controlller/login/PhabricatorLoginController.php @@ -1,122 +1,123 @@ getRequest(); $error = false; - $login_name = $request->getCookie('phu'); + $login_name = $request->getCookie('phusr'); if ($request->isFormPost()) { $login_name = $request->getStr('login'); $user = id(new PhabricatorUser())->loadOneWhere( 'username = %s', $login_name); $user->setPassword('asdf'); $user->save(); $okay = false; if ($user) { if ($user->comparePassword($request->getStr('password'))) { $conn_w = $user->establishConnection('w'); $urandom = fopen('/dev/urandom', 'r'); if (!$urandom) { throw new Exception("Failed to open /dev/urandom!"); } $entropy = fread($urandom, 20); if (strlen($entropy) != 20) { throw new Exception("Failed to read /dev/urandom!"); } $session_key = sha1($entropy); queryfx( $conn_w, 'INSERT INTO phabricator_session '. '(userPHID, type, sessionKey, sessionStart)'. ' VALUES '. '(%s, %s, %s, UNIX_TIMESTAMP()) '. 'ON DUPLICATE KEY UPDATE '. 'sessionKey = VALUES(sessionKey), '. 'sessionStart = VALUES(sessionStart)', $user->getPHID(), 'web', $session_key); $request->setCookie('phusr', $user->getUsername()); $request->setCookie('phsid', $session_key); return id(new AphrontRedirectResponse()) ->setURI('/'); } } if (!$okay) { $request->clearCookie('phusr'); $request->clearCookie('phsid'); } $error = true; } $error_view = null; if ($error) { $error_view = new AphrontErrorView(); $error_view->setTitle('Bad username/password.'); } $form = new AphrontFormView(); $form + ->setUser($request->getUser()) ->setAction('/login/') ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Login') ->setName('login') ->setValue($login_name)) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Password') ->setName('password')) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Login')); $panel = new AphrontPanelView(); $panel->setHeader('Phabricator Login'); $panel->setWidth(AphrontPanelView::WIDTH_FORM); $panel->appendChild($form); return $this->buildStandardPageResponse( array( $error_view, $panel, ), array( 'title' => 'Login', )); } } diff --git a/src/applications/auth/controlller/logout/PhabricatorLogoutController.php b/src/applications/auth/controlller/logout/PhabricatorLogoutController.php new file mode 100644 index 0000000000..7570c251b5 --- /dev/null +++ b/src/applications/auth/controlller/logout/PhabricatorLogoutController.php @@ -0,0 +1,37 @@ +getRequest(); + + if ($request->isFormPost()) { + $request->clearCookie('phsid'); + return id(new AphrontRedirectResponse()) + ->setURI('/login/'); + } + + return id(new AphrontRedirectResponse())->setURI('/'); + } + +} diff --git a/src/applications/auth/controlller/logout/__init__.php b/src/applications/auth/controlller/logout/__init__.php new file mode 100644 index 0000000000..4665a47f1f --- /dev/null +++ b/src/applications/auth/controlller/logout/__init__.php @@ -0,0 +1,15 @@ +method = idx($data, 'method'); } public function processRequest() { + + $request = $this->getRequest(); + $methods = $this->getAllMethods(); if (empty($methods[$this->method])) { $this->method = key($methods); } $method_class = $methods[$this->method]; PhutilSymbolLoader::loadClass($method_class); $method_object = newv($method_class, array()); $error_description = array(); $error_types = $method_object->defineErrorTypes(); if ($error_types) { $error_description[] = '
    '; foreach ($error_types as $error => $meaning) { $error_description[] = '
  • '. ''.phutil_escape_html($error).': '. phutil_escape_html($meaning). '
  • '; } $error_description[] = '
'; $error_description = implode("\n", $error_description); } else { $error_description = "This method does not raise any specific errors."; } $form = new AphrontFormView(); $form + ->setUser($request->getUser()) ->setAction('/api/'.$this->method) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel('Description') ->setValue($method_object->getMethodDescription())) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel('Returns') ->setValue($method_object->defineReturnType())) ->appendChild( id(new AphrontFormMarkupControl()) ->setLabel('Errors') ->setValue($error_description)) ->appendChild( '

Enter parameters using '. 'JSON. For instance, to enter a list, type: '. '["apple", "banana", "cherry"]'); $params = $method_object->defineParamTypes(); foreach ($params as $param => $desc) { $form->appendChild( id(new AphrontFormTextControl()) ->setLabel($param) ->setName("params[{$param}]") ->setCaption($desc)); } $form ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Output Format') ->setName('output') ->setOptions( array( 'human' => 'Human Readable', 'json' => 'JSON', ))) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Call Method')); $panel = new AphrontPanelView(); $panel->setHeader('Conduit API: '.phutil_escape_html($this->method)); $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_WIDE); $view = new AphrontSideNavView(); foreach ($this->buildNavItems() as $item) { $view->addNavItem($item); } $view->appendChild($panel); return $this->buildStandardPageResponse( array($view), array( 'title' => 'Conduit Console', 'tab' => 'console', )); } private function buildNavItems() { $classes = $this->getAllMethodImplementationClasses(); $method_names = array(); foreach ($classes as $method_class) { $method_name = ConduitAPIMethod::getAPIMethodNameFromClassName( $method_class); $method_names[] = array( 'full_name' => $method_name, 'group_name' => reset(explode('.', $method_name)), ); } $method_names = igroup($method_names, 'group_name'); ksort($method_names); $items = array(); foreach ($method_names as $group => $methods) { $items[] = phutil_render_tag( 'a', array( ), phutil_escape_html($group)); foreach ($methods as $method) { $method_name = $method['full_name']; $selected = ($method_name == $this->method); $items[] = phutil_render_tag( 'a', array( 'class' => $selected ? 'aphront-side-nav-selected' : null, 'href' => '/conduit/method/'.$method_name, ), ''. phutil_escape_html($method_name). ''); } $items[] = '


'; } // Pop off the last '
'. array_pop($items); return $items; } private function getAllMethods() { $classes = $this->getAllMethodImplementationClasses(); $methods = array(); foreach ($classes as $class) { $name = ConduitAPIMethod::getAPIMethodNameFromClassName($class); $methods[$name] = $class; } return $methods; } private function getAllMethodImplementationClasses() { $classes = id(new PhutilSymbolLoader()) ->setAncestorClass('ConduitAPIMethod') ->setType('class') ->selectSymbolsWithoutLoading(); return array_values(ipull($classes, 'name')); } } diff --git a/src/applications/differential/controller/diffview/DifferentialDiffViewController.php b/src/applications/differential/controller/diffview/DifferentialDiffViewController.php index 2e686d1a16..db37db9308 100644 --- a/src/applications/differential/controller/diffview/DifferentialDiffViewController.php +++ b/src/applications/differential/controller/diffview/DifferentialDiffViewController.php @@ -1,86 +1,89 @@ id = $data['id']; } public function processRequest() { + $request = $this->getRequest(); + $diff = id(new DifferentialDiff())->load($this->id); if (!$diff) { return new Aphront404Response(); } $action_panel = new AphrontPanelView(); $action_panel->setHeader('Preview Diff'); $action_panel->setWidth(AphrontPanelView::WIDTH_WIDE); $action_panel->appendChild( '

Review the diff for correctness. '. 'When you are satisfied, either create a new revision '. 'or update an existing revision.'); $action_form = new AphrontFormView(); $action_form + ->setUser($request->getUser()) ->setAction('/differential/revision/edit/') ->addHiddenInput('diffID', $diff->getID()) ->addHiddenInput('viaDiffView', 1) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Attach To') ->setName('revisionID') ->setValue('') ->setOptions(array( '' => "Create a new Revision...", ))) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Continue')); $action_panel->appendChild($action_form); $changesets = $diff->loadChangesets(); $changesets = msort($changesets, 'getSortKey'); $table_of_contents = id(new DifferentialDiffTableOfContentsView()) ->setChangesets($changesets); $details = id(new DifferentialChangesetListView()) ->setChangesets($changesets); return $this->buildStandardPageResponse( '

'. implode( "\n", array( $action_panel->render(), $table_of_contents->render(), $details->render(), )). '
', array( 'title' => 'Diff View', )); } } diff --git a/src/applications/differential/controller/revisionedit/DifferentialRevisionEditController.php b/src/applications/differential/controller/revisionedit/DifferentialRevisionEditController.php index f767cba6c4..d26e3442c1 100644 --- a/src/applications/differential/controller/revisionedit/DifferentialRevisionEditController.php +++ b/src/applications/differential/controller/revisionedit/DifferentialRevisionEditController.php @@ -1,192 +1,193 @@ id = idx($data, 'id'); } public function processRequest() { if ($this->id) { $revision = id(new DifferentialRevision())->load($this->id); if (!$revision) { return new Aphront404Response(); } } else { $revision = new DifferentialRevision(); } $request = $this->getRequest(); $diff_id = $request->getInt('diffID'); if ($diff_id) { $diff = id(new DifferentialDiff())->load($diff_id); if (!$diff) { return new Aphront404Response(); } if ($diff->getRevisionID()) { // TODO: Redirect? throw new Exception("This diff is already attached to a revision!"); } } else { $diff = null; } $e_title = true; $e_testplan = true; $errors = array(); if ($request->isFormPost() && !$request->getStr('viaDiffView')) { $revision->setTitle($request->getStr('title')); $revision->setSummary($request->getStr('summary')); $revision->setTestPlan($request->getStr('testplan')); $revision->setBlameRevision($request->getStr('blame')); $revision->setRevertPlan($request->getStr('revert')); if (!strlen(trim($revision->getTitle()))) { $errors[] = 'You must provide a title.'; $e_title = 'Required'; } if (!strlen(trim($revision->getTestPlan()))) { $errors[] = 'You must provide a test plan.'; $e_testplan = 'Required'; } $user_phid = $request->getUser()->getPHID(); if (in_array($user_phid, $request->getArr('reviewers'))) { $errors[] = 'You may not review your own revision.'; } if (!$errors) { $editor = new DifferentialRevisionEditor($revision, $user_phid); if ($diff) { $editor->addDiff($diff, $request->getStr('comments')); } $editor->setCCPHIDs($request->getArr('cc')); $editor->setReviewers($request->getArr('reviewers')); $editor->save(); return id(new AphrontRedirectResponse()) ->setURI('/D'.$revision->getID()); } $reviewer_phids = $request->getArr('reviewers'); $cc_phids = $request->getArr('cc'); } else { // $reviewer_phids = $revision->getReviewers(); // $cc_phids = $revision->getCCPHIDs(); $reviewer_phids = array(); $cc_phids = array(); } $form = new AphrontFormView(); + $form->setUser($request->getUser()); if ($diff) { $form->addHiddenInput('diffID', $diff->getID()); } if ($revision->getID()) { $form->setAction('/differential/revision/edit/'.$revision->getID().'/'); } else { $form->setAction('/differential/revision/edit/'); } $error_view = null; if ($errors) { $error_view = id(new AphrontErrorView()) ->setTitle('Form Errors') ->setErrors($errors); } $form ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel('Title') ->setName('title') ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT) ->setValue($revision->getTitle()) ->setError($e_title)) ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel('Summary') ->setName('summary') ->setValue($revision->getSummary())) ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel('Test Plan') ->setName('testplan') ->setValue($revision->getTestPlan()) ->setError($e_testplan)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel('Reviewers') ->setName('reviewers') ->setDatasource('/typeahead/common/users/') ->setValue($reviewer_map)) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel('CC') ->setName('cc') ->setDatasource('/typeahead/common/mailable/') ->setValue($reviewer_map)) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Blame Revision') ->setName('blame') ->setValue($revision->getBlameRevision()) ->setCaption('Revision which broke the stuff which this '. 'change fixes.')) ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel('Revert Plan') ->setName('revert') ->setValue($revision->getRevertPlan()) ->setCaption('Special steps required to safely revert this change.')); $submit = id(new AphrontFormSubmitControl()) ->setValue('Save'); if ($diff) { $submit->addCancelButton('/differential/diff/'.$diff->getID().'/'); } else { $submit->addCancelButton('/D'.$revision->getID()); } $form->appendChild($submit); $panel = new AphrontPanelView(); if ($revision->getID()) { $panel->setHeader('Edit Differential Revision'); } else { $panel->setHeader('Create New Differential Revision'); } $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_FORM); return $this->buildStandardPageResponse( array($error_view, $panel), array( 'title' => 'Edit Differential Revision', )); } } diff --git a/src/applications/differential/controller/revisionview/DifferentialRevisionViewController.php b/src/applications/differential/controller/revisionview/DifferentialRevisionViewController.php index 1e55f8c825..ef077224d0 100644 --- a/src/applications/differential/controller/revisionview/DifferentialRevisionViewController.php +++ b/src/applications/differential/controller/revisionview/DifferentialRevisionViewController.php @@ -1,1728 +1,1729 @@ revisionID = $data['id']; } public function processRequest() { $request = $this->getRequest(); $revision = id(new DifferentialRevision())->load($this->revisionID); if (!$revision) { return new Aphront404Response(); } $revision->loadRelationships(); $diffs = $revision->loadDiffs(); $target = end($diffs); $changesets = $target->loadChangesets(); $comments = $revision->loadComments(); $comments = array_merge( $this->getImplicitComments($revision), $comments); $object_phids = array_merge( $revision->getReviewers(), $revision->getCCPHIDs(), array( $revision->getAuthorPHID(), $request->getUser()->getPHID(), ), mpull($comments, 'getAuthorPHID')); $handles = id(new PhabricatorObjectHandleData($object_phids)) ->loadHandles(); $revision_detail = new DifferentialRevisionDetailView(); $revision_detail->setRevision($revision); $properties = $this->getRevisionProperties($revision, $target, $handles); $revision_detail->setProperties($properties); $actions = $this->getRevisionActions($revision); $revision_detail->setActions($actions); $comment_view = new DifferentialRevisionCommentListView(); $comment_view->setComments($comments); $comment_view->setHandles($handles); $diff_history = new DifferentialRevisionUpdateHistoryView(); $diff_history->setDiffs($diffs); $toc_view = new DifferentialDiffTableOfContentsView(); $toc_view->setChangesets($changesets); $changeset_view = new DifferentialChangesetListView(); $changeset_view->setChangesets($changesets); $comment_form = new DifferentialAddCommentView(); $comment_form->setRevision($revision); $comment_form->setActions($this->getRevisionCommentActions($revision)); $comment_form->setActionURI('/differential/comment/save/'); + $comment_form->setUser($request->getUser()); return $this->buildStandardPageResponse( '
'. $revision_detail->render(). $comment_view->render(). $diff_history->render(). $toc_view->render(). $changeset_view->render(). $comment_form->render(). '
', array( 'title' => $revision->getTitle(), )); } private function getImplicitComments(DifferentialRevision $revision) { $template = new DifferentialComment(); $template->setAuthorPHID($revision->getAuthorPHID()); $template->setRevisionID($revision->getID()); $template->setDateCreated($revision->getDateCreated()); $comments = array(); if (strlen($revision->getSummary())) { $summary_comment = clone $template; $summary_comment->setContent($revision->getSummary()); $summary_comment->setAction(DifferentialAction::ACTION_SUMMARIZE); $comments[] = $summary_comment; } if (strlen($revision->getTestPlan())) { $testplan_comment = clone $template; $testplan_comment->setContent($revision->getTestPlan()); $testplan_comment->setAction(DifferentialAction::ACTION_TESTPLAN); $comments[] = $testplan_comment; } return $comments; } private function getRevisionProperties( DifferentialRevision $revision, DifferentialDiff $diff, array $handles) { $properties = array(); $status = $revision->getStatus(); $status = DifferentialRevisionStatus::getNameForRevisionStatus($status); $properties['Revision Status'] = ''.$status.''; $author = $handles[$revision->getAuthorPHID()]; $properties['Author'] = $author->renderLink(); $properties['Reviewers'] = $this->renderHandleLinkList( array_select_keys( $handles, $revision->getReviewers())); $properties['CCs'] = $this->renderHandleLinkList( array_select_keys( $handles, $revision->getCCPHIDs())); $path = $diff->getSourcePath(); if ($path) { $branch = $diff->getBranch() ? ' (' . $diff->getBranch() . ')' : ''; $host = $diff->getSourceMachine(); if ($host) { $host .= ':'; } $properties['Path'] = phutil_escape_html("{$host}{$path} {$branch}"); } $properties['Lint'] = 'TODO'; $properties['Unit'] = 'TODO'; return $properties; } private function getRevisionActions(DifferentialRevision $revision) { $viewer_phid = $this->getRequest()->getUser()->getPHID(); $viewer_is_owner = ($revision->getAuthorPHID() == $viewer_phid); $viewer_is_reviewer = in_array($viewer_phid, $revision->getReviewers()); $viewer_is_cc = in_array($viewer_phid, $revision->getCCPHIDs()); $status = $revision->getStatus(); $revision_id = $revision->getID(); $revision_phid = $revision->getPHID(); $links = array(); if ($viewer_is_owner) { $links[] = array( 'class' => 'revision-edit', 'href' => "/differential/revision/edit/{$revision_id}/", 'name' => 'Edit Revision', ); } if (!$viewer_is_owner && !$viewer_is_reviewer) { $action = $viewer_is_cc ? 'rem' : 'add'; $links[] = array( 'class' => $viewer_is_cc ? 'subscribe-rem' : 'subscribe-add', 'href' => "/differential/subscribe/{$action}/{$revision_id}/", 'name' => $viewer_is_cc ? 'Unsubscribe' : 'Subscribe', ); } else { $links[] = array( 'class' => 'subscribe-rem unavailable', 'name' => 'Automatically Subscribed', ); } $links[] = array( 'class' => 'transcripts-metamta', 'name' => 'MetaMTA Transcripts', 'href' => "/mail/?phid={$revision_phid}", ); return $links; } private function renderHandleLinkList(array $list) { if (empty($list)) { return 'None'; } return implode(', ', mpull($list, 'renderLink')); } private function getRevisionCommentActions(DifferentialRevision $revision) { $actions = array( DifferentialAction::ACTION_COMMENT => true, ); $viewer_phid = $this->getRequest()->getUser()->getPHID(); $viewer_is_owner = ($viewer_phid == $revision->getAuthorPHID()); if ($viewer_is_owner) { switch ($revision->getStatus()) { case DifferentialRevisionStatus::NEEDS_REVIEW: $actions[DifferentialAction::ACTION_ABANDON] = true; break; case DifferentialRevisionStatus::NEEDS_REVISION: case DifferentialRevisionStatus::ACCEPTED: $actions[DifferentialAction::ACTION_ABANDON] = true; $actions[DifferentialAction::ACTION_REQUEST] = true; break; case DifferentialRevisionStatus::COMMITTED: break; case DifferentialRevisionStatus::ABANDONED: $actions[DifferentialAction::ACTION_RECLAIM] = true; break; } } else { switch ($revision->getStatus()) { case DifferentialRevisionStatus::NEEDS_REVIEW: $actions[DifferentialAction::ACTION_ACCEPT] = true; $actions[DifferentialAction::ACTION_REJECT] = true; break; case DifferentialRevisionStatus::NEEDS_REVISION: $actions[DifferentialAction::ACTION_ACCEPT] = true; break; case DifferentialRevisionStatus::ACCEPTED: $actions[DifferentialAction::ACTION_REJECT] = true; break; case DifferentialRevisionStatus::COMMITTED: case DifferentialRevisionStatus::ABANDONED: break; } } $actions[DifferentialAction::ACTION_ADDREVIEWERS] = true; return array_keys($actions); } } /* protected function getRevisionActions(DifferentialRevision $revision) { $viewer_id = $this->getRequest()->getViewerContext()->getUserID(); $viewer_is_owner = ($viewer_id == $revision->getOwnerID()); $viewer_is_reviewer = ((array_search($viewer_id, $revision->getReviewers())) !== false); $viewer_is_cc = ((array_search($viewer_id, $revision->getCCFBIDs())) !== false); $status = $revision->getStatus(); $links = array(); if (!$viewer_is_owner && !$viewer_is_reviewer) { $action = $viewer_is_cc ? 'rem' : 'add'; $revision_id = $revision->getID(); $href = "/differential/subscribe/{$action}/{$revision_id}"; $links[] = array( $viewer_is_cc ? 'subscribe-disabled' : 'subscribe-enabled', {$viewer_is_cc ? 'Unsubscribe' : 'Subscribe'}, ); } else { $links[] = array( 'subscribe-disabled unavailable', Automatically Subscribed, ); } $blast_uri = RedirectURI( '/intern/differential/?action=tasks&fbid='.$revision->getFBID()) ->setTier('intern'); $links[] = array( 'tasks', Edit Tasks, ); $engineering_repository_id = RepositoryRef::getByCallsign('E')->getID(); $svn_revision = $revision->getSVNRevision(); if ($status == DifferentialConstants::COMMITTED && $svn_revision && $revision->getRepositoryID() == $engineering_repository_id) { $href = '/intern/push/request.php?rev='.$svn_revision; $href = RedirectURI($href)->setTier('intern'); $links[] = array( 'merge', Ask for Merge, ); } $links[] = array( 'herald-transcript', getFBID()} >Herald Transcripts, ); $links[] = array( 'metamta-transcript', getFBID()} >MetaMTA Transcripts, ); $list =
    ; foreach ($links as $link) { list($class, $tag) = $link; $list->appendChild(
  • {$tag}
  • ); } return $list; /* // TODO // $sandcastle = $this->getSandcastleURI($diff); // if ($sandcastle) { // $fields['Sandcastle'] = {$sandcastle}; // } $path = $diff->getSourcePath(); if ($path) { $host = $diff->getSourceMachine(); $branch = $diff->getGitBranch() ? ' (' . $diff->getGitBranch() . ')' : ''; if ($host) { // TODO // $user = $handles[$this->getRequest()->getViewerContext()->getUserID()] // ->getName(); $user = 'TODO'; $fields['Path'] = {$host}:{$path}{$branch} ; } else { $fields['Path'] = $path; } } $reviewer_links = array(); foreach ($revision->getReviewers() as $reviewer) { $reviewer_links[] = ; } if ($reviewer_links) { $fields['Reviewers'] = array_implode(', ', $reviewer_links); } else { $fields['Reviewers'] = None; } $ccs = $revision->getCCFBIDs(); if ($ccs) { $links = array(); foreach ($ccs as $cc) { $links[] = ; } $fields['CCs'] = array_implode(', ', $links); } $blame_rev = $revision->getSvnBlameRevision(); if ($blame_rev) { if ($revision->getRepositoryRef() && is_numeric($blame_rev)) { $ref = new RevisionRef($revision->getRepositoryRef(), $blame_rev); $fields['Blame Revision'] = getDetailURL())}> {$ref->getName()} ; } else { $fields['Blame Revision'] = $blame_rev; } } $tasks = $revision->getTaskHandles(); if ($tasks) { $links = array(); foreach ($tasks as $task) { $links[] = ; } $fields['Tasks'] = array_implode(
    , $links); } $bugzilla_id = $revision->getBugzillaID(); if ($bugzilla_id) { $href = 'http://bugs.developers.facebook.com/show_bug.cgi?id='. $bugzilla_id; $fields['Bugzilla'] = {'#'.$bugzilla_id}; } $fields['Apply Patch'] = arc patch --revision {$revision->getID()}; if ($diff->getParentRevisionID()) { $parent = id(new DifferentialRevision())->load( $diff->getParentRevisionID()); if ($parent) { $fields['Depends On'] = getURI()}> D{$parent->getID()}: {$parent->getName()} ; } } $star = {"\xE2\x98\x85"}; Javelin::initBehavior('differential-star-more'); switch ($diff->getLinted()) { case Diff::LINT_FAIL: $more = $this->renderDiffPropertyMoreLink($diff, 'lint'); $fields['Lint'] = {$star} Lint Failures {$more} ; break; case Diff::LINT_WARNINGS: $more = $this->renderDiffPropertyMoreLink($diff, 'lint'); $fields['Lint'] = {$star} Lint Warnings {$more} ; break; case Diff::LINT_OKAY: $fields['Lint'] = {$star} Lint Free; break; default: case Diff::LINT_NO: $fields['Lint'] = {$star} Not Linted; break; } $unit_details = false; switch ($diff->getUnitTested()) { case Diff::UNIT_FAIL: $fields['Unit Tests'] = {$star} Unit Test Failures; $unit_details = true; break; case Diff::UNIT_WARN: $fields['Unit Tests'] = {$star} Unit Test Warnings; $unit_details = true; break; case Diff::UNIT_OKAY: $fields['Unit Tests'] = {$star} Unit Tests Passed; $unit_details = true; break; case Diff::UNIT_NO_TESTS: $fields['Unit Tests'] = {$star} No Test Coverage; break; case Diff::UNIT_NO: default: $fields['Unit Tests'] = {$star} Not Unit Tested; break; } if ($unit_details) { $fields['Unit Tests'] = {$fields['Unit Tests']} {$this->renderDiffPropertyMoreLink($diff, 'unit')} ; } $platform_impact = $revision->getPlatformImpact(); if ($platform_impact) { $fields['Platform Impact'] = {$platform_impact}; } return $fields; } } /* protected function getSandcastleURI(Diff $diff) { $uri = $this->getDiffProperty($diff, 'facebook:sandcastle_uri'); if (!$uri) { $uri = $diff->getSandboxURL(); } return $uri; } protected function getDiffProperty(Diff $diff, $property, $default = null) { $diff_id = $diff->getID(); if (empty($this->diffProperties[$diff_id])) { $props = id(new DifferentialDiffProperty()) ->loadAllWhere('diffID = %s', $diff_id); $dict = array_pull($props, 'getData', 'getName'); $this->diffProperties[$diff_id] = $dict; } return idx($this->diffProperties[$diff_id], $property, $default); } public function process() { $uri = $this->getRequest()->getPath(); if (starts_with($uri, '/d')) { return ; } $revision = id(new DifferentialRevision())->load($this->revisionID); if (!$revision) { throw new Exception("Bad revision ID."); } $diffs = id(new Diff())->loadAllWhere( 'revisionID = %d', $revision->getID()); $diffs = array_psort($diffs, 'getID'); $request = $this->getRequest(); $new = $request->getInt('new'); $old = $request->getInt('old'); if (($new || $old) && $new <= $old) { throw new Exception( "You can only view the diff of an older update relative to a newer ". "update."); } if ($new && empty($diffs[$new])) { throw new Exception( "The 'new' diff does not exist."); } else if ($new) { $diff = $diffs[$new]; } else { $diff = end($diffs); if (!$diff) { throw new Exception("No diff attached to this revision?"); } $new = $diff->getID(); } $target_diff = $diff; if ($old && empty($diffs[$old])) { throw new Exception( "The 'old' diff does not exist."); } $rows = array(array('Base', '', true, false, null, $diff->getSourceControlBaseRevision() ? $diff->getSourceControlBaseRevision() : Master)); $idx = 0; foreach ($diffs as $cdiff) { $rows[] = array( 'Diff '.(++$idx), $cdiff->getID(), $cdiff->getID() != max(array_pull($diffs, 'getID')), true, $cdiff->getDateCreated(), $cdiff->getDescription() ? $cdiff->getDescription() : No description available., $cdiff->getUnitTested(), $cdiff->getLinted()); } $diff_table =
    Diff Diff ID Description Age Lint Unit
    ; $ii = 0; $old_ids = array(); foreach ($rows as $row) { $xold = null; if ($row[2]) { $lradio = = $new} checked={$old == $row[1]} />; if ($old == $row[1]) { $xold = 'old-now'; } $old_ids[] = $lradio->requireUniqueID(); } else { $lradio = null; } $xnew = null; if ($row[3]) { $rradio = ; if ($new == $row[1]) { $xnew = 'new-now'; } } else { $rradio = null; } if ($row[3]) { $unit_star = 'star-none'; switch ($row[6]) { case Diff::UNIT_FAIL: case Diff::UNIT_WARN: $unit_star = 'star-warn'; break; case Diff::UNIT_OKAY: $unit_star = 'star-okay'; break; } $lint_star = 'star-none'; switch ($row[7]) { case Diff::LINT_FAIL: case Diff::LINT_WARNINGS: $lint_star = 'star-warn'; break; case Diff::LINT_OKAY: $lint_star = 'star-okay'; break; } $star = "\xE2\x98\x85"; $unit_star = {$star} ; $lint_star = {$star} ; } else { $unit_star = null; $lint_star = null; } $diff_table->appendChild( {$row[0]} {$row[1]} {$row[5]} {$row[4] ? ago(time() - $row[4]) : null} {$lint_star} {$unit_star} {$lradio} {$rradio} ); } Javelin::initBehavior('differential-diff-radios', array( 'radios' => $old_ids, )); $diff_table->appendChild( {id() ->setOptions($actions)} {$content} {$preview} ; $notice = null; if ($this->getRequest()->getBool('diff_changed')) { $notice = This revision was updated with a new diff while you were providing feedback. Your inline comments appear on the old diff. ; } return getName()}>
    {$warning} {$notice} {$info} {$diff_table} {$table_of_contents} {$against_warn} {$detail_view} {$feedback_form}
    ; } protected function getQuickLinks(DifferentialRevision $revision) { $viewer_id = $this->getRequest()->getViewerContext()->getUserID(); $viewer_is_owner = ($viewer_id == $revision->getOwnerID()); $viewer_is_reviewer = ((array_search($viewer_id, $revision->getReviewers())) !== false); $viewer_is_cc = ((array_search($viewer_id, $revision->getCCFBIDs())) !== false); $status = $revision->getStatus(); $links = array(); if (!$viewer_is_owner && !$viewer_is_reviewer) { $action = $viewer_is_cc ? 'rem' : 'add'; $revision_id = $revision->getID(); $href = "/differential/subscribe/{$action}/{$revision_id}"; $links[] = array( $viewer_is_cc ? 'subscribe-disabled' : 'subscribe-enabled', {$viewer_is_cc ? 'Unsubscribe' : 'Subscribe'}, ); } else { $links[] = array( 'subscribe-disabled unavailable', Automatically Subscribed, ); } $blast_uri = RedirectURI( '/intern/differential/?action=blast&fbid='.$revision->getFBID()) ->setTier('intern'); $links[] = array( 'blast', Blast Revision, ); $blast_uri = RedirectURI( '/intern/differential/?action=tasks&fbid='.$revision->getFBID()) ->setTier('intern'); $links[] = array( 'tasks', Edit Tasks, ); if ($viewer_is_owner && false) { $perflab_uri = RedirectURI( '/intern/differential/?action=perflab&fbid='.$revision->getFBID()) ->setTier('intern'); $links[] = array( 'perflab', Run in Perflab, ); } $engineering_repository_id = RepositoryRef::getByCallsign('E')->getID(); $svn_revision = $revision->getSVNRevision(); if ($status == DifferentialConstants::COMMITTED && $svn_revision && $revision->getRepositoryID() == $engineering_repository_id) { $href = '/intern/push/request.php?rev='.$svn_revision; $href = RedirectURI($href)->setTier('intern'); $links[] = array( 'merge', Ask for Merge, ); } $links[] = array( 'herald-transcript', getFBID()} >Herald Transcripts, ); $links[] = array( 'metamta-transcript', getFBID()} >MetaMTA Transcripts, ); $list =
      ; foreach ($links as $link) { list($class, $tag) = $link; $list->appendChild(
    • {$tag}
    • ); } return $list; } protected function getDetailFields( DifferentialRevision $revision, Diff $diff, array $handles) { $fields = array(); $fields['Revision Status'] = $this->getRevisionStatusDisplay($revision); $author = $revision->getOwnerID(); $fields['Author'] = ; $sandcastle = $this->getSandcastleURI($diff); if ($sandcastle) { $fields['Sandcastle'] = {$sandcastle}; } $path = $diff->getSourcePath(); if ($path) { $host = $diff->getSourceMachine(); $branch = $diff->getGitBranch() ? ' (' . $diff->getGitBranch() . ')' : ''; if ($host) { $user = $handles[$this->getRequest()->getViewerContext()->getUserID()] ->getName(); $fields['Path'] = {$host}:{$path}{$branch} ; } else { $fields['Path'] = $path; } } $reviewer_links = array(); foreach ($revision->getReviewers() as $reviewer) { $reviewer_links[] = ; } if ($reviewer_links) { $fields['Reviewers'] = array_implode(', ', $reviewer_links); } else { $fields['Reviewers'] = None; } $ccs = $revision->getCCFBIDs(); if ($ccs) { $links = array(); foreach ($ccs as $cc) { $links[] = ; } $fields['CCs'] = array_implode(', ', $links); } $blame_rev = $revision->getSvnBlameRevision(); if ($blame_rev) { if ($revision->getRepositoryRef() && is_numeric($blame_rev)) { $ref = new RevisionRef($revision->getRepositoryRef(), $blame_rev); $fields['Blame Revision'] = getDetailURL())}> {$ref->getName()} ; } else { $fields['Blame Revision'] = $blame_rev; } } $tasks = $revision->getTaskHandles(); if ($tasks) { $links = array(); foreach ($tasks as $task) { $links[] = ; } $fields['Tasks'] = array_implode(
      , $links); } $bugzilla_id = $revision->getBugzillaID(); if ($bugzilla_id) { $href = 'http://bugs.developers.facebook.com/show_bug.cgi?id='. $bugzilla_id; $fields['Bugzilla'] = {'#'.$bugzilla_id}; } $fields['Apply Patch'] = arc patch --revision {$revision->getID()}; if ($diff->getParentRevisionID()) { $parent = id(new DifferentialRevision())->load( $diff->getParentRevisionID()); if ($parent) { $fields['Depends On'] = getURI()}> D{$parent->getID()}: {$parent->getName()} ; } } $star = {"\xE2\x98\x85"}; Javelin::initBehavior('differential-star-more'); switch ($diff->getLinted()) { case Diff::LINT_FAIL: $more = $this->renderDiffPropertyMoreLink($diff, 'lint'); $fields['Lint'] = {$star} Lint Failures {$more} ; break; case Diff::LINT_WARNINGS: $more = $this->renderDiffPropertyMoreLink($diff, 'lint'); $fields['Lint'] = {$star} Lint Warnings {$more} ; break; case Diff::LINT_OKAY: $fields['Lint'] = {$star} Lint Free; break; default: case Diff::LINT_NO: $fields['Lint'] = {$star} Not Linted; break; } $unit_details = false; switch ($diff->getUnitTested()) { case Diff::UNIT_FAIL: $fields['Unit Tests'] = {$star} Unit Test Failures; $unit_details = true; break; case Diff::UNIT_WARN: $fields['Unit Tests'] = {$star} Unit Test Warnings; $unit_details = true; break; case Diff::UNIT_OKAY: $fields['Unit Tests'] = {$star} Unit Tests Passed; $unit_details = true; break; case Diff::UNIT_NO_TESTS: $fields['Unit Tests'] = {$star} No Test Coverage; break; case Diff::UNIT_NO: default: $fields['Unit Tests'] = {$star} Not Unit Tested; break; } if ($unit_details) { $fields['Unit Tests'] = {$fields['Unit Tests']} {$this->renderDiffPropertyMoreLink($diff, 'unit')} ; } $platform_impact = $revision->getPlatformImpact(); if ($platform_impact) { $fields['Platform Impact'] = {$platform_impact}; } return $fields; } protected function renderDiffPropertyMoreLink(Diff $diff, $name) { $target = ; $meta = array( 'target' => $target->requireUniqueID(), 'uri' => '/differential/diffprop/'.$diff->getID().'/'.$name.'/', ); $more = · Show Details ; return {$more}{$target}; } protected function loadInlineComments(array $feedback, array &$changesets) { $inline_comments = array(); $feedback_ids = array_filter(array_pull($feedback, 'getID')); if (!$feedback_ids) { return $inline_comments; } $inline_comments = id(new DifferentialInlineComment()) ->loadAllWhere('feedbackID in (%Ld)', $feedback_ids); $load_changesets = array(); $load_hunks = array(); foreach ($inline_comments as $inline) { $changeset_id = $inline->getChangesetID(); if (isset($changesets[$changeset_id])) { continue; } $load_changesets[$changeset_id] = true; } $more_changesets = array(); if ($load_changesets) { $changeset_ids = array_keys($load_changesets); $more_changesets += id(new DifferentialChangeset()) ->loadAllWithIDs($changeset_ids); } if ($more_changesets) { $changesets += $more_changesets; $changesets = array_psort($changesets, 'getSortKey'); } return $inline_comments; } protected function getRevisionStatusDisplay(DifferentialRevision $revision) { $viewer_id = $this->getRequest()->getViewerContext()->getUserID(); $viewer_is_owner = ($viewer_id == $revision->getOwnerID()); $status = $revision->getStatus(); $more = null; switch ($status) { case DifferentialConstants::NEEDS_REVIEW: $message = 'Pending Review'; break; case DifferentialConstants::NEEDS_REVISION: $message = 'Awaiting Revision'; if ($viewer_is_owner) { $more = 'Make the requested changes and update the revision.'; } break; case DifferentialConstants::ACCEPTED: $message = 'Ready for Commit'; if ($viewer_is_owner) { $more = Run arc commit (svn) or arc amend (git) to proceed. ; } break; case DifferentialConstants::COMMITTED: $message = 'Committed'; $ref = $revision->getRevisionRef(); $more = $ref ? (getDetailURL())}> {$ref->getName()} ) : null; $engineering_repository_id = RepositoryRef::getByCallsign('E')->getID(); if ($revision->getSVNRevision() && $revision->getRepositoryID() == $engineering_repository_id) { Javelin::initBehavior( 'differential-revtracker-status', array( 'uri' => '/differential/revtracker/'.$revision->getID().'/', 'statusId' => 'revtracker_status', 'mergeLinkId' => 'ask_for_merge_link', )); } break; case DifferentialConstants::ABANDONED: $message = 'Abandoned'; break; default: throw new Exception("Unknown revision status."); } if ($more) { $message = {$message} · {$more} ; } else { $message = {$message}; } return $message; } protected function renderFeedbackList(array $xhp, array $obj, $viewer_id) { // Use magical heuristics to try to hide older comments. $obj = array_reverse($obj); $obj = array_values($obj); $xhp = array_reverse($xhp); $xhp = array_values($xhp); $last_comment = null; foreach ($obj as $position => $feedback) { if ($feedback->getUserID() == $viewer_id) { if ($last_comment === null) { $last_comment = $position; } else if ($last_comment == $position - 1) { // If you made consecuitive comments, show them all. This is a spaz // rule for epriestley comments. $last_comment = $position; } } } $header = array(); $hide = array(); if ($last_comment !== null) { foreach ($obj as $position => $feedback) { $action = $feedback->getAction(); if ($action == 'testplan' || $action == 'summarize') { // Always show summary and test plan. $header[] = $xhp[$position]; unset($xhp[$position]); continue; } if ($position <= $last_comment) { // Always show comments after your last comment. continue; } if ($position < 3) { // Always show the most recent 3 comments. continue; } // Hide everything else. $hide[] = $position; } } if (count($hide) <= 3) { // Don't hide if there's not much to hide. $hide = array(); } $header = array_reverse($header); $hidden = array_select_keys($xhp, $hide); $visible = array_diff_key($xhp, $hidden); $visible = array_reverse($visible); $hidden = array_reverse($hidden); if ($hidden) { Javelin::initBehavior( 'differential-show-all-feedback', array( 'markup' => id({$hidden})->toString(), )); $hidden =
      {number_format(count($hidden))} older replies are hidden. Show all feedback.
      ; } else { $hidden = null; } return {$header} {$hidden} {$visible} ; } } protected function getDetailFields( DifferentialRevision $revision, Diff $diff, array $handles) { $fields = array(); $fields['Revision Status'] = $this->getRevisionStatusDisplay($revision); $author = $revision->getOwnerID(); $fields['Author'] = ; $sandcastle = $this->getSandcastleURI($diff); if ($sandcastle) { $fields['Sandcastle'] = {$sandcastle}; } $path = $diff->getSourcePath(); if ($path) { $host = $diff->getSourceMachine(); $branch = $diff->getGitBranch() ? ' (' . $diff->getGitBranch() . ')' : ''; if ($host) { $user = $handles[$this->getRequest()->getViewerContext()->getUserID()] ->getName(); $fields['Path'] = {$host}:{$path}{$branch} ; } else { $fields['Path'] = $path; } } $reviewer_links = array(); foreach ($revision->getReviewers() as $reviewer) { $reviewer_links[] = ; } if ($reviewer_links) { $fields['Reviewers'] = array_implode(', ', $reviewer_links); } else { $fields['Reviewers'] = None; } $ccs = $revision->getCCFBIDs(); if ($ccs) { $links = array(); foreach ($ccs as $cc) { $links[] = ; } $fields['CCs'] = array_implode(', ', $links); } $blame_rev = $revision->getSvnBlameRevision(); if ($blame_rev) { if ($revision->getRepositoryRef() && is_numeric($blame_rev)) { $ref = new RevisionRef($revision->getRepositoryRef(), $blame_rev); $fields['Blame Revision'] = getDetailURL())}> {$ref->getName()} ; } else { $fields['Blame Revision'] = $blame_rev; } } $tasks = $revision->getTaskHandles(); if ($tasks) { $links = array(); foreach ($tasks as $task) { $links[] = ; } $fields['Tasks'] = array_implode(
      , $links); } $bugzilla_id = $revision->getBugzillaID(); if ($bugzilla_id) { $href = 'http://bugs.developers.facebook.com/show_bug.cgi?id='. $bugzilla_id; $fields['Bugzilla'] = {'#'.$bugzilla_id}; } $fields['Apply Patch'] = arc patch --revision {$revision->getID()}; if ($diff->getParentRevisionID()) { $parent = id(new DifferentialRevision())->load( $diff->getParentRevisionID()); if ($parent) { $fields['Depends On'] = getURI()}> D{$parent->getID()}: {$parent->getName()} ; } } $star = {"\xE2\x98\x85"}; Javelin::initBehavior('differential-star-more'); switch ($diff->getLinted()) { case Diff::LINT_FAIL: $more = $this->renderDiffPropertyMoreLink($diff, 'lint'); $fields['Lint'] = {$star} Lint Failures {$more} ; break; case Diff::LINT_WARNINGS: $more = $this->renderDiffPropertyMoreLink($diff, 'lint'); $fields['Lint'] = {$star} Lint Warnings {$more} ; break; case Diff::LINT_OKAY: $fields['Lint'] = {$star} Lint Free; break; default: case Diff::LINT_NO: $fields['Lint'] = {$star} Not Linted; break; } $unit_details = false; switch ($diff->getUnitTested()) { case Diff::UNIT_FAIL: $fields['Unit Tests'] = {$star} Unit Test Failures; $unit_details = true; break; case Diff::UNIT_WARN: $fields['Unit Tests'] = {$star} Unit Test Warnings; $unit_details = true; break; case Diff::UNIT_OKAY: $fields['Unit Tests'] = {$star} Unit Tests Passed; $unit_details = true; break; case Diff::UNIT_NO_TESTS: $fields['Unit Tests'] = {$star} No Test Coverage; break; case Diff::UNIT_NO: default: $fields['Unit Tests'] = {$star} Not Unit Tested; break; } if ($unit_details) { $fields['Unit Tests'] = {$fields['Unit Tests']} {$this->renderDiffPropertyMoreLink($diff, 'unit')} ; } $platform_impact = $revision->getPlatformImpact(); if ($platform_impact) { $fields['Platform Impact'] = {$platform_impact}; } return $fields; } */ diff --git a/src/applications/differential/view/addcomment/DifferentialAddCommentView.php b/src/applications/differential/view/addcomment/DifferentialAddCommentView.php index 7d8c135baf..b390c5a083 100644 --- a/src/applications/differential/view/addcomment/DifferentialAddCommentView.php +++ b/src/applications/differential/view/addcomment/DifferentialAddCommentView.php @@ -1,71 +1,76 @@ revision = $revision; return $this; } public function setActions(array $actions) { $this->actions = $actions; return $this; } public function setActionURI($uri) { $this->actionURI = $uri; } - public function render() { + public function setUser(PhabricatorUser $user) { + $this->user = $user; + } + public function render() { $revision = $this->revision; $actions = array(); foreach ($this->actions as $action) { $actions[$action] = DifferentialAction::getActionVerb($action); } $form = new AphrontFormView(); $form + ->setUser($this->user) ->setAction($this->actionURI) ->addHiddenInput('revision_id', $revision->getID()) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Action') ->setName('action') ->setOptions($actions)) ->appendChild( id(new AphrontFormTextAreaControl()) ->setName('comment') ->setLabel('Comment')) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Comment')); return '
      '. '

      Add Comment

      '. $form->render(). '
      '; } } diff --git a/src/applications/directory/controller/categoryedit/PhabricatorDirectoryCategoryEditController.php b/src/applications/directory/controller/categoryedit/PhabricatorDirectoryCategoryEditController.php index 7194fc796b..a20db00702 100644 --- a/src/applications/directory/controller/categoryedit/PhabricatorDirectoryCategoryEditController.php +++ b/src/applications/directory/controller/categoryedit/PhabricatorDirectoryCategoryEditController.php @@ -1,110 +1,111 @@ id = idx($data, 'id'); } public function processRequest() { if ($this->id) { $category = id(new PhabricatorDirectoryCategory())->load($this->id); if (!$category) { return new Aphront404Response(); } } else { $category = new PhabricatorDirectoryCategory(); } $e_name = true; $errors = array(); $request = $this->getRequest(); if ($request->isFormPost()) { $category->setName($request->getStr('name')); $category->setSequence($request->getStr('sequence')); if (!strlen($category->getName())) { $errors[] = 'Category name is required.'; $e_name = 'Required'; } if (!$errors) { $category->save(); return id(new AphrontRedirectResponse()) ->setURI('/directory/category/'); } } $error_view = null; if ($errors) { $error_view = id(new AphrontErrorView()) ->setTitle('Form Errors') ->setErrors($errors); } $form = new AphrontFormView(); + $form->setUser($request->getUser()); if ($category->getID()) { $form->setAction('/directory/category/edit/'.$category->getID().'/'); } else { $form->setAction('/directory/category/edit/'); } $categories = id(new PhabricatorDirectoryCategory())->loadAll(); $category_map = mpull($categories, 'getName', 'getID'); $form ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Name') ->setName('name') ->setValue($category->getName()) ->setError($e_name)) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Order') ->setName('sequence') ->setValue((int)$category->getSequence())) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Save') ->addCancelButton('/directory/category/')); $panel = new AphrontPanelView(); if ($category->getID()) { $panel->setHeader('Edit Directory Category'); } else { $panel->setHeader('Create New Directory Category'); } $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_FORM); return $this->buildStandardPageResponse( array($error_view, $panel), array( 'title' => 'Edit Directory Category', )); } } diff --git a/src/applications/directory/controller/itemedit/PhabricatorDirectoryItemEditController.php b/src/applications/directory/controller/itemedit/PhabricatorDirectoryItemEditController.php index 0d3c58ff12..f4da31fafe 100644 --- a/src/applications/directory/controller/itemedit/PhabricatorDirectoryItemEditController.php +++ b/src/applications/directory/controller/itemedit/PhabricatorDirectoryItemEditController.php @@ -1,138 +1,140 @@ id = idx($data, 'id'); } public function processRequest() { if ($this->id) { $item = id(new PhabricatorDirectoryItem())->load($this->id); if (!$item) { return new Aphront404Response(); } } else { $item = new PhabricatorDirectoryItem(); } $e_name = true; $e_href = true; $errors = array(); $request = $this->getRequest(); if ($request->isFormPost()) { $item->setName($request->getStr('name')); $item->setHref($request->getStr('href')); $item->setDescription($request->getStr('description')); $item->setCategoryID($request->getStr('categoryID')); $item->setSequence($request->getStr('sequence')); if (!strlen($item->getName())) { $errors[] = 'Item name is required.'; $e_name = 'Required'; } if (!strlen($item->getHref())) { $errors[] = 'Item link is required.'; $e_href = 'Required'; } if (!$errors) { $item->save(); return id(new AphrontRedirectResponse()) ->setURI('/directory/item/'); } } $error_view = null; if ($errors) { $error_view = id(new AphrontErrorView()) ->setTitle('Form Errors') ->setErrors($errors); } $form = new AphrontFormView(); + $form->setUser($request->getUser()); + if ($item->getID()) { $form->setAction('/directory/item/edit/'.$item->getID().'/'); } else { $form->setAction('/directory/item/edit/'); } $categories = id(new PhabricatorDirectoryCategory())->loadAll(); $category_map = mpull($categories, 'getName', 'getID'); $form ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Name') ->setName('name') ->setValue($item->getName()) ->setError($e_name)) ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('Category') ->setName('categoryID') ->setOptions($category_map) ->setValue($item->getCategoryID())) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Link') ->setName('href') ->setValue($item->getHref()) ->setError($e_href)) ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel('Description') ->setName('description') ->setValue($item->getDescription())) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Order') ->setName('sequence') ->setCaption( 'Items in a category are sorted by "order", then by name.') ->setValue((int)$item->getSequence())) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Save') ->addCancelButton('/directory/item/')); $panel = new AphrontPanelView(); if ($item->getID()) { $panel->setHeader('Edit Directory Item'); } else { $panel->setHeader('Create New Directory Item'); } $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_FORM); return $this->buildStandardPageResponse( array($error_view, $panel), array( 'title' => 'Edit Directory Item', )); } } diff --git a/src/applications/files/controller/upload/PhabricatorFileUploadController.php b/src/applications/files/controller/upload/PhabricatorFileUploadController.php index 12d6f83a81..9d4b9e2be2 100644 --- a/src/applications/files/controller/upload/PhabricatorFileUploadController.php +++ b/src/applications/files/controller/upload/PhabricatorFileUploadController.php @@ -1,68 +1,69 @@ getRequest(); if ($request->isFormPost()) { $file = PhabricatorFile::newFromPHPUpload( idx($_FILES, 'file'), array( 'name' => $request->getStr('name'), )); return id(new AphrontRedirectResponse()) ->setURI('/file/info/'.phutil_escape_uri($file->getPHID()).'/'); } $form = new AphrontFormView(); $form->setAction('/file/upload/'); + $form->setUser($request->getUser()); $form ->setEncType('multipart/form-data') ->appendChild( id(new AphrontFormFileControl()) ->setLabel('File') ->setName('file') ->setError(true)) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Name') ->setName('name') ->setCaption('Optional file display name.')) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Upload') ->addCancelButton('/file/')); $panel = new AphrontPanelView(); $panel->setHeader('Upload File'); $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_FORM); return $this->buildStandardPageResponse( array($panel), array( 'title' => 'Upload File', )); } } diff --git a/src/applications/metamta/controller/mailinglistedit/PhabricatorMetaMTAMailingListEditController.php b/src/applications/metamta/controller/mailinglistedit/PhabricatorMetaMTAMailingListEditController.php index cffa047b8b..65fd88ec45 100644 --- a/src/applications/metamta/controller/mailinglistedit/PhabricatorMetaMTAMailingListEditController.php +++ b/src/applications/metamta/controller/mailinglistedit/PhabricatorMetaMTAMailingListEditController.php @@ -1,121 +1,122 @@ id = idx($data, 'id'); } public function processRequest() { if ($this->id) { $list = id(new PhabricatorMetaMTAMailingList())->load($this->id); if (!$list) { return new Aphront404Response(); } } else { $list = new PhabricatorMetaMTAMailingList(); } $e_email = true; $errors = array(); $request = $this->getRequest(); if ($request->isFormPost()) { $list->setName($request->getStr('name')); $list->setEmail($request->getStr('email')); $list->setURI($request->getStr('uri')); if (!strlen($list->getEmail())) { $e_email = 'Required'; $errors[] = 'Email is required.'; } if (!$errors) { $list->save(); return id(new AphrontRedirectResponse()) ->setURI('/mail/lists/'); } } $error_view = null; if ($errors) { $error_view = id(new AphrontErrorView()) ->setTitle('Form Errors') ->setErrors($errors); } $form = new AphrontFormView(); + $form->setUser($request->getUser()); if ($list->getID()) { $form->setAction('/mail/lists/edit/'.$list->getID().'/'); } else { $form->setAction('/mail/lists/edit/'); } $form ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Email') ->setName('email') ->setValue($list->getEmail()) ->setError($e_email)) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Name') ->setName('name') ->setValue($list->getName())) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('URI') ->setName('uri') ->setValue($list->getURI())) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel('ID') ->setValue(nonempty($list->getID(), '-'))) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel('PHID') ->setValue(nonempty($list->getPHID(), '-'))) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Save') ->addCancelButton('/mail/lists/')); $panel = new AphrontPanelView(); if ($list->getID()) { $panel->setHeader('Edit Mailing List'); } else { $panel->setHeader('Create New Mailing List'); } $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_FORM); return $this->buildStandardPageResponse( array($error_view, $panel), array( 'title' => 'Edit Mailing List', )); } } diff --git a/src/applications/metamta/controller/send/PhabricatorMetaMTASendController.php b/src/applications/metamta/controller/send/PhabricatorMetaMTASendController.php index a33dd62d6a..07374421b8 100644 --- a/src/applications/metamta/controller/send/PhabricatorMetaMTASendController.php +++ b/src/applications/metamta/controller/send/PhabricatorMetaMTASendController.php @@ -1,107 +1,108 @@ getRequest(); if ($request->isFormPost()) { $mail = new PhabricatorMetaMTAMail(); $mail->addTos($request->getArr('to')); $mail->addCCs($request->getArr('cc')); $mail->setSubject($request->getStr('subject')); $mail->setBody($request->getStr('body')); $mail->setFrom($request->getUser()->getPHID()); $mail->setSimulatedFailureCount($request->getInt('failures')); $mail->setIsHTML($request->getInt('html')); $mail->save(); if ($request->getInt('immediately')) { $mail->sendNow( $force_send = true, new PhabricatorMailImplementationPHPMailerLiteAdapter()); } return id(new AphrontRedirectResponse()) ->setURI('/mail/view/'.$mail->getID().'/'); } $failure_caption = "Enter a number to simulate that many consecutive send failures before ". "really attempting to deliver via the underlying MTA."; $form = new AphrontFormView(); + $form->setUser($request->getUser()); $form->setAction('/mail/send/'); $form ->appendChild( '

      This form will send a normal '. 'email using MetaMTA as a transport mechanism.

      ') ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel('To') ->setName('to') ->setDatasource('/typeahead/common/mailable/')) ->appendChild( id(new AphrontFormTokenizerControl()) ->setLabel('CC') ->setName('cc') ->setDatasource('/typeahead/common/mailable/')) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Subject') ->setName('subject')) ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel('Body') ->setName('body')) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Simulate Failures') ->setName('failures') ->setCaption($failure_caption)) ->appendChild( id(new AphrontFormCheckboxControl()) ->setLabel('HTML') ->addCheckbox('html', '1', 'Send as HTML email.')) ->appendChild( id(new AphrontFormCheckboxControl()) ->setLabel('Send Now') ->addCheckbox( 'immediately', '1', 'Send immediately, not via MetaMTA background script.')) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Send Mail')); $panel = new AphrontPanelView(); $panel->setHeader('Send Email'); $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_WIDE); return $this->buildStandardPageResponse( $panel, array( 'title' => 'Send Mail', )); } } diff --git a/src/applications/metamta/controller/view/PhabricatorMetaMTAViewController.php b/src/applications/metamta/controller/view/PhabricatorMetaMTAViewController.php index 0d75c25394..8d716d8331 100644 --- a/src/applications/metamta/controller/view/PhabricatorMetaMTAViewController.php +++ b/src/applications/metamta/controller/view/PhabricatorMetaMTAViewController.php @@ -1,79 +1,82 @@ id = $data['id']; } public function processRequest() { + $request = $this->getRequest(); + $mail = id(new PhabricatorMetaMTAMail())->load($this->id); if (!$mail) { return new Aphront404Response(); } - + $status = PhabricatorMetaMTAMail::getReadableStatus($mail->getStatus()); $form = new AphrontFormView(); + $form->setUser($request->getUser()); $form->setAction('/mail/send/'); $form ->appendChild( id(new AphrontFormStaticControl()) ->setLabel('Subject') ->setValue($mail->getSubject())) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel('Created') ->setValue(date('F jS, Y g:i:s A', $mail->getDateCreated()))) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel('Status') ->setValue($status)) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel('Message') ->setValue($mail->getMessage())) ->appendChild( id(new AphrontFormStaticControl()) ->setLabel('Related PHID') ->setValue($mail->getRelatedPHID())) ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel('Parameters') ->setValue(json_encode($mail->getParameters()))) ->appendChild( id(new AphrontFormSubmitControl()) ->addCancelButton('/mail/', 'Done')); $panel = new AphrontPanelView(); $panel->setHeader('View Email'); $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_WIDE); return $this->buildStandardPageResponse( $panel, array( 'title' => 'View Mail', )); } } diff --git a/src/applications/people/controller/edit/PhabricatorPeopleEditController.php b/src/applications/people/controller/edit/PhabricatorPeopleEditController.php index 3af6f63d6d..fe52b50df5 100644 --- a/src/applications/people/controller/edit/PhabricatorPeopleEditController.php +++ b/src/applications/people/controller/edit/PhabricatorPeopleEditController.php @@ -1,142 +1,143 @@ username = idx($data, 'username'); } public function processRequest() { if ($this->username) { $user = id(new PhabricatorUser())->loadOneWhere( 'userName = %s', $this->username); if (!$user) { return new Aphront404Response(); } } else { $user = new PhabricatorUser(); } $e_username = true; $e_realname = true; $e_email = true; $errors = array(); $request = $this->getRequest(); if ($request->isFormPost()) { if (!$user->getID()) { $user->setUsername($request->getStr('username')); } $user->setRealName($request->getStr('realname')); $user->setEmail($request->getStr('email')); if (!strlen($user->getUsername())) { $errors[] = "Username is required."; $e_username = 'Required'; } else if (!preg_match('/^[a-z0-9]+$/', $user->getUsername())) { $errors[] = "Username must consist of only numbers and letters."; $e_username = 'Invalid'; } if (!strlen($user->getRealName())) { $errors[] = 'Real name is required.'; $e_realname = 'Required'; } if (!strlen($user->getEmail())) { $errors[] = 'Email is required.'; $e_email = 'Required'; } if (!$errors) { $user->save(); $response = id(new AphrontRedirectResponse()) ->setURI('/p/'.$user->getUsername().'/'); return $response; } } $error_view = null; if ($errors) { $error_view = id(new AphrontErrorView()) ->setTitle('Form Errors') ->setErrors($errors); } $form = new AphrontFormView(); + $form->setUser($request->getUser()); if ($user->getUsername()) { $form->setAction('/people/edit/'.$user->getUsername().'/'); } else { $form->setAction('/people/edit/'); } if ($user->getID()) { $is_immutable = true; } else { $is_immutable = false; } $form ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Username') ->setName('username') ->setValue($user->getUsername()) ->setError($e_username) ->setDisabled($is_immutable) ->setCaption('Usernames are permanent and can not be changed later!')) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Real Name') ->setName('realname') ->setValue($user->getRealName()) ->setError($e_realname)) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Email') ->setName('email') ->setValue($user->getEmail()) ->setError($e_email)) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Save') ->addCancelButton('/people/')); $panel = new AphrontPanelView(); if ($user->getID()) { $panel->setHeader('Edit User'); } else { $panel->setHeader('Create New User'); } $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_FORM); return $this->buildStandardPageResponse( array($error_view, $panel), array( 'title' => 'Edit User', )); } } diff --git a/src/applications/people/storage/user/PhabricatorUser.php b/src/applications/people/storage/user/PhabricatorUser.php index 64417b55a3..f5ea83f038 100644 --- a/src/applications/people/storage/user/PhabricatorUser.php +++ b/src/applications/people/storage/user/PhabricatorUser.php @@ -1,63 +1,90 @@ true, ) + parent::getConfiguration(); } public function generatePHID() { return PhabricatorPHID::generateNewPHID(self::PHID_TYPE); } public function setPassword($password) { $this->setPasswordSalt(md5(mt_rand())); $hash = $this->hashPassword($password); $this->setPasswordHash($hash); return $this; } public function comparePassword($password) { $password = $this->hashPassword($password); return ($password === $this->getPasswordHash()); } private function hashPassword($password) { $password = $this->getUsername(). $password. $this->getPHID(). $this->getPasswordSalt(); for ($ii = 0; $ii < 1000; $ii++) { $password = md5($password); } return $password; } + const CSRF_CYCLE_FREQUENCY = 3600; + + public function getCSRFToken() { + return $this->generateCSRFToken(time()); + } + + public function validateCSRFToken($token) { + for ($ii = -1; $ii <= 1; $ii++) { + $time = time() + (self::CSRF_CYCLE_FREQUENCY * $ii); + $valid = $this->generateCSRFToken($time); + if ($token == $valid) { + return true; + } + } + return false; + } + + private function generateCSRFToken($epoch) { + $time_block = floor($epoch / (60 * 60)); + // TODO: this should be a secret lolol + $key = '0b7ec0592e0a2829d8b71df2fa269b2c6172eca3'; + $vec = $this->getPHID().$this->passwordHash.$key.$time_block; + return substr(md5($vec), 0, 16); + } + } diff --git a/src/applications/phid/controller/allocate/PhabricatorPHIDAllocateController.php b/src/applications/phid/controller/allocate/PhabricatorPHIDAllocateController.php index 53f8af3e14..910f17ab3b 100644 --- a/src/applications/phid/controller/allocate/PhabricatorPHIDAllocateController.php +++ b/src/applications/phid/controller/allocate/PhabricatorPHIDAllocateController.php @@ -1,68 +1,69 @@ getRequest(); if ($request->isFormPost()) { $type = $request->getStr('type'); $phid = PhabricatorPHID::generateNewPHID($type); return id(new AphrontRedirectResponse()) ->setURI('/phid/?phid='.phutil_escape_uri($phid)); } $types = id(new PhabricatorPHIDType())->loadAll(); - + $options = array(); foreach ($types as $type) { $options[$type->getType()] = $type->getType().': '.$type->getName(); } asort($options); $form = new AphrontFormView(); + $form->setUser($request->getUser()); $form->setAction('/phid/new/'); $form ->appendChild( id(new AphrontFormSelectControl()) ->setLabel('PHID Type') ->setName('type') ->setOptions($options)) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Allocate') ->addCancelButton('/phid/')); $panel = new AphrontPanelView(); $panel->setHeader('Allocate New PHID'); $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_FORM); return $this->buildStandardPageResponse( array($panel), array( 'title' => 'Allocate New PHID', )); } } diff --git a/src/applications/phid/controller/allocate/__init__.php b/src/applications/phid/controller/allocate/__init__.php index 0605962517..d007a63f53 100644 --- a/src/applications/phid/controller/allocate/__init__.php +++ b/src/applications/phid/controller/allocate/__init__.php @@ -1,20 +1,21 @@ getRequest(); if ($request->isFormPost()) { $phids = preg_split('/[\s,]+/', $request->getStr('phids')); $phids = array_filter($phids); if ($phids) { $handles = id(new PhabricatorObjectHandleData($phids)) ->loadHandles(); $rows = array(); foreach ($handles as $handle) { if ($handle->getURI()) { $link = phutil_render_tag( 'a', array( 'href' => $handle->getURI(), ), phutil_escape_html($handle->getURI())); } else { $link = null; } $rows[] = array( phutil_escape_html($handle->getPHID()), phutil_escape_html($handle->getType()), phutil_escape_html($handle->getName()), phutil_escape_html($handle->getEmail()), $link, ); } $table = new AphrontTableView($rows); $table->setHeaders( array( 'PHID', 'Type', 'Name', 'Email', 'URI', )); $table->setColumnClasses( array( null, null, null, null, 'wide', )); $panel = new AphrontPanelView(); $panel->setHeader('PHID Handles'); $panel->appendChild($table); return $this->buildStandardPageResponse( $panel, array( 'title' => 'PHID Lookup Results', )); } } $lookup_form = new AphrontFormView(); + $lookup_form->setUser($request->getUser()); $lookup_form ->setAction('/phid/') ->appendChild( id(new AphrontFormTextAreaControl()) ->setName('phids') // ->setHeight(AphrontFormTextAreaControl::HEIGHT_VERY_SHORT) TODO ->setCaption('Enter PHIDs separated by spaces or commas.')) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Lookup PHIDs')); $lookup_panel = new AphrontPanelView(); $lookup_panel->setHeader('Lookup PHIDs'); $lookup_panel->appendChild($lookup_form); $lookup_panel->setWidth(AphrontPanelView::WIDTH_WIDE); return $this->buildStandardPageResponse( array( $lookup_panel, ), array( 'title' => 'PHID Lookup', 'tab' => 'lookup', )); } } diff --git a/src/applications/phid/controller/typeedit/PhabricatorPHIDTypeEditController.php b/src/applications/phid/controller/typeedit/PhabricatorPHIDTypeEditController.php index a82e63c778..11a1477fc7 100644 --- a/src/applications/phid/controller/typeedit/PhabricatorPHIDTypeEditController.php +++ b/src/applications/phid/controller/typeedit/PhabricatorPHIDTypeEditController.php @@ -1,132 +1,135 @@ id = idx($data, 'id'); } public function processRequest() { if ($this->id) { $type = id(new PhabricatorPHIDType())->load($this->id); if (!$type) { return new Aphront404Response(); } } else { $type = new PhabricatorPHIDType(); } $e_type = true; $e_name = true; $errors = array(); $request = $this->getRequest(); if ($request->isFormPost()) { $type->setName($request->getStr('name')); if (!$type->getID()) { $type->setType($request->getStr('type')); } $type->setDescription($request->getStr('description')); if (!strlen($type->getType())) { $errors[] = 'Type code is required.'; $e_type = 'Required'; } if (!strlen($type->getName())) { $errors[] = 'Type name is required.'; $e_name = 'Required'; } if (!$errors) { $type->save(); return id(new AphrontRedirectResponse()) ->setURI('/phid/type/'); } } $error_view = null; if ($errors) { $error_view = id(new AphrontErrorView()) ->setTitle('Form Errors') ->setErrors($errors); } $form = new AphrontFormView(); + $form->setUser($request->getUser()); + if ($type->getID()) { $form->setAction('/phid/type/edit/'.$type->getID().'/'); } else { $form->setAction('/phid/type/edit/'); } if ($type->getID()) { $type_immutable = true; } else { $type_immutable = false; } + $form ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Type') ->setName('type') ->setValue($type->getType()) ->setError($e_type) ->setCaption( 'Four character type identifier. This can not be changed once '. 'it is created.') ->setDisabled($type_immutable)) ->appendChild( id(new AphrontFormTextControl()) ->setLabel('Name') ->setName('name') ->setValue($type->getName()) ->setError($e_name)) ->appendChild( id(new AphrontFormTextAreaControl()) ->setLabel('Description') ->setName('description') ->setValue($type->getDescription())) ->appendChild( id(new AphrontFormSubmitControl()) ->setValue('Save') ->addCancelButton('/phid/type/')); $panel = new AphrontPanelView(); if ($type->getID()) { $panel->setHeader('Edit PHID Type'); } else { $panel->setHeader('Create New PHID Type'); } $panel->appendChild($form); $panel->setWidth(AphrontPanelView::WIDTH_FORM); return $this->buildStandardPageResponse( array($error_view, $panel), array( 'title' => 'Edit PHID Type', )); } } diff --git a/src/view/form/base/AphrontFormView.php b/src/view/form/base/AphrontFormView.php index 77aa14f64d..e6e0e73840 100755 --- a/src/view/form/base/AphrontFormView.php +++ b/src/view/form/base/AphrontFormView.php @@ -1,81 +1,92 @@ user = $user; + return $this; + } public function setAction($action) { $this->action = $action; return $this; } public function setMethod($method) { $this->method = $method; return $this; } public function setEncType($enc_type) { $this->encType = $enc_type; return $this; } public function addHiddenInput($key, $value) { $this->data[$key] = $value; return $this; } public function render() { require_celerity_resource('aphront-form-view-css'); return phutil_render_tag( 'form', array( 'action' => $this->action, 'method' => $this->method, 'class' => 'aphront-form-view', 'enctype' => $this->encType, ), $this->renderDataInputs(). $this->renderChildren()); } private function renderDataInputs() { + if (!$this->user) { + throw new Exception('You must pass the user to AphrontFormView.'); + } + $data = $this->data + array( '__form__' => 1, + '__csrf__' => $this->user->getCSRFToken(), ); $inputs = array(); foreach ($data as $key => $value) { if ($value === null) { continue; } $inputs[] = phutil_render_tag( 'input', array( 'type' => 'hidden', 'name' => $key, 'value' => $value, )); } return implode("\n", $inputs); } } diff --git a/src/view/page/standard/PhabricatorStandardPageView.php b/src/view/page/standard/PhabricatorStandardPageView.php index 7956b4ba2b..26a15aeeba 100755 --- a/src/view/page/standard/PhabricatorStandardPageView.php +++ b/src/view/page/standard/PhabricatorStandardPageView.php @@ -1,152 +1,171 @@ request = $request; return $this; } public function getRequest() { return $this->request; } public function setApplicationName($application_name) { $this->applicationName = $application_name; return $this; } public function getApplicationName() { return $this->applicationName; } public function setBaseURI($base_uri) { $this->baseURI = $base_uri; return $this; } public function getBaseURI() { return $this->baseURI; } public function setTabs(array $tabs, $selected_tab) { $this->tabs = $tabs; $this->selectedTab = $selected_tab; return $this; } public function getTitle() { return $this->getGlyph().' '.parent::getTitle(); } protected function willRenderPage() { require_celerity_resource('phabricator-core-css'); require_celerity_resource('phabricator-core-buttons-css'); require_celerity_resource('phabricator-standard-page-view'); require_celerity_resource('javelin-lib-dev'); $this->bodyContent = $this->renderChildren(); } protected function getHead() { $response = CelerityAPI::getStaticResourceResponse(); return $response->renderResourcesOfType('css'). ''. ''; } public function setGlyph($glyph) { $this->glyph = $glyph; return $this; } public function getGlyph() { return $this->glyph; } protected function getBody() { $tabs = array(); foreach ($this->tabs as $name => $tab) { $tabs[] = phutil_render_tag( 'a', array( 'href' => idx($tab, 'href'), 'class' => ($name == $this->selectedTab) ? 'phabricator-selected-tab' : null, ), phutil_escape_html(idx($tab, 'name'))); } $tabs = implode('', $tabs); if ($tabs) { $tabs = ''.$tabs.''; } $login_stuff = null; $request = $this->getRequest(); if ($request) { $user = $request->getUser(); if ($user->getPHID()) { - $login_stuff = 'Logged in as '.phutil_escape_html($user->getUsername()); + $login_stuff = + 'Logged in as '.phutil_escape_html($user->getUsername()). + ' · '. + '
      '. + phutil_render_tag( + 'input', + array( + 'type' => 'hidden', + 'name' => '__csrf__', + 'value' => $user->getCSRFToken(), + )). + phutil_render_tag( + 'input', + array( + 'type' => 'hidden', + 'name' => '__form__', + 'value' => true, + )). + ''. + '
      '; } } return '
      '. '
      '. ''. 'Phabricator '. phutil_render_tag( 'a', array( 'href' => $this->getBaseURI(), 'class' => 'phabricator-head-appname', ), phutil_escape_html($this->getApplicationName())). $tabs. '
      '. $this->bodyContent. '
      '. '
      '; } protected function getTail() { $response = CelerityAPI::getStaticResourceResponse(); return $response->renderResourcesOfType('js'). $response->renderHTMLFooter(); } } diff --git a/src/view/utils/viewutils.php b/src/view/utils/viewutils.php index 83588de047..c884a051a7 100644 --- a/src/view/utils/viewutils.php +++ b/src/view/utils/viewutils.php @@ -1,85 +1,85 @@ $scale && count($labels)) { $remainder += ($n % $scale) * $accum; $n /= $scale; $accum *= $scale; $label = array_shift($labels); if (!count($scales)) { break; } $scale = array_shift($scales); } if ($is_negative) { $n = -$n; $remainder = -$remainder; } if ($precision) { $num_string = number_format($n, $precision); } else { $num_string = (int)floor($n); } if ($label) { $num_string .= ' '.$label; } return $num_string; }