init
This commit is contained in:
@@ -0,0 +1,46 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
OneToMany,
|
||||
} from 'typeorm';
|
||||
import { UserRole } from '../../common/enums';
|
||||
import { Application } from '../../applications/entities/application.entity';
|
||||
|
||||
@Entity('users')
|
||||
export class User {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ unique: true })
|
||||
email: string;
|
||||
|
||||
@Column()
|
||||
password: string;
|
||||
|
||||
@Column()
|
||||
firstName: string;
|
||||
|
||||
@Column()
|
||||
lastName: string;
|
||||
|
||||
@Column({ type: 'enum', enum: UserRole, default: UserRole.USER })
|
||||
role: UserRole;
|
||||
|
||||
@Column({ default: true })
|
||||
isActive: boolean;
|
||||
|
||||
@Column({ nullable: true })
|
||||
namespace: string; // K8s namespace assigned to user
|
||||
|
||||
@OneToMany(() => Application, (app: Application) => app.user)
|
||||
applications: Application[];
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updatedAt: Date;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
import {
|
||||
Controller,
|
||||
Get,
|
||||
Patch,
|
||||
Param,
|
||||
Body,
|
||||
UseGuards,
|
||||
Request,
|
||||
} from '@nestjs/common';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { UsersService } from './users.service';
|
||||
import { RolesGuard } from '../common/guards/roles.guard';
|
||||
import { Roles } from '../common/decorators/roles.decorator';
|
||||
import { UserRole } from '../common/enums';
|
||||
|
||||
@ApiTags('Users')
|
||||
@ApiBearerAuth()
|
||||
@Controller('users')
|
||||
@UseGuards(AuthGuard('jwt'), RolesGuard)
|
||||
export class UsersController {
|
||||
constructor(private readonly usersService: UsersService) {}
|
||||
|
||||
@Get('me')
|
||||
@ApiOperation({ summary: 'Get current user profile' })
|
||||
async getProfile(@Request() req: any) {
|
||||
const user = await this.usersService.findById(req.user.id);
|
||||
if (user) {
|
||||
const { password, ...result } = user;
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Get()
|
||||
@Roles(UserRole.ADMIN)
|
||||
@ApiOperation({ summary: 'List all users (Admin only)' })
|
||||
async findAll() {
|
||||
return this.usersService.findAll();
|
||||
}
|
||||
|
||||
@Patch(':id/deactivate')
|
||||
@Roles(UserRole.ADMIN)
|
||||
@ApiOperation({ summary: 'Deactivate a user (Admin only)' })
|
||||
async deactivate(@Param('id') id: string) {
|
||||
await this.usersService.deactivate(id);
|
||||
return { message: 'User deactivated' };
|
||||
}
|
||||
|
||||
@Patch(':id/activate')
|
||||
@Roles(UserRole.ADMIN)
|
||||
@ApiOperation({ summary: 'Activate a user (Admin only)' })
|
||||
async activate(@Param('id') id: string) {
|
||||
await this.usersService.activate(id);
|
||||
return { message: 'User activated' };
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { UsersService } from './users.service';
|
||||
import { UsersController } from './users.controller';
|
||||
import { User } from './entities/user.entity';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([User])],
|
||||
controllers: [UsersController],
|
||||
providers: [UsersService],
|
||||
exports: [UsersService],
|
||||
})
|
||||
export class UsersModule {}
|
||||
@@ -0,0 +1,52 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Repository } from 'typeorm';
|
||||
import { User } from './entities/user.entity';
|
||||
import { UserRole } from '../common/enums';
|
||||
|
||||
@Injectable()
|
||||
export class UsersService {
|
||||
constructor(
|
||||
@InjectRepository(User)
|
||||
private usersRepository: Repository<User>,
|
||||
) {}
|
||||
|
||||
async create(data: Partial<User>): Promise<User> {
|
||||
const user = this.usersRepository.create(data);
|
||||
// Assign a unique namespace based on user ID
|
||||
const saved = await this.usersRepository.save(user);
|
||||
saved.namespace = `user-${saved.id.split('-')[0]}`;
|
||||
return this.usersRepository.save(saved);
|
||||
}
|
||||
|
||||
async findByEmail(email: string): Promise<User | null> {
|
||||
return this.usersRepository.findOne({ where: { email } });
|
||||
}
|
||||
|
||||
async findById(id: string): Promise<User | null> {
|
||||
return this.usersRepository.findOne({ where: { id } });
|
||||
}
|
||||
|
||||
async findAll(): Promise<User[]> {
|
||||
return this.usersRepository.find({
|
||||
select: ['id', 'email', 'firstName', 'lastName', 'role', 'isActive', 'namespace', 'createdAt'],
|
||||
});
|
||||
}
|
||||
|
||||
async update(id: string, data: Partial<User>): Promise<User> {
|
||||
const user = await this.findById(id);
|
||||
if (!user) {
|
||||
throw new NotFoundException('User not found');
|
||||
}
|
||||
Object.assign(user, data);
|
||||
return this.usersRepository.save(user);
|
||||
}
|
||||
|
||||
async deactivate(id: string): Promise<void> {
|
||||
await this.usersRepository.update(id, { isActive: false });
|
||||
}
|
||||
|
||||
async activate(id: string): Promise<void> {
|
||||
await this.usersRepository.update(id, { isActive: true });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user