Skip to content

Commit

Permalink
Merge pull request #14 from akbarsaputrait/5-api-owner---restaurant-t…
Browse files Browse the repository at this point in the history
…ables

Owner - Restaurant Table
  • Loading branch information
akbarsaputrait authored Jan 24, 2024
2 parents 9dc96bb + 5e2021d commit ca7e9ba
Show file tree
Hide file tree
Showing 14 changed files with 177 additions and 16 deletions.
5 changes: 5 additions & 0 deletions src/app.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { OwnerModule } from './app/owner/owner.module';
import { OwnerProfileModule } from './app/owner/profile/profile.module';
import { OwnerLocationModule } from './app/owner/restaurant/location/location.module';
import { OwnerRestaurantModule } from './app/owner/restaurant/restaurant.module';
import { OwnerTableModule } from './app/owner/restaurant/table/table.module';

export const routes: Routes = [
// { path: '/auth', module: AuthModule },
Expand All @@ -22,6 +23,10 @@ export const routes: Routes = [
path: '/:restaurant_id/locations',
module: OwnerLocationModule,
},
{
path: '/:restaurant_id/tables',
module: OwnerTableModule,
},
],
},
],
Expand Down
2 changes: 1 addition & 1 deletion src/app/owner/auth/auth.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ export class AuthController {
throw new UnauthorizedException('Password is incorrect');
}

