From 7b40c616d6cdb0e64ad36a585c9d27534b57b184 Mon Sep 17 00:00:00 2001 From: epriestley Date: Mon, 18 Jul 2011 08:02:00 -0700 Subject: [PATCH] Refactor user settings Summary: I want to do two things here: - Add SSH Keys - Move "Preferences" into this panel But this controller was pretty gigantic and messy. Split it apart and use delegation instead. There are no functional changes. I changed some of the conduit certificate text to simplify it since no one should need to go through that workflow anymore, given the existence of "arc install-certificate". Test Plan: - Edited realname, including attempting to remove it. - Edited profile picture. - Edited timezone. - Edited email, including attempting to remove it. - Regenerated condiut certificate. - Linked and unlinked an OAuth account. Reviewed By: jungejason Reviewers: jungejason, tuomaspelkonen, aran CC: aran, jungejason Differential Revision: 688 --- src/__phutil_library_map__.php | 10 + .../PhabricatorUserSettingsController.php | 525 ++---------------- .../people/controller/settings/__init__.php | 26 +- ...atorUserAccountSettingsPanelController.php | 166 ++++++ .../settings/panels/account/__init__.php | 30 + ...PhabricatorUserSettingsPanelController.php | 26 + .../settings/panels/base/__init__.php | 13 + ...atorUserConduitSettingsPanelController.php | 114 ++++ .../settings/panels/conduit/__init__.php | 25 + ...icatorUserEmailSettingsPanelController.php | 96 ++++ .../settings/panels/email/__init__.php | 22 + ...icatorUserOAuthSettingsPanelController.php | 171 ++++++ .../settings/panels/oauth/__init__.php | 22 + 13 files changed, 730 insertions(+), 516 deletions(-) create mode 100644 src/applications/people/controller/settings/panels/account/PhabricatorUserAccountSettingsPanelController.php create mode 100644 src/applications/people/controller/settings/panels/account/__init__.php create mode 100644 src/applications/people/controller/settings/panels/base/PhabricatorUserSettingsPanelController.php create mode 100644 src/applications/people/controller/settings/panels/base/__init__.php create mode 100644 src/applications/people/controller/settings/panels/conduit/PhabricatorUserConduitSettingsPanelController.php create mode 100644 src/applications/people/controller/settings/panels/conduit/__init__.php create mode 100644 src/applications/people/controller/settings/panels/email/PhabricatorUserEmailSettingsPanelController.php create mode 100644 src/applications/people/controller/settings/panels/email/__init__.php create mode 100644 src/applications/people/controller/settings/panels/oauth/PhabricatorUserOAuthSettingsPanelController.php create mode 100644 src/applications/people/controller/settings/panels/oauth/__init__.php diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php index eff5f409a9..f0e1c05184 100644 --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -561,12 +561,17 @@ phutil_register_library_map(array( 'PhabricatorUIListFilterExample' => 'applications/uiexample/examples/listfilter', 'PhabricatorUIPagerExample' => 'applications/uiexample/examples/pager', 'PhabricatorUser' => 'applications/people/storage/user', + 'PhabricatorUserAccountSettingsPanelController' => 'applications/people/controller/settings/panels/account', + 'PhabricatorUserConduitSettingsPanelController' => 'applications/people/controller/settings/panels/conduit', 'PhabricatorUserDAO' => 'applications/people/storage/base', + 'PhabricatorUserEmailSettingsPanelController' => 'applications/people/controller/settings/panels/email', 'PhabricatorUserLog' => 'applications/people/storage/log', 'PhabricatorUserOAuthInfo' => 'applications/people/storage/useroauthinfo', + 'PhabricatorUserOAuthSettingsPanelController' => 'applications/people/controller/settings/panels/oauth', 'PhabricatorUserPreferences' => 'applications/people/storage/preferences', 'PhabricatorUserProfile' => 'applications/people/storage/profile', 'PhabricatorUserSettingsController' => 'applications/people/controller/settings', + 'PhabricatorUserSettingsPanelController' => 'applications/people/controller/settings/panels/base', 'PhabricatorWorker' => 'infrastructure/daemon/workers/worker', 'PhabricatorWorkerDAO' => 'infrastructure/daemon/workers/storage/base', 'PhabricatorWorkerTask' => 'infrastructure/daemon/workers/storage/task', @@ -1070,12 +1075,17 @@ phutil_register_library_map(array( 'PhabricatorUIListFilterExample' => 'PhabricatorUIExample', 'PhabricatorUIPagerExample' => 'PhabricatorUIExample', 'PhabricatorUser' => 'PhabricatorUserDAO', + 'PhabricatorUserAccountSettingsPanelController' => 'PhabricatorUserSettingsPanelController', + 'PhabricatorUserConduitSettingsPanelController' => 'PhabricatorUserSettingsPanelController', 'PhabricatorUserDAO' => 'PhabricatorLiskDAO', + 'PhabricatorUserEmailSettingsPanelController' => 'PhabricatorUserSettingsPanelController', 'PhabricatorUserLog' => 'PhabricatorUserDAO', 'PhabricatorUserOAuthInfo' => 'PhabricatorUserDAO', + 'PhabricatorUserOAuthSettingsPanelController' => 'PhabricatorUserSettingsPanelController', 'PhabricatorUserPreferences' => 'PhabricatorUserDAO', 'PhabricatorUserProfile' => 'PhabricatorUserDAO', 'PhabricatorUserSettingsController' => 'PhabricatorPeopleController', + 'PhabricatorUserSettingsPanelController' => 'PhabricatorPeopleController', 'PhabricatorWorkerDAO' => 'PhabricatorLiskDAO', 'PhabricatorWorkerTask' => 'PhabricatorWorkerDAO', 'PhabricatorWorkerTaskData' => 'PhabricatorWorkerDAO', diff --git a/src/applications/people/controller/settings/PhabricatorUserSettingsController.php b/src/applications/people/controller/settings/PhabricatorUserSettingsController.php index 024ed82630..e164daf6f4 100644 --- a/src/applications/people/controller/settings/PhabricatorUserSettingsController.php +++ b/src/applications/people/controller/settings/PhabricatorUserSettingsController.php @@ -19,7 +19,7 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController { private $page; - private $accountEditable; + private $pages; public function willProcessRequest(array $data) { $this->page = idx($data, 'page'); @@ -28,13 +28,12 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController { public function processRequest() { $request = $this->getRequest(); - $user = $request->getUser(); - $pages = array( + $this->pages = array( 'account' => 'Account', 'email' => 'Email', // 'password' => 'Password', - 'arcanist' => 'Arcanist Certificate', + 'conduit' => 'Conduit Certificate', ); $oauth_providers = PhabricatorOAuthProvider::getAllProviders(); @@ -44,148 +43,49 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController { } $key = $provider->getProviderKey(); $name = $provider->getProviderName(); - $pages[$key] = $name.' Account'; + $this->pages[$key] = $name.' Account'; } - if (empty($pages[$this->page])) { - $this->page = key($pages); + if (empty($this->pages[$this->page])) { + $this->page = key($this->pages); } - $account_editable = PhabricatorEnv::getEnvConfig('account.editable'); - $this->accountEditable = $account_editable; - - $e_realname = true; - $e_email = true; - $errors = array(); - - if ($request->isFormPost()) { - switch ($this->page) { - case 'email': - if (!$account_editable) { - return new Aphront400Response(); - } - - $user->setEmail($request->getStr('email')); - - if (!strlen($user->getEmail())) { - $errors[] = 'You must enter an e-mail address'; - $e_email = 'Required'; - } - - if (!$errors) { - $user->save(); - - return id(new AphrontRedirectResponse()) - ->setURI('/settings/page/email/?saved=true'); - } - break; - case 'arcanist': - - if (!$request->isDialogFormPost()) { - $dialog = new AphrontDialogView(); - $dialog->setUser($user); - $dialog->setTitle('Really regenerate session?'); - $dialog->setSubmitURI('/settings/page/arcanist/'); - $dialog->addSubmitButton('Regenerate'); - $dialog->addCancelbutton('/settings/page/arcanist/'); - $dialog->appendChild( - '

Really destroy the old certificate? Any established '. - 'sessions will be terminated.'); - - return id(new AphrontDialogResponse()) - ->setDialog($dialog); - } - - $conn = $user->establishConnection('w'); - queryfx( - $conn, - 'DELETE FROM %T WHERE userPHID = %s AND type LIKE %>', - PhabricatorUser::SESSION_TABLE, - $user->getPHID(), - 'conduit'); - // This implicitly regenerates the certificate. - $user->setConduitCertificate(null); - $user->save(); - return id(new AphrontRedirectResponse()) - ->setURI('/settings/page/arcanist/?regenerated=true'); - break; - case 'account': - if (!$account_editable) { - return new Aphront400Response(); - } - - if (!empty($_FILES['profile'])) { - $err = idx($_FILES['profile'], 'error'); - if ($err != UPLOAD_ERR_NO_FILE) { - $file = PhabricatorFile::newFromPHPUpload( - $_FILES['profile'], - array( - 'authorPHID' => $user->getPHID(), - )); - $okay = $file->isTransformableImage(); - if ($okay) { - $xformer = new PhabricatorImageTransformer(); - $xformed = $xformer->executeProfileTransform( - $file, - $width = 50, - $min_height = 50, - $max_height = 50); - $user->setProfileImagePHID($xformed->getPHID()); - } else { - $errors[] = - 'Only valid image files (jpg, jpeg, png or gif) '. - 'will be accepted.'; - } - } - } - - $user->setRealName($request->getStr('realname')); - - if (!strlen($user->getRealName())) { - $errors[] = 'Real name must be nonempty.'; - $e_realname = 'Required'; - } - - $new_timezone = $request->getStr('timezone'); - if (in_array($new_timezone, DateTimeZone::listIdentifiers(), true)) { - $user->setTimezoneIdentifier($new_timezone); - } else { - $errors[] = - 'The selected timezone is not a valid timezone.'; - } - - if (!$errors) { - $user->save(); - - return id(new AphrontRedirectResponse()) - ->setURI('/settings/page/account/?saved=true'); - } - break; - } - } - - switch ($this->page) { - case 'arcanist': - $content = $this->renderArcanistCertificateForm(); - break; case 'account': - $content = $this->renderAccountForm($errors, $e_realname); + $delegate = new PhabricatorUserAccountSettingsPanelController($request); break; case 'email': - $content = $this->renderEmailForm($errors, $e_email); + $delegate = new PhabricatorUserEmailSettingsPanelController($request); + break; + case 'conduit': + $delegate = new PhabricatorUserConduitSettingsPanelController($request); break; default: - if (empty($pages[$this->page])) { + if (empty($this->pages[$this->page])) { return new Aphront404Response(); } - $content = $this->renderOAuthForm($oauth_providers[$this->page]); - break; + $delegate = new PhabricatorUserOAuthSettingsPanelController($request); + $delegate->setOAuthProvider($oauth_providers[$this->page]); } + $response = $this->delegateToController($delegate); + if ($response instanceof AphrontView) { + $sidenav = $this->renderSideNav(); + $sidenav->appendChild($response); + return $this->buildStandardPageResponse( + $sidenav, + array( + 'title' => 'Account Settings', + )); + } else { + return $response; + } + } + + private function renderSideNav() { $sidenav = new AphrontSideNavView(); - foreach ($pages as $page => $name) { + foreach ($this->pages as $page => $name) { $sidenav->addNavItem( phutil_render_tag( 'a', @@ -197,369 +97,6 @@ class PhabricatorUserSettingsController extends PhabricatorPeopleController { ), phutil_escape_html($name))); } - - $sidenav->appendChild($content); - - return $this->buildStandardPageResponse( - $sidenav, - array( - 'title' => 'Account Settings', - )); - } - - private function renderArcanistCertificateForm() { - $request = $this->getRequest(); - $user = $request->getUser(); - - if ($request->getStr('regenerated')) { - $notice = new AphrontErrorView(); - $notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE); - $notice->setTitle('Certificate Regenerated'); - $notice->appendChild( - '

Your old certificate has been destroyed and you have been issued '. - 'a new certificate. Sessions established under the old certificate '. - 'are no longer valid.

'); - $notice = $notice->render(); - } else { - $notice = null; - } - - $host = PhabricatorEnv::getEnvConfig('phabricator.base-uri') . 'api/'; - $conduit_setting = sprintf( - ' %s: {'."\n". - ' "user" : %s,'."\n". - ' "cert" : %s'."\n". - ' }'."\n", - json_encode($host), - json_encode($user->getUserName()), - json_encode($user->getConduitCertificate())); - - $cert_form = new AphrontFormView(); - $cert_form - ->setUser($user) - ->appendChild( - '

Copy and paste the host info '. - 'including the certificate into your ~/.arcrc in the "hosts" '. - 'session to enable Arcanist to authenticate against this host.

') - ->appendChild( - id(new AphrontFormMarkupControl()) - ->setControlStyle('white-space: pre; font-family: monospace') - ->setValue( - '{'."\n". - ' ...'."\n". - ' "hosts" : {'."\n")) - ->appendChild( - id(new AphrontFormTextAreaControl()) - ->setLabel('Credentials') - ->setHeight(AphrontFormTextAreaControl::HEIGHT_SHORT) - ->setControlStyle('font-family: monospace') - ->setValue($conduit_setting)) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setControlStyle('white-space: pre; font-family: monospace') - ->setValue( - ' }'."\n". - ' ...'."\n". - '}')); - - $cert = new AphrontPanelView(); - $cert->setHeader('Arcanist Certificate'); - $cert->appendChild($cert_form); - $cert->setWidth(AphrontPanelView::WIDTH_FORM); - - $regen_form = new AphrontFormView(); - $regen_form - ->setUser($user) - ->setAction('/settings/page/arcanist/') - ->appendChild( - '

You can regenerate this '. - 'certificate, which will invalidate the old certificate and create '. - 'a new one.

') - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue('Regenerate Certificate')); - - $regen = new AphrontPanelView(); - $regen->setHeader('Regenerate Certificate'); - $regen->appendChild($regen_form); - $regen->setWidth(AphrontPanelView::WIDTH_FORM); - - return $notice.$cert->render().$regen->render(); - } - - private function renderAccountForm(array $errors, $e_realname) { - $request = $this->getRequest(); - $user = $request->getUser(); - - $img_src = PhabricatorFileURI::getViewURIForPHID( - $user->getProfileImagePHID()); - - $editable = $this->accountEditable; - - $notice = null; - if (!$errors) { - if ($request->getStr('saved')) { - $notice = new AphrontErrorView(); - $notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE); - $notice->setTitle('Changes Saved'); - $notice->appendChild('

Your changes have been saved.

'); - $notice = $notice->render(); - } - } else { - $notice = new AphrontErrorView(); - $notice->setTitle('Form Errors'); - $notice->setErrors($errors); - $notice = $notice->render(); - } - - $form = new AphrontFormView(); - $form - ->setUser($user) - ->setEncType('multipart/form-data') - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel('Username') - ->setValue($user->getUsername())) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel('Real Name') - ->setName('realname') - ->setError($e_realname) - ->setValue($user->getRealName()) - ->setDisabled(!$editable)) - ->appendChild( - id(new AphrontFormMarkupControl()) - ->setValue('
')) - ->appendChild( - id(new AphrontFormMarkupControl()) - ->setLabel('Profile Image') - ->setValue( - phutil_render_tag( - 'img', - array( - 'src' => $img_src, - )))); - - if ($editable) { - $timezone_ids = DateTimeZone::listIdentifiers(); - $timezone_id_map = array_combine($timezone_ids, $timezone_ids); - - $form - ->appendChild( - id(new AphrontFormFileControl()) - ->setLabel('Change Image') - ->setName('profile')) - ->appendChild( - id(new AphrontFormMarkupControl()) - ->setValue('
')) - ->appendChild( - id(new AphrontFormSelectControl()) - ->setLabel('Timezone') - ->setName('timezone') - ->setOptions($timezone_id_map) - ->setValue($user->getTimezoneIdentifier())) - ->appendChild( - id(new AphrontFormMarkupControl()) - ->setValue('
')) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue('Save')); - } - - $panel = new AphrontPanelView(); - $panel->setHeader('Profile Settings'); - $panel->setWidth(AphrontPanelView::WIDTH_FORM); - $panel->appendChild($form); - - return $notice.$panel->render(); - } - - private function renderEmailForm(array $errors, $e_email) { - $request = $this->getRequest(); - $user = $request->getUser(); - - $editable = $this->accountEditable; - - $notice = null; - if (!$errors) { - if ($request->getStr('saved')) { - $notice = new AphrontErrorView(); - $notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE); - $notice->setTitle('Changes Saved'); - $notice->appendChild('

Your changes have been saved.

'); - $notice = $notice->render(); - } - } else { - $notice = new AphrontErrorView(); - $notice->setTitle('Form Errors'); - $notice->setErrors($errors); - $notice = $notice->render(); - } - - $form = new AphrontFormView(); - $form - ->setUser($user) - ->appendChild( - id(new AphrontFormTextControl()) - ->setLabel('Email') - ->setName('email') - ->setDisabled(!$editable) - ->setCaption( - 'Note: there is no email validation yet; double-check your '. - 'typing.') - ->setValue($user->getEmail()) - ->setError($e_email)); - - if ($editable) { - $form - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue('Save')); - } - - $panel = new AphrontPanelView(); - $panel->setHeader('Email Settings'); - $panel->setWidth(AphrontPanelView::WIDTH_FORM); - $panel->appendChild($form); - - return $notice.$panel->render(); - } - - private function renderOAuthForm(PhabricatorOAuthProvider $provider) { - - $request = $this->getRequest(); - $user = $request->getUser(); - - $notice = null; - - $provider_name = $provider->getProviderName(); - $provider_key = $provider->getProviderKey(); - - $oauth_info = id(new PhabricatorUserOAuthInfo())->loadOneWhere( - 'userID = %d AND oauthProvider = %s', - $user->getID(), - $provider->getProviderKey()); - - $form = new AphrontFormView(); - $form - ->setUser($user); - - $forms = array(); - $forms[] = $form; - if (!$oauth_info) { - $form - ->appendChild( - '

There is currently no '. - $provider_name.' account linked to your Phabricator account. You '. - 'can link an account, which will allow you to use it to log into '. - 'Phabricator.

'); - - switch ($provider_key) { - case PhabricatorOAuthProvider::PROVIDER_GITHUB: - $form->appendChild( - '

Additionally, you must '. - 'link your Github account before Phabricator can access any '. - 'information about hosted repositories.

'); - break; - } - - $auth_uri = $provider->getAuthURI(); - $client_id = $provider->getClientID(); - $redirect_uri = $provider->getRedirectURI(); - - $form - ->setAction($auth_uri) - ->setMethod('GET') - ->addHiddenInput('redirect_uri', $redirect_uri) - ->addHiddenInput('client_id', $client_id) - ->appendChild( - id(new AphrontFormSubmitControl()) - ->setValue('Link '.$provider_name." Account \xC2\xBB")); - } else { - $form - ->appendChild( - '

Your account is linked with '. - 'a '.$provider_name.' account. You may use your '.$provider_name.' '. - 'credentials to log into Phabricator.

') - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel($provider_name.' ID') - ->setValue($oauth_info->getOAuthUID())) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel($provider_name.' Name') - ->setValue($oauth_info->getAccountName())) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel($provider_name.' URI') - ->setValue($oauth_info->getAccountURI())); - - if (!$provider->isProviderLinkPermanent()) { - $unlink = 'Unlink '.$provider_name.' Account'; - $unlink_form = new AphrontFormView(); - $unlink_form - ->setUser($user) - ->appendChild( - '

You may unlink this account '. - 'from your '.$provider_name.' account. This will prevent you from '. - 'logging in with your '.$provider_name.' credentials.

') - ->appendChild( - id(new AphrontFormSubmitControl()) - ->addCancelButton('/oauth/'.$provider_key.'/unlink/', $unlink)); - $forms['Unlink Account'] = $unlink_form; - } - - $expires = $oauth_info->getTokenExpires(); - if ($expires) { - if ($expires <= time()) { - $expires = "Expired"; - } else { - $expires = phabricator_format_timestamp($expires); - } - } else { - $expires = 'No Information Available'; - } - - $scope = $oauth_info->getTokenScope(); - if (!$scope) { - $scope = 'No Information Available'; - } - - $status = $oauth_info->getTokenStatus(); - $status = PhabricatorUserOAuthInfo::getReadableTokenStatus($status); - - $token_form = new AphrontFormView(); - $token_form - ->setUser($user) - ->appendChild( - '

insert rap about tokens

') - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel('Token Status') - ->setValue($status)) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel('Expires') - ->setValue($expires)) - ->appendChild( - id(new AphrontFormStaticControl()) - ->setLabel('Scope') - ->setValue($scope)); - - $forms['Account Token Information'] = $token_form; - } - - $panel = new AphrontPanelView(); - $panel->setHeader($provider_name.' Account Settings'); - $panel->setWidth(AphrontPanelView::WIDTH_FORM); - foreach ($forms as $name => $form) { - if ($name) { - $panel->appendChild('

'.$name.'

'); - } - $panel->appendChild($form); - } - - return $notice.$panel->render(); - + return $sidenav; } } diff --git a/src/applications/people/controller/settings/__init__.php b/src/applications/people/controller/settings/__init__.php index b85ec56b52..67477364d7 100644 --- a/src/applications/people/controller/settings/__init__.php +++ b/src/applications/people/controller/settings/__init__.php @@ -6,32 +6,14 @@ -phutil_require_module('phabricator', 'aphront/response/400'); phutil_require_module('phabricator', 'aphront/response/404'); -phutil_require_module('phabricator', 'aphront/response/dialog'); -phutil_require_module('phabricator', 'aphront/response/redirect'); phutil_require_module('phabricator', 'applications/auth/oauth/provider/base'); -phutil_require_module('phabricator', 'applications/files/storage/file'); -phutil_require_module('phabricator', 'applications/files/transform'); -phutil_require_module('phabricator', 'applications/files/uri'); phutil_require_module('phabricator', 'applications/people/controller/base'); -phutil_require_module('phabricator', 'applications/people/storage/user'); -phutil_require_module('phabricator', 'applications/people/storage/useroauthinfo'); -phutil_require_module('phabricator', 'infrastructure/env'); -phutil_require_module('phabricator', 'storage/queryfx'); -phutil_require_module('phabricator', 'view/dialog'); -phutil_require_module('phabricator', 'view/form/base'); -phutil_require_module('phabricator', 'view/form/control/file'); -phutil_require_module('phabricator', 'view/form/control/markup'); -phutil_require_module('phabricator', 'view/form/control/select'); -phutil_require_module('phabricator', 'view/form/control/static'); -phutil_require_module('phabricator', 'view/form/control/submit'); -phutil_require_module('phabricator', 'view/form/control/text'); -phutil_require_module('phabricator', 'view/form/control/textarea'); -phutil_require_module('phabricator', 'view/form/error'); -phutil_require_module('phabricator', 'view/layout/panel'); +phutil_require_module('phabricator', 'applications/people/controller/settings/panels/account'); +phutil_require_module('phabricator', 'applications/people/controller/settings/panels/conduit'); +phutil_require_module('phabricator', 'applications/people/controller/settings/panels/email'); +phutil_require_module('phabricator', 'applications/people/controller/settings/panels/oauth'); phutil_require_module('phabricator', 'view/layout/sidenav'); -phutil_require_module('phabricator', 'view/utils'); phutil_require_module('phutil', 'markup'); phutil_require_module('phutil', 'utils'); diff --git a/src/applications/people/controller/settings/panels/account/PhabricatorUserAccountSettingsPanelController.php b/src/applications/people/controller/settings/panels/account/PhabricatorUserAccountSettingsPanelController.php new file mode 100644 index 0000000000..a6f20909d7 --- /dev/null +++ b/src/applications/people/controller/settings/panels/account/PhabricatorUserAccountSettingsPanelController.php @@ -0,0 +1,166 @@ +getRequest(); + $user = $request->getUser(); + $editable = $this->getAccountEditable(); + + $e_realname = true; + $errors = array(); + if ($request->isFormPost()) { + if (!$editable) { + return new Aphront400Response(); + } + + if (!empty($_FILES['profile'])) { + $err = idx($_FILES['profile'], 'error'); + if ($err != UPLOAD_ERR_NO_FILE) { + $file = PhabricatorFile::newFromPHPUpload( + $_FILES['profile'], + array( + 'authorPHID' => $user->getPHID(), + )); + $okay = $file->isTransformableImage(); + if ($okay) { + $xformer = new PhabricatorImageTransformer(); + $xformed = $xformer->executeProfileTransform( + $file, + $width = 50, + $min_height = 50, + $max_height = 50); + $user->setProfileImagePHID($xformed->getPHID()); + } else { + $errors[] = + 'Only valid image files (jpg, jpeg, png or gif) '. + 'will be accepted.'; + } + } + } + + $user->setRealName($request->getStr('realname')); + + if (!strlen($user->getRealName())) { + $errors[] = 'Real name must be nonempty.'; + $e_realname = 'Required'; + } + + $new_timezone = $request->getStr('timezone'); + if (in_array($new_timezone, DateTimeZone::listIdentifiers(), true)) { + $user->setTimezoneIdentifier($new_timezone); + } else { + $errors[] = 'The selected timezone is not a valid timezone.'; + } + + if (!$errors) { + $user->save(); + return id(new AphrontRedirectResponse()) + ->setURI('/settings/page/account/?saved=true'); + } + } + + $img_src = PhabricatorFileURI::getViewURIForPHID( + $user->getProfileImagePHID()); + + $notice = null; + if (!$errors) { + if ($request->getStr('saved')) { + $notice = new AphrontErrorView(); + $notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE); + $notice->setTitle('Changes Saved'); + $notice->appendChild('

Your changes have been saved.

'); + $notice = $notice->render(); + } + } else { + $notice = new AphrontErrorView(); + $notice->setTitle('Form Errors'); + $notice->setErrors($errors); + $notice = $notice->render(); + } + + $form = new AphrontFormView(); + $form + ->setUser($user) + ->setEncType('multipart/form-data') + ->appendChild( + id(new AphrontFormStaticControl()) + ->setLabel('Username') + ->setValue($user->getUsername())) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Real Name') + ->setName('realname') + ->setError($e_realname) + ->setValue($user->getRealName()) + ->setDisabled(!$editable)) + ->appendChild( + id(new AphrontFormMarkupControl()) + ->setValue('
')) + ->appendChild( + id(new AphrontFormMarkupControl()) + ->setLabel('Profile Image') + ->setValue( + phutil_render_tag( + 'img', + array( + 'src' => $img_src, + )))); + + if ($editable) { + $timezone_ids = DateTimeZone::listIdentifiers(); + $timezone_id_map = array_combine($timezone_ids, $timezone_ids); + + $form + ->appendChild( + id(new AphrontFormFileControl()) + ->setLabel('Change Image') + ->setName('profile')) + ->appendChild( + id(new AphrontFormMarkupControl()) + ->setValue('
')) + ->appendChild( + id(new AphrontFormSelectControl()) + ->setLabel('Timezone') + ->setName('timezone') + ->setOptions($timezone_id_map) + ->setValue($user->getTimezoneIdentifier())) + ->appendChild( + id(new AphrontFormMarkupControl()) + ->setValue('
')) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue('Save')); + } + + $panel = new AphrontPanelView(); + $panel->setHeader('Profile Settings'); + $panel->setWidth(AphrontPanelView::WIDTH_FORM); + $panel->appendChild($form); + + return id(new AphrontNullView()) + ->appendChild( + array( + $notice, + $panel, + )); + } +} diff --git a/src/applications/people/controller/settings/panels/account/__init__.php b/src/applications/people/controller/settings/panels/account/__init__.php new file mode 100644 index 0000000000..eb7b21e092 --- /dev/null +++ b/src/applications/people/controller/settings/panels/account/__init__.php @@ -0,0 +1,30 @@ +getRequest(); + $user = $request->getUser(); + + if ($request->isFormPost()) { + if (!$request->isDialogFormPost()) { + $dialog = new AphrontDialogView(); + $dialog->setUser($user); + $dialog->setTitle('Really regenerate session?'); + $dialog->setSubmitURI('/settings/page/conduit/'); + $dialog->addSubmitButton('Regenerate'); + $dialog->addCancelbutton('/settings/page/conduit/'); + $dialog->appendChild( + '

Really destroy the old certificate? Any established '. + 'sessions will be terminated.'); + + return id(new AphrontDialogResponse()) + ->setDialog($dialog); + } + + $conn = $user->establishConnection('w'); + queryfx( + $conn, + 'DELETE FROM %T WHERE userPHID = %s AND type LIKE %>', + PhabricatorUser::SESSION_TABLE, + $user->getPHID(), + 'conduit'); + + // This implicitly regenerates the certificate. + $user->setConduitCertificate(null); + $user->save(); + return id(new AphrontRedirectResponse()) + ->setURI('/settings/page/conduit/?regenerated=true'); + } + + if ($request->getStr('regenerated')) { + $notice = new AphrontErrorView(); + $notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE); + $notice->setTitle('Certificate Regenerated'); + $notice->appendChild( + '

Your old certificate has been destroyed and you have been issued '. + 'a new certificate. Sessions established under the old certificate '. + 'are no longer valid.

'); + $notice = $notice->render(); + } else { + $notice = null; + } + + $cert_form = new AphrontFormView(); + $cert_form + ->setUser($user) + ->appendChild( + '

This certificate allows you to '. + 'authenticate over Conduit, the Phabricator API. Normally, you just '. + 'run arc install-certificate to install it.') + ->appendChild( + id(new AphrontFormTextAreaControl()) + ->setLabel('Certificate') + ->setHeight(AphrontFormTextAreaControl::HEIGHT_SHORT) + ->setValue($user->getConduitCertificate())); + + $cert = new AphrontPanelView(); + $cert->setHeader('Arcanist Certificate'); + $cert->appendChild($cert_form); + $cert->setWidth(AphrontPanelView::WIDTH_FORM); + + $regen_form = new AphrontFormView(); + $regen_form + ->setUser($user) + ->setAction('/settings/page/conduit/') + ->appendChild( + '

You can regenerate this '. + 'certificate, which will invalidate the old certificate and create '. + 'a new one.

') + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue('Regenerate Certificate')); + + $regen = new AphrontPanelView(); + $regen->setHeader('Regenerate Certificate'); + $regen->appendChild($regen_form); + $regen->setWidth(AphrontPanelView::WIDTH_FORM); + + return id(new AphrontNullView()) + ->appendChild( + array( + $notice, + $cert, + $regen, + )); + } +} diff --git a/src/applications/people/controller/settings/panels/conduit/__init__.php b/src/applications/people/controller/settings/panels/conduit/__init__.php new file mode 100644 index 0000000000..8ae85a88bc --- /dev/null +++ b/src/applications/people/controller/settings/panels/conduit/__init__.php @@ -0,0 +1,25 @@ +getRequest(); + $user = $request->getUser(); + $editable = $this->getAccountEditable(); + + $e_email = true; + $errors = array(); + if ($request->isFormPost()) { + if (!$editable) { + return new Aphront400Response(); + } + + $user->setEmail($request->getStr('email')); + + if (!strlen($user->getEmail())) { + $errors[] = 'You must enter an e-mail address.'; + $e_email = 'Required'; + } + + if (!$errors) { + $user->save(); + return id(new AphrontRedirectResponse()) + ->setURI('/settings/page/email/?saved=true'); + } + } + + $notice = null; + if (!$errors) { + if ($request->getStr('saved')) { + $notice = new AphrontErrorView(); + $notice->setSeverity(AphrontErrorView::SEVERITY_NOTICE); + $notice->setTitle('Changes Saved'); + $notice->appendChild('

Your changes have been saved.

'); + } + } else { + $notice = new AphrontErrorView(); + $notice->setTitle('Form Errors'); + $notice->setErrors($errors); + } + + $form = new AphrontFormView(); + $form + ->setUser($user) + ->appendChild( + id(new AphrontFormTextControl()) + ->setLabel('Email') + ->setName('email') + ->setDisabled(!$editable) + ->setCaption( + 'Note: there is no email validation yet; double-check your '. + 'typing.') + ->setValue($user->getEmail()) + ->setError($e_email)); + + if ($editable) { + $form + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue('Save')); + } + + $panel = new AphrontPanelView(); + $panel->setHeader('Email Settings'); + $panel->setWidth(AphrontPanelView::WIDTH_FORM); + $panel->appendChild($form); + + return id(new AphrontNullView()) + ->appendChild( + array( + $notice, + $panel, + )); + } +} diff --git a/src/applications/people/controller/settings/panels/email/__init__.php b/src/applications/people/controller/settings/panels/email/__init__.php new file mode 100644 index 0000000000..c991e43a42 --- /dev/null +++ b/src/applications/people/controller/settings/panels/email/__init__.php @@ -0,0 +1,22 @@ +provider = $oauth_provider; + return $this; + } + + public function processRequest() { + + $request = $this->getRequest(); + $user = $request->getUser(); + $provider = $this->provider; + + $notice = null; + + $provider_name = $provider->getProviderName(); + $provider_key = $provider->getProviderKey(); + + $oauth_info = id(new PhabricatorUserOAuthInfo())->loadOneWhere( + 'userID = %d AND oauthProvider = %s', + $user->getID(), + $provider->getProviderKey()); + + $form = new AphrontFormView(); + $form + ->setUser($user); + + $forms = array(); + $forms[] = $form; + if (!$oauth_info) { + $form + ->appendChild( + '

There is currently no '. + $provider_name.' account linked to your Phabricator account. You '. + 'can link an account, which will allow you to use it to log into '. + 'Phabricator.

'); + + switch ($provider_key) { + case PhabricatorOAuthProvider::PROVIDER_GITHUB: + $form->appendChild( + '

Additionally, you must '. + 'link your Github account before Phabricator can access any '. + 'information about hosted repositories.

'); + break; + } + + $auth_uri = $provider->getAuthURI(); + $client_id = $provider->getClientID(); + $redirect_uri = $provider->getRedirectURI(); + + $form + ->setAction($auth_uri) + ->setMethod('GET') + ->addHiddenInput('redirect_uri', $redirect_uri) + ->addHiddenInput('client_id', $client_id) + ->appendChild( + id(new AphrontFormSubmitControl()) + ->setValue('Link '.$provider_name." Account \xC2\xBB")); + } else { + $form + ->appendChild( + '

Your account is linked with '. + 'a '.$provider_name.' account. You may use your '.$provider_name.' '. + 'credentials to log into Phabricator.

') + ->appendChild( + id(new AphrontFormStaticControl()) + ->setLabel($provider_name.' ID') + ->setValue($oauth_info->getOAuthUID())) + ->appendChild( + id(new AphrontFormStaticControl()) + ->setLabel($provider_name.' Name') + ->setValue($oauth_info->getAccountName())) + ->appendChild( + id(new AphrontFormStaticControl()) + ->setLabel($provider_name.' URI') + ->setValue($oauth_info->getAccountURI())); + + if (!$provider->isProviderLinkPermanent()) { + $unlink = 'Unlink '.$provider_name.' Account'; + $unlink_form = new AphrontFormView(); + $unlink_form + ->setUser($user) + ->appendChild( + '

You may unlink this account '. + 'from your '.$provider_name.' account. This will prevent you from '. + 'logging in with your '.$provider_name.' credentials.

') + ->appendChild( + id(new AphrontFormSubmitControl()) + ->addCancelButton('/oauth/'.$provider_key.'/unlink/', $unlink)); + $forms['Unlink Account'] = $unlink_form; + } + + $expires = $oauth_info->getTokenExpires(); + if ($expires) { + if ($expires <= time()) { + $expires = "Expired"; + } else { + $expires = phabricator_format_timestamp($expires); + } + } else { + $expires = 'No Information Available'; + } + + $scope = $oauth_info->getTokenScope(); + if (!$scope) { + $scope = 'No Information Available'; + } + + $status = $oauth_info->getTokenStatus(); + $status = PhabricatorUserOAuthInfo::getReadableTokenStatus($status); + + $token_form = new AphrontFormView(); + $token_form + ->setUser($user) + ->appendChild( + '

insert rap about tokens

') + ->appendChild( + id(new AphrontFormStaticControl()) + ->setLabel('Token Status') + ->setValue($status)) + ->appendChild( + id(new AphrontFormStaticControl()) + ->setLabel('Expires') + ->setValue($expires)) + ->appendChild( + id(new AphrontFormStaticControl()) + ->setLabel('Scope') + ->setValue($scope)); + + $forms['Account Token Information'] = $token_form; + } + + $panel = new AphrontPanelView(); + $panel->setHeader($provider_name.' Account Settings'); + $panel->setWidth(AphrontPanelView::WIDTH_FORM); + foreach ($forms as $name => $form) { + if ($name) { + $panel->appendChild('

'.$name.'

'); + } + $panel->appendChild($form); + } + + return id(new AphrontNullView()) + ->appendChild( + array( + $notice, + $panel, + )); + } +} diff --git a/src/applications/people/controller/settings/panels/oauth/__init__.php b/src/applications/people/controller/settings/panels/oauth/__init__.php new file mode 100644 index 0000000000..173c57fcb7 --- /dev/null +++ b/src/applications/people/controller/settings/panels/oauth/__init__.php @@ -0,0 +1,22 @@ +