Skip to content

Commit

Permalink
Introduced etag caching and SessionState class
Browse files Browse the repository at this point in the history
  • Loading branch information
kielbasa-elp committed Aug 30, 2024
1 parent 92226b9 commit 04dfcf4
Show file tree
Hide file tree
Showing 31 changed files with 279 additions and 123 deletions.
2 changes: 2 additions & 0 deletions apps/api/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { ReceiptModule } from '~/modules/organization/receipt/receipt.module';
import { StatisticsModule } from '~/modules/organization/statistics/statistics.module';
import { CacheModule } from '@nestjs/cache-manager';
import { redisStore } from 'cache-manager-redis-yet';
import { UserModule } from '~/modules/user/user.module';

@Module({
imports: [
Expand Down Expand Up @@ -73,6 +74,7 @@ import { redisStore } from 'cache-manager-redis-yet';
RouterModule,

AuthModule,
UserModule,
OrganizationModule,
TransactionModule,
StatisticsModule,
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/modules/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { JwtModule } from '@nestjs/jwt';

import { JwtStrategy } from '~/modules/auth/jwt.strategy';
import { LocalStrategy } from '~/modules/auth/local.strategy';
import { UserModule } from '~/modules/organization/user/user.module';
import { UserModule } from '~/modules/user/user.module';

import { AuthController } from './auth.controller';
import { AuthService } from './auth.service';
Expand Down
16 changes: 12 additions & 4 deletions apps/api/src/modules/auth/auth.service.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,16 @@
import { BadRequestException, Injectable } from '@nestjs/common';
import {
BadRequestException,
Injectable,
NotFoundException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import * as bcrypt from 'bcrypt';

import { SignInDto } from '~/dtos/auth/sign-in.dto';
import { CreateUserDto } from '~/dtos/users/create-user.dto';
import { GetUserDto } from '~/dtos/users/get-user.dto';
import { User } from '~/entities/user/user.entity';
import { UserService } from '~/modules/organization/user/user.service';
import { UserService } from '~/modules/user/user.service';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Session } from '~/entities/session/session.entity';
Expand Down Expand Up @@ -64,10 +68,14 @@ export class AuthService {
}

async signUp(user: CreateUserDto) {
const existingUser = await this.userService.findOneByEmail(user.email);
try {
await this.userService.findOneByEmail(user.email);

if (existingUser) {
throw new BadRequestException('Email already exists');
} catch (err) {
if (!(err instanceof NotFoundException)) {
throw err;
}
}

const hashedPassword = await bcrypt.hash(user.password, 10);
Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/modules/organization/organization.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Organization } from '~/entities/organization/organization.entity';
import { User } from '~/entities/user/user.entity';
import { OrganizationController } from '~/modules/organization/organization.controller';
import { OrganizationService } from '~/modules/organization/organization.service';
import { UserModule } from '~/modules/organization/user/user.module';
import { UserModule } from '~/modules/user/user.module';
import { SecretModule } from '~/modules/organization/secret/secret.module';
import { Secret } from '~/entities/secret/secret.entity';

Expand Down
2 changes: 1 addition & 1 deletion apps/api/src/modules/organization/organization.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { Repository } from 'typeorm';
import { CreateOrganizationDto } from '~/dtos/organization/create-organization.dto';
import { Organization } from '~/entities/organization/organization.entity';
import { User } from '~/entities/user/user.entity';
import { UserService } from '~/modules/organization/user/user.service';
import { UserService } from '~/modules/user/user.service';
import { SecretService } from '~/modules/organization/secret/secret.service';
import { Secret } from '~/entities/secret/secret.entity';
import { CreateSecretDto } from '~/dtos/secret/create-secret.dto';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import { StatisticsController } from '~/modules/organization/statistics/statisti
import { TransactionModule } from '~/modules/organization/transaction/transaction.module';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Transaction } from '~/entities/transaction/transaction.entity';
import { UserModule } from '~/modules/organization/user/user.module';
import { UserModule } from '~/modules/user/user.module';

@Module({
imports: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { OrganizationModule } from '~/modules/organization/organization.module';
import { TransactionItemModule } from '~/modules/organization/transaction/transaction-item/transaction-item.module';
import { TransactionController } from '~/modules/organization/transaction/transaction.controller';
import { TransactionService } from '~/modules/organization/transaction/transaction.service';
import { UserModule } from '~/modules/organization/user/user.module';
import { UserModule } from '~/modules/user/user.module';

@Module({
imports: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { Transaction } from '~/entities/transaction/transaction.entity';
import { TransactionItem } from '~/entities/transaction/transactionItem.entity';
import { TransactionItemCategory } from '~/entities/transaction/transactionItemCategory.entity';
import { OrganizationService } from '~/modules/organization/organization.service';
import { UserService } from '~/modules/organization/user/user.service';
import { UserService } from '~/modules/user/user.service';
import {
FilterOperator,
paginate,
Expand Down
14 changes: 0 additions & 14 deletions apps/api/src/modules/organization/user/user.controller.ts

This file was deleted.

5 changes: 5 additions & 0 deletions apps/api/src/modules/router/router.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { TransactionModule } from '~/modules/organization/transaction/transactio
import { StatisticsModule } from '~/modules/organization/statistics/statistics.module';
import { ReceiptModule } from '~/modules/organization/receipt/receipt.module';
import { Module } from '@nestjs/common';
import { UserModule } from '~/modules/user/user.module';

@Module({
imports: [
Expand All @@ -26,6 +27,10 @@ import { Module } from '@nestjs/common';
},
],
},
{
path: 'users',
module: UserModule,
},
]),
],
})
Expand Down
15 changes: 15 additions & 0 deletions apps/api/src/modules/user/user.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Controller, Get } from '@nestjs/common';

import { GetUserDto } from '~/dtos/users/get-user.dto';
import { AuthUser, User } from '~/modules/decorators/user.decorator';
import { UserService } from './user.service';

@Controller()
export class UserController {
constructor(private readonly userService: UserService) {}

@Get('me')
me(@User() user: AuthUser): Promise<GetUserDto> {
return this.userService.findOneByEmail(user.email);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';

import { User } from '~/entities/user/user.entity';
import { UserController } from '~/modules/organization/user/user.controller';
import { UserService } from '~/modules/organization/user/user.service';
import { UserController } from './user.controller';
import { UserService } from './user.service';

@Module({
imports: [TypeOrmModule.forFeature([User])],
Expand Down
File renamed without changes.
21 changes: 21 additions & 0 deletions apps/web/app/api/User/UserApi.server.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { userMeSchema } from '~/api/User/userApi.contracts';
import { typedFetch, TypedFetch } from '~/utils/fetch';

export class UserApi {
private readonly baseUrl = '/users';
private readonly client: TypedFetch;

constructor(client: TypedFetch = typedFetch) {
this.client = client;
}

me() {
return this.client(userMeSchema, `${this.baseUrl}/me`);
}

meWithSessionCookie(cookie: string) {
return this.client(userMeSchema, `${this.baseUrl}/me`, {
headers: { Cookie: cookie },
});
}
}
6 changes: 6 additions & 0 deletions apps/web/app/api/User/userApi.contracts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { z } from 'zod';

export const userMeSchema = z.object({
email: z.string().email(),
id: z.string(),
});
5 changes: 5 additions & 0 deletions apps/web/app/api/User/userApi.types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import { z } from 'zod';

import { userMeSchema } from './userApi.contracts';

export type UserMeDto = z.TypeOf<typeof userMeSchema>;
19 changes: 16 additions & 3 deletions apps/web/app/pages/auth/signin/action.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,9 @@ import { json, redirect } from '@remix-run/node';
import { parseWithZod } from '@conform-to/zod';

import { AuthApi } from '~/api/Auth/AuthApi.server';
import { UserApi } from '~/api/User/UserApi.server';
import { routes } from '~/routes';
import { setAuthSession } from '~/session.server';
import { SessionState } from '~/session.server';
import { actionHandler } from '~/utils/action.server';

import { schema } from './schema';
Expand All @@ -19,10 +20,22 @@ export const action = actionHandler({
}

const authApi = new AuthApi(fetch);

const response = await authApi.signIn(submission.value);

const sessionCookie = response.headers.get('Set-Cookie')!;

const userApi = new UserApi(fetch);
const { data: user } = await userApi.meWithSessionCookie(sessionCookie);

const session = await SessionState.fromRequest(request);

return redirect(routes.dashboard.getPath(), {
headers: { 'Set-cookie': await setAuthSession(request, response) },
headers: {
'Set-cookie': await session
.setAuthCookie(sessionCookie)
.setCurrentUser(user)
.commit(),
},
});
},
});
6 changes: 4 additions & 2 deletions apps/web/app/pages/auth/signout/action.server.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { redirect } from '@remix-run/node';

import { routes } from '~/routes';
import { logout } from '~/session.server';
import { SessionState } from '~/session.server';
import { actionHandler } from '~/utils/action.server';

export const action = actionHandler({
post: async ({ request }) => {
const sessionState = await SessionState.fromRequest(request);

return redirect(routes.signIn.getPath(), {
headers: { 'Set-cookie': await logout(request) },
headers: { 'Set-cookie': await sessionState.logout() },
});
},
});
25 changes: 22 additions & 3 deletions apps/web/app/pages/auth/signup/action.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ import { parseWithZod } from '@conform-to/zod';

import { signUpSchema } from '~/api/Auth/authApi.contracts';
import { AuthApi } from '~/api/Auth/AuthApi.server';
import { UserApi } from '~/api/User/UserApi.server';
import { routes } from '~/routes';
import { setAuthSession } from '~/session.server';
import { SessionState } from '~/session.server';
import { actionHandler } from '~/utils/action.server';

export const action = actionHandler({
Expand All @@ -21,8 +22,26 @@ export const action = actionHandler({

const response = await authApi.signUp(submission.value);

return redirect(routes.signIn.getPath(), {
headers: { 'Set-cookie': await setAuthSession(request, response) },
const sessionCookie = response.headers.get('Set-Cookie')!;

const userApi = new UserApi(fetch);
const { data: user } = await userApi.meWithSessionCookie(sessionCookie);

const session = await SessionState.fromRequest(request);

return redirect(routes.newOrganization.getPath(), {
headers: {
'Set-cookie': await session
.setAuthCookie(sessionCookie)
.setCurrentUser(user)
.setToasts({
success: {
title: 'Account created successfully!',
description: 'You can now create a new organization.',
},
})
.commit(),
},
});
},
});
6 changes: 4 additions & 2 deletions apps/web/app/pages/dashboard/layout/loader.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { redirect } from '@remix-run/node';

import { OrganizationApi } from '~/api/Organization/OrganizationApi.server';
import { routes } from '~/routes';
import { getLastOrganization, requireSignedIn } from '~/session.server';
import { requireSignedIn, SessionState } from '~/session.server';
import { loaderHandler } from '~/utils/loader.server';

export const loader = loaderHandler(async ({ request }, { fetch }) => {
Expand All @@ -14,7 +14,9 @@ export const loader = loaderHandler(async ({ request }, { fetch }) => {

if (data.length <= 0) return redirect(routes.newOrganization.getPath());

const lastOrganization = await getLastOrganization(request);
const sessionState = await SessionState.fromRequest(request);
const lastOrganization = sessionState.organizationName;

if (lastOrganization) {
return redirect(routes.organization.getPath(lastOrganization));
}
Expand Down
12 changes: 11 additions & 1 deletion apps/web/app/pages/dashboard/organization/new/action.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { parseWithZod } from '@conform-to/zod';
import { createOrganizationSchema } from '~/api/Organization/organizationApi.contracts';
import { OrganizationApi } from '~/api/Organization/OrganizationApi.server';
import { routes } from '~/routes';
import { SessionState } from '~/session.server';
import { actionHandler } from '~/utils/action.server';

export const action = actionHandler({
Expand All @@ -21,6 +22,15 @@ export const action = actionHandler({

const { data } = await organizationApi.create(submission.value);

return redirect(routes.organization.getPath(data.name));
const sessionData = await SessionState.fromRequest(request);
sessionData
.setOrganizationName(data.name)
.setToasts({ success: 'Organization created' });

return redirect(routes.organization.getPath(data.name), {
headers: {
'Set-Cookie': await sessionData.commit(),
},
});
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { parseWithZod } from '@conform-to/zod';
import { createTransactionSchema } from '~/api/Transaction/transactionApi.contracts';
import { TransactionApi } from '~/api/Transaction/TransactionApi.server';
import { routes } from '~/routes';
import { requireSignedIn, setServerToasts } from '~/session.server';
import { requireSignedIn, SessionState } from '~/session.server';
import { actionHandler } from '~/utils/action.server';
import { assert } from '~/utils/assert';

Expand All @@ -26,14 +26,18 @@ export const action = actionHandler({

await transactionApi.create(params.organizationName, submission.value);

const sessionState = await SessionState.fromRequest(request);

return redirect(routes.organization.getPath(params.organizationName), {
headers: {
'Set-Cookie': await setServerToasts(request, {
success: {
title: 'Transaction created',
description: `You've successfully created the transaction`,
},
}),
'Set-Cookie': await sessionState
.setToasts({
success: {
title: 'Transaction created',
description: `You've successfully created the transaction`,
},
})
.commit(),
},
});
},
Expand Down
Loading

0 comments on commit 04dfcf4

Please sign in to comment.