Add phone and display name field

Signed-off-by: Joas Schilling <coding@schilljs.com>
This commit is contained in:
Joas Schilling 2021-03-31 15:26:03 +02:00
parent 58712c82d0
commit d140ee8d77
No known key found for this signature in database
GPG Key ID: 7076EA9751AACDDA
4 changed files with 145 additions and 38 deletions

View File

@ -1,13 +1,17 @@
#body-login #email, #body-login #email,
#body-login #token, #body-login #token,
#body-login #username, #body-login #loginname,
#body-login #fullname,
#body-login #phone,
#body-login #password { #body-login #password {
width: calc(100% - 56px); width: calc(100% - 56px);
padding-left: 36px; padding-left: 36px;
} }
#email-icon, #email-icon,
#token-icon, #token-icon,
#username-icon, #loginname-icon,
#fullname-icon,
#phone-icon,
#password-icon { #password-icon {
position: absolute; position: absolute;
left: 16px; left: 16px;
@ -16,8 +20,8 @@
filter: alpha(opacity=30); filter: alpha(opacity=30);
opacity: .3; opacity: .3;
} }
#username-icon { #email-icon {
top: 17px; top: 27px;
} }
input[type="submit"] { input[type="submit"] {
@ -41,3 +45,7 @@ input[type="submit"] {
.groupofone { .groupofone {
position: relative; position: relative;
} }
.toggle-password {
top: 22px !important;
}

View File

@ -214,11 +214,13 @@ class RegisterController extends Controller {
* *
* @param string $secret * @param string $secret
* @param string $token * @param string $token
* @param string $username * @param string $loginname
* @param string $fullname
* @param string $phone
* @param string $message * @param string $message
* @return TemplateResponse * @return TemplateResponse
*/ */
public function showUserForm(string $secret, string $token, string $username = '', string $message = ''): TemplateResponse { public function showUserForm(string $secret, string $token, string $loginname = '', string $fullname = '', string $phone = '', string $password = '', string $message = ''): TemplateResponse {
try { try {
$registration = $this->validateSecretAndToken($secret, $token); $registration = $this->validateSecretAndToken($secret, $token);
} catch (RegistrationException $e) { } catch (RegistrationException $e) {
@ -230,8 +232,13 @@ class RegisterController extends Controller {
return new TemplateResponse('registration', 'form/user', [ return new TemplateResponse('registration', 'form/user', [
'email' => $registration->getEmail(), 'email' => $registration->getEmail(),
'email_is_login' => $this->config->getAppValue('registration', 'email_is_login', 'no') === 'yes', 'email_is_login' => $this->config->getAppValue('registration', 'email_is_login', 'no') === 'yes',
'username' => $username, 'loginname' => $loginname,
'fullname' => $fullname,
'show_fullname' => $this->config->getAppValue('registration', 'enfore_fullname', 'no') === 'yes',
'phone' => $phone,
'show_phone' => $this->config->getAppValue('registration', 'enfore_phone', 'no') === 'yes',
'message' => $message, 'message' => $message,
'password' => $password,
'additional_hint' => $additional_hint, 'additional_hint' => $additional_hint,
], 'guest'); ], 'guest');
} }
@ -243,11 +250,13 @@ class RegisterController extends Controller {
* *
* @param string $secret * @param string $secret
* @param string $token * @param string $token
* @param string $username * @param string $loginname
* @param string $fullname
* @param string $phone
* @param string $password * @param string $password
* @return RedirectResponse|TemplateResponse * @return RedirectResponse|TemplateResponse
*/ */
public function submitUserForm(string $secret, string $token, string $username, string $password): Response { public function submitUserForm(string $secret, string $token, string $loginname, string $fullname, string $phone, string $password): Response {
try { try {
$registration = $this->validateSecretAndToken($secret, $token); $registration = $this->validateSecretAndToken($secret, $token);
} catch (RegistrationException $e) { } catch (RegistrationException $e) {
@ -255,13 +264,13 @@ class RegisterController extends Controller {
} }
if ($this->config->getAppValue('registration', 'email_is_login', 'no') === 'yes') { if ($this->config->getAppValue('registration', 'email_is_login', 'no') === 'yes') {
$username = $registration->getEmail(); $loginname = $registration->getEmail();
} }
try { try {
$user = $this->registrationService->createAccount($registration, $username, $password); $user = $this->registrationService->createAccount($registration, $loginname, $fullname, $phone, $password);
} catch (Exception $exception) { } catch (Exception $exception) {
return $this->showUserForm($secret, $token, $username, $exception->getMessage()); return $this->showUserForm($secret, $token, $loginname, $fullname, $phone, $password, $exception->getMessage());
} }
// Delete registration // Delete registration

View File

@ -30,6 +30,10 @@ declare(strict_types=1);
namespace OCA\Registration\Service; namespace OCA\Registration\Service;
use InvalidArgumentException;
use libphonenumber\NumberParseException;
use libphonenumber\PhoneNumber;
use libphonenumber\PhoneNumberUtil;
use OC\Authentication\Exceptions\InvalidTokenException; use OC\Authentication\Exceptions\InvalidTokenException;
use OC\Authentication\Exceptions\PasswordlessTokenException; use OC\Authentication\Exceptions\PasswordlessTokenException;
use OC\Authentication\Token\IProvider; use OC\Authentication\Token\IProvider;
@ -37,6 +41,7 @@ use OC\Authentication\Token\IToken;
use OCA\Registration\AppInfo\Application; use OCA\Registration\AppInfo\Application;
use OCA\Registration\Db\Registration; use OCA\Registration\Db\Registration;
use OCA\Registration\Db\RegistrationMapper; use OCA\Registration\Db\RegistrationMapper;
use OCP\Accounts\IAccountManager;
use OCP\AppFramework\Db\DoesNotExistException; use OCP\AppFramework\Db\DoesNotExistException;
use OCP\ILogger; use OCP\ILogger;
use OCP\IRequest; use OCP\IRequest;
@ -66,6 +71,8 @@ class RegistrationService {
private $registrationMapper; private $registrationMapper;
/** @var IUserManager */ /** @var IUserManager */
private $userManager; private $userManager;
/** @var IAccountManager */
private $accountManager;
/** @var IConfig */ /** @var IConfig */
private $config; private $config;
/** @var IGroupManager */ /** @var IGroupManager */
@ -92,6 +99,7 @@ class RegistrationService {
IURLGenerator $urlGenerator, IURLGenerator $urlGenerator,
RegistrationMapper $registrationMapper, RegistrationMapper $registrationMapper,
IUserManager $userManager, IUserManager $userManager,
IAccountManager $accountManager,
IConfig $config, IConfig $config,
IGroupManager $groupManager, IGroupManager $groupManager,
ISecureRandom $random, ISecureRandom $random,
@ -108,6 +116,7 @@ class RegistrationService {
$this->urlGenerator = $urlGenerator; $this->urlGenerator = $urlGenerator;
$this->registrationMapper = $registrationMapper; $this->registrationMapper = $registrationMapper;
$this->userManager = $userManager; $this->userManager = $userManager;
$this->accountManager = $accountManager;
$this->config = $config; $this->config = $config;
$this->groupManager = $groupManager; $this->groupManager = $groupManager;
$this->random = $random; $this->random = $random;
@ -229,17 +238,44 @@ class RegistrationService {
* @throws RegistrationException * @throws RegistrationException
*/ */
public function validateUsername(string $username): void { public function validateUsername(string $username): void {
if ($username === "") { if ($username === '') {
throw new RegistrationException($this->l10n->t('Please provide a valid user name.')); throw new RegistrationException($this->l10n->t('Please provide a valid login name.'));
} }
$regex = $this->config->getAppValue($this->appName, 'username_policy_regex', ''); $regex = $this->config->getAppValue($this->appName, 'username_policy_regex', '');
if ($regex && preg_match($regex, $username) === 0) { if ($regex && preg_match($regex, $username) === 0) {
throw new RegistrationException($this->l10n->t('Please provide a valid user name.')); throw new RegistrationException($this->l10n->t('Please provide a valid login name.'));
} }
if ($this->registrationMapper->usernameIsPending($username) || $this->userManager->get($username) !== null) { if ($this->registrationMapper->usernameIsPending($username) || $this->userManager->get($username) !== null) {
throw new RegistrationException($this->l10n->t('The username you have chosen already exists.')); throw new RegistrationException($this->l10n->t('The login name you have chosen already exists.'));
}
}
/**
* @param string $phone
* @throws RegistrationException
*/
public function validatePhoneNumber(string $phone): void {
$defaultRegion = $this->config->getSystemValueString('default_phone_region', '');
if ($defaultRegion === '') {
// When no default region is set, only +49… numbers are valid
if (strpos($phone, '+') !== 0) {
throw new RegistrationException($this->l10n->t('The phone number needs to contain the country code.'));
}
$defaultRegion = 'EN';
}
$phoneUtil = PhoneNumberUtil::getInstance();
try {
$phoneNumber = $phoneUtil->parse($phone, $defaultRegion);
if (!$phoneNumber instanceof PhoneNumber || !$phoneUtil->isValidNumber($phoneNumber)) {
throw new RegistrationException($this->l10n->t('The phone number is invalid.'));
}
} catch (NumberParseException $e) {
throw new RegistrationException($this->l10n->t('The phone number is invalid.'));
} }
} }
@ -290,41 +326,53 @@ class RegistrationService {
} }
/** /**
* @param $registration * @param Registration $registration
* @param string|null $username * @param string|null $loginName
* @param string|null $fullName
* @param string|null $phone
* @param string|null $password * @param string|null $password
* @return IUser * @return IUser
* @throws RegistrationException|InvalidTokenException * @throws RegistrationException|InvalidArgumentException
*/ */
public function createAccount(Registration $registration, ?string $username = null, ?string $password = null): IUser { public function createAccount(Registration $registration, ?string $loginName = null, ?string $fullName = null, ?string $phone = null, ?string $password = null): IUser {
if ($password === null && $registration->getPassword() === null) { if ($loginName === null) {
$generatedPassword = $this->generateRandomDeviceToken(); $loginName = $registration->getUsername();
$registration->setPassword($this->crypto->encrypt($generatedPassword));
}
if ($username === null) {
$username = $registration->getUsername();
} }
if ($registration->getPassword() !== null) { if ($registration->getPassword() !== null) {
$password = $this->crypto->decrypt($registration->getPassword()); $password = $this->crypto->decrypt($registration->getPassword());
} }
$this->validateUsername($username); if (!$password) {
throw new RegistrationException($this->l10n->t('Please provide a password.'));
}
$this->validateUsername($loginName);
if ($this->config->getAppValue('registration', 'enfore_fullname', 'no') === 'yes') {
$this->validateDisplayname($fullName);
}
if ($phone) {
$this->validatePhoneNumber($phone);
} elseif ($this->config->getAppValue('registration', 'enfore_phone', 'no') === 'yes') {
throw new RegistrationException($this->l10n->t('Please provide a valid phone number.'));
}
/* TODO /* TODO
* createUser tests username validity once, but validateUsername already checked it, * createUser tests username validity once, but validateUsername already checked it,
* but createUser doesn't check if there is a pending registration with that name * but createUser doesn't check if there is a pending registration with that name
* *
* And validateUsername will throw RegistrationException while * And validateUsername will throw RegistrationException while
* createUser throws \InvalidTokenException in NC, \Exception in OC * createUser throws \InvalidArgumentException
*/ */
$user = $this->userManager->createUser($username, $password); $user = $this->userManager->createUser($loginName, $password);
if ($user === false) { if ($user === false) {
throw new RegistrationException($this->l10n->t('Unable to create user, there are problems with the user backend.')); throw new RegistrationException($this->l10n->t('Unable to create user, there are problems with the user backend.'));
} }
$userId = $user->getUID(); $userId = $user->getUID();
// Set user email // Set user email
try { try {
$user->setEMailAddress($registration->getEmail()); $user->setEMailAddress($registration->getEmail());
@ -332,6 +380,22 @@ class RegistrationService {
throw new RegistrationException($this->l10n->t('Unable to set user email: ' . $e->getMessage())); throw new RegistrationException($this->l10n->t('Unable to set user email: ' . $e->getMessage()));
} }
// Set display name
if ($fullName) {
$user->setDisplayName($fullName);
}
// Set phone number in account data
$account = $this->accountManager->getAccount($user);
$property = $account->getProperty(IAccountManager::PROPERTY_PHONE);
$account->setProperty(
IAccountManager::PROPERTY_PHONE,
$phone,
$property->getScope(),
IAccountManager::NOT_VERIFIED
);
$this->accountManager->updateAccount($account);
// Add user to group // Add user to group
$registeredUserGroup = $this->config->getAppValue($this->appName, 'registered_user_group', 'none'); $registeredUserGroup = $this->config->getAppValue($this->appName, 'registered_user_group', 'none');
if ($registeredUserGroup !== 'none') { if ($registeredUserGroup !== 'none') {

View File

@ -19,7 +19,7 @@ script('registration', 'form');
<?php if (!empty($_['additional_hint'])): ?> <?php if (!empty($_['additional_hint'])): ?>
<ul class="msg"> <ul class="msg">
<li><?php p($_['additional_hint']); ?></li> <li><?php p($_['additional_hint']); ?></li>
</ul> </ul>
<?php endif; ?> <?php endif; ?>
@ -30,19 +30,45 @@ script('registration', 'form');
</p> </p>
<?php if (!$_['email_is_login']) { ?> <?php if (!$_['email_is_login']) { ?>
<p class="groupmiddle">
<input type="text" name=loginname" id="loginname" value="<?php if (!empty($_['login'])) {
p($_['login']);
} ?>" placeholder="<?php p($l->t('Login name')); ?>" />
<label for="loginname" class="infield"><?php p($l->t('Login name')); ?></label>
<img id="loginname-icon" class="svg" src="<?php print_unescaped(image_path('', 'categories/auth.svg')); ?>" alt=""/>
</p>
<?php } else { ?>
<input type="hidden" name="loginname" value="<?php p($_['email']); ?>" />
<?php } ?>
<?php if ($_['show_fullname']) { ?>
<p class="groupmiddle"> <p class="groupmiddle">
<input type="text" name="username" id="username" value="<?php if (!empty($_['entered_data']['user'])) { <input type="text" name="fullname" id="fullname" value="<?php if (!empty($_['fullname'])) {
p($_['entered_data']['user']); p($_['fullname']);
} ?>" placeholder="<?php p($l->t('Username')); ?>" /> } ?>" placeholder="<?php p($l->t('Full name')); ?>" />
<label for="username" class="infield"><?php p($l->t('Username')); ?></label> <label for="fullname" class="infield"><?php p($l->t('Full name')); ?></label>
<img id="username-icon" class="svg" src="<?php print_unescaped(image_path('', 'actions/user.svg')); ?>" alt=""/> <img id="fullname-icon" class="svg" src="<?php print_unescaped(image_path('', 'actions/user.svg')); ?>" alt=""/>
</p> </p>
<?php } else { ?> <?php } else { ?>
<input type="hidden" name="username" value="<?php p($_['email']); ?>" /> <input type="hidden" name="fullname" value="" />
<?php } ?>
<?php if ($_['show_phone']) { ?>
<p class="groupmiddle">
<input type="text" name="phone" id="phone" value="<?php if (!empty($_['phone'])) {
p($_['phone']);
} ?>" placeholder="<?php p($l->t('Phone number')); ?>" />
<label for="phone" class="infield"><?php p($l->t('Phone number')); ?></label>
<img id="phone-icon" class="svg" src="<?php print_unescaped(image_path('', 'clients/phone.svg')); ?>" alt=""/>
</p>
<?php } else { ?>
<input type="hidden" name="phone" value="" />
<?php } ?> <?php } ?>
<p class="groupbottom"> <p class="groupbottom">
<input type="password" name="password" id="password" placeholder="<?php p($l->t('Password')); ?>"/> <input type="password" name="password" id="password" value="<?php if (!empty($_['password'])) {
p($_['password']);
} ?>" placeholder="<?php p($l->t('Password')); ?>"/>
<label for="password" class="infield"><?php p($l->t('Password')); ?></label> <label for="password" class="infield"><?php p($l->t('Password')); ?></label>
<img id="password-icon" class="svg" src="<?php print_unescaped(image_path('', 'actions/password.svg')); ?>" alt=""/> <img id="password-icon" class="svg" src="<?php print_unescaped(image_path('', 'actions/password.svg')); ?>" alt=""/>
<a id="showadminpass" href="#" class="toggle-password"> <a id="showadminpass" href="#" class="toggle-password">