if (user.isActive) {
if (!user.isActive) {
throw new UnauthorizedException('Your account was inactive by system');
}

Expand Down
7 changes: 4 additions & 3 deletions src/app/owner/restaurant/location/location.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { Location } from '@db/entities/owner/location.entity';
import { LocationTransformer } from '@db/transformers/location.transformer';
import { PlainTransformer } from '@db/transformers/plain.transformer';
import { ValidationException } from '@lib/exceptions/validation.exception';
import { isTrue } from '@lib/helpers/utils.helper';
import { Validator } from '@lib/helpers/validator.helper';
import { Permissions } from '@lib/rbac';
import AppDataSource from '@lib/typeorm/datasource.typeorm';
Expand All @@ -30,7 +31,7 @@ export class LocationController {
@UseGuards(OwnerGuard)
@Permissions(`${PermOwner.Location}@${PermAct.R}`)
async show(@Rest() rest, @Res() response, @Param() param) {
const location = await Location.findOneBy({ restaurant_id: rest.id, id: param.location_id });
const location = await Location.findOneByOrFail({ restaurant_id: rest.id, id: param.location_id });
await response.item(location, LocationTransformer);
}

Expand All @@ -49,7 +50,7 @@ export class LocationController {

const loc = new Location();
loc.name = body.name;
loc.is_default = false;
loc.is_default = isTrue(body.is_default);
loc.restaurant_id = rest.id;
await loc.save();

Expand All @@ -75,7 +76,7 @@ export class LocationController {

const loc = await Location.findOneByOrFail({ id: param.location_id });
loc.name = body.name;
loc.is_default = body.is_default;
loc.is_default = isTrue(body.is_default);
await loc.save();

return response.item(loc, LocationTransformer);
Expand Down
3 changes: 2 additions & 1 deletion src/app/owner/restaurant/restaurant.module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Module } from '@nestjs/common';
import { OwnerLocationModule } from './location/location.module';
import { RestaurantController } from './restaurant.controller';
import { OwnerTableModule } from './table/table.module';

@Module({
imports: [OwnerLocationModule],
imports: [OwnerLocationModule, OwnerTableModule],
controllers: [RestaurantController],
providers: [],
})
Expand Down
98 changes: 98 additions & 0 deletions src/app/owner/restaurant/table/table.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import { Quero } from '@core/decorators/quero.decorator';
import { Rest } from '@core/decorators/restaurant.decorator';
import { OwnerAuthGuard } from '@core/guards/auth.guard';
import { OwnerGuard } from '@core/guards/owner.guard';
import { PermAct, PermOwner } from '@core/services/role.service';
import { Location } from '@db/entities/owner/location.entity';
import { Restaurant } from '@db/entities/owner/restaurant.entity';
import { Table, TableStatus } from '@db/entities/owner/table.entity';
import { PlainTransformer } from '@db/transformers/plain.transformer';
import { TableTransformer } from '@db/transformers/table.transformer';
import { ValidationException } from '@lib/exceptions/validation.exception';
import { Validator } from '@lib/helpers/validator.helper';
import { Permissions } from '@lib/rbac';
import AppDataSource from '@lib/typeorm/datasource.typeorm';
import { BadRequestException, Body, Controller, Get, Param, Post, Put, Res, UseGuards } from '@nestjs/common';

@Controller()
@UseGuards(OwnerAuthGuard())
export class TableController {
@Get()
@UseGuards(OwnerGuard)
@Permissions(`${PermOwner.Table}@${PermAct.R}`)
async index(@Rest() rest, @Res() response, @Quero() quero) {
const tables = AppDataSource.createQueryBuilder(Table, 't1');
tables.where({ restaurant_id: rest.id });

if (quero.location_id) {
tables.andWhere({ location_id: quero.location_id });
}

const data = await tables.search().sort().getPaged();

await response.paginate(data, PlainTransformer);
}

@Get('/:table_id')
@UseGuards(OwnerGuard)
@Permissions(`${PermOwner.Table}@${PermAct.R}`)
async show(@Rest() rest, @Res() response, @Param() param) {
const table = await Table.findOneByOrFail({ restaurant_id: rest.id, id: param.table_id });
await response.item(table, TableTransformer);
}

@Post()
@UseGuards(OwnerGuard)
@Permissions(`${PermOwner.Table}@${PermAct.C}`)
async create(@Rest() rest: Restaurant, @Body() body, @Res() response) {
console.log(Object.values(TableStatus).join(','));
const rules = {
number: 'required|unique|safe_text',
location_id: 'required',
status: `required|in:${Object.values(TableStatus).join(',')}`,
};
const validation = Validator.init(body, rules);
if (validation.fails()) {
throw new ValidationException(validation);
}

const loc = await Location.findOneByOrFail({ id: body.location_id });

const table = new Table();
table.number = body.number;
table.status = body.status;
table.location_id = loc.id;
table.restaurant_id = rest.id;
await table.save();

return response.item(table, TableTransformer);
}

@Put('/:table_id')
@UseGuards(OwnerGuard)
@Permissions(`${PermOwner.Location}@${PermAct.C}`)
async update(@Rest() rest: Restaurant, @Body() body, @Res() response, @Param() param) {
const rules = {
number: 'required|unique|safe_text',
location_id: 'required',
status: `required|in:${Object.values(TableStatus).join(',')}`,
};
const validation = Validator.init(body, rules);
if (validation.fails()) {
throw new ValidationException(validation);
}

if (!param.table_id) {
throw new BadRequestException();
}

const table = await Table.findOneByOrFail({ id: param.table_id });
table.number = body.number;
table.status = body.status;
table.location_id = body.location_id;
table.restaurant_id = rest.id;
await table.save();

return response.item(table, TableTransformer);
}
}
9 changes: 9 additions & 0 deletions src/app/owner/restaurant/table/table.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Module } from '@nestjs/common';
import { TableController } from './table.controller';

@Module({
imports: [],
controllers: [TableController],
providers: [],
})
export class OwnerTableModule {}
7 changes: 7 additions & 0 deletions src/core/decorators/location.decorator.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { createParamDecorator, ExecutionContext } from '@nestjs/common';

export const Loc = createParamDecorator((data: unknown, ctx: ExecutionContext) => {
const request = ctx.switchToHttp().getRequest();

return request.current.location || null;
});
19 changes: 13 additions & 6 deletions src/core/guards/owner.guard.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Role } from '@db/entities/core/role.entity';
import { Location } from '@db/entities/owner/location.entity';
import { Owner } from '@db/entities/owner/owner.entity';
import { Restaurant } from '@db/entities/owner/restaurant.entity';
import { GuardException } from '@lib/exceptions/guard.exception';
Expand Down Expand Up @@ -31,22 +32,28 @@ const validateRestaurant = async (request: any) => {
throw new GuardException('Getting role was failed');
}

return { user, restaurant, roles, role };
let location: Location = null;
if (user.location_id) {
location = await Location.findOneBy({ id: user.location_id });
}

return { user, restaurant, roles, role, location };
};

