Skip to content

Commit

Permalink
feat: add groups, roles
Browse files Browse the repository at this point in the history
  • Loading branch information
Eddie023 committed Oct 21, 2024
1 parent 418db20 commit d3e85db
Show file tree
Hide file tree
Showing 15 changed files with 155 additions and 31 deletions.
20 changes: 0 additions & 20 deletions migrations/1729310485752-create_users_table.ts

This file was deleted.

55 changes: 55 additions & 0 deletions migrations/1729468099287-initial_tables.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

const rawSQL = `
CREATE TABLE IF NOT EXISTS users(
id VARCHAR (100) PRIMARY KEY,
email VARCHAR (100) NOT NULL,
first_name VARCHAR (50) NOT NULL,
last_name VARCHAR (50) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
is_verified BOOLEAN NOT NULL DEFAULT FALSE
);
CREATE TABLE IF NOT EXISTS groups(
id SERIAL PRIMARY KEY,
name VARCHAR(50),
description VARCHAR(100),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS roles(
id SERIAL PRIMARY KEY,
name VARCHAR(50),
description VARCHAR(100),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE TABLE IF NOT EXISTS user_group(
user_id VARCHAR(100) REFERENCES users(id),
group_id INT REFERENCES groups(id)
);
CREATE TABLE IF NOT EXISTS group_role(
group_id INT REFERENCES groups(id),
role_id INT REFERENCES roles(id)
);
`;

export class InitialTables1729468099287 implements MigrationInterface {
public async up(queryRunner: QueryRunner): Promise<void> {
return queryRunner.query(rawSQL);
}

public async down(queryRunner: QueryRunner): Promise<void> {
return queryRunner.query(`
DROP table group_role;
DROP table user_group;
DROP table users;
DROP table groups;
DROP table roles;
`);
}
}
13 changes: 13 additions & 0 deletions migrations/seeds/seed.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
INSERT INTO groups (name, description) VALUES
('Admin', 'Administrative group with full system access'),
('Supply Chain Manager', 'Manages the supply chain operations'),
('Warehouse Operator', 'Responsible for warehouse operations and stock control'),
('Procurement Officer', 'Handles purchasing and procurement of goods and services'),
('Logistics Coordinator', 'Coordinates transportation and logistics operations');

INSERT INTO users (id, email, first_name, last_name, created_at, updated_at, is_verified) VALUES
('user_001', '[email protected]','John', 'Doe', NOW(), NOW(), TRUE),
('user_002', '[email protected]','Jane', 'Smith', NOW(), NOW(), FALSE),
('user_003', '[email protected]','Alice', 'Johnson', NOW(), NOW(), TRUE),
('user_004', '[email protected]','Bob', 'Brown', NOW(), NOW(), FALSE),
('user_005', '[email protected]','Charlie', 'Davis', NOW(), NOW(), TRUE);
2 changes: 1 addition & 1 deletion src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { ConfigModule, ConfigService } from '@nestjs/config';
import { LoggerModule } from 'nestjs-pino';

import { AppController } from './app.controller';
import { DatabaseModule } from './database/module';
import { DatabaseModule } from './database/database.module';
import { UserModule } from './user/user.module';

@Module({
Expand Down
5 changes: 3 additions & 2 deletions src/database/database.service.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { User } from 'src/user/user.entity';
import { Group } from 'src/user/entities/group.entity';
import { User } from 'src/user/entities/user.entity';
import { DataSourceOptions } from 'typeorm';

@Injectable()
Expand All @@ -15,7 +16,7 @@ export class DBConfig {
username: this.configService.getOrThrow('DB_USER'),
password: this.configService.getOrThrow('DB_PASSWORD'),
database: this.configService.getOrThrow('DB_NAME'),
entities: [User]
entities: [User, Group]
};
}
}
3 changes: 1 addition & 2 deletions src/user/dto/create-user.dto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,4 @@ export class CreateUserDto {
email: string;
firstName: string;
lastName: string;
};

}
20 changes: 20 additions & 0 deletions src/user/entities/group.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Column, Entity, JoinColumn, JoinTable, ManyToMany, PrimaryColumn } from 'typeorm';
import { User } from './user.entity';

