diff --git a/backend/src/main/java/com/alttd/altitudeweb/controllers/application/AppealController.java b/backend/src/main/java/com/alttd/altitudeweb/controllers/application/AppealController.java new file mode 100644 index 0000000..e8b8ee7 --- /dev/null +++ b/backend/src/main/java/com/alttd/altitudeweb/controllers/application/AppealController.java @@ -0,0 +1,28 @@ +package com.alttd.altitudeweb.controllers.application; + +import com.alttd.altitudeweb.api.AppealsApi; +import com.alttd.altitudeweb.model.AppealResponseDto; +import com.alttd.altitudeweb.model.DiscordAppealDto; +import com.alttd.altitudeweb.model.MinecraftAppealDto; +import com.alttd.altitudeweb.model.UpdateMailDto; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.ResponseEntity; +import org.springframework.web.server.ResponseStatusException; + +public class AppealController implements AppealsApi { + + @Override + public ResponseEntity submitDiscordAppeal(DiscordAppealDto discordAppealDto) { + throw new ResponseStatusException(HttpStatusCode.valueOf(501), "Discord appeals are not yet supported"); + } + + @Override + public ResponseEntity submitMinecraftAppeal(MinecraftAppealDto minecraftAppealDto) { + throw new ResponseStatusException(HttpStatusCode.valueOf(501), "Minecraft appeals are not yet supported"); + } + + @Override + public ResponseEntity updateMail(UpdateMailDto updateMailDto) { + throw new ResponseStatusException(HttpStatusCode.valueOf(501), "Updating mail is not yet supported"); + } +} diff --git a/backend/src/main/java/com/alttd/altitudeweb/controllers/login/LoginController.java b/backend/src/main/java/com/alttd/altitudeweb/controllers/login/LoginController.java new file mode 100644 index 0000000..8b81255 --- /dev/null +++ b/backend/src/main/java/com/alttd/altitudeweb/controllers/login/LoginController.java @@ -0,0 +1,22 @@ +package com.alttd.altitudeweb.controllers.login; + +import com.alttd.altitudeweb.api.LoginApi; +import com.alttd.altitudeweb.model.AddLoginDto; +import com.alttd.altitudeweb.model.LoginDataDto; +import com.alttd.altitudeweb.model.LoginResultDto; +import org.springframework.http.HttpStatusCode; +import org.springframework.http.ResponseEntity; +import org.springframework.web.server.ResponseStatusException; + +public class LoginController implements LoginApi { + + @Override + public ResponseEntity addLogin(AddLoginDto addLoginDto) { + throw new ResponseStatusException(HttpStatusCode.valueOf(501), "Adding login is not yet supported"); + } + + @Override + public ResponseEntity login(LoginDataDto loginDataDto) { + throw new ResponseStatusException(HttpStatusCode.valueOf(501), "Logging in is not yet supported"); + } +} diff --git a/frontend/src/app/forms/appeal/appeal.component.html b/frontend/src/app/forms/appeal/appeal.component.html new file mode 100644 index 0000000..6ca9adc --- /dev/null +++ b/frontend/src/app/forms/appeal/appeal.component.html @@ -0,0 +1,5 @@ + +
+ +
+
diff --git a/frontend/src/app/forms/appeal/appeal.component.scss b/frontend/src/app/forms/appeal/appeal.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/app/forms/appeal/appeal.component.spec.ts b/frontend/src/app/forms/appeal/appeal.component.spec.ts new file mode 100644 index 0000000..9af6eed --- /dev/null +++ b/frontend/src/app/forms/appeal/appeal.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { AppealComponent } from './appeal.component'; + +describe('AppealComponent', () => { + let component: AppealComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [AppealComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(AppealComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/forms/appeal/appeal.component.ts b/frontend/src/app/forms/appeal/appeal.component.ts new file mode 100644 index 0000000..e51191f --- /dev/null +++ b/frontend/src/app/forms/appeal/appeal.component.ts @@ -0,0 +1,63 @@ +import {Component, OnInit} from '@angular/core'; +import {FormsComponent} from '../forms.component'; +import {FormBuilder, FormGroup, Validators} from '@angular/forms'; +import {AppealsService} from '../../../api'; + +@Component({ + selector: 'app-appeal', + imports: [ + FormsComponent + ], + templateUrl: './appeal.component.html', + styleUrl: './appeal.component.scss' +}) +export class AppealComponent implements OnInit { + + public form: FormGroup | undefined; + + constructor(private fb: FormBuilder, private appealApi: AppealsService) { + } + + ngOnInit() { + this.initForm() + } + + private initForm() { + this.form = this.fb.group({ + name: ['', [Validators.required]], + punishmentId: ['', [Validators.required]], + email: ['', [Validators.required, Validators.email]], + message: ['', [Validators.required, Validators.minLength(10)]] + }); + } + + public onSubmit() { + if (this.form === undefined) { + console.error('Form is undefined'); + return + } + if (this.form.valid) { + console.log('Form submitted:', this.form.value); + // Process form submission here + } else { + // Mark all fields as touched to trigger validation display + Object.keys(this.form.controls).forEach(field => { + const control = this.form!.get(field); + if (!(control instanceof FormGroup)) { + console.error('Control [' + control + '] is not a FormGroup'); + return; + } + control.markAsTouched({onlySelf: true}); + }); + } + } + + private sendForm(validForm: FormGroup) { + // const appeal: MinecraftAppeal = { + // + // } + // this.appealApi.submitMinecraftAppeal() + } + + +} diff --git a/frontend/src/app/forms/forms.component.html b/frontend/src/app/forms/forms.component.html new file mode 100644 index 0000000..9f04ed1 --- /dev/null +++ b/frontend/src/app/forms/forms.component.html @@ -0,0 +1,12 @@ + + +
+

{{ formTitle }}

+
+
+ +
+ +
+
diff --git a/frontend/src/app/forms/forms.component.scss b/frontend/src/app/forms/forms.component.scss new file mode 100644 index 0000000..e69de29 diff --git a/frontend/src/app/forms/forms.component.spec.ts b/frontend/src/app/forms/forms.component.spec.ts new file mode 100644 index 0000000..84fe7b1 --- /dev/null +++ b/frontend/src/app/forms/forms.component.spec.ts @@ -0,0 +1,23 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { FormsComponent } from './forms.component'; + +describe('FormsComponent', () => { + let component: FormsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + imports: [FormsComponent] + }) + .compileComponents(); + + fixture = TestBed.createComponent(FormsComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/forms/forms.component.ts b/frontend/src/app/forms/forms.component.ts new file mode 100644 index 0000000..fffed0e --- /dev/null +++ b/frontend/src/app/forms/forms.component.ts @@ -0,0 +1,15 @@ +import {Component, Input} from '@angular/core'; +import {HeaderComponent} from '../header/header.component'; + +@Component({ + selector: 'app-forms', + imports: [ + HeaderComponent + ], + templateUrl: './forms.component.html', + styleUrl: './forms.component.scss' +}) +export class FormsComponent { + @Input() formTitle: string = 'Form'; + @Input() currentPage: string = 'forms'; +} diff --git a/open_api/src/main/resources/api.yml b/open_api/src/main/resources/api.yml index 7102696..6428127 100644 --- a/open_api/src/main/resources/api.yml +++ b/open_api/src/main/resources/api.yml @@ -36,3 +36,7 @@ paths: $ref: './schemas/forms/appeal/appeal.yml#/MinecraftAppeal' /appeal/discord-appeal: $ref: './schemas/forms/appeal/appeal.yml#/DiscordAppeal' + /login/addUserLogin: + $ref: './schemas/login/login.yml#/AddUserLogin' + /login/userLogin: + $ref: './schemas/login/login.yml#/UserLogin' diff --git a/open_api/src/main/resources/schemas/login/login.yml b/open_api/src/main/resources/schemas/login/login.yml new file mode 100644 index 0000000..05cf30e --- /dev/null +++ b/open_api/src/main/resources/schemas/login/login.yml @@ -0,0 +1,97 @@ +UserLogin: + post: + tags: + - login + summary: Log in to the site + description: Log in to the site through a code from the server + operationId: login + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/LoginData' + responses: + '200': + description: Logged in + content: + application/json: + schema: + $ref: '#/components/schemas/LoginResult' + '401': + description: Login failed - Invalid credentials + content: + application/json: + schema: + $ref: '../generic/errors.yml#/components/schemas/ApiError' + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '../generic/errors.yml#/components/schemas/ApiError' +AddUserLogin: + post: + tags: + - login + summary: Add a login + description: Add a code, user combination that can be used to log in + operationId: addLogin + requestBody: + required: true + content: + application/json: + schema: + $ref: '#/components/schemas/AddLogin' + responses: + '200': + description: Success + default: + description: Unexpected error + content: + application/json: + schema: + $ref: '../generic/errors.yml#/components/schemas/ApiError' +components: + schemas: + LoginData: + type: object + required: + - loginCode + properties: + loginCode: + type: string + description: The code to log in + LoginResult: + type: object + required: + - uuid + - userName + - auth + properties: + uuid: + type: string + format: uuid + description: UUID of logged in user + userName: + type: string + description: Name of the logged in user + auth: + type: string + description: Token to use along side requests + AddLogin: + type: object + required: + - loginCode + - uuid + properties: + auth: + type: string + description: Token to verify the sender is allowed to add logins + loginCode: + type: string + description: The code that can be logged in with + uuid: + type: string + format: uuid + description: UUID of the user that will get logged in