diff --git a/.gitea/workflows/docs.yml b/.gitea/workflows/docs.yml deleted file mode 100644 index 3efc73d..0000000 --- a/.gitea/workflows/docs.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: Build docs - -on: - push: - branches: [main] - -jobs: - build-docs: - runs-on: ubuntu-latest - container: - image: git.kjan.de/actions/runner-latex:latest - env: - # Edit here with the names of your latex file and directory (can use ".") - DIR: docs - FILE: projektdokumentation.tex - steps: - - name: Checkout - uses: actions/checkout@v4 - - - name: LaTeX compile - working-directory: ${{ env.DIR }} - run: latexmk -pdf -xelatex ${{ env.FILE }} - - - name: Upload artifacts - uses: https://git.kjan.de/actions/upload-artifact@v4 - with: - name: Doku - path: docs/projektdokumentation.pdf diff --git a/backend/Readme.md b/backend/Readme.md index 228842e..8f945dc 100644 --- a/backend/Readme.md +++ b/backend/Readme.md @@ -1,137 +1,59 @@ -# Casino Gaming Platform - Backend API +# Starter für das LF08 Projekt -A Spring Boot backend application providing REST APIs for a casino gaming platform with multiple games, user management, authentication, and payment processing. +## Requirements +* Docker https://docs.docker.com/get-docker/ +* Docker compose (bei Windows und Mac schon in Docker enthalten) https://docs.docker.com/compose/install/ -## Features - -### Games -- **Blackjack** - Classic card game with deck management -- **Coinflip** - Simple heads/tails betting game -- **Dice** - Dice rolling game -- **Slots** - Slot machine with symbols and payouts -- **Lootboxes** - Reward system with configurable prizes - -### User Management -- User registration and authentication -- OAuth2 integration (Google, GitHub) -- Email verification and password reset -- Balance management and transaction history - -### Payment System -- Deposit functionality with webhook support -- Transaction tracking and status management -- Balance updates and fund validation - -## Tech Stack -- **Java 17** with Spring Boot -- **Spring Security** with JWT authentication -- **Spring Data JPA** with PostgreSQL -- **OAuth2** for social login -- **Email service** for notifications -- **OpenAPI/Swagger** for API documentation - -## Build & Run - -### Prerequisites -- Java 17+ -- Gradle -- Docker & Docker Compose (for PostgreSQL) - -### Build Commands -```bash -# Build the application -./gradlew build - -# Clean build -./gradlew clean build - -# Run the application -./gradlew bootRun - -# Generate JAR file -./gradlew bootJar +## Endpunkt +``` +http://localhost:8080 +``` +## Swagger +``` +http://localhost:8080/swagger ``` -### Testing + +# Postgres +### Terminal öffnen +für alles gilt, im Terminal im Ordner docker/local sein ```bash -# Run all tests -./gradlew test - -# Run specific test class -./gradlew test --tests "FullyQualifiedClassName" - -# Run checkstyle -./gradlew checkstyleMain checkstyleTest -``` - -## API Endpoints - -The application runs on `http://localhost:8080` - -### API Documentation -- **Swagger UI**: `http://localhost:8080/swagger-ui.html` -- **OpenAPI Spec**: `http://localhost:8080/v3/api-docs` - -### Main Endpoints -- `/api/auth/**` - Authentication and user management -- `/api/games/blackjack/**` - Blackjack game operations -- `/api/games/coinflip/**` - Coinflip game operations -- `/api/games/dice/**` - Dice game operations -- `/api/games/slots/**` - Slot machine operations -- `/api/lootboxes/**` - Lootbox management -- `/api/deposits/**` - Payment and deposit handling -- `/api/users/**` - User profile management -- `/api/health` - Health check endpoint - -## Database Setup - -### PostgreSQL with Docker -```bash -# Start PostgreSQL container cd docker/local +``` +### Postgres starten +```bash docker compose up +``` +Achtung: Der Docker-Container läuft dauerhaft! Wenn er nicht mehr benötigt wird, sollten Sie ihn stoppen. -# Stop PostgreSQL container +### Postgres stoppen +```bash docker compose down +``` -# Reset database (if needed) +### Postgres Datenbank wipen, z.B. bei Problemen +```bash docker compose down docker volume rm local_lf8_starter_postgres_data docker compose up ``` -### Database Configuration -Database connection settings are configured in `src/main/resources/application.properties` +### Intellij-Ansicht für Postgres Datenbank einrichten +```bash +1. Lasse den Docker-Container mit der PostgreSQL-Datenbank laufen +2. im Ordner resources die Datei application.properties öffnen und die URL der Datenbank kopieren +3. rechts im Fenster den Reiter Database öffnen +4. In der Database-Symbolleiste auf das Datenbanksymbol mit dem Schlüssel klicken +5. auf das Pluszeichen klicken +6. Datasource from URL auswählen +7. URL der DB einfügen und PostgreSQL-Treiber auswählen, mit OK bestätigen +8. Username lf8_starter und Passwort secret eintragen (siehe application.properties), mit Apply bestätigen +9. im Reiter Schemas alle Häkchen entfernen und lediglich vor lf8_starter_db und public Häkchen setzen +10. mit Apply und ok bestätigen +``` +# Keycloak -### IntelliJ Database Setup -1. Start the PostgreSQL Docker container -2. Open `application.properties` and copy the database URL -3. In IntelliJ, open the Database tab (right panel) -4. Click the database icon with key in the toolbar -5. Click the plus (+) icon -6. Select "Datasource from URL" -7. Paste the database URL and select PostgreSQL driver -8. Enter credentials (username: `lf8_starter`, password: `secret`) -9. In Schemas tab, uncheck all except `lf8_starter_db` and `public` -10. Apply and confirm - -## Authentication - -The application supports multiple authentication methods: -- JWT-based authentication -- OAuth2 (Google, GitHub) -- Email/password with verification - -### Getting Bearer Token -For API testing, use the provided HTTP client file: -1. Open `GetBearerToken.http` at project root -2. Execute the request -3. Copy the `access_token` from the response -4. Use in Authorization header: `Bearer ` - -## Configuration - -Key configuration files: -- `application.properties` - Main application configuration -- `SecurityConfig.java` - Security and CORS settings -- `OpenAPIConfiguration.java` - API documentation setup \ No newline at end of file +### Keycloak Token +1. Auf der Projektebene [GetBearerToken.http](../GetBearerToken.http) öffnen. +2. Neben der Request auf den grünen Pfeil drücken +3. Aus dem Reponse das access_token kopieren \ No newline at end of file diff --git a/backend/build.gradle.kts b/backend/build.gradle.kts index 548c9aa..1d73b90 100644 --- a/backend/build.gradle.kts +++ b/backend/build.gradle.kts @@ -39,7 +39,7 @@ repositories { } dependencies { - implementation("com.stripe:stripe-java:29.2.0") + implementation("com.stripe:stripe-java:29.1.0") implementation("org.springframework.boot:spring-boot-starter-data-jpa") implementation("org.springframework.boot:spring-boot-starter-web") compileOnly("org.projectlombok:lombok") @@ -47,13 +47,13 @@ dependencies { testImplementation("org.springframework.boot:spring-boot-starter-test") testRuntimeOnly("org.junit.platform:junit-platform-launcher") implementation("org.springframework.boot:spring-boot-starter-security") - implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server:3.5.0") - implementation("org.springframework.boot:spring-boot-starter-oauth2-client:3.5.0") + implementation("org.springframework.boot:spring-boot-starter-oauth2-resource-server:3.4.5") + implementation("org.springframework.boot:spring-boot-starter-oauth2-client:3.4.5") runtimeOnly("org.postgresql:postgresql") implementation("org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.8") - implementation("io.jsonwebtoken:jjwt-api:0.12.6") - runtimeOnly("io.jsonwebtoken:jjwt-impl:0.12.6") - runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.12.6") + implementation("io.jsonwebtoken:jjwt-api:0.11.5") + runtimeOnly("io.jsonwebtoken:jjwt-impl:0.11.5") + runtimeOnly("io.jsonwebtoken:jjwt-jackson:0.11.5") implementation("org.springframework.boot:spring-boot-starter-mail") } diff --git a/backend/src/main/java/de/szut/casino/security/jwt/JwtUtils.java b/backend/src/main/java/de/szut/casino/security/jwt/JwtUtils.java index b34f1e1..1a7d08d 100644 --- a/backend/src/main/java/de/szut/casino/security/jwt/JwtUtils.java +++ b/backend/src/main/java/de/szut/casino/security/jwt/JwtUtils.java @@ -91,7 +91,7 @@ public class JwtUtils { } private Claims extractAllClaims(String token) { - return Jwts.parser() + return Jwts.parserBuilder() .setSigningKey(getSigningKey()) .build() .parseClaimsJws(token) diff --git a/frontend/README.md b/frontend/README.md index a67f78f..daf35fe 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,106 +1,18 @@ # Casino Gaming Platform - Frontend -A modern Angular 20 casino gaming platform featuring multiple games including Blackjack, Coinflip, Dice, Slots, and Lootboxes. Built with Angular 20, TailwindCSS 4, and powered by Bun for fast development. +This is the frontend application for the Casino Gaming Platform. It's built with Angular 18 and TailwindCSS, providing a responsive and modern UI for the casino gaming experience. -## 🎮 Features +## Development -- **Multiple Games**: Blackjack, Coinflip, Dice, Slots, Lootboxes -- **User Authentication**: OAuth2, email verification, password recovery -- **Real-time Gaming**: Interactive game mechanics with animations -- **Payment Integration**: Stripe integration for deposits -- **Responsive Design**: Mobile-first design with TailwindCSS -- **Audio Experience**: Game sounds and audio feedback -- **Transaction History**: Complete betting and transaction tracking +### Commands -## 🚀 Getting Started - -### Prerequisites - -- [Bun](https://bun.sh/) (recommended) or Node.js 18+ -- Angular CLI 20+ - -### Installation - -```bash -# Install dependencies -bun install - -# Start development server -bun run start -``` - -The app will be available at `http://localhost:4200` - -## 📋 Commands - -### Development -- **Start Dev Server**: `bun run start` - Starts dev server with proxy configuration -- **Build**: `bun run build` - Production build -- **Watch Build**: `bun run watch` - Development build with file watching - -### Code Quality -- **Format**: `bun run format` - Format code with Prettier -- **Format Check**: `bun run format:check` - Check code formatting -- **Lint**: `bun run lint` - Run ESLint -- **OxLint**: `bun run oxlint` - Run OxLint with strict warnings - -### Testing -- **Test All**: `bun run test` - Run all tests with Karma/Jasmine +- **Build**: `bun run build` or `bunx @angular/cli build` +- **Start Dev Server**: `bun run start` or `bunx @angular/cli serve --proxy-config src/proxy.conf.json` +- **Format Code**: `bun run format` or `prettier --write "src/**/*.{ts,html,css,scss}"` +- **Lint**: `bun run lint` or `ng lint` +- **Test**: `bun run test` or `bunx @angular/cli test` - **Test Single File**: `bunx @angular/cli test --include=path/to/test.spec.ts` -## 🛠️ Technology Stack - -### Core -- **Angular 20**: Latest Angular framework with standalone components -- **TypeScript 5.8**: Strongly typed JavaScript -- **RxJS 7.8**: Reactive programming for HTTP and state management - -### Styling & UI -- **TailwindCSS 4**: Utility-first CSS framework -- **PostCSS**: CSS processing and optimization -- **FontAwesome**: Icon library with Angular integration - -### Animation & Interaction -- **GSAP**: High-performance animations -- **CountUp.js**: Number animation effects -- **Custom Audio Service**: Game sound effects and feedback - -### Development Tools -- **Bun**: Fast JavaScript runtime and package manager -- **ESLint + Angular ESLint**: Code linting with Angular-specific rules -- **OxLint**: Fast Rust-based linter -- **Prettier**: Code formatting -- **Karma + Jasmine**: Testing framework - -### Payment & APIs -- **Stripe**: Payment processing integration -- **Custom HTTP Interceptors**: API communication and error handling - -## 🏗️ Architecture - -### Project Structure -``` -src/ -├── app/ -│ ├── feature/ # Feature modules -│ │ ├── auth/ # Authentication (login, register, OAuth2) -│ │ ├── game/ # Game modules (blackjack, coinflip, dice, slots) -│ │ ├── lootboxes/ # Lootbox system -│ │ └── deposit/ # Payment and deposits -│ ├── model/ # Data models and interfaces -│ ├── service/ # Core services (auth, user, transaction) -│ └── shared/ # Shared components, directives, services -├── environments/ # Environment configurations -└── public/ # Static assets (images, sounds) -``` - -### Key Components -- **Game Components**: Modular game implementations with services -- **Shared Components**: Reusable UI components (navbar, footer, modals) -- **Services**: Business logic and API communication -- **Guards**: Route protection and authentication -- **Interceptors**: HTTP request/response handling - ## Style Guide ### Color Palette diff --git a/frontend/angular.json b/frontend/angular.json index d8c3879..a9f9a84 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -21,8 +21,7 @@ { "glob": "**/*", "input": "public" - }, - "src/assets" + } ], "styles": [ "src/styles.css" diff --git a/frontend/src/app/app.routes.ts b/frontend/src/app/app.routes.ts index f6611b9..88f4fe1 100644 --- a/frontend/src/app/app.routes.ts +++ b/frontend/src/app/app.routes.ts @@ -62,12 +62,14 @@ export const routes: Routes = [ loadComponent: () => import('./feature/lootboxes/lootbox-selection/lootbox-selection.component'), canActivate: [authGuard], - }, - { - path: 'lootboxes/open/:id', - loadComponent: () => - import('./feature/lootboxes/lootbox-opening/lootbox-opening.component'), - canActivate: [authGuard], + children: [ + { + path: 'open/:id', + loadComponent: () => + import('./feature/lootboxes/lootbox-opening/lootbox-opening.component'), + canActivate: [authGuard], + }, + ], }, { path: 'dice', diff --git a/frontend/src/app/feature/game/blackjack/components/animated-number/animated-number.component.ts b/frontend/src/app/feature/game/blackjack/components/animated-number/animated-number.component.ts index 9b07eee..6e61c0e 100644 --- a/frontend/src/app/feature/game/blackjack/components/animated-number/animated-number.component.ts +++ b/frontend/src/app/feature/game/blackjack/components/animated-number/animated-number.component.ts @@ -61,9 +61,6 @@ export class AnimatedNumberComponent implements OnChanges, AfterViewInit { this.countUp = new CountUp(this.numberElement.nativeElement, this.value, { startVal: this.previousValue, duration: this.duration, - decimalPlaces: 2, - useEasing: true, - useGrouping: false, easingFn: (t, b, c, d) => { if (this.ease === 'power1.out') { return c * (1 - Math.pow(1 - t / d, 1)) + b; diff --git a/frontend/src/app/feature/home/home.component.html b/frontend/src/app/feature/home/home.component.html index 9b79a9e..b0b77d3 100644 --- a/frontend/src/app/feature/home/home.component.html +++ b/frontend/src/app/feature/home/home.component.html @@ -4,7 +4,7 @@
-
+

