From 1902ed8df6a621623af2840d9a37a31ed443c985 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 15:55:49 +0000 Subject: [PATCH 1/9] Initial plan From 415518554f3f1ef5bf772dda64cdebd525f64b7f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 16:01:30 +0000 Subject: [PATCH 2/9] Add GraphQL operation files and configure codegen for local schema Co-authored-by: PhantomDave <34485699+PhantomDave@users.noreply.github.com> --- frontend/codegen.ts | 2 +- frontend/src/graphql/create-account.mutation.graphql | 8 ++++++++ frontend/src/graphql/get-account-by-email.query.graphql | 8 ++++++++ frontend/src/graphql/get-accounts.query.graphql | 8 ++++++++ frontend/src/graphql/login-account.query.graphql | 8 ++++++++ 5 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 frontend/src/graphql/create-account.mutation.graphql create mode 100644 frontend/src/graphql/get-account-by-email.query.graphql create mode 100644 frontend/src/graphql/get-accounts.query.graphql create mode 100644 frontend/src/graphql/login-account.query.graphql diff --git a/frontend/codegen.ts b/frontend/codegen.ts index 9440e1c..954b334 100644 --- a/frontend/codegen.ts +++ b/frontend/codegen.ts @@ -1,7 +1,7 @@ import type { CodegenConfig } from '@graphql-codegen/cli'; const config: CodegenConfig = { - schema: 'http://localhost:5095/graphql', + schema: './schema.graphql', documents: ['src/**/*.graphql'], generates: { './src/generated/graphql.ts': { diff --git a/frontend/src/graphql/create-account.mutation.graphql b/frontend/src/graphql/create-account.mutation.graphql new file mode 100644 index 0000000..6fc1041 --- /dev/null +++ b/frontend/src/graphql/create-account.mutation.graphql @@ -0,0 +1,8 @@ +mutation CreateAccount($email: String!, $password: String!) { + createAccount(email: $email, password: $password) { + id + email + createdAt + updatedAt + } +} diff --git a/frontend/src/graphql/get-account-by-email.query.graphql b/frontend/src/graphql/get-account-by-email.query.graphql new file mode 100644 index 0000000..56f68ad --- /dev/null +++ b/frontend/src/graphql/get-account-by-email.query.graphql @@ -0,0 +1,8 @@ +query GetAccountByEmail($email: String!) { + accountByEmail(email: $email) { + id + email + createdAt + updatedAt + } +} diff --git a/frontend/src/graphql/get-accounts.query.graphql b/frontend/src/graphql/get-accounts.query.graphql new file mode 100644 index 0000000..9c11ce8 --- /dev/null +++ b/frontend/src/graphql/get-accounts.query.graphql @@ -0,0 +1,8 @@ +query GetAccounts { + accounts { + id + email + createdAt + updatedAt + } +} diff --git a/frontend/src/graphql/login-account.query.graphql b/frontend/src/graphql/login-account.query.graphql new file mode 100644 index 0000000..155c5ed --- /dev/null +++ b/frontend/src/graphql/login-account.query.graphql @@ -0,0 +1,8 @@ +query LoginAccount($email: String!, $password: String!) { + loginAccount(email: $email, password: $password) { + id + email + createdAt + updatedAt + } +} From 61750ed566db2019956c2beafc7542f9fef99b97 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 16:10:57 +0000 Subject: [PATCH 3/9] Refactor AccountService to use generated Apollo Angular GQL classes Co-authored-by: PhantomDave <34485699+PhantomDave@users.noreply.github.com> --- .../login-component/login-component.ts | 7 +- .../src/models/account/account-service.ts | 88 ++++++++++++++++--- frontend/src/models/account/account.ts | 2 +- 3 files changed, 80 insertions(+), 17 deletions(-) diff --git a/frontend/src/app/components/welcome-layout/login-component/login-component.ts b/frontend/src/app/components/welcome-layout/login-component/login-component.ts index 570df89..7d8444c 100644 --- a/frontend/src/app/components/welcome-layout/login-component/login-component.ts +++ b/frontend/src/app/components/welcome-layout/login-component/login-component.ts @@ -5,6 +5,7 @@ import {MatSelectModule} from '@angular/material/select'; import {MatInputModule} from '@angular/material/input'; import {MatFormFieldModule} from '@angular/material/form-field'; import {FlexComponent} from '../../flex-component/flex-component'; +import {AccountService} from '../../../../models/account/account-service'; @Component({ selector: 'app-login-component', @@ -22,17 +23,17 @@ import {FlexComponent} from '../../flex-component/flex-component'; }) export class LoginComponent { private readonly fb = inject(FormBuilder); + private readonly accountService = inject(AccountService); protected readonly loginForm: FormGroup = this.fb.group({ email: ['', [Validators.required, Validators.email]], password: ['', [Validators.required, Validators.minLength(6)]] }); - protected onSubmit() { + protected async onSubmit() { if (this.loginForm.valid) { const {email, password} = this.loginForm.value; - console.log('Email:', email); - console.log('Password:', password); + await this.accountService.loginAccount(email, password); } else { this.loginForm.markAllAsTouched(); } diff --git a/frontend/src/models/account/account-service.ts b/frontend/src/models/account/account-service.ts index 3b149b9..02824d6 100644 --- a/frontend/src/models/account/account-service.ts +++ b/frontend/src/models/account/account-service.ts @@ -1,16 +1,22 @@ import {inject, Injectable, signal, Signal} from '@angular/core'; import {Account} from './account'; -import {Apollo} from 'apollo-angular'; -import {GET_ACCOUNT_BY_EMAIL} from './account.queries'; import {firstValueFrom} from 'rxjs'; -import {CREATE_ACCOUNT} from './account.mutations'; import { SnackbarService } from '../../shared/services/snackbar.service'; +import { + CreateAccountGQL, + GetAccountByEmailGQL, + GetAccountsGQL, + LoginAccountGQL +} from '../../generated/graphql'; @Injectable({ providedIn: 'root' }) export class AccountService { - private readonly apollo = inject(Apollo); + private readonly createAccountGQL = inject(CreateAccountGQL); + private readonly getAccountByEmailGQL = inject(GetAccountByEmailGQL); + private readonly getAccountsGQL = inject(GetAccountsGQL); + private readonly loginAccountGQL = inject(LoginAccountGQL); private readonly snackbar = inject(SnackbarService); private readonly _selectedAccount = signal(null); @@ -31,14 +37,11 @@ export class AccountService { try { const result = await firstValueFrom( - this.apollo.query<{ accountByEmail: Account | null }>({ - query: GET_ACCOUNT_BY_EMAIL, - variables: {email} - }) + this.getAccountByEmailGQL.watch({ variables: { email } }).valueChanges ); if (result?.data?.accountByEmail !== null && result?.data?.accountByEmail !== undefined) { - this._selectedAccount.set(result.data.accountByEmail); + this._selectedAccount.set(result.data.accountByEmail as Account); } if (result && (result as any).error) { @@ -60,10 +63,9 @@ export class AccountService { this._error.set(null); try { - const result = await firstValueFrom(this.apollo.mutate<{createAccount: Account | null}>({ - mutation: CREATE_ACCOUNT, - variables: {email, password} - })); + const result = await firstValueFrom( + this.createAccountGQL.mutate({ variables: { email, password } }) + ); if (result?.data?.createAccount) { this.snackbar.success('Account creato con successo'); @@ -90,4 +92,64 @@ export class AccountService { this._loading.set(false); } } + + async loginAccount(email: string, password: string): Promise { + this._loading.set(true); + this._error.set(null); + + try { + const result = await firstValueFrom( + this.loginAccountGQL.watch({ variables: { email, password } }).valueChanges + ); + + if (result?.data?.loginAccount) { + const account = result.data.loginAccount as Account; + this._selectedAccount.set(account); + this.snackbar.success('Login effettuato con successo'); + return account; + } + + if (result && (result as any).error) { + const message = (result as any).error?.message ?? 'Login fallito'; + this._error.set(message); + this.snackbar.error(message); + } + + return null; + } catch (err: unknown) { + const message = err instanceof Error ? err.message : 'Errore imprevisto'; + this._error.set(message); + this.snackbar.error(message); + return null; + } finally { + this._loading.set(false); + } + } + + async getAllAccounts(): Promise { + this._loading.set(true); + this._error.set(null); + + try { + const result = await firstValueFrom( + this.getAccountsGQL.watch().valueChanges + ); + + if (result?.data?.accounts) { + this._accounts.set(result.data.accounts as readonly Account[]); + } + + if (result && (result as any).error) { + const message = (result as any).error?.message ?? 'Errore durante il caricamento degli account'; + this._error.set(message); + this.snackbar.error(message); + } + } catch (err: unknown) { + const message = err instanceof Error ? err.message : 'Errore imprevisto'; + this._error.set(message); + this.snackbar.error(message); + } finally { + this._loading.set(false); + } + } } diff --git a/frontend/src/models/account/account.ts b/frontend/src/models/account/account.ts index 956a415..4575486 100644 --- a/frontend/src/models/account/account.ts +++ b/frontend/src/models/account/account.ts @@ -2,5 +2,5 @@ export interface Account { id: number; email: string; createdAt: string; - updatedAt: string | null; + updatedAt?: string | null; } From 9d5759cc92c2cae89301914908a28f92325f98e8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 16:11:48 +0000 Subject: [PATCH 4/9] Remove deprecated account query and mutation files Co-authored-by: PhantomDave <34485699+PhantomDave@users.noreply.github.com> --- frontend/src/models/account/account.mutations.ts | 13 ------------- frontend/src/models/account/account.queries.ts | 12 ------------ 2 files changed, 25 deletions(-) delete mode 100644 frontend/src/models/account/account.mutations.ts delete mode 100644 frontend/src/models/account/account.queries.ts diff --git a/frontend/src/models/account/account.mutations.ts b/frontend/src/models/account/account.mutations.ts deleted file mode 100644 index b53f7d5..0000000 --- a/frontend/src/models/account/account.mutations.ts +++ /dev/null @@ -1,13 +0,0 @@ -import { gql } from 'apollo-angular'; - -export const CREATE_ACCOUNT = gql` - mutation CreateAccount($email: String!, $password: String!) { - createAccount(email: $email, password: $password) { - id - email - createdAt - updatedAt - } - } -`; - diff --git a/frontend/src/models/account/account.queries.ts b/frontend/src/models/account/account.queries.ts deleted file mode 100644 index 829a774..0000000 --- a/frontend/src/models/account/account.queries.ts +++ /dev/null @@ -1,12 +0,0 @@ -import {gql} from 'apollo-angular'; - -export const GET_ACCOUNT_BY_EMAIL = gql` - query GetAccountByEmail($email: String!) { - accountByEmail(email: $email) { - id - email - createdAt - updatedAt - } - } -`; From bade8214a5e72383d1109cc3784342975db67870 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 16:18:11 +0000 Subject: [PATCH 5/9] Add documentation for GraphQL refactoring Co-authored-by: PhantomDave <34485699+PhantomDave@users.noreply.github.com> --- frontend/GRAPHQL_REFACTORING.md | 142 ++++++++++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 frontend/GRAPHQL_REFACTORING.md diff --git a/frontend/GRAPHQL_REFACTORING.md b/frontend/GRAPHQL_REFACTORING.md new file mode 100644 index 0000000..e77c41d --- /dev/null +++ b/frontend/GRAPHQL_REFACTORING.md @@ -0,0 +1,142 @@ +# Account GraphQL Operations Refactoring + +This document explains the refactoring of account-related GraphQL operations to use Apollo Angular's typed GQL service pattern. + +## Overview + +All account operations have been migrated from using raw GraphQL queries/mutations with Apollo client to using generated, type-safe Apollo Angular GQL services. + +## What Changed + +### Before +```typescript +// Direct Apollo usage +this.apollo.query({ + query: GET_ACCOUNT_BY_EMAIL, + variables: { email } +}) + +this.apollo.mutate({ + mutation: CREATE_ACCOUNT, + variables: { email, password } +}) +``` + +### After +```typescript +// Generated typed GQL services +this.getAccountByEmailGQL.watch({ variables: { email } }).valueChanges +this.createAccountGQL.mutate({ variables: { email, password } }) +``` + +## Generated GQL Classes + +The following injectable GQL classes are now available in `src/generated/graphql.ts`: + +### Queries +- **GetAccountByEmailGQL** - Fetch account by email +- **GetAccountsGQL** - Fetch all accounts +- **LoginAccountGQL** - Login with email and password + +### Mutations +- **CreateAccountGQL** - Create a new account + +## Usage + +### Using AccountService (Recommended) +The AccountService provides high-level methods that wrap the GQL classes with error handling and state management: + +```typescript +import { AccountService } from './models/account/account-service'; + +export class MyComponent { + private readonly accountService = inject(AccountService); + + async login() { + const account = await this.accountService.loginAccount(email, password); + } + + async register() { + const result = await this.accountService.createAccount(email, password); + } +} +``` + +### Using GQL Classes Directly (Advanced) +For more control, you can inject the GQL classes directly: + +```typescript +import { LoginAccountGQL, CreateAccountGQL } from './generated/graphql'; +import { firstValueFrom } from 'rxjs'; + +export class MyComponent { + private readonly loginGQL = inject(LoginAccountGQL); + private readonly createAccountGQL = inject(CreateAccountGQL); + + async login(email: string, password: string) { + const result = await firstValueFrom( + this.loginGQL.watch({ variables: { email, password } }).valueChanges + ); + return result.data?.loginAccount; + } + + async register(email: string, password: string) { + const result = await firstValueFrom( + this.createAccountGQL.mutate({ variables: { email, password } }) + ); + return result.data?.createAccount; + } +} +``` + +## Adding New Operations + +To add a new account operation: + +1. Create a `.graphql` file in `src/graphql/`: +```graphql +# src/graphql/update-account.mutation.graphql +mutation UpdateAccount($id: Int!, $email: String!) { + updateAccount(id: $id, email: $email) { + id + email + createdAt + updatedAt + } +} +``` + +2. Run code generation: +```bash +npm run codegen +``` + +3. The new `UpdateAccountGQL` class will be generated and can be injected: +```typescript +import { UpdateAccountGQL } from './generated/graphql'; + +export class AccountService { + private readonly updateAccountGQL = inject(UpdateAccountGQL); + + async updateAccount(id: number, email: string) { + const result = await firstValueFrom( + this.updateAccountGQL.mutate({ variables: { id, email } }) + ); + return result.data?.updateAccount; + } +} +``` + +## Benefits + +1. **Type Safety**: Full TypeScript type checking for all GraphQL operations +2. **Auto-completion**: IDE provides suggestions for available fields and variables +3. **Consistency**: All operations follow the same pattern +4. **Maintainability**: Easier to add, modify, and remove operations +5. **Code Generation**: No manual type definitions needed + +## Migration Notes + +- Old `account.queries.ts` and `account.mutations.ts` files have been removed +- The `Account` interface was updated to match generated types (`updatedAt?: string | null`) +- All existing components using AccountService continue to work without changes From 7eb9ba3b4a3b4d6144cd2bd4dbdc79a2d2dd1f0c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 16:25:42 +0000 Subject: [PATCH 6/9] Replace .watch() with .fetch() for one-time GraphQL queries Changed getAccountByEmail, loginAccount, and getAllAccounts methods to use .fetch() instead of .watch().valueChanges for better performance as these are one-time data fetches, not subscriptions that need to watch for updates. Co-authored-by: PhantomDave <34485699+PhantomDave@users.noreply.github.com> --- frontend/src/models/account/account-service.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/models/account/account-service.ts b/frontend/src/models/account/account-service.ts index 02824d6..a7cfa27 100644 --- a/frontend/src/models/account/account-service.ts +++ b/frontend/src/models/account/account-service.ts @@ -37,7 +37,7 @@ export class AccountService { try { const result = await firstValueFrom( - this.getAccountByEmailGQL.watch({ variables: { email } }).valueChanges + this.getAccountByEmailGQL.fetch({ variables: { email } }) ); if (result?.data?.accountByEmail !== null && result?.data?.accountByEmail !== undefined) { @@ -99,7 +99,7 @@ export class AccountService { try { const result = await firstValueFrom( - this.loginAccountGQL.watch({ variables: { email, password } }).valueChanges + this.loginAccountGQL.fetch({ variables: { email, password } }) ); if (result?.data?.loginAccount) { @@ -132,7 +132,7 @@ export class AccountService { try { const result = await firstValueFrom( - this.getAccountsGQL.watch().valueChanges + this.getAccountsGQL.fetch({}) ); if (result?.data?.accounts) { From d0f3bb2f366716c93e049cd5be86d2fb1e4a25c4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 18:54:21 +0000 Subject: [PATCH 7/9] Move LoginAccount from Query to Mutation in backend and frontend Backend changes: - Moved LoginAccount method from AccountQueries to AccountMutations - Added proper validation and error handling for login credentials Frontend changes: - Updated login-account GraphQL file to use mutation instead of query - Renamed file to login-account.mutation.graphql - Updated schema.graphql to reflect loginAccount as a mutation - Regenerated TypeScript types with codegen - Updated AccountService to use .mutate() instead of .fetch() for login - Updated documentation to reflect login as a mutation Co-authored-by: PhantomDave <34485699+PhantomDave@users.noreply.github.com> --- .../Types/Mutations/AccountMutations.cs | 45 +++++++++++++++++++ .../Types/Queries/AccountQueries.cs | 9 ---- frontend/GRAPHQL_REFACTORING.md | 5 ++- frontend/schema.graphql | 2 +- ...graphql => login-account.mutation.graphql} | 2 +- .../src/models/account/account-service.ts | 2 +- 6 files changed, 51 insertions(+), 14 deletions(-) rename frontend/src/graphql/{login-account.query.graphql => login-account.mutation.graphql} (63%) diff --git a/PhantomDave.BankTracking.Api/Types/Mutations/AccountMutations.cs b/PhantomDave.BankTracking.Api/Types/Mutations/AccountMutations.cs index 838f95e..c04df18 100644 --- a/PhantomDave.BankTracking.Api/Types/Mutations/AccountMutations.cs +++ b/PhantomDave.BankTracking.Api/Types/Mutations/AccountMutations.cs @@ -53,5 +53,50 @@ public async Task CreateAccount( return AccountType.FromAccount(account); } + + /// + /// Login to an account + /// + public async Task LoginAccount( + string email, + string password, + [Service] AccountService accountService) + { + if (string.IsNullOrWhiteSpace(email)) + { + throw new GraphQLException( + ErrorBuilder.New() + .SetMessage("Email is required.") + .SetCode("BAD_USER_INPUT") + .SetExtension("field", "email") + .SetExtension("reason", "required") + .Build()); + } + + if (string.IsNullOrWhiteSpace(password)) + { + throw new GraphQLException( + ErrorBuilder.New() + .SetMessage("Password is required.") + .SetCode("BAD_USER_INPUT") + .SetExtension("field", "password") + .SetExtension("reason", "required") + .Build()); + } + + var account = await accountService.LoginAccountAsync(email, password); + if (account is null) + { + throw new GraphQLException( + ErrorBuilder.New() + .SetMessage("Invalid email or password.") + .SetCode("AUTHENTICATION_FAILED") + .SetExtension("field", "email") + .SetExtension("reason", "invalid_credentials") + .Build()); + } + + return AccountType.FromAccount(account); + } } diff --git a/PhantomDave.BankTracking.Api/Types/Queries/AccountQueries.cs b/PhantomDave.BankTracking.Api/Types/Queries/AccountQueries.cs index 009bc19..aaea9ff 100644 --- a/PhantomDave.BankTracking.Api/Types/Queries/AccountQueries.cs +++ b/PhantomDave.BankTracking.Api/Types/Queries/AccountQueries.cs @@ -29,14 +29,5 @@ public async Task> GetAccounts( var account = await accountService.GetAccountByEmail(email); return account != null ? AccountType.FromAccount(account) : null; } - - public async Task LoginAccount( - string email, - string password, - [Service] AccountService accountService) - { - var account = await accountService.LoginAccountAsync(email, password); - return account != null ? AccountType.FromAccount(account) : null; - } } diff --git a/frontend/GRAPHQL_REFACTORING.md b/frontend/GRAPHQL_REFACTORING.md index e77c41d..2450e04 100644 --- a/frontend/GRAPHQL_REFACTORING.md +++ b/frontend/GRAPHQL_REFACTORING.md @@ -25,8 +25,9 @@ this.apollo.mutate({ ### After ```typescript // Generated typed GQL services -this.getAccountByEmailGQL.watch({ variables: { email } }).valueChanges +this.getAccountByEmailGQL.fetch({ variables: { email } }) this.createAccountGQL.mutate({ variables: { email, password } }) +this.loginAccountGQL.mutate({ variables: { email, password } }) ``` ## Generated GQL Classes @@ -36,10 +37,10 @@ The following injectable GQL classes are now available in `src/generated/graphql ### Queries - **GetAccountByEmailGQL** - Fetch account by email - **GetAccountsGQL** - Fetch all accounts -- **LoginAccountGQL** - Login with email and password ### Mutations - **CreateAccountGQL** - Create a new account +- **LoginAccountGQL** - Login with email and password (changed from Query to Mutation for proper authentication semantics) ## Usage diff --git a/frontend/schema.graphql b/frontend/schema.graphql index 73c1c57..5935752 100644 --- a/frontend/schema.graphql +++ b/frontend/schema.graphql @@ -25,10 +25,10 @@ scalar DateTime type Mutation { createAccount(email: String!, password: String!): AccountType! + loginAccount(email: String!, password: String!): AccountType } type Query { accountByEmail(email: String!): AccountType accounts: [AccountType!]! - loginAccount(email: String!, password: String!): AccountType } \ No newline at end of file diff --git a/frontend/src/graphql/login-account.query.graphql b/frontend/src/graphql/login-account.mutation.graphql similarity index 63% rename from frontend/src/graphql/login-account.query.graphql rename to frontend/src/graphql/login-account.mutation.graphql index 155c5ed..8e5cb75 100644 --- a/frontend/src/graphql/login-account.query.graphql +++ b/frontend/src/graphql/login-account.mutation.graphql @@ -1,4 +1,4 @@ -query LoginAccount($email: String!, $password: String!) { +mutation LoginAccount($email: String!, $password: String!) { loginAccount(email: $email, password: $password) { id email diff --git a/frontend/src/models/account/account-service.ts b/frontend/src/models/account/account-service.ts index a7cfa27..b5aa445 100644 --- a/frontend/src/models/account/account-service.ts +++ b/frontend/src/models/account/account-service.ts @@ -99,7 +99,7 @@ export class AccountService { try { const result = await firstValueFrom( - this.loginAccountGQL.fetch({ variables: { email, password } }) + this.loginAccountGQL.mutate({ variables: { email, password } }) ); if (result?.data?.loginAccount) { From 18d73f2cafbfc7216d4728a2eae84a517b799512 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 19:02:52 +0000 Subject: [PATCH 8/9] Fix code formatting issues in AccountService Applied dotnet format to fix whitespace formatting errors: - Fixed spacing after if statements - Fixed blank line spacing between methods - Ensures CI/CD formatting checks pass Co-authored-by: PhantomDave <34485699+PhantomDave@users.noreply.github.com> --- PhantomDave.BankTracking.Api/Services/AccountService.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/PhantomDave.BankTracking.Api/Services/AccountService.cs b/PhantomDave.BankTracking.Api/Services/AccountService.cs index 1acb319..1b03376 100644 --- a/PhantomDave.BankTracking.Api/Services/AccountService.cs +++ b/PhantomDave.BankTracking.Api/Services/AccountService.cs @@ -22,7 +22,7 @@ public AccountService(IUnitOfWork unitOfWork) { return await _unitOfWork.Accounts.GetSingleOrDefaultAsync(a => a.Email == email); } - + public async Task> GetAllAccountsAsync() { return await _unitOfWork.Accounts.GetAllAsync(); @@ -74,11 +74,11 @@ private async Task IsEmailAlreadyPresent(string email) public async Task LoginAccountAsync(string email, string password) { var account = await GetAccountByEmail(email); - if(account == null) + if (account == null) return null; return VerifyPassword(password, account.PasswordHash) ? account : null; } - + private static string HashPassword(string password) { const int iterations = 100_000; @@ -90,7 +90,7 @@ private static string HashPassword(string password) return $"PBKDF2-SHA256${iterations}${Convert.ToBase64String(salt)}${Convert.ToBase64String(hash)}"; } - + private static bool VerifyPassword(string password, string stored) { if (string.IsNullOrWhiteSpace(stored)) From f476c634a30f578ff51a71d120fe2bee52621979 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 30 Oct 2025 19:08:55 +0000 Subject: [PATCH 9/9] Add codegen step to frontend CI/CD workflow The generated GraphQL types are in .gitignore and need to be generated during CI/CD. Added npm run codegen step before TypeScript compilation and build to ensure the generated files exist. Co-authored-by: PhantomDave <34485699+PhantomDave@users.noreply.github.com> --- .github/workflows/frontend.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/frontend.yml b/.github/workflows/frontend.yml index 5777ce9..1f732f3 100644 --- a/.github/workflows/frontend.yml +++ b/.github/workflows/frontend.yml @@ -34,6 +34,10 @@ jobs: working-directory: ./frontend run: npm ci + - name: Generate GraphQL types + working-directory: ./frontend + run: npm run codegen + - name: Check TypeScript compilation working-directory: ./frontend run: npx tsc --noEmit