Skip to content

Commit a55cb88

Browse files
Merge pull request #720 from Mkalbani/feat/be-41-42-43-44-697-699
feat: implement bulk assets, tags, upload service, and notification p…
2 parents 222310f + 602728b commit a55cb88

14 files changed

Lines changed: 299 additions & 0 deletions

.gitignore

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# Dependencies
2+
node_modules/
3+
package-lock.json
4+
yarn.lock
5+
6+
# Build outputs
7+
dist/
8+
build/
9+
*.tsbuildinfo
10+
11+
# Environment
12+
.env
13+
.env.local
14+
.env.*.local
15+
16+
# IDE
17+
.vscode/
18+
.idea/
19+
*.swp
20+
*.swo
21+
*~
22+
.DS_Store
23+
24+
# Uploads
25+
uploads/
26+
27+
# Logs
28+
logs/
29+
*.log
30+
npm-debug.log*
31+
32+
# Coverage
33+
coverage/
34+
35+
# Misc
36+
.cache/
37+
.turbo/
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { IsArray, IsUUID, ArrayNotEmpty } from 'class-validator';
2+
3+
export class BulkDeleteAssetsDto {
4+
@IsArray()
5+
@ArrayNotEmpty()
6+
@IsUUID('4', { each: true })
7+
ids: string[];
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { IsArray, IsUUID, ArrayNotEmpty } from 'class-validator';
2+
3+
export class BulkTransferDepartmentDto {
4+
@IsArray()
5+
@ArrayNotEmpty()
6+
@IsUUID('4', { each: true })
7+
ids: string[];
8+
9+
@IsUUID('4')
10+
departmentId: string;
11+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { IsArray, IsEnum, IsUUID, ArrayNotEmpty } from 'class-validator';
2+
import { AssetStatus } from '../enums';
3+
4+
export class BulkUpdateStatusDto {
5+
@IsArray()
6+
@ArrayNotEmpty()
7+
@IsUUID('4', { each: true })
8+
ids: string[];
9+
10+
@IsEnum(AssetStatus)
11+
status: AssetStatus;
12+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { IsOptional, IsString } from 'class-validator';
2+
3+
export class SearchAssetsDto {
4+
@IsOptional()
5+
@IsString()
6+
q?: string;
7+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { IsArray, IsString } from 'class-validator';
2+
3+
export class UpdateAssetTagsDto {
4+
@IsArray()
5+
@IsString({ each: true })
6+
tags: string[];
7+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { SetMetadata } from '@nestjs/common';
2+
3+
export const ROLES_KEY = 'roles';
4+
export const Roles = (...roles: string[]) => SetMetadata(ROLES_KEY, roles);
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { CanActivate, ExecutionContext, ForbiddenException, Injectable } from '@nestjs/common';
2+
import { Reflector } from '@nestjs/core';
3+
import { ROLES_KEY } from '../decorators/roles.decorator';
4+
5+
@Injectable()
6+
export class RolesGuard implements CanActivate {
7+
constructor(private readonly reflector: Reflector) {}
8+
9+
canActivate(context: ExecutionContext): boolean {
10+
const requiredRoles = this.reflector.getAllAndOverride<string[]>(ROLES_KEY, [
11+
context.getHandler(),
12+
context.getClass(),
13+
]);
14+
15+
if (!requiredRoles || requiredRoles.length === 0) {
16+
return true;
17+
}
18+
19+
const request = context.switchToHttp().getRequest();
20+
const userRole = String(request.user?.role || '').toLowerCase();
21+
22+
if (!requiredRoles.map((role) => role.toLowerCase()).includes(userRole)) {
23+
throw new ForbiddenException('Insufficient role');
24+
}
25+
26+
return true;
27+
}
28+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import { IsBoolean, IsOptional } from 'class-validator';
2+
3+
export class UpdateNotificationPreferencesDto {
4+
@IsOptional()
5+
@IsBoolean()
6+
assetCreated?: boolean;
7+
8+
@IsOptional()
9+
@IsBoolean()
10+
assetTransferred?: boolean;
11+
12+
@IsOptional()
13+
@IsBoolean()
14+
maintenanceDue?: boolean;
15+
16+
@IsOptional()
17+
@IsBoolean()
18+
warrantyExpiring?: boolean;
19+
}
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import {
2+
Entity,
3+
PrimaryGeneratedColumn,
4+
Column,
5+
CreateDateColumn,
6+
UpdateDateColumn,
7+
JoinColumn,
8+
OneToOne,
9+
} from 'typeorm';
10+
import { User } from '../users/user.entity';
11+
12+
@Entity('notification_preferences')
13+
export class NotificationPreference {
14+
@PrimaryGeneratedColumn('uuid')
15+
id: string;
16+
17+
@Column({ unique: true })
18+
userId: string;
19+
20+
@OneToOne(() => User, { onDelete: 'CASCADE' })
21+
@JoinColumn({ name: 'userId' })
22+
user: User;
23+
24+
@Column({ default: true })
25+
assetCreated: boolean;
26+
27+
@Column({ default: true })
28+
assetTransferred: boolean;
29+
30+
@Column({ default: true })
31+
maintenanceDue: boolean;
32+
33+
@Column({ default: true })
34+
warrantyExpiring: boolean;
35+
36+
@CreateDateColumn()
37+
createdAt: Date;
38+
39+
@UpdateDateColumn()
40+
updatedAt: Date;
41+
}

0 commit comments

Comments
 (0)