workspace - wip

This commit is contained in:
Philipinho
2023-08-07 18:16:51 +01:00
parent 021a99e716
commit fe7c3ede01
25 changed files with 370 additions and 9464 deletions
@@ -0,0 +1,20 @@
import { Test, TestingModule } from '@nestjs/testing';
import { WorkspaceController } from './workspace.controller';
import { WorkspaceService } from '../services/workspace.service';
describe('WorkspaceController', () => {
let controller: WorkspaceController;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
controllers: [WorkspaceController],
providers: [WorkspaceService],
}).compile();
controller = module.get<WorkspaceController>(WorkspaceController);
});
it('should be defined', () => {
expect(controller).toBeDefined();
});
});
@@ -0,0 +1,7 @@
import { Controller } from '@nestjs/common';
import { WorkspaceService } from '../services/workspace.service';
@Controller('workspace')
export class WorkspaceController {
constructor(private readonly workspaceService: WorkspaceService) {}
}
@@ -0,0 +1,18 @@
import { IsOptional, IsString, MaxLength, MinLength } from 'class-validator';
export class CreateWorkspaceDto {
@MinLength(4)
@MaxLength(64)
@IsString()
name: string;
@IsOptional()
@MinLength(4)
@MaxLength(30)
@IsString()
hostname?: string;
@IsOptional()
@IsString()
description?: string;
}
@@ -0,0 +1,4 @@
import { PartialType } from '@nestjs/mapped-types';
import { CreateWorkspaceDto } from './create-workspace.dto';
export class UpdateWorkspaceDto extends PartialType(CreateWorkspaceDto) {}
@@ -0,0 +1,46 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
ManyToOne,
JoinColumn,
} from 'typeorm';
import { Workspace } from './workspace.entity';
import { User } from '../../user/entities/user.entity';
@Entity('workspace_invitations')
export class WorkspaceInvitation {
@PrimaryGeneratedColumn('uuid')
id: string;
@ManyToOne(() => Workspace, {
onDelete: 'CASCADE',
createForeignKeyConstraints: false,
})
@JoinColumn({ name: 'workspaceId' })
workspace: Workspace;
@ManyToOne(() => User, {
onDelete: 'SET NULL',
createForeignKeyConstraints: false,
})
@JoinColumn({ name: 'invitedById' })
invitedBy: User;
@Column({ type: 'varchar', length: 255 })
email: string;
@Column({ type: 'varchar', length: 100, nullable: true })
role?: string;
@Column({ type: 'varchar', length: 100, nullable: true })
status?: string;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}
@@ -0,0 +1,48 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
ManyToOne,
JoinColumn,
Unique,
} from 'typeorm';
import { Workspace } from './workspace.entity';
import { User } from '../../user/entities/user.entity';
@Entity('workspace_users')
@Unique(['workspaceId', 'userId'])
export class WorkspaceUser {
@PrimaryGeneratedColumn('uuid')
id: string;
@ManyToOne(() => User, (user) => user.workspaceUser, {
onDelete: 'CASCADE',
createForeignKeyConstraints: false,
})
@JoinColumn({ name: 'userId' })
user: User;
@Column()
userId: string;
@ManyToOne(() => Workspace, (workspace) => workspace.workspaceUser, {
onDelete: 'CASCADE',
createForeignKeyConstraints: false,
})
@JoinColumn({ name: 'workspaceId' })
workspace: Workspace;
@Column()
workspaceId: string;
@Column({ type: 'varchar', length: 100, nullable: true })
role?: string;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}
@@ -0,0 +1,62 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
ManyToOne,
OneToMany,
JoinColumn,
} from 'typeorm';
import { User } from '../../user/entities/user.entity';
import { WorkspaceUser } from './workspace-user.entity';
@Entity('workspaces')
export class Workspace {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
@Column({ type: 'text', nullable: true })
description?: string;
@Column({ nullable: true })
logo?: string;
@Column({ unique: true })
hostname: string;
@Column({ nullable: true })
customDomain?: string;
@Column({ type: 'boolean', default: true })
enableInvite: boolean;
@Column({ type: 'text', unique: true, nullable: true })
inviteCode?: string;
@Column({ type: 'jsonb', nullable: true })
settings?: any;
@ManyToOne(() => User, (user) => user.workspaces, {
createForeignKeyConstraints: false,
})
@JoinColumn({ name: 'creatorId' })
creator: User;
@Column()
creatorId: string;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
@OneToMany(() => WorkspaceUser, (workspaceUser) => workspaceUser.workspace, {
createForeignKeyConstraints: false,
})
workspaceUser: WorkspaceUser[];
}
@@ -0,0 +1,10 @@
import { Injectable } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { WorkspaceUser } from '../entities/workspace-user.entity';
@Injectable()
export class WorkspaceUserRepository extends Repository<WorkspaceUser> {
constructor(private dataSource: DataSource) {
super(WorkspaceUser, dataSource.createEntityManager());
}
}
@@ -0,0 +1,10 @@
import { Injectable } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { Workspace } from '../entities/workspace.entity';
@Injectable()
export class WorkspaceRepository extends Repository<Workspace> {
constructor(private dataSource: DataSource) {
super(Workspace, dataSource.createEntityManager());
}
}
@@ -0,0 +1,18 @@
import { Test, TestingModule } from '@nestjs/testing';
import { WorkspaceService } from './workspace.service';
describe('WorkspaceService', () => {
let service: WorkspaceService;
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [WorkspaceService],
}).compile();
service = module.get<WorkspaceService>(WorkspaceService);
});
it('should be defined', () => {
expect(service).toBeDefined();
});
});
@@ -0,0 +1,49 @@
import { Injectable } from '@nestjs/common';
import { CreateWorkspaceDto } from '../dto/create-workspace.dto';
import { WorkspaceRepository } from '../repositories/workspace.repository';
import { WorkspaceUserRepository } from '../repositories/workspace-user.repository';
import { WorkspaceUser } from '../entities/workspace-user.entity';
import { Workspace } from '../entities/workspace.entity';
import { plainToClass } from 'class-transformer';
import { v4 as uuid } from 'uuid';
import { generateHostname } from '../workspace.util';
@Injectable()
export class WorkspaceService {
constructor(
private workspaceRepository: WorkspaceRepository,
private workspaceUserRepository: WorkspaceUserRepository,
) {}
async create(
createWorkspaceDto: CreateWorkspaceDto,
userId: string,
): Promise<Workspace> {
let workspace: Workspace = plainToClass(Workspace, createWorkspaceDto);
workspace.inviteCode = uuid();
workspace.creatorId = userId;
if (!workspace.hostname?.trim()) {
workspace.hostname = generateHostname(createWorkspaceDto.name);
}
workspace = await this.workspaceRepository.save(workspace);
await this.addUserToWorkspace(userId, workspace.id, 'owner');
return workspace;
}
async addUserToWorkspace(
userId: string,
workspaceId: string,
role: string,
): Promise<WorkspaceUser> {
const workspaceUser = new WorkspaceUser();
workspaceUser.userId = userId;
workspaceUser.workspaceId = workspaceId;
workspaceUser.role = role;
return this.workspaceUserRepository.save(workspaceUser);
}
}
@@ -0,0 +1,19 @@
import { Module } from '@nestjs/common';
import { WorkspaceService } from './services/workspace.service';
import { WorkspaceController } from './controllers/workspace.controller';
import { WorkspaceRepository } from './repositories/workspace.repository';
import { TypeOrmModule } from '@nestjs/typeorm';
import { Workspace } from './entities/workspace.entity';
import { WorkspaceUser } from './entities/workspace-user.entity';
import { WorkspaceInvitation } from './entities/workspace-invitation.entity';
import { WorkspaceUserRepository } from './repositories/workspace-user.repository';
@Module({
imports: [
TypeOrmModule.forFeature([Workspace, WorkspaceUser, WorkspaceInvitation]),
],
controllers: [WorkspaceController],
providers: [WorkspaceService, WorkspaceRepository, WorkspaceUserRepository],
exports: [WorkspaceService, WorkspaceRepository, WorkspaceUserRepository],
})
export class WorkspaceModule {}
@@ -0,0 +1,5 @@
export function generateHostname(name: string): string {
let hostname = name.replace(/[^a-z0-9]/gi, '').toLowerCase();
hostname = hostname.substring(0, 30);
return hostname;
}