diff --git a/.idea/.idea.WebDesktop 2.0/.idea/inspectionProfiles/Project_Default.xml b/.idea/.idea.WebDesktop 2.0/.idea/inspectionProfiles/Project_Default.xml
new file mode 100644
index 0000000..8590396
--- /dev/null
+++ b/.idea/.idea.WebDesktop 2.0/.idea/inspectionProfiles/Project_Default.xml
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.WebDesktop 2.0/.idea/watcherTasks.xml b/.idea/.idea.WebDesktop 2.0/.idea/watcherTasks.xml
new file mode 100644
index 0000000..fb0d65a
--- /dev/null
+++ b/.idea/.idea.WebDesktop 2.0/.idea/watcherTasks.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.WebDesktop 2.0/.idea/workspace.xml b/.idea/.idea.WebDesktop 2.0/.idea/workspace.xml
index 5a154ff..c3c5ee6 100644
--- a/.idea/.idea.WebDesktop 2.0/.idea/workspace.xml
+++ b/.idea/.idea.WebDesktop 2.0/.idea/workspace.xml
@@ -6,10 +6,30 @@
-
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -20,6 +40,7 @@
@@ -48,6 +69,7 @@
"RunOnceActivity.ShowReadmeOnStart": "true",
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
"WebServerToolWindowFactoryState": "false",
+ "list.type.of.created.stylesheet": "SCSS",
"nodejs_package_manager_path": "npm",
"settings.editor.selected.configurable": "project.propVCSSupport.DirectoryMappings",
"ts.external.directory.path": "D:\\Programmierstuff\\Projekte\\WebDesktop 2.0\\Frontend\\node_modules\\typescript\\lib",
@@ -130,6 +152,7 @@
+
diff --git a/Backend/Controllers/UserController.cs b/Backend/Controllers/UserController.cs
index 3ef2297..aee8c6b 100644
--- a/Backend/Controllers/UserController.cs
+++ b/Backend/Controllers/UserController.cs
@@ -36,7 +36,6 @@ public class UserController : ControllerBase {
}
[HttpGet("token")]
- [Authorized]
public ActionResult GetToken() {
return this.FromLogicResult(_logic.GenerateToken(_logic.GetCurrentUserRefreshToken()));
}
diff --git a/Backend/appsettings.json b/Backend/appsettings.json
index cf43216..9a5d7af 100644
--- a/Backend/appsettings.json
+++ b/Backend/appsettings.json
@@ -33,12 +33,12 @@
],
"Messages": {
"Users": {
- "NotFound": "This user does not exist",
- "InvalidEditData": "Userdata does not match security rules",
- "InvalidRegisterData": "Userdata does not match security rules",
- "WrongPassword": "Wrong password",
- "UsernameOrEmailExist": "This username or email already exist",
- "InvalidRefreshToken": "Invalid RefreshToken"
+ "NotFound": "Dieser Benutzer existiert nicht!",
+ "InvalidEditData": "Benutzerdaten entsprechen nicht den Sicherheitsvorschritfen!",
+ "InvalidRegisterData": "Benutzerdaten entsprechen nicht den Sicherheitsvorschritfen!",
+ "WrongPassword": "Falsches Passwort!",
+ "UsernameOrEmailExist": "Der Benutzername oder die E-Mail existieren bereits",
+ "InvalidRefreshToken": "Dein RefreshToken ist abgelaufen!"
}
}
}
diff --git a/Frontend/angular.json b/Frontend/angular.json
index 196db0b..d5e372d 100644
--- a/Frontend/angular.json
+++ b/Frontend/angular.json
@@ -31,6 +31,7 @@
"src/assets"
],
"styles": [
+ "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.scss"
],
"scripts": []
@@ -99,6 +100,7 @@
"src/assets"
],
"styles": [
+ "./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
"src/styles.scss"
],
"scripts": []
diff --git a/Frontend/package-lock.json b/Frontend/package-lock.json
index 84cb63b..88c479d 100644
--- a/Frontend/package-lock.json
+++ b/Frontend/package-lock.json
@@ -9,10 +9,12 @@
"version": "0.0.0",
"dependencies": {
"@angular/animations": "~13.1.0",
+ "@angular/cdk": "^13.3.9",
"@angular/common": "~13.1.0",
"@angular/compiler": "~13.1.0",
"@angular/core": "~13.1.0",
"@angular/forms": "~13.1.0",
+ "@angular/material": "^13.3.9",
"@angular/platform-browser": "~13.1.0",
"@angular/platform-browser-dynamic": "~13.1.0",
"@angular/router": "~13.1.0",
@@ -347,6 +349,28 @@
"@angular/core": "13.1.3"
}
},
+ "node_modules/@angular/cdk": {
+ "version": "13.3.9",
+ "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-13.3.9.tgz",
+ "integrity": "sha512-XCuCbeuxWFyo3EYrgEYx7eHzwl76vaWcxtWXl00ka8d+WAOtMQ6Tf1D98ybYT5uwF9889fFpXAPw98mVnlo3MA==",
+ "dependencies": {
+ "tslib": "^2.3.0"
+ },
+ "optionalDependencies": {
+ "parse5": "^5.0.0"
+ },
+ "peerDependencies": {
+ "@angular/common": "^13.0.0 || ^14.0.0-0",
+ "@angular/core": "^13.0.0 || ^14.0.0-0",
+ "rxjs": "^6.5.3 || ^7.4.0"
+ }
+ },
+ "node_modules/@angular/cdk/node_modules/parse5": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
+ "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
+ "optional": true
+ },
"node_modules/@angular/cli": {
"version": "13.1.4",
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-13.1.4.tgz",
@@ -472,6 +496,23 @@
"rxjs": "^6.5.3 || ^7.4.0"
}
},
+ "node_modules/@angular/material": {
+ "version": "13.3.9",
+ "resolved": "https://registry.npmjs.org/@angular/material/-/material-13.3.9.tgz",
+ "integrity": "sha512-FU8lcMgo+AL8ckd27B4V097ZPoIZNRHiCe3wpgkImT1qC0YwcyXZVn0MqQTTFSdC9a/aI8wPm3AbTClJEVw5Vw==",
+ "dependencies": {
+ "tslib": "^2.3.0"
+ },
+ "peerDependencies": {
+ "@angular/animations": "^13.0.0 || ^14.0.0-0",
+ "@angular/cdk": "13.3.9",
+ "@angular/common": "^13.0.0 || ^14.0.0-0",
+ "@angular/core": "^13.0.0 || ^14.0.0-0",
+ "@angular/forms": "^13.0.0 || ^14.0.0-0",
+ "@angular/platform-browser": "^13.0.0 || ^14.0.0-0",
+ "rxjs": "^6.5.3 || ^7.4.0"
+ }
+ },
"node_modules/@angular/platform-browser": {
"version": "13.1.3",
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-13.1.3.tgz",
@@ -11779,6 +11820,23 @@
"tslib": "^2.3.0"
}
},
+ "@angular/cdk": {
+ "version": "13.3.9",
+ "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-13.3.9.tgz",
+ "integrity": "sha512-XCuCbeuxWFyo3EYrgEYx7eHzwl76vaWcxtWXl00ka8d+WAOtMQ6Tf1D98ybYT5uwF9889fFpXAPw98mVnlo3MA==",
+ "requires": {
+ "parse5": "^5.0.0",
+ "tslib": "^2.3.0"
+ },
+ "dependencies": {
+ "parse5": {
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
+ "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug==",
+ "optional": true
+ }
+ }
+ },
"@angular/cli": {
"version": "13.1.4",
"resolved": "https://registry.npmjs.org/@angular/cli/-/cli-13.1.4.tgz",
@@ -11857,6 +11915,14 @@
"tslib": "^2.3.0"
}
},
+ "@angular/material": {
+ "version": "13.3.9",
+ "resolved": "https://registry.npmjs.org/@angular/material/-/material-13.3.9.tgz",
+ "integrity": "sha512-FU8lcMgo+AL8ckd27B4V097ZPoIZNRHiCe3wpgkImT1qC0YwcyXZVn0MqQTTFSdC9a/aI8wPm3AbTClJEVw5Vw==",
+ "requires": {
+ "tslib": "^2.3.0"
+ }
+ },
"@angular/platform-browser": {
"version": "13.1.3",
"resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-13.1.3.tgz",
diff --git a/Frontend/package.json b/Frontend/package.json
index a61f27a..9a282d6 100644
--- a/Frontend/package.json
+++ b/Frontend/package.json
@@ -11,10 +11,12 @@
"private": true,
"dependencies": {
"@angular/animations": "~13.1.0",
+ "@angular/cdk": "^13.3.9",
"@angular/common": "~13.1.0",
"@angular/compiler": "~13.1.0",
"@angular/core": "~13.1.0",
"@angular/forms": "~13.1.0",
+ "@angular/material": "^13.3.9",
"@angular/platform-browser": "~13.1.0",
"@angular/platform-browser-dynamic": "~13.1.0",
"@angular/router": "~13.1.0",
@@ -36,4 +38,4 @@
"karma-jasmine-html-reporter": "~1.7.0",
"typescript": "~4.5.2"
}
-}
+}
\ No newline at end of file
diff --git a/Frontend/src/app/app-routing.module.ts b/Frontend/src/app/app-routing.module.ts
index b84ff41..8ca5f12 100644
--- a/Frontend/src/app/app-routing.module.ts
+++ b/Frontend/src/app/app-routing.module.ts
@@ -1,9 +1,11 @@
import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import {LoginComponent} from "./sites/login/login.component";
+import {RegisterComponent} from "./sites/register/register.component";
const routes: Routes = [
- {path: "login", component: LoginComponent}
+ {path: "login", component: LoginComponent},
+ {path: "register", component: RegisterComponent}
];
@NgModule({
diff --git a/Frontend/src/app/app.component.ts b/Frontend/src/app/app.component.ts
index 6169758..714aa7d 100644
--- a/Frontend/src/app/app.component.ts
+++ b/Frontend/src/app/app.component.ts
@@ -22,6 +22,7 @@ export class AppComponent implements OnInit {
if (await this.backend.requestToken()) this.loaded = true;
else await this.router.navigate(["login"]);
+ this.loaded = true;
}, 0);
}
}
diff --git a/Frontend/src/app/app.module.ts b/Frontend/src/app/app.module.ts
index e025c90..81fee20 100644
--- a/Frontend/src/app/app.module.ts
+++ b/Frontend/src/app/app.module.ts
@@ -5,16 +5,30 @@ import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import {HttpClientModule} from "@angular/common/http";
import { LoginComponent } from './sites/login/login.component';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import {MatFormFieldModule} from "@angular/material/form-field";
+import {MatInputModule} from "@angular/material/input";
+import {MatButtonModule} from "@angular/material/button";
+import {MatDividerModule} from "@angular/material/divider";
+import { RegisterComponent } from './sites/register/register.component';
+import {ReactiveFormsModule} from "@angular/forms";
@NgModule({
declarations: [
AppComponent,
- LoginComponent
+ LoginComponent,
+ RegisterComponent
],
imports: [
BrowserModule,
AppRoutingModule,
- HttpClientModule
+ HttpClientModule,
+ BrowserAnimationsModule,
+ MatFormFieldModule,
+ MatInputModule,
+ MatButtonModule,
+ MatDividerModule,
+ ReactiveFormsModule
],
providers: [],
bootstrap: [AppComponent]
diff --git a/Frontend/src/app/entitys/user.ts b/Frontend/src/app/entitys/user.ts
index 600b416..fbbee08 100644
--- a/Frontend/src/app/entitys/user.ts
+++ b/Frontend/src/app/entitys/user.ts
@@ -1,6 +1,6 @@
export interface User extends UserEditor {
id: string;
- created: Date;
+ created: string;
}
export interface UserLogin {
diff --git a/Frontend/src/app/services/backend.service.ts b/Frontend/src/app/services/backend.service.ts
index 97f4361..837af99 100644
--- a/Frontend/src/app/services/backend.service.ts
+++ b/Frontend/src/app/services/backend.service.ts
@@ -74,7 +74,7 @@ export class BackendService {
}
}
- return {content: undefined, success: false, code: error.status, message: error.error.title};
+ return {content: undefined, success: false, code: error.status, message: error.error};
}
}
diff --git a/Frontend/src/app/services/users.service.ts b/Frontend/src/app/services/users.service.ts
index 1a7a8dd..f30177d 100644
--- a/Frontend/src/app/services/users.service.ts
+++ b/Frontend/src/app/services/users.service.ts
@@ -32,8 +32,8 @@ export class UserApi {
return response.success;
}
- public async getUserPermissions(id: string, includeGroupPermissions: boolean = true): Promise {
- const response = await this.backend.sendRequest(RequestTypes.GET, "users/" + id + "/permissions" + (includeGroupPermissions ? "/raw" : ""), undefined, {authorized: true});
+ public async getUserPermissions(id: string, excludeGroupPermissions: boolean = false): Promise {
+ const response = await this.backend.sendRequest(RequestTypes.GET, "users/" + id + "/permissions" + (excludeGroupPermissions ? "/raw" : ""), undefined, {authorized: true});
if (!response.success) return [];
return response.content;
}
@@ -48,7 +48,7 @@ export class UserApi {
return response.success;
}
- public async login(login: UserLogin): Promise<{success: boolean, errorMessage: string}> {
+ public async login(login: UserLogin): Promise<{success: boolean, errorMessage: string, errorCode: number}> {
const response = await this.backend.sendRequest(RequestTypes.PUT, "users/login", login, {withCredentials: true});
if (response.success) {
@@ -56,10 +56,10 @@ export class UserApi {
await this.getAuthorizedUser();
}
- return {success: response.success, errorMessage: response.message};
+ return {success: response.success, errorMessage: response.message, errorCode: response.code};
}
- public async register(register: UserEditor): Promise<{success: boolean, errorMessage: string}> {
+ public async register(register: UserEditor): Promise<{success: boolean, errorMessage: string, errorCode: number}> {
const response = await this.backend.sendRequest(RequestTypes.POST, "users/register", register, {withCredentials: true});
if (response.success) {
@@ -67,7 +67,7 @@ export class UserApi {
await this.getAuthorizedUser();
}
- return {success: response.success, errorMessage: response.message};
+ return {success: response.success, errorMessage: response.message, errorCode: response.code};
}
public async logout(id: string): Promise {
diff --git a/Frontend/src/app/sites/login/login.component.html b/Frontend/src/app/sites/login/login.component.html
index 147cfc4..48f4488 100644
--- a/Frontend/src/app/sites/login/login.component.html
+++ b/Frontend/src/app/sites/login/login.component.html
@@ -1 +1,24 @@
-login works!
+
+
+
diff --git a/Frontend/src/app/sites/login/login.component.scss b/Frontend/src/app/sites/login/login.component.scss
index e69de29..0cdcb67 100644
--- a/Frontend/src/app/sites/login/login.component.scss
+++ b/Frontend/src/app/sites/login/login.component.scss
@@ -0,0 +1,42 @@
+@use "src/styles";
+
+.login {
+ width: 100vw;
+ height: 100vh;
+ overflow: hidden;
+ background-image: url(styles.$background);
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ form {
+ padding: 30px;
+ display: flex;
+ gap: 5px;
+ flex-direction: column;
+
+ button[type="submit"] {
+ width: max-content;
+ align-self: center;
+ }
+
+ mat-divider {
+ margin-top: 10px;
+ }
+ }
+}
+
+.error {
+ position: absolute;
+ bottom: 120px;
+ left: 50%;
+ transform: translateX(-50%);
+
+ background-color: #F00;
+ padding: 10px;
+ border-radius: 5px;
+ opacity: 0;
+
+ transition: 500ms;
+}
diff --git a/Frontend/src/app/sites/login/login.component.ts b/Frontend/src/app/sites/login/login.component.ts
index c74528f..5c19247 100644
--- a/Frontend/src/app/sites/login/login.component.ts
+++ b/Frontend/src/app/sites/login/login.component.ts
@@ -1,15 +1,45 @@
-import { Component, OnInit } from '@angular/core';
+import {Component, ElementRef, ViewChild} from '@angular/core';
+import {UserApi} from "../../services/users.service";
+import {UserLogin} from "../../entitys/user";
+import {Router} from "@angular/router";
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.scss']
})
-export class LoginComponent implements OnInit {
+export class LoginComponent {
+ @ViewChild('error') error: ElementRef;
+ public disableLogin: boolean = false;
- constructor() { }
+ constructor(private users: UserApi, private router: Router) { }
- ngOnInit(): void {
+ public async login(form: HTMLFormElement, username: string, password: string) {
+ if (!form.reportValidity()) return;
+
+ const login: UserLogin = {usernameOrEmail: username, password: password};
+ const response = await this.users.login(login);
+
+ if (!response.success) {
+ this.showError(response.errorMessage)
+ return;
+ }
+
+ await this.router.navigate([""]);
+ }
+
+ public showError(error: string) {
+ this.disableLogin = true;
+ this.error.nativeElement.innerText = error;
+
+ this.error.nativeElement.style.opacity = "1";
+ this.error.nativeElement.style.bottom = "150px";
+
+ setTimeout(() => {
+ this.error.nativeElement.style.opacity = "0";
+ this.error.nativeElement.style.bottom = "120px";
+ this.disableLogin = false;
+ }, 5000)
}
}
diff --git a/Frontend/src/app/sites/register/register.component.html b/Frontend/src/app/sites/register/register.component.html
new file mode 100644
index 0000000..61c25be
--- /dev/null
+++ b/Frontend/src/app/sites/register/register.component.html
@@ -0,0 +1,57 @@
+
+
+
diff --git a/Frontend/src/app/sites/register/register.component.scss b/Frontend/src/app/sites/register/register.component.scss
new file mode 100644
index 0000000..0cdcb67
--- /dev/null
+++ b/Frontend/src/app/sites/register/register.component.scss
@@ -0,0 +1,42 @@
+@use "src/styles";
+
+.login {
+ width: 100vw;
+ height: 100vh;
+ overflow: hidden;
+ background-image: url(styles.$background);
+
+ display: flex;
+ align-items: center;
+ justify-content: center;
+
+ form {
+ padding: 30px;
+ display: flex;
+ gap: 5px;
+ flex-direction: column;
+
+ button[type="submit"] {
+ width: max-content;
+ align-self: center;
+ }
+
+ mat-divider {
+ margin-top: 10px;
+ }
+ }
+}
+
+.error {
+ position: absolute;
+ bottom: 120px;
+ left: 50%;
+ transform: translateX(-50%);
+
+ background-color: #F00;
+ padding: 10px;
+ border-radius: 5px;
+ opacity: 0;
+
+ transition: 500ms;
+}
diff --git a/Frontend/src/app/sites/register/register.component.ts b/Frontend/src/app/sites/register/register.component.ts
new file mode 100644
index 0000000..eaada3e
--- /dev/null
+++ b/Frontend/src/app/sites/register/register.component.ts
@@ -0,0 +1,64 @@
+import {Component, ElementRef, ViewChild} from '@angular/core';
+import {UserApi} from "../../services/users.service";
+import {Router} from "@angular/router";
+import {UserEditor} from "../../entitys/user";
+
+@Component({
+ selector: 'app-register',
+ templateUrl: './register.component.html',
+ styleUrls: ['./register.component.scss']
+})
+export class RegisterComponent {
+ @ViewChild('error') error: ElementRef;
+ public disableRegister: boolean = false;
+
+ constructor(private users: UserApi, private router: Router) { }
+
+ public async register(form: HTMLFormElement, register: UserEditor, pwRepeat: string) {
+ if (!form.reportValidity()) return;
+
+ if (register.password !== pwRepeat) {
+ this.showError("Passwörter stimmen nicht überein!");
+ return;
+ }
+
+ if (!register.email.includes("@") || !register.email.includes(".")) {
+ this.showError("Bitte gebe eine gültige E-Mail Adresse ein!");
+ return;
+ }
+
+ if (register.username.includes("@")) {
+ this.showError("Benutzername enthätlt ungültige Zeichen!");
+ return;
+ }
+
+ if (register.password.length < 8) {
+ this.showError("Dein Passwort muss mindestens 8 Zeichen lang sein!");
+ return;
+ }
+
+ const response = await this.users.register(register);
+
+ if (!response.success) {
+ this.showError(response.errorMessage);
+ return;
+ }
+
+ await this.router.navigate([""]);
+ }
+
+ public showError(error: string) {
+ this.disableRegister = true;
+ this.error.nativeElement.innerText = error;
+
+ this.error.nativeElement.style.opacity = "1";
+ this.error.nativeElement.style.bottom = "150px";
+
+ setTimeout(() => {
+ this.error.nativeElement.style.opacity = "0";
+ this.error.nativeElement.style.bottom = "120px";
+ this.disableRegister = false;
+ }, 5000)
+ }
+
+}
diff --git a/Frontend/src/assets/background.png b/Frontend/src/assets/background.png
new file mode 100644
index 0000000..69a13d8
Binary files /dev/null and b/Frontend/src/assets/background.png differ
diff --git a/Frontend/src/colors.scss b/Frontend/src/colors.scss
new file mode 100644
index 0000000..d2f38e9
--- /dev/null
+++ b/Frontend/src/colors.scss
@@ -0,0 +1,4 @@
+$dark: #0D1321;
+$medium: #1D2D44;
+$light: #3E5C76;
+$text: #FFFFFF;
diff --git a/Frontend/src/index.html b/Frontend/src/index.html
index b6d7b4e..dfdc8ee 100644
--- a/Frontend/src/index.html
+++ b/Frontend/src/index.html
@@ -6,8 +6,11 @@
+
+
+
-
+
diff --git a/Frontend/src/styles.scss b/Frontend/src/styles.scss
index 90d4ee0..8bd0938 100644
--- a/Frontend/src/styles.scss
+++ b/Frontend/src/styles.scss
@@ -1 +1,31 @@
/* You can add global styles to this file, and also import other style files */
+@use "colors";
+
+html, body { height: 100%; overflow: hidden; }
+body { margin: 0; font-family: Roboto, "Helvetica Neue", sans-serif; }
+
+$background: "/assets/background.png";
+
+* {
+ color: colors.$text;
+}
+
+.glass {
+ background: rgba(colors.$light, 0.15);
+ backdrop-filter: blur(10px);
+ border-radius: 20px;
+ overflow: hidden;
+}
+
+@mixin mat-select-theme() {
+ .mat-form-field-appearance-fill .mat-form-field-underline::before {
+ background-color: colors.$text;
+ }
+
+ .mat-divider {
+ border-top-color: colors.$text;
+ }
+}
+
+@include mat-select-theme();
+