export const setupPermission = async (request) => {
const restaurant = await validateRestaurant(request);
const { restaurant, role, roles, location } = await validateRestaurant(request);

// assign additional data to request object
Object.assign(request, {
current: {
restaurant: restaurant.restaurant,
role: restaurant.role,
restaurant: restaurant,
role,
location,
},
});

// filter based on available modules on plan
const grants = restaurant.roles.reduce((acc, cur) => {
const grants = roles.reduce((acc, cur) => {
acc[cur.slug] = cur.permissions || [];
return acc;
}, {});
Expand All @@ -57,7 +64,7 @@ export const setupPermission = async (request) => {
const filter = new ParamsFilter();
filter.setParam(RBAC_REQUEST_FILTER, { ...request });

return { ...restaurant, filter };
return { restaurant, role, roles, location, filter };
};

@Injectable()
Expand Down
2 changes: 0 additions & 2 deletions src/core/services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { jwt } from '@config/jwt.config';
import { Role } from '@db/entities/core/role.entity';
import { Owner, OwnerStatus } from '@db/entities/owner/owner.entity';
import { Restaurant, RestaurantStatus } from '@db/entities/owner/restaurant.entity';
import { config } from '@lib/helpers/config.helper';
import { hash, hashAreEqual } from '@lib/helpers/encrypt.helper';
import Logger from '@lib/logger/logger.library';
import AppDataSource from '@lib/typeorm/datasource.typeorm';
Expand Down Expand Up @@ -32,7 +31,6 @@ export class AuthService {
const payload = { email: user.email, phone: user.phone, sub: user.id };
return {
access_token: JWT.sign(payload, jwt.secret, jwt.signOptions),
pubsub_token: JWT.sign(payload, config.get('CENTRIFUGO_SECRET')),
};
}

Expand Down
4 changes: 3 additions & 1 deletion src/core/services/role.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ export enum PermOwner {
Profile = 'profile',
Restaurant = 'restaurant',
Location = 'location',
Table = 'table',
}

export const DefaultPerms = [PermOwner.Profile, PermOwner.Restaurant, PermOwner.Location];
export const DefaultPerms = [PermOwner.Profile, PermOwner.Restaurant];

@Injectable()
export class RoleService implements IDynamicStorageRbac {
Expand All @@ -31,6 +32,7 @@ export class RoleService implements IDynamicStorageRbac {
[PermOwner.Profile]: [PermAct.R, PermAct.C, PermAct.U, PermAct.D],
[PermOwner.Restaurant]: [PermAct.R, PermAct.C, PermAct.U, PermAct.D],
[PermOwner.Location]: [PermAct.R, PermAct.C, PermAct.U, PermAct.D],
[PermOwner.Table]: [PermAct.R, PermAct.C, PermAct.U, PermAct.D],
};

return {
Expand Down
8 changes: 8 additions & 0 deletions src/database/entities/owner/owner.entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { Exclude } from 'class-transformer';
import { JoinColumn, ManyToOne, OneToOne } from 'typeorm';
import { Role } from '../core/role.entity';
import { Location } from './location.entity';
import { Restaurant } from './restaurant.entity';

export enum OwnerStatus {
Expand Down Expand Up @@ -73,6 +74,13 @@ export class Owner extends BaseEntity {
@OneToOne(() => Restaurant, { onDelete: 'RESTRICT' })
restaurant: Promise<Restaurant>;

@Exclude()
@ForeignColumn()
location_id: string;

@ManyToOne(() => Location, { onDelete: 'SET NULL' })
location: Promise<Location>;

@Exclude()
@OneToOne(() => Media, (media) => media.owner)
image: Media;
Expand Down
17 changes: 17 additions & 0 deletions src/database/migrations/1706111840738-owner-location.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class ownerLocation1706111840738 implements MigrationInterface {
name = 'ownerLocation1706111840738';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`owner\` ADD \`location_id\` varchar(26) NULL`);
await queryRunner.query(
`ALTER TABLE \`owner\` ADD CONSTRAINT \`FK_71cfe28bf443954332aca78d9e1\` FOREIGN KEY (\`location_id\`) REFERENCES \`location\`(\`id\`) ON DELETE SET NULL ON UPDATE NO ACTION`
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE \`owner\` DROP FOREIGN KEY \`FK_71cfe28bf443954332aca78d9e1\``);
await queryRunner.query(`ALTER TABLE \`owner\` DROP COLUMN \`location_id\``);
}
}
4 changes: 2 additions & 2 deletions src/database/transformers/location.transformer.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Owner } from '@db/entities/owner/owner.entity';
import { Location } from '@db/entities/owner/location.entity';
import { TransformerAbstract } from '@lib/transformer/abstract.transformer';

export class LocationTransformer extends TransformerAbstract {
transform(entity: Owner) {
transform(entity: Location) {
return entity.toJSON();
}
}
8 changes: 8 additions & 0 deletions src/database/transformers/table.transformer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Table } from '@db/entities/owner/table.entity';
import { TransformerAbstract } from '@lib/transformer/abstract.transformer';

export class TableTransformer extends TransformerAbstract {
transform(entity: Table) {
return entity.toJSON();
}
}

0 comments on commit ca7e9ba

Please sign in to comment.