Alle Spiele

@@ -18,54 +18,24 @@
-
- -
-
-
- +
+
+
+ +
-
-

{{ game.name }}

- -
-
-
-
-
- - -
-
-
- -
-
-

{{ game.name }}

- -
+

{{ game.name }}

+
@@ -73,5 +43,53 @@
+ +
+
+

Konto

+
+ + + + +
+
+ + + +
+

Letzte Transaktionen

+
+
+
+

{{ transaction.status }}

+

+ {{ transaction.createdAt | date: 'd.m.y H:m' }} +

+
+ + {{ transaction.amount | currency: 'EUR' }} + +
+
+
+
diff --git a/frontend/src/app/feature/home/home.component.ts b/frontend/src/app/feature/home/home.component.ts index f032246..ef947f9 100644 --- a/frontend/src/app/feature/home/home.component.ts +++ b/frontend/src/app/feature/home/home.component.ts @@ -1,18 +1,34 @@ -import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; -import { NgFor } from '@angular/common'; +import { ChangeDetectionStrategy, Component, inject, OnInit } from '@angular/core'; +import { AsyncPipe, CurrencyPipe, DatePipe, NgFor } from '@angular/common'; +import { DepositComponent } from '../deposit/deposit.component'; import { ActivatedRoute, Router } from '@angular/router'; +import { ConfirmationComponent } from '@shared/components/confirmation/confirmation.component'; import { Game } from 'app/model/Game'; +import { Observable } from 'rxjs'; +import { TransactionService } from '@service/transaction.service'; import format from 'ajv/dist/vocabularies/format'; +import { TransactionHistoryComponent } from '../transaction-history/transaction-history.component'; +import { TransactionData } from '../../model/TransactionData'; @Component({ selector: 'app-homepage', standalone: true, - imports: [NgFor], + imports: [ + CurrencyPipe, + NgFor, + DepositComponent, + ConfirmationComponent, + AsyncPipe, + DatePipe, + TransactionHistoryComponent, + ], templateUrl: './home.component.html', changeDetection: ChangeDetectionStrategy.OnPush, }) export default class HomeComponent implements OnInit { + isDepositModalOpen = false; isDepositSuccessful = false; + isTransactionModalOpen = false; constructor( public route: ActivatedRoute, @@ -62,10 +78,35 @@ export default class HomeComponent implements OnInit { }, ]; + allGames: Game[] = [...this.featuredGames]; + + recentTransactionData: Observable = + inject(TransactionService).getUsersTransactions(5); + + openDepositModal() { + this.isDepositModalOpen = true; + } + + closeDepositModal() { + this.isDepositModalOpen = false; + } + openDepositConfirmationModal() { this.isDepositSuccessful = true; } + openTransactionModal() { + this.isTransactionModalOpen = true; + } + + closeDepositConfirmationModal() { + this.isDepositSuccessful = false; + } + + closeTransactionModal() { + this.isTransactionModalOpen = false; + } + navigateToGame(route: string) { this.router.navigate([route]); } diff --git a/frontend/src/app/feature/landing/landing.component.html b/frontend/src/app/feature/landing/landing.component.html index a7cb79e..ae963a9 100644 --- a/frontend/src/app/feature/landing/landing.component.html +++ b/frontend/src/app/feature/landing/landing.component.html @@ -21,7 +21,13 @@ (click)="showRegisterForm()" class="w-full sm:w-auto button-primary px-6 sm:px-8 py-3 shadow-lg" > - Jetzt registrieren + Konto erstellen + + }
@@ -40,108 +46,58 @@