@Entity('groups')
export class Group {
@PrimaryColumn()
id: string;

@Column()
name: string;

@Column()
description: string;

@Column({ name: 'created_at' })
createdAt: Date;

@Column({ name: 'updated_at' })
updatedAt: Date;
}
19 changes: 19 additions & 0 deletions src/user/entities/role.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';

@Entity('roles')
export class User {
@PrimaryColumn()
id: string;

@Column()
name: string;

@Column()
description: string;

@Column({ name: 'created_at' })
createdAt: Date;

@Column({ name: 'updated_at' })
updatedAt: Date;
}
9 changes: 8 additions & 1 deletion src/user/user.entity.ts → src/user/entities/user.entity.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';
import { Column, Entity, JoinTable, ManyToMany, PrimaryColumn, JoinColumn } from 'typeorm';
import { Group } from './group.entity';

@Entity('users')
export class User {
Expand All @@ -22,4 +23,10 @@ export class User {

@Column({ default: false, name: 'is_verified' })
isVerified: boolean;

@ManyToMany(type => Group)
@JoinTable({name: "user_group"})
groups: Group[]
}


10 changes: 10 additions & 0 deletions src/user/entities/usergroup.entity.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Column, Entity, PrimaryColumn } from 'typeorm';

@Entity('user_group')
export class UserGroup {
@Column({name: "user_id"})
user_id: string;

@Column()
group_id: number;
}
5 changes: 5 additions & 0 deletions src/user/user.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,9 @@ export class UserController {
findOne(@Param('id') id: string) {
return this.userService.findOne(id);
}

@Get(':id/groups')
getAllUserGroups(@Param('id') id: string) {
return this.userService.getUserGroups(id)
}
}
2 changes: 1 addition & 1 deletion src/user/user.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { TypeOrmModule } from '@nestjs/typeorm';
import { LoggerModule } from 'nestjs-pino';

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

@Module({
Expand Down
3 changes: 2 additions & 1 deletion src/user/user.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getRepositoryToken } from '@nestjs/typeorm';
import { beforeEach, describe, expect, jest, mock, test } from 'bun:test';
import { Repository } from 'typeorm';

import { User } from './user.entity';
import { User } from './entities/user.entity';
import { UserService } from './user.service';

const mockUserRepository = {
Expand Down Expand Up @@ -52,3 +52,4 @@ describe('UserService', () => {
});
});
});

16 changes: 15 additions & 1 deletion src/user/user.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';

import { CreateUserDto } from './dto/create-user.dto';
import { User } from './user.entity';
import { User } from './entities/user.entity';

@Injectable()
export class UserService {
Expand Down Expand Up @@ -33,4 +33,18 @@ export class UserService {
this.logger.log('fetching user info', 'id', id);
return this.usersRepository.findOneBy({ id });
}

// TODO: use TyeORM functionalities for many to many relation.
async getUserGroups(userId: string) {
const userGroups = await this.usersRepository.query(
`
SELECT u.id, u.email, groups.id as group_id, groups.name, groups.description
FROM users u
INNER JOIN user_group ug ON ug.user_id = u.id
INNER JOIN groups ON ug.group_id = groups.id
WHERE u.id = '${userId}';
`
)
return userGroups;
}
}
4 changes: 2 additions & 2 deletions tsconfig.json
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
{
"compilerOptions": {
"module": "ESNext",
"module": "ESNext", // NOTE: need to change to CommonJS for typeorm cmds to work.
"target": "ESNext",
"moduleResolution": "Bundler",
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "ES2021",
"sourceMap": true,
"baseUrl": "./",
"outDir": "./dist",
Expand Down

0 comments on commit d3e85db

Please sign in to comment.