Skip to content

Commit

Permalink
feat: list daily order by orderId
Browse files Browse the repository at this point in the history
  • Loading branch information
alpemreelmas committed May 23, 2024
1 parent cf5437b commit 4f86a38
Show file tree
Hide file tree
Showing 16 changed files with 244 additions and 41 deletions.
19 changes: 19 additions & 0 deletions .env.local
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
MONGODB_URI=mongodb://127.0.0.1:27017/AIBackend
JWT_SECRET_KEY=123

MAIL_HOST=email-smtp.eu-north-1.amazonaws.com
MAIL_PORT=25
MAIL_SECURE=false
MAIL_USERNAME=AKIA5FTY7FF2ADQZF66C
MAIL_PASSWORD=BBoXNWCEzb7GgfK5La+alTH+pAqbIlyegV0sT4Bz8k9V
MAIL_DEFAULT_FROM=[email protected]

NOTIFICATION_CHANNEL=mail

REDIS_HOST=127.0.0.1
REDIS_PORT=6379

OPENAI_API_KEY=
ORGANIZATON_ID=

SITE_URL=http://localhost:5173/
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ RUN rm package*.json

EXPOSE 3000

CMD ["node", "./dist/main.js"]
CMD ["node", "./dist/main.js"]
CMD ["node", "./dist/seeder.js"]
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json",
"seed": "node ./dist/src/seeder",
"seed:refresh": "node ./dist/src/seeder --refresh"
"seed": "node ./dist/seeder",
"seed:refresh": "node ./dist/seeder --refresh"
},
"dependencies": {
"@bull-board/api": "^5.17.0",
Expand Down
2 changes: 1 addition & 1 deletion src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { BullAdapter } from '@bull-board/api/bullAdapter';
ConfigModule.forRoot({
isGlobal: true,
load: [notificationConfig],
envFilePath: '.env',
envFilePath: '.env.local',
}),
MongooseModule.forRoot(process.env.MONGODB_URI),
ThrottlerModule.forRoot([
Expand Down
2 changes: 1 addition & 1 deletion src/auth/auth.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,6 @@ import { ResetPasswordService } from './services/reset-password.service';
RolesService,
ResetPasswordService,
],
exports: [MongooseModule, RolesService],
exports: [MongooseModule, RolesService, AuthService],
})
export class AuthModule {}
24 changes: 16 additions & 8 deletions src/auth/guards/auth.guard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,17 @@ import { Reflector } from '@nestjs/core';

@Injectable()
export class AuthGuard implements CanActivate {
constructor(private jwtService: JwtService, private rolesService: RolesService, private reflector: Reflector,) {}
constructor(
private jwtService: JwtService,
private rolesService: RolesService,
private reflector: Reflector,
) {}

async canActivate(context: ExecutionContext): Promise<boolean> {
const requiredRole = this.reflector.get<string>('requiredRole', context.getHandler());

const requiredRole = this.reflector.get<string>(
'requiredRole',
context.getHandler(),
);

const request = context.switchToHttp().getRequest();
const token = this.extractTokenFromHeader(request);
Expand All @@ -29,16 +35,18 @@ export class AuthGuard implements CanActivate {
// 💡 We're assigning the payload to the request object here
// so that we can access it in our route handlers
request['user'] = payload;

//TODO: cache user roles
//@ts-ignore
const userRoles = (await this.rolesService.getUserRoles(payload._id)).map((userRole) => userRole.roleId.name);
if(requiredRole){
const userRoles = (await this.rolesService.getUserRoles(payload.sub)).map(
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
(userRole) => userRole.roleId.name,
);

if (requiredRole) {
if (!userRoles.includes(requiredRole)) {
throw new UnauthorizedException();
}
}

} catch {
throw new UnauthorizedException();
}
Expand Down
1 change: 0 additions & 1 deletion src/auth/services/auth.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import { NotificationService } from 'src/notification/notification.service';
import { LoggedInNotification } from 'src/notification/notifiables/loggedInNotification.notification';
import { welcomeNotification } from 'src/notification/notifiables/welcomeNotification.notification';
import { verificationNotification } from 'src/notification/notifiables/verificationNotification.notification';
import { RolesService } from 'src/users/services/roles.service';
import { Roles, rolesDocument } from 'src/users/entities/roles.schema';
import {
UserAndRoles,
Expand Down
6 changes: 6 additions & 0 deletions src/config/roles.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { registerAs } from '@nestjs/config';

export default registerAs('roles', () => ({
ADMIN_ROLE: 'admin',
USER_ROLE: 'user',
}));
34 changes: 33 additions & 1 deletion src/daily/daily.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,52 @@
import { Test, TestingModule } from '@nestjs/testing';
import { DailyController } from './daily.controller';
import { DailyService } from './daily.service';
import { REQUEST } from '@nestjs/core';
import { CreateDailyDto } from './dto/create-daily.dto';
import { AuthGuard } from '../auth/guards/auth.guard';
import { CanActivate } from '@nestjs/common';

describe('DailyController', () => {
let controller: DailyController;
let service: DailyService;

const mockDailyService = {
create: jest.fn((dto) => dto),
};

const mock_ForceFailGuard: CanActivate = { canActivate: jest.fn(() => true) };

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [DailyController],
providers: [DailyService],
}).compile();
})
.overrideProvider(DailyService)
.useValue(mockDailyService)
.overrideGuard(AuthGuard)
.useValue(mock_ForceFailGuard)
.compile();

controller = module.get<DailyController>(DailyController);
service = module.get<DailyService>(DailyService);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});

