diff --git a/backend/src/main/java/de/champonthis/buntspecht/controller/validation/PasswordModelValidator.java b/backend/src/main/java/de/champonthis/buntspecht/controller/validation/PasswordModelValidator.java index 03f2b10..e498f80 100644 --- a/backend/src/main/java/de/champonthis/buntspecht/controller/validation/PasswordModelValidator.java +++ b/backend/src/main/java/de/champonthis/buntspecht/controller/validation/PasswordModelValidator.java @@ -28,6 +28,7 @@ public class PasswordModelValidator implements Validator { public static final String SYSTEM_PROPERTY_PASSWORD_RULE_WHITESPACE = "password.rule.whitespace"; public static final String SYSTEM_PROPERTY_PASSWORD_RULE_LENGTH = "password.rule.length"; + public static final String SYSTEM_PROPERTY_PASSWORD_RULE_LOWERCASE = "password.rule.lowercase"; public static final String SYSTEM_PROPERTY_PASSWORD_RULE_UPPERCASE = "password.rule.uppercase"; public static final String SYSTEM_PROPERTY_PASSWORD_RULE_DIGIT = "password.rule.digit"; public static final String SYSTEM_PROPERTY_PASSWORD_RULE_SPECIAL = "password.rule.special"; @@ -52,6 +53,11 @@ public class PasswordModelValidator implements Validator { rules.add(new LengthRule(length, 4096)); } + int lowercase = systemPropertyManager.getInteger(SYSTEM_PROPERTY_PASSWORD_RULE_LOWERCASE, 1); + if (lowercase > 0) { + rules.add(new CharacterRule(EnglishCharacterData.LowerCase, lowercase)); + } + int uppercase = systemPropertyManager.getInteger(SYSTEM_PROPERTY_PASSWORD_RULE_UPPERCASE, 1); if (uppercase > 0) { rules.add(new CharacterRule(EnglishCharacterData.UpperCase, uppercase)); @@ -73,7 +79,7 @@ public class PasswordModelValidator implements Validator { if (!result.isValid()) { for (RuleResultDetail ruleResultDetail : result.getDetails()) { - errors.rejectValue("password", ruleResultDetail.getErrorCode()); + errors.rejectValue("password", ruleResultDetail.getErrorCode(), ruleResultDetail.getValues(), null); } } diff --git a/backend/src/main/java/de/champonthis/buntspecht/controller/validation/TurnoverValidator.java b/backend/src/main/java/de/champonthis/buntspecht/controller/validation/TurnoverValidator.java index baf1727..2ae38b0 100644 --- a/backend/src/main/java/de/champonthis/buntspecht/controller/validation/TurnoverValidator.java +++ b/backend/src/main/java/de/champonthis/buntspecht/controller/validation/TurnoverValidator.java @@ -32,11 +32,11 @@ public class TurnoverValidator implements Validator { } if (turnover.getPrice() < 0) { - errors.rejectValue("price", "POSITIVE_VALUE"); + errors.rejectValue("price", "MIN"); } if (turnover.getGiftcardPrice() != null && turnover.getGiftcardPrice() < 0) { - errors.rejectValue("giftcardPrice", "POSITIVE_VALUE"); + errors.rejectValue("giftcardPrice", "MIN"); } else if (turnover.getGiftcardPrice() != null && turnover.getGiftcardPrice() > turnover.getPrice()) { errors.rejectValue("giftcardPrice", "GREATER_THAN_PRICE"); } diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 1e83a72..daac779 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -19,7 +19,7 @@ import { PageNotFound } from './pages/notfound/notfound.page'; import { PageProfile } from './pages/profile/profile.page'; import { PageUnavailable } from './pages/unavailable/unavailable.page'; import { UiMain } from './ui/main/main.ui'; -import { I18nEmptyPipe, I18nPipe } from './utils/i18n.pipe'; +import { ErrorCodePipe, I18nEmptyPipe, I18nPipe } from './utils/i18n.pipe'; import { MomentPipe } from './utils/moment.pipe'; import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field'; @@ -66,32 +66,33 @@ export class XhrInterceptor implements HttpInterceptor { @NgModule({ declarations: [ + AppComponent, AutofocusDirective, + ConfirmDialog, + ErrorCodePipe, I18nPipe, I18nEmptyPipe, MomentPipe, - AppComponent, - PageTurnovers, - PageTurnoversManage, - PageTurnover, PageLogin, PageManagement, PageNotFound, PagePassword, PageProfile, + PageTurnover, + PageTurnovers, + PageTurnoversManage, PageUnavailable, PageUsers, PageUserCreate, UiMain, - UiTurnovers, - ConfirmDialog + UiTurnovers ], imports: [ - BrowserModule, AppRoutingModule, + BrowserModule, BrowserAnimationsModule, - MaterialModule, FormsModule, + MaterialModule, ReactiveFormsModule, ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production, registrationStrategy: 'registerWhenStable:30000' }), ], diff --git a/frontend/src/app/pages/password/password.page.html b/frontend/src/app/pages/password/password.page.html index 5ded0ad..7c2acc9 100644 --- a/frontend/src/app/pages/password/password.page.html +++ b/frontend/src/app/pages/password/password.page.html @@ -7,21 +7,21 @@ {{'password.old' | i18n}} - {{'password.error.' + error.key | i18n}} + {{'password.error.' + (error.key | errorCode) | i18n:error.value}} {{'password.new' | i18n}} - {{'password.error.' + error.key | i18n}} + {{'password.error.' + (error.key | errorCode) | i18n:error.value}} {{'password.repeat' | i18n}} - {{'password.error.' + error.key | i18n}} + {{'password.error.' + (error.key | errorCode) | i18n:error.value}} diff --git a/frontend/src/app/pages/password/password.page.ts b/frontend/src/app/pages/password/password.page.ts index dd4d120..3887a77 100644 --- a/frontend/src/app/pages/password/password.page.ts +++ b/frontend/src/app/pages/password/password.page.ts @@ -53,9 +53,9 @@ export class PagePassword implements OnInit, OnDestroy { this.working = false; if (error.status == 409) { let errors = {}; - for (let code of error.error) { - errors[code.field] = errors[code.field] || {}; - errors[code.field][code.code] = true; + for (let errorObject of error.error) { + errors[errorObject.field] = errors[errorObject.field] || {}; + errors[errorObject.field][errorObject.code] = errorObject.arguments || true; } for (let code in errors) { diff --git a/frontend/src/app/pages/profile/profile.page.html b/frontend/src/app/pages/profile/profile.page.html index 476ac97..11f7b86 100644 --- a/frontend/src/app/pages/profile/profile.page.html +++ b/frontend/src/app/pages/profile/profile.page.html @@ -50,14 +50,14 @@ {{'password.new' | i18n}} - {{'password.error.' + error.key | i18n}} + {{'password.error.' + (error.key | errorCode) | i18n:error.value}} {{'password.repeat' | i18n}} - {{'password.error.' + error.key | i18n}} + {{'password.error.' + (error.key | errorCode) | i18n:error.value}} diff --git a/frontend/src/app/pages/profile/profile.page.ts b/frontend/src/app/pages/profile/profile.page.ts index e719bab..a6cece4 100644 --- a/frontend/src/app/pages/profile/profile.page.ts +++ b/frontend/src/app/pages/profile/profile.page.ts @@ -108,10 +108,10 @@ export class PageProfile implements OnInit, OnDestroy { this.working = false; if (error.status == 422) { let errors = {}; - for (let code of error.error) { - errors[code.field] = errors[code.field] || {}; - errors[code.field][code.code] = true; - } + for (let errorObject of error.error) { + errors[errorObject.field] = errors[errorObject.field] || {}; + errors[errorObject.field][errorObject.code] = errorObject.arguments || true; + } for (let code in errors) { this.profileForm.get(code).setErrors(errors[code]); @@ -138,10 +138,10 @@ export class PageProfile implements OnInit, OnDestroy { this.working = false; if (error.status == 409) { let errors = {}; - for (let code of error.error) { - errors[code.field] = errors[code.field] || {}; - errors[code.field][code.code] = true; - } + for (let errorObject of error.error) { + errors[errorObject.field] = errors[errorObject.field] || {}; + errors[errorObject.field][errorObject.code] = errorObject.arguments || true; + } for (let code in errors) { this.passwordForm.get(code).setErrors(errors[code]); diff --git a/frontend/src/app/pages/turnover/turnover.page.html b/frontend/src/app/pages/turnover/turnover.page.html index 4ececb6..0ac8df6 100644 --- a/frontend/src/app/pages/turnover/turnover.page.html +++ b/frontend/src/app/pages/turnover/turnover.page.html @@ -25,7 +25,7 @@ {{'turnover.customer' | i18n}} - {{'turnover.customer.error.' + error.key | i18n}} + {{'turnover.customer.error.' + (error.key | errorCode) | i18n:error.value}} @@ -33,7 +33,7 @@ {{'turnover.motif' | i18n}} - {{'turnover.motif.error.' + error.key | i18n}} + {{'turnover.motif.error.' + (error.key | errorCode) | i18n:error.value}} @@ -42,7 +42,7 @@ {{'turnover.price.suffix' | i18n}} - {{'turnover.price.error.' + error.key | i18n}} + {{'turnover.price.error.' + (error.key | errorCode) | i18n:error.value}} @@ -54,7 +54,7 @@ {{'turnover.giftcard.number' | i18n}} - {{'turnover.giftcard.number.error.' + error.key | i18n}} + {{'turnover.giftcard.number.error.' + (error.key | errorCode) | i18n:error.value}} @@ -63,7 +63,7 @@ {{'turnover.price.suffix' | i18n}} - {{'turnover.giftcard.price.error.' + error.key | i18n}} + {{'turnover.giftcard.price.error.' + (error.key | errorCode) | i18n:error.value}} @@ -72,7 +72,7 @@ {{'turnover.timeInvestment.suffix' | i18n}} - {{'turnover.timeInvestment.error.' + error.key | i18n}} + {{'turnover.timeInvestment.error.' + (error.key | errorCode) | i18n:error.value}} @@ -80,7 +80,7 @@ {{'turnover.remark' | i18n}} - {{'turnover.remark.error.' + error.key | i18n}} + {{'turnover.remark.error.' + (error.key | errorCode) | i18n:error.value}} @@ -88,7 +88,7 @@ {{'turnover.materialConsumption' | i18n}} - {{'turnover.materialConsumption.error.' + error.key | i18n}} + {{'turnover.materialConsumption.error.' + (error.key | errorCode) | i18n:error.value}} diff --git a/frontend/src/app/pages/turnover/turnover.page.ts b/frontend/src/app/pages/turnover/turnover.page.ts index 2b3a5f2..9c4f684 100644 --- a/frontend/src/app/pages/turnover/turnover.page.ts +++ b/frontend/src/app/pages/turnover/turnover.page.ts @@ -137,10 +137,10 @@ export class PageTurnover implements OnInit { this.working = false; if (error.status == 422) { let errors = {}; - for (let code of error.error) { - errors[code.field] = errors[code.field] || {}; - errors[code.field][code.code] = true; - } + for (let errorObject of error.error) { + errors[errorObject.field] = errors[errorObject.field] || {}; + errors[errorObject.field][errorObject.code] = errorObject.arguments || true; + } for (let code in errors) { this.form.get(code).setErrors(errors[code]); @@ -188,10 +188,10 @@ export class PageTurnover implements OnInit { } if (error.status == 409) { let errors = {}; - for (let code of error.error) { - errors[code.field] = errors[code.field] || {}; - errors[code.field][code.code] = true; - } + for (let errorObject of error.error) { + errors[errorObject.field] = errors[errorObject.field] || {}; + errors[errorObject.field][errorObject.code] = errorObject.arguments || true; + } for (let code in errors) { this.form.get(code).setErrors(errors[code]); diff --git a/frontend/src/app/pages/users/create/users.create.page.html b/frontend/src/app/pages/users/create/users.create.page.html index a64d9d7..54081d2 100644 --- a/frontend/src/app/pages/users/create/users.create.page.html +++ b/frontend/src/app/pages/users/create/users.create.page.html @@ -6,7 +6,7 @@ {{'profile.username' | i18n}} - {{'user.error.' + error.key | i18n}} + {{'user.error.' + (error.key | errorCode) | i18n:error.value}} @@ -14,7 +14,7 @@ {{'profile.name' | i18n}} - {{'user.error.' + error.key | i18n}} + {{'user.error.' + (error.key | errorCode) | i18n:error.value}} @@ -22,7 +22,7 @@ {{'profile.email' | i18n}} - {{'user.error.' + error.key | i18n}} + {{'user.error.' + (error.key | errorCode) | i18n:error.value}} @@ -30,7 +30,7 @@ {{'user.password' | i18n}} - {{'password.error.' + error.key | i18n}} + {{'password.error.' + (error.key | errorCode) | i18n:error.value}} diff --git a/frontend/src/app/pages/users/create/users.create.page.ts b/frontend/src/app/pages/users/create/users.create.page.ts index dcbe44f..044981e 100644 --- a/frontend/src/app/pages/users/create/users.create.page.ts +++ b/frontend/src/app/pages/users/create/users.create.page.ts @@ -52,12 +52,13 @@ export class PageUserCreate implements OnInit { this.working = false; if (error.status == 409) { let errors = {}; - for (let code of error.error) { - errors[code.field] = errors[code.field] || {}; - errors[code.field][code.code] = true; + for (let errorObject of error.error) { + errors[errorObject.field] = errors[errorObject.field] || {}; + errors[errorObject.field][errorObject.code] = errorObject.arguments || true; } for (let code in errors) { + console.log(code, errors[code]); this.form.get(code).setErrors(errors[code]); } } @@ -68,9 +69,9 @@ export class PageUserCreate implements OnInit { this.working = false; if (error.status == 409) { let errors = {}; - for (let code of error.error) { - errors[code.field] = errors[code.field] || {}; - errors[code.field][code.code] = true; + for (let errorObject of error.error) { + errors[errorObject.field] = errors[errorObject.field] || {}; + errors[errorObject.field][errorObject.code] = errorObject.arguments || true; } for (let code in errors) { diff --git a/frontend/src/app/ui/main/main.ui.ts b/frontend/src/app/ui/main/main.ui.ts index 44ca97c..664cdc9 100644 --- a/frontend/src/app/ui/main/main.ui.ts +++ b/frontend/src/app/ui/main/main.ui.ts @@ -22,8 +22,8 @@ export class UiMain { opened: boolean = true; darkTheme: boolean = false; title = 'buntspecht'; - currentLocale: String; - datetimeformat: String; + currentLocale: string; + datetimeformat: string; locales; authenticated: boolean = false; username: string = ""; diff --git a/frontend/src/app/utils/i18n.pipe.ts b/frontend/src/app/utils/i18n.pipe.ts index 516a63d..86da1f1 100644 --- a/frontend/src/app/utils/i18n.pipe.ts +++ b/frontend/src/app/utils/i18n.pipe.ts @@ -12,7 +12,10 @@ export class I18nPipe implements PipeTransform { constructor(private i18n: I18nService) { } - transform(value: String, ...args: any[]): String { + transform(value: string, ...args: any[]): string { + if (args.length === 1 && Array.isArray(args[0])) { + args = args[0]; + } return this.i18n.get(value, args); } } @@ -25,7 +28,17 @@ export class I18nEmptyPipe implements PipeTransform { constructor(private i18n: I18nService) { } - transform(value: String, ...args: any[]): String { + transform(value: string, ...args: any[]): string { return this.i18n.getEmpty(value, args); } +} + +@Pipe({ + name: 'errorCode' +}) +export class ErrorCodePipe implements PipeTransform { + + transform(value: string): string { + return value && value.toUpperCase().replaceAll('-', '_') || value; + } } \ No newline at end of file diff --git a/frontend/src/assets/i18n/de-informal.json b/frontend/src/assets/i18n/de-informal.json index 7f4a631..6a93dd7 100644 --- a/frontend/src/assets/i18n/de-informal.json +++ b/frontend/src/assets/i18n/de-informal.json @@ -63,12 +63,12 @@ ".": "Passwort ändern", "error": { "ILLEGAL_WHITESPACE": "Bitte keine Leerzeichen verwenden.", - "INSUFFICIENT_DIGIT": "Bitte mindestens eine Zahl eingeben.", - "INSUFFICIENT_LOWERCASE": "Bitte mindestens einen Kleinbuchstaben eingeben.", - "INSUFFICIENT_SPECIAL": "Bitte mindestens ein Sonderzeichen eingeben.", - "INSUFFICIENT_UPPERCASE": "Bitte mindestens einen Großbuchstaben eingeben.", + "INSUFFICIENT_DIGIT": "Bitte mindestens {0} Zahl/en eingeben.", + "INSUFFICIENT_LOWERCASE": "Bitte mindestens {0} Kleinbuchstaben eingeben.", + "INSUFFICIENT_SPECIAL": "Bitte mindestens {0} Sonderzeichen eingeben.", + "INSUFFICIENT_UPPERCASE": "Bitte mindestens {0} Großbuchstaben eingeben.", "NOT_MATCH": "Passwörter stimmen nicht überein.", - "TOO_SHORT": "Bitte ein längeres Passwort wählen.", + "TOO_SHORT": "Bitte Mindestens {0} Zeichen verwenden.", "UNAUTHORIZED": "Falsches Passwort" }, "old": "Altes Password", @@ -108,7 +108,7 @@ "customer": { ".": "Kunde", "error": { - "required": "Angabe von Kunde erforderlich" + "REQUIRED": "Angabe von Kunde erforderlich" } }, "dueDate": { @@ -122,14 +122,13 @@ "giftcard": { ".": "Gutschein", "number": { - ".": "Gutscheinnummer", - "error": "" + ".": "Gutscheinnummer" }, "price": { ".": "Gutscheinwert", "error": { "GREATER_THAN_PRICE": "Gutscheinwert übersteigt Preis", - "min": "Üngültiger Wert" + "MIN": "Üngültiger Wert" } }, "priceUsage": "Gutscheinanteil" @@ -139,14 +138,14 @@ "motif": { ".": "Motiv", "error": { - "required": "Angabe von Motiv erforderlich" + "REQUIRED": "Angabe von Motiv erforderlich" } }, "price": { ".": "Preis", "error": { - "min": "Üngültiger Wert", - "required": "Angabe des Preises erforderlich" + "MIN": "Üngültiger Wert", + "REQUIRED": "Angabe des Preises erforderlich" }, "suffix": "€", "total": "Umsatz: {0} €" @@ -156,7 +155,7 @@ "timeInvestment": { ".": "Zeiteinsatz", "error": { - "min": "Üngültiger Wert" + "MIN": "Üngültiger Wert" }, "suffix": "Std.", "total": "Zeiteinsatz: {0} Std." @@ -199,7 +198,8 @@ "create": "Neuen User erstellen", "delete": "User löschen", "error": { - "ALREADY_EXISTS": "User existiert bereits" + "ALREADY_EXISTS": "User existiert bereits", + "REQUIRED": "Angabe eines Usernames erforderlich" }, "manage": "Verwalten", "password": "Passwort",