diff --git a/alfa-client/apps/admin/src/app/app.component.html b/alfa-client/apps/admin/src/app/app.component.html index e504907b9ccb1ec0508e433b30f040f7ca174f99..f9f6573f38f14c261b0d6c431ad1fb0a1cd327c5 100644 --- a/alfa-client/apps/admin/src/app/app.component.html +++ b/alfa-client/apps/admin/src/app/app.component.html @@ -2,18 +2,22 @@ <header class="flex items-center justify-between bg-white p-6" data-test-id="admin-header"> <div class="text-ozgblue font-extrabold">OZG-Cloud Administration</div> <div> - <user-profile-button-container data-test-id="user-profile-button"></user-profile-button-container> + <user-profile-button-container + data-test-id="user-profile-button" + ></user-profile-button-container> </div> </header> <div class="relative flex w-full flex-auto justify-center"> - <div class="w-96 bg-slate-300 p-6"> - <nav> - NAV - </nav> - </div> + <div class="w-60 bg-slate-100 p-6"> + <nav> + <postfach-navigation-item + data-test-id="postfach-navigation-item" + ></postfach-navigation-item> + </nav> + </div> <main class="flex-auto bg-slate-200 p-6"> - <router-outlet></router-outlet> + <router-outlet></router-outlet> </main> </div> <span data-test-id="build-version">Version: {{ apiRoot.buildVersion }}</span> -</ng-container> \ No newline at end of file +</ng-container> diff --git a/alfa-client/apps/admin/src/app/app.component.spec.ts b/alfa-client/apps/admin/src/app/app.component.spec.ts index 29671cb8504f5d6630a96f8b757de417386b917b..0fd3f5bb0cc54356d34ab02ddcff92a344d730bc 100644 --- a/alfa-client/apps/admin/src/app/app.component.spec.ts +++ b/alfa-client/apps/admin/src/app/app.component.spec.ts @@ -10,6 +10,7 @@ import { of } from 'rxjs'; import { createApiRootResource } from 'libs/api-root-shared/test/api-root'; import { MockComponent } from 'ng-mocks'; import { UserProfileButtonContainerComponent } from '../common/user-profile-button-container/user-profile.button-container.component'; +import { PostfachNavigationItemComponent } from '../pages/postfach/postfach-navigation-item/postfach-navigation-item.component'; describe('AppComponent', () => { let component: AppComponent; @@ -18,13 +19,18 @@ describe('AppComponent', () => { const adminHeader: string = getDataTestIdOf('admin-header'); const buildVersion: string = getDataTestIdOf('build-version'); const userProfileButton: string = getDataTestIdOf('user-profile-button'); + const postfachNavigationItem: string = getDataTestIdOf('postfach-navigation-item'); const authService: Mock<AuthService> = mock(AuthService); const apiRootService: Mock<ApiRootService> = mock(ApiRootService); beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [AppComponent, MockComponent(UserProfileButtonContainerComponent)], + declarations: [ + AppComponent, + MockComponent(UserProfileButtonContainerComponent), + MockComponent(PostfachNavigationItemComponent), + ], imports: [RouterTestingModule], providers: [ { @@ -94,6 +100,17 @@ describe('AppComponent', () => { }); }); + describe('navigation', () => { + beforeEach(() => { + component.apiRoot$ = of(createStateResource(createApiRootResource())); + }); + it('should have postfach item', () => { + fixture.detectChanges(); + + existsAsHtmlElement(fixture, postfachNavigationItem); + }); + }); + describe('build version', () => { beforeEach(() => { component.apiRoot$ = of(createStateResource(createApiRootResource())); diff --git a/alfa-client/apps/admin/src/app/app.module.ts b/alfa-client/apps/admin/src/app/app.module.ts index 1c61909253212188bb0e527b6238e60c33f3ddae..e13deaf980ec4811058fd72666bd6a47659f2c47 100644 --- a/alfa-client/apps/admin/src/app/app.module.ts +++ b/alfa-client/apps/admin/src/app/app.module.ts @@ -16,11 +16,19 @@ import { environment } from '../environments/environment'; import { AppComponent } from './app.component'; import { initializeKeycloak } from './app.config'; import { appRoutes } from './app.routes'; +import { PostfachPageComponent } from '../pages/postfach/postfach-page/postfach-page.component'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { UserProfileButtonContainerComponent } from '../common/user-profile-button-container/user-profile.button-container.component'; +import { AdminSettingsModule } from '@admin-client/admin-settings'; +import { PostfachNavigationItemComponent } from '../pages/postfach/postfach-navigation-item/postfach-navigation-item.component'; @NgModule({ - declarations: [AppComponent, UserProfileButtonContainerComponent], + declarations: [ + AppComponent, + PostfachPageComponent, + UserProfileButtonContainerComponent, + PostfachNavigationItemComponent, + ], imports: [ CommonModule, TestbtnComponent, @@ -37,6 +45,7 @@ import { UserProfileButtonContainerComponent } from '../common/user-profile-butt StoreRouterConnectingModule.forRoot(), FormsModule, ReactiveFormsModule, + AdminSettingsModule, ], providers: [ { diff --git a/alfa-client/apps/admin/src/app/app.routes.ts b/alfa-client/apps/admin/src/app/app.routes.ts index 8762dfe2c6510c01425b35c6cf76371cc0b332c6..1834aa696228932a34d0b76ea2398d7e6a80b9c6 100644 --- a/alfa-client/apps/admin/src/app/app.routes.ts +++ b/alfa-client/apps/admin/src/app/app.routes.ts @@ -1,3 +1,15 @@ import { Route } from '@angular/router'; +import { PostfachPageComponent } from '../pages/postfach/postfach-page/postfach-page.component'; -export const appRoutes: Route[] = []; +export const appRoutes: Route[] = [ + { + path: '', + redirectTo: 'postfach', + pathMatch: 'full', + }, + { + path: 'postfach', + component: PostfachPageComponent, + title: 'Admin | Postfach', + }, +]; diff --git a/alfa-client/apps/admin/src/assets/mail.svg b/alfa-client/apps/admin/src/assets/mail.svg new file mode 100644 index 0000000000000000000000000000000000000000..510a1dc44dadd31e431e74cae39be8f248344465 --- /dev/null +++ b/alfa-client/apps/admin/src/assets/mail.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" height="24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M20 4H4c-1.1 0-1.99.9-1.99 2L2 18c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 14H4V8l8 5 8-5v10zm-8-7L4 6h16l-8 5z"/></svg> \ No newline at end of file diff --git a/alfa-client/apps/admin/src/main.ts b/alfa-client/apps/admin/src/main.ts index 5d388e265a6adda237cd7b2c9650f0055ca1457d..5e03b925b784465a49e2f49ead63c0801124b6b0 100644 --- a/alfa-client/apps/admin/src/main.ts +++ b/alfa-client/apps/admin/src/main.ts @@ -1,22 +1,23 @@ import { loadEnvironment } from '@alfa-client/environment-shared'; import { enableProdMode } from '@angular/core'; import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; -import { isNil } from 'lodash-es'; import { AppModule } from './app/app.module'; +import { isNil } from 'lodash-es'; import { environment } from './environments/environment'; loadEnvironment(environment.environmentUrl).then((env) => { - if (isNil(env)) { - console.error('Connection Error: environment is undefined'); - return; - } - if (env.production) { - enableProdMode(); - } - console.info('init bootstrap application...'); - //Für Standalone AppComponent - //bootstrapApplication(AppComponent, appConfig).catch(err => console.error(err)); - platformBrowserDynamic() - .bootstrapModule(AppModule) - .catch((err) => console.log(err)); + if (isNil(env?.production)) { + console.error('Connection Error: environment is ', env); + return; + } + + if (env.production) { + enableProdMode(); + } + console.info('init bootstrap application...'); + //Für Standalone AppComponent + //bootstrapApplication(AppComponent, appConfig).catch(err => console.error(err)); + platformBrowserDynamic() + .bootstrapModule(AppModule) + .catch((err) => console.log(err)); }); diff --git a/alfa-client/apps/admin/src/pages/postfach/postfach-navigation-item/postfach-navigation-item.component.html b/alfa-client/apps/admin/src/pages/postfach/postfach-navigation-item/postfach-navigation-item.component.html new file mode 100644 index 0000000000000000000000000000000000000000..aeceb900769ddcc0a0c4865c1b50fc0bf86f7a7b --- /dev/null +++ b/alfa-client/apps/admin/src/pages/postfach/postfach-navigation-item/postfach-navigation-item.component.html @@ -0,0 +1 @@ +<navigation-item name="Postfach" imageSrc="/assets/mail.svg" link="/postfach"></navigation-item> diff --git a/alfa-client/apps/admin/src/pages/postfach/postfach-navigation-item/postfach-navigation-item.component.spec.ts b/alfa-client/apps/admin/src/pages/postfach/postfach-navigation-item/postfach-navigation-item.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..d56e1f5c365d0aa5f650dcba1ae0345a3e41e8c9 --- /dev/null +++ b/alfa-client/apps/admin/src/pages/postfach/postfach-navigation-item/postfach-navigation-item.component.spec.ts @@ -0,0 +1,28 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { PostfachNavigationItemComponent } from './postfach-navigation-item.component'; +import { MockComponent } from 'ng-mocks'; +import { ReactiveFormsModule } from '@angular/forms'; +import { NavigationItemComponent } from '@admin-client/admin-settings'; + +describe('PostfachPageComponent', () => { + let component: PostfachNavigationItemComponent; + let fixture: ComponentFixture<PostfachNavigationItemComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [PostfachNavigationItemComponent, MockComponent(NavigationItemComponent)], + imports: [ReactiveFormsModule], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(PostfachNavigationItemComponent); + component = fixture.componentInstance; + + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/alfa-client/apps/admin/src/pages/postfach/postfach-navigation-item/postfach-navigation-item.component.ts b/alfa-client/apps/admin/src/pages/postfach/postfach-navigation-item/postfach-navigation-item.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..4c4820aa819932b900cd38d56aeb455124937ff5 --- /dev/null +++ b/alfa-client/apps/admin/src/pages/postfach/postfach-navigation-item/postfach-navigation-item.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'postfach-navigation-item', + templateUrl: './postfach-navigation-item.component.html', +}) +export class PostfachNavigationItemComponent {} diff --git a/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.html b/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.html new file mode 100644 index 0000000000000000000000000000000000000000..f066382bdd23dcf46af0b372491f28b4ba678b06 --- /dev/null +++ b/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.html @@ -0,0 +1 @@ +<postfach-container></postfach-container> diff --git a/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.spec.ts b/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..8392b508a608c5dae1ba4c1edb6df5bf7e223114 --- /dev/null +++ b/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.spec.ts @@ -0,0 +1,28 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { PostfachPageComponent } from './postfach-page.component'; +import { MockComponent } from 'ng-mocks'; +import { ReactiveFormsModule } from '@angular/forms'; +import { PostfachContainerComponent } from '@admin-client/admin-settings'; + +describe('PostfachPageComponent', () => { + let component: PostfachPageComponent; + let fixture: ComponentFixture<PostfachPageComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [PostfachPageComponent, MockComponent(PostfachContainerComponent)], + imports: [ReactiveFormsModule], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(PostfachPageComponent); + component = fixture.componentInstance; + + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.ts b/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..1d9a54ceddbd6e663477e382dbbff95d9ab13c66 --- /dev/null +++ b/alfa-client/apps/admin/src/pages/postfach/postfach-page/postfach-page.component.ts @@ -0,0 +1,7 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'postfach-page', + templateUrl: './postfach-page.component.html', +}) +export class PostfachPageComponent {} diff --git a/alfa-client/apps/alfa-e2e/docker-compose.yml b/alfa-client/apps/alfa-e2e/docker-compose.yml index 55b84abeda18c7c04c75da79cff584fb70f53efa..fc0bb1476055b3067a232095fb0c74b355ae3e15 100644 --- a/alfa-client/apps/alfa-e2e/docker-compose.yml +++ b/alfa-client/apps/alfa-e2e/docker-compose.yml @@ -45,7 +45,7 @@ services: - OZGCLOUD_PROCESSORS_0_NAME=ticketCheck - OZGCLOUD_USER-MANAGER_URL=http://localhost:9092 - SPRING_DATA_MONGODB_HOST=mongodb - - SPRING_PROFILES_ACTIVE=${SPRING_PROFILE:-dev,e2e} + - SPRING_PROFILES_ACTIVE=${SPRING_PROFILE:-local,e2e} - LOGGING_CONFIG=classpath:log4j2-local.xml ports: - 9091:9090 diff --git a/alfa-client/apps/alfa-e2e/start-e2e-environment.sh b/alfa-client/apps/alfa-e2e/start-e2e-environment.sh index 313de4ccbb708485a795958aee88f6e1c945dc01..32720f469eb17d82a17d60713992a8907a528946 100755 --- a/alfa-client/apps/alfa-e2e/start-e2e-environment.sh +++ b/alfa-client/apps/alfa-e2e/start-e2e-environment.sh @@ -45,7 +45,7 @@ docker compose -f ${SCRIPT_DIR}/docker-compose.yml up -d mongodb user-manager el echo echo "Starting VorgangManager to init search index." -SPRING_PROFILE=dev,e2e,initSearchIndex docker compose -f ${SCRIPT_DIR}/docker-compose.yml up -d vorgang-manager +SPRING_PROFILE=local,e2e,initSearchIndex docker compose -f ${SCRIPT_DIR}/docker-compose.yml up -d vorgang-manager echo waitForInitSearchIndex() { @@ -63,7 +63,7 @@ echo echo echo "Starting VorgangManager and Alfa Server for normal operations." -SPRING_PROFILE=dev,e2e docker compose -f ${SCRIPT_DIR}/docker-compose.yml up -d vorgang-manager alfa +docker compose -f ${SCRIPT_DIR}/docker-compose.yml up -d vorgang-manager alfa waitForServerStarted() { (docker compose -f ${SCRIPT_DIR}/docker-compose.yml logs | awk 'BEGIN{RS="\0"} /Started AlfaServerApplication/ && /Started VorgangManagerServerApplication/ { exit 1 }') diff --git a/alfa-client/libs/admin-settings/.eslintrc.json b/alfa-client/libs/admin-settings/.eslintrc.json new file mode 100644 index 0000000000000000000000000000000000000000..adbe7ae2dfabd4a42804f00846baec80877f4c5c --- /dev/null +++ b/alfa-client/libs/admin-settings/.eslintrc.json @@ -0,0 +1,25 @@ +{ + "extends": ["../../.eslintrc.json"], + "ignorePatterns": ["!**/*"], + "overrides": [ + { + "files": ["*.ts", "*.tsx", "*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.ts", "*.tsx"], + "rules": {} + }, + { + "files": ["*.js", "*.jsx"], + "rules": {} + }, + { + "files": ["*.json"], + "parser": "jsonc-eslint-parser", + "rules": { + "@nx/dependency-checks": "error" + } + } + ] +} diff --git a/alfa-client/libs/admin-settings/README.md b/alfa-client/libs/admin-settings/README.md new file mode 100644 index 0000000000000000000000000000000000000000..01b723f8400c9c3dd0f79fe697c5b1be2441a3eb --- /dev/null +++ b/alfa-client/libs/admin-settings/README.md @@ -0,0 +1,7 @@ +# admin-settings + +This library was generated with [Nx](https://nx.dev). + +## Running unit tests + +Run `nx test admin-settings` to execute the unit tests via [Jest](https://jestjs.io). diff --git a/alfa-client/libs/admin-settings/jest.config.ts b/alfa-client/libs/admin-settings/jest.config.ts new file mode 100644 index 0000000000000000000000000000000000000000..84427413b7cbe34595a96099da2cfafce5e69036 --- /dev/null +++ b/alfa-client/libs/admin-settings/jest.config.ts @@ -0,0 +1,23 @@ +/* eslint-disable */ +export default { + displayName: 'admin-settings', + preset: '../../jest.preset.js', + setupFilesAfterEnv: ['<rootDir>/src/test-setup.ts'], + globals: {}, + coverageDirectory: '../../coverage/libs/admin-settings', + transform: { + '^.+\\.(ts|mjs|js|html)$': [ + 'jest-preset-angular', + { + tsconfig: '<rootDir>/tsconfig.spec.json', + stringifyContentPathRegex: '\\.(html|svg)$', + }, + ], + }, + transformIgnorePatterns: ['node_modules/(?!.*\\.mjs$)'], + snapshotSerializers: [ + 'jest-preset-angular/build/serializers/no-ng-attributes', + 'jest-preset-angular/build/serializers/ng-snapshot', + 'jest-preset-angular/build/serializers/html-comment', + ], +}; diff --git a/alfa-client/libs/admin-settings/project.json b/alfa-client/libs/admin-settings/project.json new file mode 100644 index 0000000000000000000000000000000000000000..073f1bfb8ef6bc708062de6387ef1a3fd9e31dd6 --- /dev/null +++ b/alfa-client/libs/admin-settings/project.json @@ -0,0 +1,25 @@ +{ + "name": "admin-settings", + "$schema": "../../node_modules/nx/schemas/project-schema.json", + "sourceRoot": "libs/admin-settings/src", + "projectType": "library", + "prefix": "admin", + "targets": { + "lint": { + "executor": "@nx/eslint:lint", + "outputs": ["{options.outputFile}"], + "options": { + "lintFilePatterns": ["libs/admin-settings/package.json"] + } + }, + "test": { + "executor": "@nx/jest:jest", + "outputs": ["{workspaceRoot}/coverage/{projectRoot}"], + "options": { + "jestConfig": "libs/admin-settings/jest.config.ts", + "passWithNoTests": true + } + } + }, + "tags": [] +} diff --git a/alfa-client/libs/admin-settings/src/index.ts b/alfa-client/libs/admin-settings/src/index.ts new file mode 100644 index 0000000000000000000000000000000000000000..c0ce9b0d2d421edb40ae3069ce1adcb3884b6d36 --- /dev/null +++ b/alfa-client/libs/admin-settings/src/index.ts @@ -0,0 +1,3 @@ +export * from './lib/admin-settings.module'; +export * from './lib/postfach/postfach-container/postfach-container.component'; +export * from './lib/shared/navigation-item/navigation-item.component'; diff --git a/alfa-client/libs/admin-settings/src/lib/admin-settings.module.spec.ts b/alfa-client/libs/admin-settings/src/lib/admin-settings.module.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..088fd75aa2076bf00593453f508704a6e6634344 --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/admin-settings.module.spec.ts @@ -0,0 +1,14 @@ +import { TestBed } from '@angular/core/testing'; +import { AdminSettingsModule } from './admin-settings.module'; + +describe('AdminSettingsModule', () => { + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [AdminSettingsModule], + }); + }); + + it('should create', () => { + expect(AdminSettingsModule).toBeDefined(); + }); +}); diff --git a/alfa-client/libs/admin-settings/src/lib/admin-settings.module.ts b/alfa-client/libs/admin-settings/src/lib/admin-settings.module.ts new file mode 100644 index 0000000000000000000000000000000000000000..7e62764c345cbfc8915b7d11d2132e0e3382c83a --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/admin-settings.module.ts @@ -0,0 +1,21 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { TechSharedModule } from '@alfa-client/tech-shared'; +import { NavigationItemComponent } from './shared/navigation-item/navigation-item.component'; +import { RouterModule } from '@angular/router'; +import { ReactiveFormsModule } from '@angular/forms'; +import { PostfachContainerComponent } from './postfach/postfach-container/postfach-container.component'; +import { PostfachFormComponent } from './postfach/postfach-container/postfach-form/postfach-form.component'; +import { TextFieldComponent } from './shared/text-field/text-field.component'; + +@NgModule({ + declarations: [ + PostfachContainerComponent, + PostfachFormComponent, + NavigationItemComponent, + TextFieldComponent, + ], + imports: [CommonModule, TechSharedModule, RouterModule, ReactiveFormsModule], + exports: [PostfachContainerComponent, NavigationItemComponent], +}) +export class AdminSettingsModule {} diff --git a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-container.component.html b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-container.component.html new file mode 100644 index 0000000000000000000000000000000000000000..f2e1c9803bf2ba4b38f629bdac9187c6a5d22a2c --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-container.component.html @@ -0,0 +1 @@ +<postfach-form></postfach-form> diff --git a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-container.component.scss b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-container.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-container.component.spec.ts b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-container.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..6d086752157a5429e787661c76783f5250df42e9 --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-container.component.spec.ts @@ -0,0 +1,31 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { PostfachContainerComponent } from '@admin-client/admin-settings'; + +import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { ReactiveFormsModule, UntypedFormGroup } from '@angular/forms'; + +import { PostfachFormComponent } from './postfach-form/postfach-form.component'; +import { MockComponent } from 'ng-mocks'; + +describe('PostfachContainerComponent', () => { + let component: PostfachContainerComponent; + let fixture: ComponentFixture<PostfachContainerComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [PostfachContainerComponent, MockComponent(PostfachFormComponent)], + imports: [ReactiveFormsModule], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(PostfachContainerComponent); + component = fixture.componentInstance; + + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-container.component.ts b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-container.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..6a9e73281ece58b6f3c416d8bd34a95d9eb9d217 --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-container.component.ts @@ -0,0 +1,8 @@ +import { Component } from '@angular/core'; + +@Component({ + selector: 'postfach-container', + templateUrl: './postfach-container.component.html', + styleUrls: ['./postfach-container.component.scss'], +}) +export class PostfachContainerComponent {} diff --git a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.html b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.html new file mode 100644 index 0000000000000000000000000000000000000000..4ddfd2b7a927afdb4016395058ed22486429588a --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.html @@ -0,0 +1,53 @@ +<form class="form flex-col" [formGroup]="formService.form"> + <h1 class="text-2xl font-bold">Absender</h1> + <p id="absender-desc" class="p-1">Hinterlegen Sie Absenderinformationen zu Ihrem Postfach.</p> + <div aria-describedby="absender-desc" class="grid-col-1 mb-2 mt-2 grid w-96 gap-1"> + <text-field + inputId="absender-name" + data-test-id="absender-name" + label="Name" + [formControlName]="PostfachFormService.NAME_FIELD" + ></text-field> + <text-field + inputId="absender-anschrift" + data-test-id="absender-anschrift" + label="Anschrift" + [formControlName]="PostfachFormService.ANSCHRIFT_FIELD" + ></text-field> + <text-field + inputId="absender-dienst" + data-test-id="absender-dienst" + label="Dienst" + [formControlName]="PostfachFormService.DIENST_FIELD" + ></text-field> + <text-field + inputId="absender-mandant" + data-test-id="absender-mandant" + label="Mandant" + [formControlName]="PostfachFormService.MANDANT_FIELD" + ></text-field> + <text-field + inputId="absender-gemeindeschluessel" + data-test-id="absender-gemeindeschluessel" + label="Gemeindeschlüssel" + [formControlName]="PostfachFormService.GEMEINDESCHLUESSEL_FIELD" + ></text-field> + </div> + <div class="h-20"></div> + <h1 class="text-2xl font-bold">Signatur</h1> + <p id="signatur-desc">Erstellen oder ändern Sie die Signatur für Nachrichten.</p> + <textarea + data-test-id="signatur-text" + aria-describedby="signatur-desc" + [formControlName]="PostfachFormService.SIGNATUR_FIELD" + class="mb-2 mt-2 block h-40 w-96 p-1" + ></textarea> + + <button + (click)="submit()" + data-test-id="save-button" + class="bg-ozgblue-700 hover:bg-ozgblue-600 active:bg-ozgblue-600/90 focus-visible:outline-ozgblue-800 rounded-md px-3 py-2 text-sm font-semibold text-white shadow-sm focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2" + > + Speichern + </button> +</form> diff --git a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.scss b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.spec.ts b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..ee99eb6160254fa35e04559a9f11fa2bece3e8f4 --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.spec.ts @@ -0,0 +1,93 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { PostfachFormComponent } from './postfach-form.component'; +import { FormsModule, ReactiveFormsModule, UntypedFormGroup } from '@angular/forms'; +import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { + dispatchEventFromFixture, + existsAsHtmlElement, + getElementFromFixture, +} from '@alfa-client/test-utils'; +import { PostfachFormService } from './postfach.formservice'; +import { MockComponent } from 'ng-mocks'; +import { TextFieldComponent } from '../../../shared/text-field/text-field.component'; + +describe('PostfachFormComponent', () => { + let component: PostfachFormComponent; + let fixture: ComponentFixture<PostfachFormComponent>; + let form: UntypedFormGroup; + + const saveButton: string = getDataTestIdOf('save-button'); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [PostfachFormComponent, MockComponent(TextFieldComponent)], + imports: [ReactiveFormsModule, FormsModule], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(PostfachFormComponent); + component = fixture.componentInstance; + form = fixture.componentInstance.formService.form; + + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('Absender section', () => { + const fields = [ + [PostfachFormService.NAME_FIELD, 'Name', 'absender-name'], + [PostfachFormService.ANSCHRIFT_FIELD, 'Anschrift', 'absender-anschrift'], + [PostfachFormService.DIENST_FIELD, 'Dienst', 'absender-dienst'], + [PostfachFormService.MANDANT_FIELD, 'Mandant', 'absender-mandant'], + [ + PostfachFormService.GEMEINDESCHLUESSEL_FIELD, + 'Gemeindeschlüssel', + 'absender-gemeindeschluessel', + ], + ]; + + test.each(fields)( + 'should have label for field "%s" with name "%s"', + (fieldName, text, inputId) => { + const textFieldElement = getElementFromFixture(fixture, getDataTestIdOf(inputId)); + expect(textFieldElement.getAttribute('label')).toBe(text); + }, + ); + + test.each(fields)('should have inputId for field "%s"', (fieldName, text, inputId) => { + const textFieldElement = getElementFromFixture(fixture, getDataTestIdOf(inputId)); + expect(textFieldElement.getAttribute('inputId')).toBe(inputId); + }); + }); + + describe('Signatur section', () => { + const signaturTextarea = getDataTestIdOf('signatur-text'); + + it('should have signatur-text', () => { + existsAsHtmlElement(fixture, signaturTextarea); + }); + + it('should use form control for signatur-text', () => { + const someText = 'some signatur text'; + + form.get(PostfachFormService.SIGNATUR_FIELD).setValue(someText); + + const signatur = getElementFromFixture(fixture, signaturTextarea); + expect(signatur.value).toBe(someText); + }); + }); + + describe('save button', () => { + it('should call submit on click', () => { + component.submit = jest.fn(); + + dispatchEventFromFixture(fixture, saveButton, 'click'); + + expect(component.submit).toHaveBeenCalled(); + }); + }); +}); diff --git a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.ts b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..f63f202379e5516f96668102acda229996af14f8 --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach-form.component.ts @@ -0,0 +1,18 @@ +import { Component } from '@angular/core'; +import { PostfachFormService } from './postfach.formservice'; + +@Component({ + selector: 'postfach-form', + templateUrl: './postfach-form.component.html', + styleUrls: ['./postfach-form.component.scss'], + providers: [PostfachFormService], +}) +export class PostfachFormComponent { + constructor(public formService: PostfachFormService) {} + + protected readonly PostfachFormService = PostfachFormService; + + public submit() { + this.formService.submit(); + } +} diff --git a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach.formservice.spec.ts b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach.formservice.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..0927e3991e8386cae53cb79bd05ec7b1f8359d91 --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach.formservice.spec.ts @@ -0,0 +1,16 @@ +import { FormBuilder } from '@angular/forms'; +import { PostfachFormService } from './postfach.formservice'; + +describe('PostfachFormService', () => { + let formService: PostfachFormService; + + const formBuilder: FormBuilder = new FormBuilder(); + + beforeEach(() => { + formService = new PostfachFormService(formBuilder); + }); + + it('should create', () => { + expect(formService).toBeTruthy(); + }); +}); diff --git a/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach.formservice.ts b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach.formservice.ts new file mode 100644 index 0000000000000000000000000000000000000000..53829e1fce73f0d3dbb83fcb30d91fafc1a576d0 --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/postfach/postfach-container/postfach-form/postfach.formservice.ts @@ -0,0 +1,43 @@ +import { + AbstractFormService, + StateResource, + createEmptyStateResource, +} from '@alfa-client/tech-shared'; +import { Injectable } from '@angular/core'; +import { FormControl, UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { Resource } from '@ngxp/rest'; +import { Observable, of } from 'rxjs'; + +@Injectable() +export class PostfachFormService extends AbstractFormService { + public static readonly NAME_FIELD: string = 'name'; + public static readonly ANSCHRIFT_FIELD: string = 'anschrift'; + public static readonly DIENST_FIELD: string = 'dienst'; + public static readonly MANDANT_FIELD: string = 'mandant'; + public static readonly GEMEINDESCHLUESSEL_FIELD: string = 'gemeindeschluessel'; + public static readonly SIGNATUR_FIELD: string = 'signatur'; + + constructor(formBuilder: UntypedFormBuilder) { + super(formBuilder); + } + + protected initForm(): UntypedFormGroup { + return this.formBuilder.group({ + [PostfachFormService.NAME_FIELD]: new FormControl(), + [PostfachFormService.ANSCHRIFT_FIELD]: new FormControl(), + [PostfachFormService.DIENST_FIELD]: new FormControl(), + [PostfachFormService.MANDANT_FIELD]: new FormControl(), + [PostfachFormService.GEMEINDESCHLUESSEL_FIELD]: new FormControl(), + [PostfachFormService.SIGNATUR_FIELD]: new FormControl(), + }); + } + + protected doSubmit(): Observable<StateResource<Resource>> { + console.info('FormValue: ', this.getFormValue()); + return of(createEmptyStateResource<Resource>()); + } + + protected getPathPrefix(): string { + return ''; + } +} diff --git a/alfa-client/libs/admin-settings/src/lib/shared/navigation-item/navigation-item.component.html b/alfa-client/libs/admin-settings/src/lib/shared/navigation-item/navigation-item.component.html new file mode 100644 index 0000000000000000000000000000000000000000..c9f7e36c16335c9f94d205e9724542a219c62612 --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/shared/navigation-item/navigation-item.component.html @@ -0,0 +1,9 @@ +<a + [routerLink]="link" + routerLinkActive="active-link" + data-test-id="anchor" + class="hover:bg-ozgblue-200 active:bg-ozgblue-200/75 flex items-center gap-4 rounded-full p-3 font-semibold" +> + <img [src]="imageSrc" [alt]="name" class="w-6" [attr.data-test-id]="'image-' + name" /> + <span [attr.data-test-id]="'navigation-label-' + name | convertForDataTest">{{ name }}</span> +</a> diff --git a/alfa-client/libs/admin-settings/src/lib/shared/navigation-item/navigation-item.component.scss b/alfa-client/libs/admin-settings/src/lib/shared/navigation-item/navigation-item.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..9214426c081848ac1a46efac41e715a120eeff02 --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/shared/navigation-item/navigation-item.component.scss @@ -0,0 +1,3 @@ +.active-link:not(:hover):not(:active) { + @apply bg-ozgblue-100; +} diff --git a/alfa-client/libs/admin-settings/src/lib/shared/navigation-item/navigation-item.component.spec.ts b/alfa-client/libs/admin-settings/src/lib/shared/navigation-item/navigation-item.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..e800d7acf9df48a08b81190c029858010e332ad3 --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/shared/navigation-item/navigation-item.component.spec.ts @@ -0,0 +1,67 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ReactiveFormsModule } from '@angular/forms'; +import { NavigationItemComponent } from './navigation-item.component'; +import { getElementFromFixture } from '@alfa-client/test-utils'; +import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { RouterTestingModule } from '@angular/router/testing'; +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; + +describe('NavigationItemComponent', () => { + let component: NavigationItemComponent; + let fixture: ComponentFixture<NavigationItemComponent>; + + const anchorLink = getDataTestIdOf('anchor'); + const navigationLabelName = 'test'; + const image = getDataTestIdOf('image-' + navigationLabelName); + const label = getDataTestIdOf('navigation-label-' + navigationLabelName); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [NavigationItemComponent, ConvertForDataTestPipe], + imports: [ReactiveFormsModule, RouterTestingModule], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(NavigationItemComponent); + component = fixture.componentInstance; + component.name = 'test'; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should use imageSrc input', () => { + const imageSrc = 'imagesrc'; + component.imageSrc = imageSrc; + + fixture.detectChanges(); + + const imageElement: HTMLImageElement = getElementFromFixture(fixture, image); + expect(imageElement.getAttribute('src')).toBe(imageSrc); + }); + + it('should use router link', () => { + const link = '/testroute'; + component.link = link; + + fixture.detectChanges(); + + const anchorElement: HTMLAnchorElement = getElementFromFixture(fixture, anchorLink); + expect(anchorElement.getAttribute('ng-reflect-router-link')).toBe(link); + }); + + describe('image name', () => { + it('should be used for alt', () => { + const imageElement = getElementFromFixture(fixture, image); + expect(imageElement.alt).toBe(navigationLabelName); + }); + + it('should be used for navigation-label', () => { + const labelElement = getElementFromFixture(fixture, label); + expect(labelElement.textContent).toBe(navigationLabelName); + }); + }); +}); diff --git a/alfa-client/libs/admin-settings/src/lib/shared/navigation-item/navigation-item.component.ts b/alfa-client/libs/admin-settings/src/lib/shared/navigation-item/navigation-item.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..f1b2e5f0f36c2575bf567d660fb63f1ff6da2938 --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/shared/navigation-item/navigation-item.component.ts @@ -0,0 +1,15 @@ +import { Component, Input } from '@angular/core'; + +@Component({ + selector: 'navigation-item', + templateUrl: './navigation-item.component.html', + styleUrls: ['./navigation-item.component.scss'], +}) +export class NavigationItemComponent { + @Input() + link: string; + @Input() + imageSrc: string; + @Input() + name = 'Navigations-Link'; +} diff --git a/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.html b/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.html new file mode 100644 index 0000000000000000000000000000000000000000..c11e2cfdb73de1e35a9eb09c2e32846a8cbe4265 --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.html @@ -0,0 +1,8 @@ +<label class="grid grid-cols-2"> + <span [attr.data-test-id]="'text-field-span-' + label | convertForDataTest">{{ label }}</span> + <input + [attr.data-test-id]="'text-field-input-' + label | convertForDataTest" + type="text" + [formControl]="fieldControl" + /> +</label> diff --git a/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.spec.ts b/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..27baea4a3893bd7107800d210579220e9c621f93 --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.spec.ts @@ -0,0 +1,46 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { TextFieldComponent } from './text-field.component'; +import { getElementFromFixture } from '@alfa-client/test-utils'; +import { ReactiveFormsModule } from '@angular/forms'; +import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; + +describe('TextFieldComponent', () => { + let component: TextFieldComponent; + let fixture: ComponentFixture<TextFieldComponent>; + + const label = 'custom'; + const span = getDataTestIdOf('text-field-span-' + label); + const input = getDataTestIdOf('text-field-input-' + label); + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TextFieldComponent, ConvertForDataTestPipe], + imports: [ReactiveFormsModule], + }).compileComponents(); + + fixture = TestBed.createComponent(TextFieldComponent); + component = fixture.componentInstance; + component.label = label; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should use label', () => { + const labelElement = getElementFromFixture(fixture, span); + expect(labelElement.textContent).toBe(label); + }); + + it('should use form control', () => { + const fieldText = 'text'; + component.writeValue(fieldText); + + fixture.detectChanges(); + + const inputElement = getElementFromFixture(fixture, input); + expect(inputElement.value).toBe(fieldText); + }); +}); diff --git a/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.ts b/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..92abc83d9409865ee79be841d06d3b255c57ff3a --- /dev/null +++ b/alfa-client/libs/admin-settings/src/lib/shared/text-field/text-field.component.ts @@ -0,0 +1,11 @@ +import { Component, Input } from '@angular/core'; +import { FormControlEditorAbstractComponent } from 'libs/ui/src/lib/ui/editor/formcontrol-editor.abstract.component'; + +@Component({ + selector: 'text-field', + templateUrl: './text-field.component.html', +}) +export class TextFieldComponent extends FormControlEditorAbstractComponent { + @Input() + label: string; +} diff --git a/alfa-client/libs/admin-settings/src/test-setup.ts b/alfa-client/libs/admin-settings/src/test-setup.ts new file mode 100644 index 0000000000000000000000000000000000000000..e09d95a1bd4455db9bfd16809b94659c30a83956 --- /dev/null +++ b/alfa-client/libs/admin-settings/src/test-setup.ts @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2022 Das Land Schleswig-Holstein vertreten durch den + * Ministerpräsidenten des Landes Schleswig-Holstein + * Staatskanzlei + * Abteilung Digitalisierung und zentrales IT-Management der Landesregierung + * + * Lizenziert unter der EUPL, Version 1.2 oder - sobald + * diese von der Europäischen Kommission genehmigt wurden - + * Folgeversionen der EUPL ("Lizenz"); + * Sie dürfen dieses Werk ausschließlich gemäß + * dieser Lizenz nutzen. + * Eine Kopie der Lizenz finden Sie hier: + * + * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12 + * + * Sofern nicht durch anwendbare Rechtsvorschriften + * gefordert oder in schriftlicher Form vereinbart, wird + * die unter der Lizenz verbreitete Software "so wie sie + * ist", OHNE JEGLICHE GEWÄHRLEISTUNG ODER BEDINGUNGEN - + * ausdrücklich oder stillschweigend - verbreitet. + * Die sprachspezifischen Genehmigungen und Beschränkungen + * unter der Lizenz sind dem Lizenztext zu entnehmen. + */ +import '@testing-library/jest-dom'; +import 'jest-preset-angular/setup-jest'; + +import { getTestBed } from '@angular/core/testing'; +import { + BrowserDynamicTestingModule, + platformBrowserDynamicTesting, +} from '@angular/platform-browser-dynamic/testing'; + +getTestBed().resetTestEnvironment(); +getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { + teardown: { destroyAfterEach: false }, + errorOnUnknownProperties: true, + errorOnUnknownElements: true, +}); diff --git a/alfa-client/libs/admin-settings/tsconfig.json b/alfa-client/libs/admin-settings/tsconfig.json new file mode 100644 index 0000000000000000000000000000000000000000..03261df5a47903bb7d4de17fbef9e9a14b048bed --- /dev/null +++ b/alfa-client/libs/admin-settings/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../tsconfig.base.json", + "files": [], + "include": [], + "references": [ + { + "path": "./tsconfig.lib.json" + }, + { + "path": "./tsconfig.spec.json" + } + ], + "compilerOptions": { + "target": "es2020" + } +} diff --git a/alfa-client/libs/admin-settings/tsconfig.lib.json b/alfa-client/libs/admin-settings/tsconfig.lib.json new file mode 100644 index 0000000000000000000000000000000000000000..dcc35a71ee8a26bc9394b9cf96b02996be26ec16 --- /dev/null +++ b/alfa-client/libs/admin-settings/tsconfig.lib.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "declaration": true, + "declarationMap": true, + "inlineSources": true, + "types": [] + }, + "exclude": ["src/test-setup.ts", "src/**/*.spec.ts", "jest.config.ts", "src/**/*.test.ts"], + "include": ["src/**/*.ts"] +} diff --git a/alfa-client/libs/admin-settings/tsconfig.spec.json b/alfa-client/libs/admin-settings/tsconfig.spec.json new file mode 100644 index 0000000000000000000000000000000000000000..c3cb17f784fa2f7b9a4b0e7c9b03663500f4ee3d --- /dev/null +++ b/alfa-client/libs/admin-settings/tsconfig.spec.json @@ -0,0 +1,12 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "../../dist/out-tsc", + "module": "commonjs", + "types": ["jest", "node"], + "target": "ES2022", + "useDefineForClassFields": false + }, + "files": ["src/test-setup.ts"], + "include": ["**/*.test.ts", "**/*.spec.ts", "**/*.d.ts", "jest.config.ts"] +} diff --git a/alfa-client/libs/postfach-shared/src/lib/postfach.util.ts b/alfa-client/libs/postfach-shared/src/lib/postfach.util.ts index 8b8507d5e77ccbe0074810da1d3a47a93b1aa10d..4b0e6396bccece591f7fbbfc09bc428bc15e5148 100644 --- a/alfa-client/libs/postfach-shared/src/lib/postfach.util.ts +++ b/alfa-client/libs/postfach-shared/src/lib/postfach.util.ts @@ -21,7 +21,7 @@ * Die sprachspezifischen Genehmigungen und Beschränkungen * unter der Lizenz sind dem Lizenztext zu entnehmen. */ -import { EnumEditorItem } from '@alfa-client/ui'; +import { CheckboxEnumEditorItem } from '@alfa-client/ui'; import { getEmbeddedResource } from '@ngxp/rest'; import { isNil } from 'lodash-es'; import { PostfachMailListLinkRel } from './postfach.linkrel'; @@ -77,13 +77,9 @@ export function getPostfachNachrichtenCount( } } -export const FORBIDDEN_REPLY_OPTION_ITEM: EnumEditorItem = { +export const FORBIDDEN_REPLY_OPTION_ITEM: CheckboxEnumEditorItem = { type: ReplyOption.FORBIDDEN, - svgIcon: 'no_reply', - text: 'Antworten unterbinden', }; -export const POSSIBLE_REPLY_OPTION_ITEM: EnumEditorItem = { +export const POSSIBLE_REPLY_OPTION_ITEM: CheckboxEnumEditorItem = { type: ReplyOption.POSSIBLE, - icon: 'reply', - text: 'Antworten erlauben', }; diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.html b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.html index 54088d409e922a838fb6f4350c575af9dbd92cc7..c56d5eeb8514ed4295ffba4817c573e304009ffb 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.html +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.html @@ -46,7 +46,7 @@ [postfachNachricht]="dialogData.postfachNachricht" ></alfa-postfach-nachricht-attachment-container> - <div class="button-bar-bottom"> + <div class="button-bar-bottom space-between"> <ozgcloud-stroked-button-with-spinner data-test-id="postfach-send-button" [stateResource]="sendInProgress$ | async" diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.scss b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.scss index e62869c090e63ed5b7bc93aa35b8e4d74f4e6751..d72717d84ac61991ea6146183c7800a5ed773fae 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.scss +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-mail-form.component.scss @@ -65,3 +65,8 @@ min-height: 20px; } } + +.space-between { + display: flex; + justify-content: space-between; +} diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component.html b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component.html index 4d6b60475269f0c8fea1aadf4917c03875d01581..89bb3a3050bd289ee340d028736d074c59e62265 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component.html +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component.html @@ -1,10 +1,12 @@ <ng-container *ngIf="postfachFeatures$ | async as postfachFeatures"> - <ozgcloud-enum-editor + <ozgcloud-checkbox-enum-editor *ngIf="postfachFeatures.reply" data-test-id="postfach-reply-option" + label="Antwort vom Antragsteller benötigt" [formControlName]="formServiceClass.FIELD_REPLY_OPTION" - [defaultItem]="defaultItem" - [itemList]="itemList" + [defaultItem]="checkedItem" + [checkedItem]="checkedItem" + [uncheckedItem]="uncheckedItem" > - </ozgcloud-enum-editor> + </ozgcloud-checkbox-enum-editor> </ng-container> diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component.spec.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component.spec.ts index ef6570a027fa28d5536b40d0474788aba82608a3..7f04f09813364491d022e2311d6167be12052978 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component.spec.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component.spec.ts @@ -13,12 +13,12 @@ import { mock, notExistsAsHtmlElement, } from '@alfa-client/test-utils'; -import { EnumEditorComponent } from '@alfa-client/ui'; import { getDataTestIdOf } from 'libs/tech-shared/test/data-test'; import { MockComponent } from 'ng-mocks'; import { of } from 'rxjs'; import { PostfachMailFormservice } from '../postfach-mail.formservice'; import { PostfachNachrichtReplyEditorContainerComponent } from './postfach-nachricht-reply-editor-container.component'; +import { CheckboxEnumEditorComponent } from '@alfa-client/ui'; describe('PostfachNachrichtReplyEditorContainerComponent', () => { let component: PostfachNachrichtReplyEditorContainerComponent; @@ -39,7 +39,7 @@ describe('PostfachNachrichtReplyEditorContainerComponent', () => { await TestBed.configureTestingModule({ declarations: [ PostfachNachrichtReplyEditorContainerComponent, - MockComponent(EnumEditorComponent), + MockComponent(CheckboxEnumEditorComponent), ], providers: [ { @@ -86,25 +86,41 @@ describe('PostfachNachrichtReplyEditorContainerComponent', () => { it.skip('should be called with formControlName', () => { fixture.detectChanges(); - const enumEditor: EnumEditorComponent = getMockComponent(fixture, EnumEditorComponent); + const enumEditor: CheckboxEnumEditorComponent = getMockComponent( + fixture, + CheckboxEnumEditorComponent, + ); expect(enumEditor.control).toBe(PostfachMailFormservice.FIELD_REPLY_OPTION); }); it('should be called with defaultItem', () => { fixture.detectChanges(); - const enumEditor: EnumEditorComponent = getMockComponent(fixture, EnumEditorComponent); + const enumEditor: CheckboxEnumEditorComponent = getMockComponent( + fixture, + CheckboxEnumEditorComponent, + ); expect(enumEditor.defaultItem).toBe(POSSIBLE_REPLY_OPTION_ITEM); }); - it('should be called wirh itemList', () => { + it('should be called with checked item', () => { fixture.detectChanges(); - const enumEditor: EnumEditorComponent = getMockComponent(fixture, EnumEditorComponent); - expect(enumEditor.itemList).toEqual([ - POSSIBLE_REPLY_OPTION_ITEM, - FORBIDDEN_REPLY_OPTION_ITEM, - ]); + const enumEditor: CheckboxEnumEditorComponent = getMockComponent( + fixture, + CheckboxEnumEditorComponent, + ); + expect(enumEditor.checkedItem).toBe(POSSIBLE_REPLY_OPTION_ITEM); + }); + + it('should be called with unchecked item', () => { + fixture.detectChanges(); + + const enumEditor: CheckboxEnumEditorComponent = getMockComponent( + fixture, + CheckboxEnumEditorComponent, + ); + expect(enumEditor.uncheckedItem).toBe(FORBIDDEN_REPLY_OPTION_ITEM); }); }); diff --git a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component.ts b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component.ts index dff70f9872dcaf71b52d57f44894a9a443f6c15d..1e6ae6bea4559a733a50f29c4411aedc738c8e1c 100644 --- a/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component.ts +++ b/alfa-client/libs/postfach/src/lib/postfach-mail-form/postfach-nachricht-reply-editor-container/postfach-nachricht-reply-editor-container.component.ts @@ -1,12 +1,12 @@ import { Component, OnInit } from '@angular/core'; import { - FORBIDDEN_REPLY_OPTION_ITEM, Features, + FORBIDDEN_REPLY_OPTION_ITEM, POSSIBLE_REPLY_OPTION_ITEM, PostfachService, } from '@alfa-client/postfach-shared'; import { FormProvider } from '@alfa-client/tech-shared'; -import { EnumEditorItem } from '@alfa-client/ui'; +import { CheckboxEnumEditorItem } from '@alfa-client/ui'; import { Observable } from 'rxjs'; import { PostfachMailFormservice } from '../postfach-mail.formservice'; @@ -17,16 +17,13 @@ import { PostfachMailFormservice } from '../postfach-mail.formservice'; viewProviders: [FormProvider], }) export class PostfachNachrichtReplyEditorContainerComponent implements OnInit { - public readonly itemList: EnumEditorItem[] = [ - POSSIBLE_REPLY_OPTION_ITEM, - FORBIDDEN_REPLY_OPTION_ITEM, - ]; - public readonly defaultItem: EnumEditorItem = POSSIBLE_REPLY_OPTION_ITEM; - public readonly formServiceClass = PostfachMailFormservice; public postfachFeatures$: Observable<Features>; + public checkedItem: CheckboxEnumEditorItem = POSSIBLE_REPLY_OPTION_ITEM; + public uncheckedItem: CheckboxEnumEditorItem = FORBIDDEN_REPLY_OPTION_ITEM; + constructor(private postfachService: PostfachService) {} ngOnInit(): void { diff --git a/alfa-client/libs/ui/.eslintrc.json b/alfa-client/libs/ui/.eslintrc.json index 07ceb6eb1f7d34299016dadeedc8f8546f74158e..0ff6d35a3359167cd29a27ecc2b6fbf663325bab 100644 --- a/alfa-client/libs/ui/.eslintrc.json +++ b/alfa-client/libs/ui/.eslintrc.json @@ -10,7 +10,7 @@ "error", { "type": "attribute", - "prefix": "alfa", + "prefix": "ozgcloud", "style": "camelCase" } ], @@ -18,7 +18,7 @@ "error", { "type": "element", - "prefix": "alfa", + "prefix": "ozgcloud", "style": "kebab-case" } ] diff --git a/alfa-client/libs/ui/src/index.ts b/alfa-client/libs/ui/src/index.ts index 82706251be4ccd84055ccb4e37c82717b35e59be..c1159e21d049fc4b787912e39bffd85efda89962 100644 --- a/alfa-client/libs/ui/src/index.ts +++ b/alfa-client/libs/ui/src/index.ts @@ -58,3 +58,5 @@ export * from './lib/ui/subnavigation/subnavigation.component'; export * from './lib/ui/ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component'; export * from './lib/ui/ozgcloud-paste-text-button/ozgcloud-paste-text-button.component'; export * from './lib/ui/ui.module'; +export * from './lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component'; +export * from './lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.model'; diff --git a/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.html b/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.html new file mode 100644 index 0000000000000000000000000000000000000000..3c8b8cc76209df603cbccb8c06af18a43bf9dd9e --- /dev/null +++ b/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.html @@ -0,0 +1,3 @@ +<mat-checkbox color="primary" [checked]="selected" (change)="setSelection($event)" + >{{ label }} +</mat-checkbox> diff --git a/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.scss b/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.scss new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.spec.ts b/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.spec.ts new file mode 100644 index 0000000000000000000000000000000000000000..4c0855d0914ebcca40f1287042a581b97707bea7 --- /dev/null +++ b/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.spec.ts @@ -0,0 +1,59 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ReactiveFormsModule } from '@angular/forms'; +import { MatIcon } from '@angular/material/icon'; +import { MatFormFieldModule } from '@angular/material/form-field'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { ConvertForDataTestPipe } from '@alfa-client/tech-shared'; +import { IconButtonWithSpinnerComponent, UiModule } from '@alfa-client/ui'; +import { MockComponent } from 'ng-mocks'; +import { CheckboxEnumEditorComponent } from '@alfa-client/ui'; + +describe('CheckboxEnumEditorComponent', () => { + let component: CheckboxEnumEditorComponent; + let fixture: ComponentFixture<CheckboxEnumEditorComponent>; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [ + CheckboxEnumEditorComponent, + MatIcon, + ConvertForDataTestPipe, + MockComponent(IconButtonWithSpinnerComponent), + ], + imports: [UiModule, MatFormFieldModule, ReactiveFormsModule, BrowserAnimationsModule], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(CheckboxEnumEditorComponent); + component = fixture.componentInstance; + component.defaultItem = { type: 'enumType' }; + component.checkedItem = { type: 'positive' }; + component.uncheckedItem = { type: 'negative' }; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + describe('setSelection', () => { + const writeMethodMock = jest.fn(); + + beforeEach(() => { + component.writeValue = writeMethodMock; + }); + + it('should write checked value on selected', () => { + component.setSelection({ source: null, checked: true }); + + expect(writeMethodMock).toHaveBeenCalledWith('positive'); + }); + + it('should write unchecked value on selected', () => { + component.setSelection({ source: null, checked: false }); + + expect(writeMethodMock).toHaveBeenCalledWith('negative'); + }); + }); +}); diff --git a/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.ts b/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.ts new file mode 100644 index 0000000000000000000000000000000000000000..d896c82a1626ffd500382b34f58481fd1a794124 --- /dev/null +++ b/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.component.ts @@ -0,0 +1,34 @@ +import { Component, Input, OnInit } from '@angular/core'; +import { FormControlEditorAbstractComponent } from '../formcontrol-editor.abstract.component'; +import { CheckboxEnumEditorItem } from './checkbox-enum-editor.model'; +import { MatCheckboxChange } from '@angular/material/checkbox'; + +/** + * Ein Checkbox, dessen Wert beim FormControl statt boolean als string aus dem enum editor item + * abgebildet wird. + */ +@Component({ + selector: 'ozgcloud-checkbox-enum-editor', + templateUrl: './checkbox-enum-editor.component.html', + styleUrls: ['./checkbox-enum-editor.component.scss'], +}) +export class CheckboxEnumEditorComponent + extends FormControlEditorAbstractComponent + implements OnInit +{ + @Input() label: string; + @Input() defaultItem: CheckboxEnumEditorItem; + @Input() checkedItem: CheckboxEnumEditorItem; + @Input() uncheckedItem: CheckboxEnumEditorItem; + + public selected: boolean; + + override ngOnInit(): void { + this.selected = this.defaultItem === this.checkedItem; + this.writeValue(this.defaultItem.type); + } + + setSelection(event: MatCheckboxChange): void { + this.writeValue(event.checked ? this.checkedItem.type : this.uncheckedItem.type); + } +} diff --git a/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.model.ts b/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.model.ts new file mode 100644 index 0000000000000000000000000000000000000000..1833e17688d96ea2cf28e350ee935d6974258bf5 --- /dev/null +++ b/alfa-client/libs/ui/src/lib/ui/editor/checkbox-enum-editor/checkbox-enum-editor.model.ts @@ -0,0 +1,3 @@ +export interface CheckboxEnumEditorItem { + type: any; +} diff --git a/alfa-client/libs/ui/src/lib/ui/ui.module.ts b/alfa-client/libs/ui/src/lib/ui/ui.module.ts index 61c0bd7440b5187519bb0b8397c35f88bc7f7678..26c004579db2d598a5585164729315680082ce6a 100644 --- a/alfa-client/libs/ui/src/lib/ui/ui.module.ts +++ b/alfa-client/libs/ui/src/lib/ui/ui.module.ts @@ -97,6 +97,7 @@ import { SubnavigationComponent } from './subnavigation/subnavigation.component' import { ValidationErrorComponent } from './validation-error/validation-error.component'; import { OzgcloudIconButtonPrimaryComponent } from './ozgcloud-button/ozgcloud-icon-button-primary/ozgcloud-icon-button-primary.component'; import { OzgcloudPasteTextButtonComponent } from './ozgcloud-paste-text-button/ozgcloud-paste-text-button.component'; +import { CheckboxEnumEditorComponent } from './editor/checkbox-enum-editor/checkbox-enum-editor.component'; @NgModule({ declarations: [ @@ -146,6 +147,7 @@ import { OzgcloudPasteTextButtonComponent } from './ozgcloud-paste-text-button/o BasicDialogComponent, OzgcloudButtonContentComponent, OzgcloudPasteTextButtonComponent, + CheckboxEnumEditorComponent, ], imports: [ MatButtonModule, @@ -245,6 +247,7 @@ import { OzgcloudPasteTextButtonComponent } from './ozgcloud-paste-text-button/o SnackbarCloseButtonComponent, BasicDialogComponent, OzgcloudPasteTextButtonComponent, + CheckboxEnumEditorComponent, ], providers: [ { diff --git a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-views-menu.component.scss b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-views-menu.component.scss index e6328b2c2a8d60b60bd8a536fe854ad19450a9e6..6c9cb3c6e3416570c16839d351389bcc3519ff18 100644 --- a/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-views-menu.component.scss +++ b/alfa-client/libs/vorgang/src/lib/vorgang-list-page-container/vorgang-list-page/vorgang-views-menu/vorgang-views-menu.component.scss @@ -73,4 +73,5 @@ body.dark :host { ozgcloud-icon, ozgcloud-postfach-icon { margin-right: 6px; + height: $iconHeight; } diff --git a/alfa-client/tsconfig.base.json b/alfa-client/tsconfig.base.json index d0242502a79252e59ba623be19ca9200a4e3ae4e..273aa6f0fd7e8b8dc7bfe7e87a4f644820431bf8 100644 --- a/alfa-client/tsconfig.base.json +++ b/alfa-client/tsconfig.base.json @@ -16,6 +16,7 @@ "skipDefaultLibCheck": true, "baseUrl": ".", "paths": { + "@admin-client/admin-settings": ["libs/admin-settings/src/index.ts"], "@alfa-client/api-root-shared": ["libs/api-root-shared/src/index.ts"], "@alfa-client/app-shared": ["libs/app-shared/src/index.ts"], "@alfa-client/bescheid": ["libs/bescheid/src/index.ts"], diff --git a/alfa-server/src/main/resources/application-dev.yml b/alfa-server/src/main/resources/application-dev.yml index 938a6bfeef434fd896cf8f9e7a46bf172e2a5c62..c7c2bdd8d6c319ae464c13b109ca4a191021cc68 100644 --- a/alfa-server/src/main/resources/application-dev.yml +++ b/alfa-server/src/main/resources/application-dev.yml @@ -1,7 +1,7 @@ keycloak: - auth-server-url: https://sso.dev.by.ozg-cloud.de - realm: by-kiel-dev - resource: alfa + auth-server-url: https://sso.dev.by.ozg-cloud.de + realm: by-kiel-dev + resource: alfa server: error: @@ -9,7 +9,8 @@ server: ozgcloud: feature: - vorgang-export: true + vorgang-export: true + reply-always-allowed: true production: false stage: production: false \ No newline at end of file diff --git a/alfa-server/src/main/resources/application-e2e.yml b/alfa-server/src/main/resources/application-e2e.yml index 1f0ddf6798f02a5215ba2e80b778c0cad8f2aa47..5cd02cdd6daa75998f2b06164f0065fcaf7c4afe 100644 --- a/alfa-server/src/main/resources/application-e2e.yml +++ b/alfa-server/src/main/resources/application-e2e.yml @@ -5,16 +5,17 @@ logging: keycloak: realm: by-e2e-local-dev - + ozgcloud: feature: - vorgang-export: true - createBescheid: true + vorgang-export: true + createBescheid: true + reply-always-allowed: true forwarding: lninfo: url: classpath:files/LandesnetzInfo.html user-assistance: - documentation: - url: /assets/benutzerleitfaden/benutzerleitfaden.pdf + documentation: + url: /assets/benutzerleitfaden/benutzerleitfaden.pdf user-manager: url: http://localhost:9092 \ No newline at end of file diff --git a/alfa-server/src/main/resources/application-local.yml b/alfa-server/src/main/resources/application-local.yml index 9f07a50d310e520c0d3437193b886a91001836cf..0c348fd48f2ab5dc221f5ea5c1cf3b98986cf3a6 100644 --- a/alfa-server/src/main/resources/application-local.yml +++ b/alfa-server/src/main/resources/application-local.yml @@ -12,19 +12,20 @@ grpc: user-manager: address: static://127.0.0.1:9000 negotiationType: PLAINTEXT - + ozgcloud: feature: vorgang-export: true + reply-always-allowed: true production: false user-assistance: - documentation: - url: /assets/benutzerleitfaden/benutzerleitfaden.pdf + documentation: + url: /assets/benutzerleitfaden/benutzerleitfaden.pdf user-manager: url: http://localhost:9091 profile-template: /api/userProfiles/%s search-template: /api/userProfiles/?searchBy={searchBy} - + keycloak: auth-server-url: http://localhost:8088 realm: by-kiel-dev diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/common/FeatureToggleProperties.java b/alfa-service/src/main/java/de/ozgcloud/alfa/common/FeatureToggleProperties.java index 30cb6d5e030a9de48c1ecac7e53fdff1e7c32606..1b516773c30d287d3a1571cb75f3c4009bee0873 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/common/FeatureToggleProperties.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/common/FeatureToggleProperties.java @@ -21,4 +21,9 @@ public class FeatureToggleProperties { * Enable/Disable bescheid creation feature. */ private boolean createBescheid = false; + + /** + * Enable mail reply option regardless of other configuration. + */ + private boolean replyAlwaysAllowed = false; } diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailController.java b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailController.java index 1237dc244c373c99b8803ec026bfc11519cc8c05..606c6ec3433a2d1cc012da17e56124884d83b33f 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailController.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailController.java @@ -55,29 +55,24 @@ import de.ozgcloud.alfa.common.file.OzgFile; import de.ozgcloud.alfa.vorgang.VorgangController; import de.ozgcloud.alfa.vorgang.VorgangWithEingang; import lombok.NonNull; +import lombok.RequiredArgsConstructor; +@RequiredArgsConstructor @RestController @RequestMapping(PostfachMailController.PATH) public class PostfachMailController { public static final String PATH = "/api/postfachMails"; // NOSONAR - public static final String PARAM_VORGANG_ID = "vorgangId"; - static final String PDF_NAME_TEMPLATE = "%s_%s_Nachrichten.pdf"; - static final DateTimeFormatter PDF_NAME_DATE_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd"); - @Autowired - private PostfachMailService service; - @Autowired - private PostfachMailModelAssembler assembler; + private final PostfachMailService service; - @Autowired - private VorgangController vorgangController; + private final PostfachMailModelAssembler assembler; - @Autowired - private BinaryFileController binaryFileController; + private final VorgangController vorgangController; + private final BinaryFileController binaryFileController; @GetMapping(params = PARAM_VORGANG_ID) public RepresentationModel<EntityModel<Postfach>> getAll(@RequestParam String vorgangId) { @@ -86,11 +81,15 @@ public class PostfachMailController { return assembler.toCollectionModel(sort(service.getAll(vorgangId)), buildPostfach(vorgang), vorgang); } - private Postfach buildPostfach(VorgangWithEingang vorgang) { - return Postfach.builder().features(Features.builder().reply(service.isReplyToMessageAllowed(vorgang)).build()).build(); + Postfach buildPostfach(VorgangWithEingang vorgang) { + return Postfach.builder() + .features(Features.builder() + .reply(service.isReplyToMessageAllowed(vorgang)) + .build()) + .build(); } - private Stream<PostfachMail> sort(Stream<PostfachMail> nachrichten) { + Stream<PostfachMail> sort(Stream<PostfachMail> nachrichten) { return nachrichten.sorted(new PostfachNachrichtComparator().reversed()); } diff --git a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailService.java b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailService.java index a94151852adef541a174920e40dc35081e801d4b..67b6a85aeb116118b4477b84290c7dac54d8bd2a 100644 --- a/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailService.java +++ b/alfa-service/src/main/java/de/ozgcloud/alfa/postfach/PostfachMailService.java @@ -32,9 +32,9 @@ import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import de.ozgcloud.alfa.common.FeatureToggleProperties; import de.ozgcloud.alfa.common.binaryfile.BinaryFileService; import de.ozgcloud.alfa.common.binaryfile.FileId; import de.ozgcloud.alfa.common.command.Command; @@ -47,25 +47,23 @@ import de.ozgcloud.alfa.common.user.UserProfile; import de.ozgcloud.alfa.common.user.UserService; import de.ozgcloud.alfa.vorgang.ServiceKonto; import de.ozgcloud.alfa.vorgang.VorgangWithEingang; +import lombok.RequiredArgsConstructor; import lombok.extern.log4j.Log4j2; +@RequiredArgsConstructor @Log4j2 @Service class PostfachMailService { private PostfachConfigGroup postfachConfigGroup; - @Autowired - private PostfachMailRemoteService remoteService; - @Autowired - private PostfachNachrichtPdfService pdfService; + private final PostfachMailRemoteService remoteService; + private final PostfachNachrichtPdfService pdfService; + private final BinaryFileService fileService; + private final UserService userService; + private final CommandService commandService; - @Autowired - private BinaryFileService fileService; - @Autowired - private UserService userService; - @Autowired - private CommandService commandService; + private final FeatureToggleProperties featureToggleProperties; public PostfachMail findById(PostfachNachrichtId nachrichtId) { return remoteService.findById(nachrichtId) @@ -150,9 +148,14 @@ class PostfachMailService { } boolean isReplyAllowed(String serviceKontoType) { + if (featureToggleProperties.isReplyAlwaysAllowed()) { + return true; + } + if (!isPostfachConfigured()) { return false; } + return postfachConfigGroup.getPostfachConfigs().stream() .filter(postfachConfig -> postfachConfig.getType().equals(serviceKontoType)) .map(PostfachConfig::isReplyAllowed) diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailControllerTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailControllerTest.java index 1b707f0650ed39bab2581ce7bed2dfcd288fd092..17f732923cf5995bae45c8521461e328b84b490c 100644 --- a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailControllerTest.java +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailControllerTest.java @@ -23,6 +23,7 @@ */ package de.ozgcloud.alfa.postfach; +import static org.assertj.core.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; @@ -31,13 +32,13 @@ import static org.springframework.test.web.servlet.result.MockMvcResultMatchers. import java.io.IOException; import java.io.OutputStream; import java.time.LocalDate; +import java.util.stream.Stream; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; -import org.mockito.ArgumentMatchers; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.Spy; @@ -60,10 +61,13 @@ class PostfachMailControllerTest { @Spy @InjectMocks // NOSONAR private PostfachMailController controller; + @Mock private PostfachMailService service; + @Mock private PostfachMailModelAssembler assembler; + @Mock private VorgangController vorgangController; @Mock @@ -80,9 +84,17 @@ class PostfachMailControllerTest { @Nested class TestGetAll { + private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create(); + private final Postfach postfach = PostfachTestFactory.create(); + private final Stream<PostfachMail> postfachMails = Stream.of(PostfachMailTestFactory.create()); + private final Stream<PostfachMail> sortedPostfachMails = Stream.of(PostfachMailTestFactory.create()); + @BeforeEach void mockVorgangController() { - when(vorgangController.getVorgang(anyString())).thenReturn(VorgangWithEingangTestFactory.create()); + when(vorgangController.getVorgang(anyString())).thenReturn(vorgang); + when(service.getAll(VorgangHeaderTestFactory.ID)).thenReturn(postfachMails); + doReturn(postfach).when(controller).buildPostfach(vorgang); + doReturn(sortedPostfachMails).when(controller).sort(postfachMails); } @Test @@ -103,14 +115,21 @@ class PostfachMailControllerTest { void shouldCallModelAssembler() { doRequest(); - verify(assembler).toCollectionModel(ArgumentMatchers.any(), any(Postfach.class), any()); + verify(assembler).toCollectionModel(sortedPostfachMails, postfach, vorgang); } @Test - void shouldCheckIsReplyAllowed() { + void shouldSortPostfachMails() { doRequest(); - verify(service).isReplyToMessageAllowed(any(VorgangWithEingang.class)); + verify(controller).sort(postfachMails); + } + + @Test + void shouldBuildPostfach() { + doRequest(); + + verify(controller).buildPostfach(vorgang); } @SneakyThrows @@ -120,6 +139,32 @@ class PostfachMailControllerTest { } } + @Nested + class TestBuildPostfach { + + private final VorgangWithEingang vorgang = VorgangWithEingangTestFactory.create(); + + @Test + void shouldCheckIsReplyAllowed() { + callController(); + + verify(service).isReplyToMessageAllowed(any(VorgangWithEingang.class)); + } + + @Test + void shouldSetIsReplyAllowedFeature() { + when(service.isReplyToMessageAllowed(vorgang)).thenReturn(true); + + var postfach = callController(); + + assertThat(postfach.getFeatures().isReply()).isTrue(); + } + + private Postfach callController() { + return controller.buildPostfach(vorgang); + } + } + @DisplayName("Get all as pdf") @Nested class TestGetAllAsPdf { diff --git a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailServiceTest.java b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailServiceTest.java index aa07067a624b2dbc8d8a38d77f521da35b6ed36b..ddd2d24fd82e0776b55b363b219f7422a0f5a960 100644 --- a/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailServiceTest.java +++ b/alfa-service/src/test/java/de/ozgcloud/alfa/postfach/PostfachMailServiceTest.java @@ -47,6 +47,7 @@ import org.springframework.test.util.ReflectionTestUtils; import com.thedeanda.lorem.LoremIpsum; +import de.ozgcloud.alfa.common.FeatureToggleProperties; import de.ozgcloud.alfa.common.binaryfile.BinaryFileService; import de.ozgcloud.alfa.common.binaryfile.BinaryFileTestFactory; import de.ozgcloud.alfa.common.command.CommandService; @@ -81,6 +82,9 @@ class PostfachMailServiceTest { @Mock private CommandService commandService; + @Mock + private FeatureToggleProperties featureToggleProperties; + @DisplayName("Get all") @Nested class TestGetAll { @@ -512,6 +516,11 @@ class PostfachMailServiceTest { private static final String DUMMY_SERVICE_KONTO_TYPE = LoremIpsum.getInstance().getWords(1); + @BeforeEach + void setUp() { + when(featureToggleProperties.isReplyAlwaysAllowed()).thenReturn(false); + } + @Test @DisplayName("reply not allowed for given ServiceKonto-type") void shouldReturnFalseIfPostfachNotConfigured() { @@ -568,6 +577,15 @@ class PostfachMailServiceTest { assertThat(replyAllowed).isTrue(); } + + @Test + void shouldReturnTrueIfAlwaysAllowed() { + when(featureToggleProperties.isReplyAlwaysAllowed()).thenReturn(true); + + var replyAllowed = service.isReplyAllowed(PostfachConfigTestFactory.TYPE); + + assertThat(replyAllowed).isTrue(); + } } private void setPostfachConfigGroup(PostfachConfigGroup postfachConfigGroup) {