Slots

Klassische Spielautomaten

- @if (isLoggedIn()) { - - Jetzt Spielen - - } @else { - - } + Jetzt Spielen
-
+
+
+

Poker

+

Texas Hold'em & mehr

+ Jetzt Spielen +
+

Dice

Würfelspiel

- @if (isLoggedIn()) { - - Jetzt Spielen - - } @else { - - } + Jetzt Spielen
@@ -209,7 +165,7 @@
24/7
-
Support
+
Support *
diff --git a/frontend/src/app/feature/landing/landing.component.ts b/frontend/src/app/feature/landing/landing.component.ts index 93b9e84..d354fa4 100644 --- a/frontend/src/app/feature/landing/landing.component.ts +++ b/frontend/src/app/feature/landing/landing.component.ts @@ -23,14 +23,15 @@ import RecoverPasswordComponent from '../auth/recover-password/recover-password. }) export class LandingComponent implements OnInit, OnDestroy { currentSlide = 0; + private autoplayInterval: ReturnType | undefined; authService: AuthService = inject(AuthService); route: ActivatedRoute = inject(ActivatedRoute); showLogin = signal(false); showRegister = signal(false); showRecoverPassword = signal(false); - isLoggedIn = signal(this.authService.isLoggedIn()); ngOnInit() { + this.startAutoplay(); document.body.style.overflow = 'auto'; if (this.route.snapshot.queryParamMap.get('login') === 'true') { this.showLoginForm(); @@ -38,6 +39,7 @@ export class LandingComponent implements OnInit, OnDestroy { } ngOnDestroy() { + this.stopAutoplay(); document.body.style.overflow = 'auto'; } @@ -71,13 +73,33 @@ export class LandingComponent implements OnInit, OnDestroy { prevSlide() { this.currentSlide = this.currentSlide === 0 ? 1 : 0; + this.resetAutoplay(); } nextSlide() { this.currentSlide = this.currentSlide === 1 ? 0 : 1; + this.resetAutoplay(); } goToSlide(index: number) { this.currentSlide = index; + this.resetAutoplay(); + } + + private startAutoplay() { + this.autoplayInterval = setInterval(() => { + this.nextSlide(); + }, 5000); + } + + private stopAutoplay() { + if (this.autoplayInterval) { + clearInterval(this.autoplayInterval); + } + } + + private resetAutoplay() { + this.stopAutoplay(); + this.startAutoplay(); } } diff --git a/frontend/src/app/shared/components/footer/footer.component.html b/frontend/src/app/shared/components/footer/footer.component.html index ef2de86..79cf823 100644 --- a/frontend/src/app/shared/components/footer/footer.component.html +++ b/frontend/src/app/shared/components/footer/footer.component.html @@ -5,19 +5,24 @@ +
+ @@ -49,6 +54,10 @@ Google Pay + @@ -56,6 +65,10 @@
diff --git a/frontend/src/app/shared/components/footer/footer.component.ts b/frontend/src/app/shared/components/footer/footer.component.ts index b47b6fd..2cb56e1 100644 --- a/frontend/src/app/shared/components/footer/footer.component.ts +++ b/frontend/src/app/shared/components/footer/footer.component.ts @@ -1,14 +1,13 @@ import { ChangeDetectionStrategy, Component } from '@angular/core'; import { FontAwesomeModule } from '@fortawesome/angular-fontawesome'; import { faCreditCard, faMoneyBillTransfer, faWallet } from '@fortawesome/free-solid-svg-icons'; -import { faGooglePay, faPaypal } from '@fortawesome/free-brands-svg-icons'; -import { RouterLink } from '@angular/router'; +import { faApplePay, faGooglePay, faPaypal } from '@fortawesome/free-brands-svg-icons'; @Component({ selector: 'app-footer', standalone: true, templateUrl: './footer.component.html', - imports: [FontAwesomeModule, RouterLink], + imports: [FontAwesomeModule], changeDetection: ChangeDetectionStrategy.OnPush, }) export class FooterComponent { @@ -19,4 +18,5 @@ export class FooterComponent { faMoneyBillTransfer = faMoneyBillTransfer; faWallet = faWallet; faGooglePay = faGooglePay; + faApplePay = faApplePay; } diff --git a/frontend/src/app/shared/components/navbar/navbar.component.html b/frontend/src/app/shared/components/navbar/navbar.component.html index 608f3de..7e010fa 100644 --- a/frontend/src/app/shared/components/navbar/navbar.component.html +++ b/frontend/src/app/shared/components/navbar/navbar.component.html @@ -1,120 +1,40 @@ -