forked from EVOgeek/Vmeda.Online
		
	Merge pull request #3942 from dpalou/MOBILE-4400
MOBILE-4400 signup: Check extendedusernamechars setting
This commit is contained in:
		
						commit
						76da08b645
					
				| @ -2092,6 +2092,7 @@ | ||||
|   "core.login.invalidsite": "local_moodlemobileapp", | ||||
|   "core.login.invalidtime": "local_moodlemobileapp", | ||||
|   "core.login.invalidurl": "scorm", | ||||
|   "core.login.invalidusername": "moodle", | ||||
|   "core.login.invalidvaluemax": "local_moodlemobileapp", | ||||
|   "core.login.invalidvaluemin": "local_moodlemobileapp", | ||||
|   "core.login.login": "moodle", | ||||
| @ -2155,6 +2156,7 @@ | ||||
|   "core.login.supplyinfo": "moodle", | ||||
|   "core.login.toggleremove": "local_moodlemobileapp", | ||||
|   "core.login.username": "moodle", | ||||
|   "core.login.usernamelowercase": "moodle", | ||||
|   "core.login.usernameoremail": "moodle", | ||||
|   "core.login.usernamerequired": "local_moodlemobileapp", | ||||
|   "core.login.usernotaddederror": "error", | ||||
|  | ||||
| @ -1,13 +1,18 @@ | ||||
| <ng-container *ngIf="control && control.dirty && !control.valid"> | ||||
|     <ng-container *ngFor="let error of errorKeys"> | ||||
|         <div *ngIf="control.hasError(error)" class="core-input-error"> | ||||
|             <span *ngIf="errorMessages && errorMessages[error]">{{ errorMessages[error] | translate }}</span> | ||||
|             <span *ngIf="(!errorMessages || !errorMessages[error]) && error === 'max' && control.errors?.max"> | ||||
|                 {{ 'core.login.invalidvaluemax' | translate:{$a: control.errors!.max.max} }} | ||||
|             </span> | ||||
|             <span *ngIf="(!errorMessages || !errorMessages[error]) && error === 'min' && control.errors?.min"> | ||||
|                 {{ 'core.login.invalidvaluemin' | translate:{$a: control.errors!.min.min} }} | ||||
|             </span> | ||||
|             <ng-container *ngIf="error !== 'pattern'"> | ||||
|                 <span *ngIf="errorMessages && errorMessages[error]">{{ errorMessages[error] | translate }}</span> | ||||
|                 <span *ngIf="(!errorMessages || !errorMessages[error]) && error === 'max' && control.errors?.max"> | ||||
|                     {{ 'core.login.invalidvaluemax' | translate:{$a: control.errors!.max.max} }} | ||||
|                 </span> | ||||
|                 <span *ngIf="(!errorMessages || !errorMessages[error]) && error === 'min' && control.errors?.min"> | ||||
|                     {{ 'core.login.invalidvaluemin' | translate:{$a: control.errors!.min.min} }} | ||||
|                 </span> | ||||
|             </ng-container> | ||||
|             <ng-container *ngIf="error === 'pattern' && getPatternErrorMessage() as errorMessage"> | ||||
|                 <span>{{ errorMessage | translate }}</span> | ||||
|             </ng-container> | ||||
|         </div> | ||||
|     </ng-container> | ||||
| </ng-container> | ||||
|  | ||||
| @ -41,7 +41,7 @@ import { FormControl } from '@angular/forms'; | ||||
| export class CoreInputErrorsComponent implements OnInit, OnChanges { | ||||
| 
 | ||||
|     @Input() control?: FormControl<unknown>; // Needed to be able to check the validity of the input.
 | ||||
|     @Input() errorMessages: Record<string, string> = {}; // Error messages to show. Keys must be the name of the error.
 | ||||
|     @Input() errorMessages: CoreInputErrorsMessages = {}; // Error messages to show. Keys must be the name of the error.
 | ||||
|     @Input() errorText = ''; // Set other non automatic errors.
 | ||||
|     errorKeys: string[] = []; | ||||
| 
 | ||||
| @ -124,4 +124,44 @@ export class CoreInputErrorsComponent implements OnInit, OnChanges { | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     /** | ||||
|      * Get error message for pattern error. | ||||
|      * | ||||
|      * @returns Error message, undefined if not found. | ||||
|      */ | ||||
|     getPatternErrorMessage(): string | undefined { | ||||
|         const patternError = this.control?.errors?.pattern; | ||||
|         if (!this.errorMessages?.pattern || !patternError) { | ||||
|             return; | ||||
|         } | ||||
| 
 | ||||
|         if (typeof this.errorMessages.pattern === 'string') { | ||||
|             return this.errorMessages.pattern; | ||||
|         } | ||||
| 
 | ||||
|         return this.errorMessages.pattern[patternError.requiredPattern]; | ||||
|     } | ||||
| 
 | ||||
| } | ||||
| 
 | ||||
| /** | ||||
|  * Error messages for each type of error. | ||||
|  * Error messages will be translated in the template, they don't need to be translated already. | ||||
|  */ | ||||
| export type CoreInputErrorsMessages = { | ||||
|     required?: string; | ||||
|     requiredTrue?: string; | ||||
|     email?: string; | ||||
|     date?: string; | ||||
|     datetime?: string; | ||||
|     datetimelocal?: string; | ||||
|     time?: string; | ||||
|     url?: string; | ||||
|     max?: string; | ||||
|     min?: string; | ||||
|     maxlength?: string; | ||||
|     minlength?: string; | ||||
|     // For pattern errors you can define an error for all patterns (string), or one error per pattern.
 | ||||
|     // In the latter case, the key of the object is the pattern and the value is the error message identifier.
 | ||||
|     pattern?: string | Record<string,string>; | ||||
| }; | ||||
|  | ||||
| @ -62,6 +62,7 @@ | ||||
|     "invalidsite": "The site URL is not valid.", | ||||
|     "invalidtime": "Time not valid", | ||||
|     "invalidurl": "Invalid URL specified", | ||||
|     "invalidusername": "The username can only contain alphanumeric lowercase characters (letters and numbers), underscore (_), hyphen (-), period (.) or at symbol (@).", | ||||
|     "invalidvaluemax": "The maximum value is {{$a}}", | ||||
|     "invalidvaluemin": "The minimum value is {{$a}}", | ||||
|     "login": "Log in", | ||||
| @ -125,6 +126,7 @@ | ||||
|     "supplyinfo": "More details", | ||||
|     "toggleremove": "Edit accounts list", | ||||
|     "username": "Username", | ||||
|     "usernamelowercase": "Only lowercase letters allowed", | ||||
|     "usernameoremail": "Enter either username or email address", | ||||
|     "usernamerequired": "Username required", | ||||
|     "usernotaddederror": "User not added - error", | ||||
|  | ||||
| @ -35,6 +35,7 @@ import { CorePath } from '@singletons/path'; | ||||
| import { CoreDom } from '@singletons/dom'; | ||||
| import { CoreSitesFactory } from '@services/sites-factory'; | ||||
| import { EMAIL_SIGNUP_FEATURE_NAME } from '@features/login/constants'; | ||||
| import { CoreInputErrorsMessages } from '@components/input-errors/input-errors'; | ||||
| 
 | ||||
| /** | ||||
|  * Page to signup using email. | ||||
| @ -46,6 +47,10 @@ import { EMAIL_SIGNUP_FEATURE_NAME } from '@features/login/constants'; | ||||
| }) | ||||
| export class CoreLoginEmailSignupPage implements OnInit { | ||||
| 
 | ||||
|     // Accept A-Z in strict chars pattern to be able to differentiate it from the lowercase pattern.
 | ||||
|     protected static readonly USERNAME_STRICT_CHARS_PATTERN = '^[A-Z-.@_a-z0-9]*$'; | ||||
|     protected static readonly USERNAME_LOWERCASE_PATTERN = '^[^A-Z]*$'; | ||||
| 
 | ||||
|     @ViewChild(CoreRecaptchaComponent) recaptchaComponent?: CoreRecaptchaComponent; | ||||
|     @ViewChild('ageForm') ageFormElement?: ElementRef; | ||||
|     @ViewChild('signupFormEl') signupFormElement?: ElementRef; | ||||
| @ -77,12 +82,12 @@ export class CoreLoginEmailSignupPage implements OnInit { | ||||
|     supportEmail?: string; | ||||
| 
 | ||||
|     // Validation errors.
 | ||||
|     usernameErrors: Record<string, string>; | ||||
|     passwordErrors: Record<string, string>; | ||||
|     emailErrors: Record<string, string>; | ||||
|     email2Errors: Record<string, string>; | ||||
|     policyErrors: Record<string, string>; | ||||
|     namefieldsErrors?: Record<string, Record<string, string>>; | ||||
|     usernameErrors: CoreInputErrorsMessages; | ||||
|     passwordErrors: CoreInputErrorsMessages; | ||||
|     emailErrors: CoreInputErrorsMessages; | ||||
|     email2Errors: CoreInputErrorsMessages; | ||||
|     policyErrors: CoreInputErrorsMessages; | ||||
|     namefieldsErrors?: Record<string, CoreInputErrorsMessages>; | ||||
| 
 | ||||
|     constructor( | ||||
|         protected fb: FormBuilder, | ||||
| @ -98,14 +103,19 @@ export class CoreLoginEmailSignupPage implements OnInit { | ||||
| 
 | ||||
|         // Create the signupForm with the basic controls. More controls will be added later.
 | ||||
|         this.signupForm = this.fb.group({ | ||||
|             username: ['', Validators.required], | ||||
|             password: ['', Validators.required], | ||||
|             email: ['', Validators.compose([Validators.required, Validators.email])], | ||||
|             email2: ['', Validators.compose([Validators.required, Validators.email])], | ||||
|         }); | ||||
| 
 | ||||
|         // Setup validation errors.
 | ||||
|         this.usernameErrors = { required: 'core.login.usernamerequired' }; | ||||
|         this.usernameErrors = { | ||||
|             required: 'core.login.usernamerequired', | ||||
|             pattern: { | ||||
|                 [CoreLoginEmailSignupPage.USERNAME_STRICT_CHARS_PATTERN]: 'core.login.invalidusername', | ||||
|                 [CoreLoginEmailSignupPage.USERNAME_LOWERCASE_PATTERN]: 'core.login.usernamelowercase', | ||||
|             }, | ||||
|         }; | ||||
|         this.passwordErrors = { required: 'core.login.passwordrequired' }; | ||||
|         this.emailErrors = { required: 'core.login.missingemail' }; | ||||
|         this.policyErrors = { required: 'core.login.policyagree' }; | ||||
| @ -140,6 +150,13 @@ export class CoreLoginEmailSignupPage implements OnInit { | ||||
|      * Complete the FormGroup using the settings received from server. | ||||
|      */ | ||||
|     protected completeFormGroup(): void { | ||||
|         const checkStrictChars = this.settings?.extendedusernamechars === false; | ||||
|         this.signupForm.addControl('username', this.fb.control('', Validators.compose([ | ||||
|             Validators.required, | ||||
|             Validators.pattern(CoreLoginEmailSignupPage.USERNAME_LOWERCASE_PATTERN), | ||||
|             checkStrictChars ?  Validators.pattern(CoreLoginEmailSignupPage.USERNAME_STRICT_CHARS_PATTERN) : undefined, | ||||
|         ]))); | ||||
| 
 | ||||
|         this.signupForm.addControl('city', this.fb.control(this.settings?.defaultcity || '')); | ||||
|         this.signUpCountryControl = this.fb.control(this.settings?.country || '', { nonNullable: true }); | ||||
|         this.signupForm.addControl('country', this.signUpCountryControl); | ||||
|  | ||||
| @ -1553,6 +1553,7 @@ export type AuthEmailSignupSettings = { | ||||
|     sitepolicyhandler?: string; // Site policy handler.
 | ||||
|     defaultcity?: string; // Default city.
 | ||||
|     country?: string; // Default country.
 | ||||
|     extendedusernamechars?: boolean; // @since 4.4. Extended characters in usernames or no.
 | ||||
|     profilefields?: AuthEmailSignupProfileField[]; // Required profile fields.
 | ||||
|     recaptchapublickey?: string; // Recaptcha public key.
 | ||||
|     recaptchachallengehash?: string; // Recaptcha challenge hash.
 | ||||
|  | ||||
| @ -184,3 +184,44 @@ Feature: Test signup in app | ||||
|     And I should find "1 January 2010, 11:45 AM" in the app | ||||
|     And I should find "This is my description" in the app | ||||
|     And I should find "https://moodle.com" in the app | ||||
| 
 | ||||
|   @lms_from4.4 | ||||
|   Scenario: Check extended characters in usernames show error if setting is disabled | ||||
|     Given the following config values are set as admin: | ||||
|       | extendedusernamechars | 0 | | ||||
|     When I launch the app | ||||
|     And I set the field "Your site" to "$WWWROOT" in the app | ||||
|     And I press "Connect to your site" in the app | ||||
|     And I press "Create new account" in the app | ||||
|     And I set the following fields to these values in the app: | ||||
|       | Username | u1$ | | ||||
|     Then I should find "The username can only contain alphanumeric" in the app | ||||
| 
 | ||||
|     When I set the following fields to these values in the app: | ||||
|       | Username | u1 | | ||||
|     Then I should not find "The username can only contain alphanumeric" in the app | ||||
| 
 | ||||
|   @lms_from4.4 | ||||
|   Scenario: Check can include extended characters in usernames if setting is enabled | ||||
|     Given the following config values are set as admin: | ||||
|       | extendedusernamechars | 1 | | ||||
|     When I launch the app | ||||
|     And I set the field "Your site" to "$WWWROOT" in the app | ||||
|     And I press "Connect to your site" in the app | ||||
|     And I press "Create new account" in the app | ||||
|     And I set the following fields to these values in the app: | ||||
|       | Username | u1U | | ||||
|     Then I should find "Only lowercase letters allowed" in the app | ||||
| 
 | ||||
|     When I set the following fields to these values in the app: | ||||
|       | Username | u1$ | | ||||
|     Then I should not find "The username can only contain alphanumeric" in the app | ||||
| 
 | ||||
|     When I set the following fields to these values in the app: | ||||
|       | Password | pu1 | | ||||
|       | Email address | u1@u1.com | | ||||
|       | Email (again) | u1@u1.com | | ||||
|       | First name | User | | ||||
|       | Last name | Test | | ||||
|     And I press "Create my new account" in the app | ||||
|     Then I should find "An email should have been sent to your address" in the app | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user