it('should call dailyService.create with correct parameters', async () => {
const req = { user: { id: 1, name: 'Test User' } };
const createDailyDto: CreateDailyDto = {
content: 'this is a test !',
orderId: 1,
};

const result = {};

jest.spyOn(service, 'create').mockResolvedValue(result);

expect(await controller.create(req, createDailyDto)).toBe(result);
expect(service.create).toHaveBeenCalledWith(createDailyDto, req.user);
});
});
56 changes: 55 additions & 1 deletion src/daily/daily.service.spec.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,72 @@
import { Test, TestingModule } from '@nestjs/testing';
import { DailyService } from './daily.service';
import { Daily } from './entities/daily.entity';
import { Model, ObjectId, Types } from 'mongoose';
import { getModelToken } from '@nestjs/mongoose';
import { CreateDailyDto } from './dto/create-daily.dto';

describe('DailyService', () => {
let service: DailyService;
let model: Model<Daily>;

const mockUser = {
sub: new Types.ObjectId('66479e05a279293d64585979'),
name: 'Alp Emre Elmas',
email: '[email protected]',
};

const mockDaily = {
user: new Types.ObjectId('66479e28a279293d64585982'),
content: 'Test #1',
orderId: 0,
createdAt: '2024-05-17T17:53:54.050Z',
updatedAt: '2024-05-17T17:53:54.050Z',
_id: new Types.ObjectId('66479e28a279293d64585982'),
__v: 0,
};

const mockDailyService = {
create: jest.fn(),
/*findAll: jest.fn(),
findOne: jest.fn(),
order: jest.fn(),
update: jest.fn(),
remove: jest.fn(),*/
};

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [DailyService],
providers: [
DailyService,
{
provide: getModelToken(Daily.name),
useValue: mockDailyService,
},
],
}).compile();

service = module.get<DailyService>(DailyService);
model = module.get<Model<Daily>>(getModelToken(Daily.name));
});

it('should be defined', () => {
expect(service).toBeDefined();
});

it('should create a daily', async () => {
const newDaily = {
content: 'This is a test content.',
orderId: 2,
};

jest.fn().mockResolvedValue((mockDaily) => Promise.resolve(mockDaily));

const result = await service.create(newDaily as CreateDailyDto, mockUser);
expect(result).toEqual({
_id: expect.any(Number),
content: 'This is a test content.',
});

expect(model.create).toHaveBeenCalledWith(newDaily);
});
});
6 changes: 2 additions & 4 deletions src/daily/daily.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,7 @@ import { OrderDailyDto } from './dto/order-daily.dto';

@Injectable()
export class DailyService {
constructor(
@InjectModel(Daily.name) private DailyModel: Model<DailyDocument>,
) {}
constructor(@InjectModel(Daily.name) private DailyModel: typeof Model) {}
async create(createDailyDto: CreateDailyDto, user: any) {
return await this.DailyModel.create({
...createDailyDto,
Expand All @@ -21,7 +19,7 @@ export class DailyService {
}

async findAll(user: any) {
return this.DailyModel.find({ user: user.sub });
return this.DailyModel.find({ user: user.sub }).sort({ orderId: 1 }).exec();
}

async findOne(id: string, user: any) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { join } from 'path';
import { Injectable } from '@nestjs/common';
import * as Bull from 'bull';
import { CustomNotificationSenderDto } from 'src/dashboard/dto/customNotificationSender.dto';
import { InjectQueue } from '@nestjs/bull';

@Injectable()
export class customNotification implements INotifiable {
Expand Down
21 changes: 19 additions & 2 deletions src/seeder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,28 @@ import { User, UserSchema } from './users/entities/user.schema';
import { UsersSeeder } from './users/seeders/users.seeder';
import { ConfigModule } from '@nestjs/config';
import * as process from 'process';
import { JwtModule } from '@nestjs/jwt';
import { UserModule } from './users/user.module';
import { AuthModule } from './auth/auth.module';
import notificationConfig from './config/notification';
import rolesConfig from './config/roles';
import { RolesSeeder } from './users/seeders/roles.seeder';

seeder({
imports: [
ConfigModule.forRoot(),
ConfigModule.forRoot({
isGlobal: true,
load: [notificationConfig, rolesConfig],
envFilePath: '.env.local',
}),
MongooseModule.forRoot(process.env.MONGODB_URI),
MongooseModule.forFeature([{ name: User.name, schema: UserSchema }]),
JwtModule.register({
global: true,
secret: process.env.JWT_SECRET_KEY,
signOptions: { expiresIn: '30m' },
}),
UserModule,
AuthModule,
],
}).run([UsersSeeder]);
}).run([RolesSeeder, UsersSeeder]);
34 changes: 34 additions & 0 deletions src/users/seeders/roles.seeder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import { Inject, Injectable } from '@nestjs/common';
import { InjectModel } from '@nestjs/mongoose';
import { Model } from 'mongoose';
import { User } from '../entities/user.schema';
import { v4 as uuidv4 } from 'uuid';
import { Seeder } from 'nestjs-seeder';
import * as bcrypt from 'bcrypt';
import * as moment from 'moment/moment';
import { UserAndRoles } from '../entities/userRoles';
import { AuthService } from '../../auth/services/auth.service';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import { Roles } from '../entities/roles.schema';

@Injectable()
export class RolesSeeder implements Seeder {
constructor(
@InjectModel(UserAndRoles.name)
private readonly rolesAndUser: Model<UserAndRoles>,
@InjectModel(Roles.name) private readonly roles: Model<Roles>,
private configService: ConfigService,
) {}

async seed(): Promise<any> {
const roles = this.configService.get<string>('roles');
for (const [key, value] of Object.entries(roles)) {
await this.roles.create({ name: value });
}
}

async drop(): Promise<any> {
return this.roles.deleteMany({});
}
}
Loading

0 comments on commit 4f86a38

Please sign in to comment.