Implement Space membership by group

* Add all users to default group
* Fixes and updates
This commit is contained in:
Philipinho
2024-03-20 01:26:03 +00:00
parent a821e37028
commit 51b9808382
22 changed files with 425 additions and 82 deletions

View File

@ -9,6 +9,7 @@ import { WorkspaceModule } from '../workspace/workspace.module';
import { SignupService } from './services/signup.service';
import { UserModule } from '../user/user.module';
import { SpaceModule } from '../space/space.module';
import { GroupModule } from '../group/group.module';
@Module({
imports: [
@ -26,6 +27,7 @@ import { SpaceModule } from '../space/space.module';
UserModule,
WorkspaceModule,
SpaceModule,
GroupModule,
],
controllers: [AuthController],
providers: [AuthService, SignupService, TokenService, JwtStrategy],

View File

@ -51,7 +51,7 @@ export class AuthService {
}
async setup(createAdminUserDto: CreateAdminUserDto) {
const user: User = await this.signupService.firstSetup(createAdminUserDto);
const user: User = await this.signupService.initialSetup(createAdminUserDto);
const tokens: TokensDto = await this.tokenService.generateTokens(user);

View File

@ -10,6 +10,7 @@ import { CreateWorkspaceDto } from '../../workspace/dto/create-workspace.dto';
import { Workspace } from '../../workspace/entities/workspace.entity';
import { SpaceService } from '../../space/space.service';
import { CreateAdminUserDto } from '../dto/create-admin-user.dto';
import { GroupUserService } from '../../group/services/group-user.service';
@Injectable()
export class SignupService {
@ -18,6 +19,7 @@ export class SignupService {
private workspaceRepository: WorkspaceRepository,
private workspaceService: WorkspaceService,
private spaceService: SpaceService,
private groupUserService: GroupUserService,
private dataSource: DataSource,
) {}
@ -39,7 +41,6 @@ export class SignupService {
async (transactionManager: EntityManager) => {
let user = this.prepareUser(createUserDto);
user = await transactionManager.save(user);
return user;
},
this.dataSource,
@ -57,7 +58,9 @@ export class SignupService {
workspaceId,
);
if (userCheck) {
throw new BadRequestException('You have an account on this workspace');
throw new BadRequestException(
'You already have an account on this workspace',
);
}
return await transactionWrapper(
@ -72,6 +75,14 @@ export class SignupService {
undefined,
manager,
);
// add user to default group
await this.groupUserService.addUserToDefaultGroup(
user.id,
workspaceId,
manager,
);
return user;
},
this.dataSource,
@ -99,7 +110,7 @@ export class SignupService {
);
}
async firstSetup(
async initialSetup(
createAdminUserDto: CreateAdminUserDto,
manager?: EntityManager,
): Promise<User> {
@ -119,3 +130,11 @@ export class SignupService {
);
}
}
// create user -
// create workspace -
// create default group
// create space
// add group to space instead of user
// add new users to default group

View File

@ -10,3 +10,7 @@ export class CreateGroupDto {
@IsString()
description?: string;
}
export enum DefaultGroup {
EVERYONE = 'users',
}

View File

@ -20,7 +20,7 @@ export class GroupUser {
@Column()
userId: string;
@ManyToOne(() => User, (user) => user.groups, {
@ManyToOne(() => User, {
onDelete: 'CASCADE',
})
@JoinColumn({ name: 'userId' })

View File

@ -11,8 +11,11 @@ import {
import { GroupUser } from './group-user.entity';
import { Workspace } from '../../workspace/entities/workspace.entity';
import { User } from '../../user/entities/user.entity';
import { Unique } from 'typeorm';
import { SpaceGroup } from '../../space/entities/space-group.entity';
@Entity('groups')
@Unique(['name', 'workspaceId'])
export class Group {
@PrimaryGeneratedColumn('uuid')
id: string;
@ -23,6 +26,9 @@ export class Group {
@Column({ type: 'text', nullable: true })
description: string;
@Column({ type: 'boolean', default: false })
isDefault: boolean;
@Column()
workspaceId: string;
@ -32,7 +38,7 @@ export class Group {
@JoinColumn({ name: 'workspaceId' })
workspace: Workspace;
@Column()
@Column({ nullable: true })
creatorId: string;
@ManyToOne(() => User)
@ -48,5 +54,8 @@ export class Group {
@OneToMany(() => GroupUser, (groupUser) => groupUser.group)
groupUsers: GroupUser[];
@OneToMany(() => SpaceGroup, (spaceGroup) => spaceGroup.group)
spaces: SpaceGroup[];
userCount?: number;
}

View File

@ -119,11 +119,12 @@ export class GroupController {
removeGroupMember(
@Body() removeGroupUserDto: RemoveGroupUserDto,
//@AuthUser() user: User,
//@CurrentWorkspace() workspace: Workspace,
@AuthWorkspace() workspace: Workspace,
) {
return this.groupUserService.removeUserFromGroup(
removeGroupUserDto.userId,
removeGroupUserDto.groupId,
workspace.id,
);
}

View File

@ -17,5 +17,6 @@ import { GroupUserService } from './services/group-user.service';
GroupRepository,
GroupUserRepository,
],
exports: [GroupService, GroupUserService],
})
export class GroupModule {}

View File

@ -27,7 +27,7 @@ export class GroupUserService {
workspaceId: string,
paginationOptions: PaginationOptions,
): Promise<PaginatedResult<User>> {
await this.groupService.validateGroup(groupId, workspaceId);
await this.groupService.findAndValidateGroup(groupId, workspaceId);
const [groupUsers, count] = await this.groupUserRepository.findAndCount({
relations: ['user'],
@ -49,16 +49,36 @@ export class GroupUserService {
return new PaginatedResult(users, paginationMeta);
}
async addUserToDefaultGroup(
userId: string,
workspaceId: string,
manager?: EntityManager,
): Promise<void> {
return await transactionWrapper(
async (manager) => {
const defaultGroup = await this.groupService.getDefaultGroup(
workspaceId,
manager,
);
await this.addUserToGroup(
userId,
defaultGroup.id,
workspaceId,
manager,
);
},
this.dataSource,
manager,
);
}
async addUserToGroup(
userId: string,
groupId: string,
workspaceId: string,
manager?: EntityManager,
): Promise<any> {
let addedUser;
/*
await transactionWrapper(
): Promise<GroupUser> {
return await transactionWrapper(
async (manager) => {
const group = await manager.findOneBy(Group, {
id: groupId,
@ -69,21 +89,18 @@ export class GroupUserService {
throw new NotFoundException('Group not found');
}
const userExists = await manager.exists(User, {
const find = await manager.findOne(User, {
where: { id: userId },
});
if (!userExists) {
throw new NotFoundException('User not found');
}
// only workspace users can be added to workspace groups
const workspaceUser = await manager.findOneBy(WorkspaceUser, {
userId: userId,
workspaceId: workspaceId,
console.log(find);
const userExists = await manager.exists(User, {
where: { id: userId, workspaceId },
});
if (!workspaceUser) {
throw new NotFoundException('User is not a member of this workspace');
if (!userExists) {
throw new NotFoundException('User not found');
}
const existingGroupUser = await manager.findOneBy(GroupUser, {
@ -101,16 +118,29 @@ export class GroupUserService {
groupUser.userId = userId;
groupUser.groupId = groupId;
addedUser = await manager.save(groupUser);
return manager.save(groupUser);
},
this.dataSource,
manager,
);
*/
return addedUser;
}
async removeUserFromGroup(userId: string, groupId: string): Promise<void> {
async removeUserFromGroup(
userId: string,
groupId: string,
workspaceId: string,
): Promise<void> {
const group = await this.groupService.findAndValidateGroup(
groupId,
workspaceId,
);
if (group.isDefault) {
throw new BadRequestException(
'You cannot remove users from a default group',
);
}
const groupUser = await this.getGroupUser(userId, groupId);
if (!groupUser) {
@ -129,12 +159,4 @@ export class GroupUserService {
groupId,
});
}
async getGroupUserCount(groupId: string): Promise<number> {
return await this.groupUserRepository.count({
where: {
groupId: groupId,
},
});
}
}

View File

@ -1,5 +1,9 @@
import { Injectable, NotFoundException } from '@nestjs/common';
import { CreateGroupDto } from '../dto/create-group.dto';
import {
BadRequestException,
Injectable,
NotFoundException,
} from '@nestjs/common';
import { CreateGroupDto, DefaultGroup } from '../dto/create-group.dto';
import { GroupRepository } from '../respositories/group.repository';
import { Group } from '../entities/group.entity';
import { plainToInstance } from 'class-transformer';
@ -8,10 +12,15 @@ import { PaginationMetaDto } from '../../../helpers/pagination/pagination-meta-d
import { PaginatedResult } from '../../../helpers/pagination/paginated-result';
import { PaginationOptions } from '../../../helpers/pagination/pagination-options';
import { UpdateGroupDto } from '../dto/update-group.dto';
import { DataSource, EntityManager } from 'typeorm';
import { transactionWrapper } from '../../../helpers/db.helper';
@Injectable()
export class GroupService {
constructor(private groupRepository: GroupRepository) {}
constructor(
private groupRepository: GroupRepository,
private dataSource: DataSource,
) {}
async createGroup(
authUser: User,
@ -22,9 +31,52 @@ export class GroupService {
group.creatorId = authUser.id;
group.workspaceId = workspaceId;
const groupExists = await this.findGroupByName(
createGroupDto.name,
workspaceId,
);
if (groupExists) {
throw new BadRequestException('Group name already exists');
}
return await this.groupRepository.save(group);
}
async createDefaultGroup(
workspaceId: string,
userId?: string,
manager?: EntityManager,
): Promise<Group> {
return await transactionWrapper(
async (manager: EntityManager) => {
const group = new Group();
group.name = DefaultGroup.EVERYONE;
group.isDefault = true;
group.creatorId = userId ?? null;
group.workspaceId = workspaceId;
return await manager.save(group);
},
this.dataSource,
manager,
);
}
async getDefaultGroup(
workspaceId: string,
manager: EntityManager,
): Promise<Group> {
return await transactionWrapper(
async (manager: EntityManager) => {
return await manager.findOneBy(Group, {
isDefault: true,
workspaceId,
});
},
this.dataSource,
manager,
);
}
async updateGroup(
workspaceId: string,
updateGroupDto: UpdateGroupDto,
@ -38,6 +90,18 @@ export class GroupService {
throw new NotFoundException('Group not found');
}
if (group.isDefault) {
throw new BadRequestException('You cannot update a default group');
}
const groupExists = await this.findGroupByName(
updateGroupDto.name,
workspaceId,
);
if (groupExists) {
throw new BadRequestException('Group name already exists');
}
if (updateGroupDto.name) {
group.name = updateGroupDto.name;
}
@ -90,19 +154,38 @@ export class GroupService {
}
async deleteGroup(groupId: string, workspaceId: string): Promise<void> {
await this.validateGroup(groupId, workspaceId);
const group = await this.findAndValidateGroup(groupId, workspaceId);
if (group.isDefault) {
throw new BadRequestException('You cannot delete a default group');
}
await this.groupRepository.delete(groupId);
}
async validateGroup(groupId: string, workspaceId: string): Promise<void> {
const groupExists = await this.groupRepository.exists({
async findAndValidateGroup(
groupId: string,
workspaceId: string,
): Promise<Group> {
const group = await this.groupRepository.findOne({
where: {
id: groupId,
workspaceId: workspaceId,
},
});
if (!groupExists) {
if (!group) {
throw new NotFoundException('Group not found');
}
return group;
}
async findGroupByName(
groupName: string,
workspaceId: string,
): Promise<Group> {
return this.groupRepository
.createQueryBuilder('group')
.where('LOWER(group.name) = LOWER(:groupName)', { groupName })
.andWhere('group.workspaceId = :workspaceId', { workspaceId })
.getOne();
}
}

View File

@ -0,0 +1,45 @@
import {
Entity,
PrimaryGeneratedColumn,
Column,
CreateDateColumn,
UpdateDateColumn,
ManyToOne,
JoinColumn,
Unique,
} from 'typeorm';
import { Space } from './space.entity';
import { Group } from '../../group/entities/group.entity';
@Entity('space_groups')
@Unique(['spaceId', 'groupId'])
export class SpaceGroup {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
groupId: string;
@ManyToOne(() => Group, (group) => group.spaces, {
onDelete: 'CASCADE',
})
@JoinColumn({ name: 'groupId' })
group: Group;
@Column()
spaceId: string;
@ManyToOne(() => Space, (space) => space.spaceGroups, {
onDelete: 'CASCADE',
})
space: Space;
@Column({ length: 100, nullable: true })
role: string;
@CreateDateColumn()
createdAt: Date;
@UpdateDateColumn()
updatedAt: Date;
}

View File

@ -14,6 +14,7 @@ import { Workspace } from '../../workspace/entities/workspace.entity';
import { SpaceUser } from './space-user.entity';
import { Page } from '../../page/entities/page.entity';
import { SpacePrivacy, SpaceRole } from '../../../helpers/types/permission';
import { SpaceGroup } from './space-group.entity';
@Entity('spaces')
@Unique(['slug', 'workspaceId'])
@ -42,7 +43,7 @@ export class Space {
@Column()
creatorId: string;
@ManyToOne(() => User, (user) => user.spaces)
@ManyToOne(() => User)
@JoinColumn({ name: 'creatorId' })
creator: User;
@ -58,6 +59,9 @@ export class Space {
@OneToMany(() => SpaceUser, (spaceUser) => spaceUser.space)
spaceUsers: SpaceUser[];
@OneToMany(() => SpaceGroup, (spaceGroup) => spaceGroup.space)
spaceGroups: SpaceGroup[];
@OneToMany(() => Page, (page) => page.space)
pages: Page[];

View File

@ -0,0 +1,10 @@
import { Injectable } from '@nestjs/common';
import { DataSource, Repository } from 'typeorm';
import { SpaceGroup } from '../entities/space-group.entity';
@Injectable()
export class SpaceGroupRepository extends Repository<SpaceGroup> {
constructor(private dataSource: DataSource) {
super(SpaceGroup, dataSource.createEntityManager());
}
}

View File

@ -57,6 +57,7 @@ export class SpaceController {
@HttpCode(HttpStatus.OK)
@Post('members')
async getSpaceMembers(
// todo: accept type? users | groups
@Body() spaceIdDto: SpaceIdDto,
@Body()
pagination: PaginationOptions,

View File

@ -6,11 +6,18 @@ import { Space } from './entities/space.entity';
import { SpaceUser } from './entities/space-user.entity';
import { SpaceRepository } from './repositories/space.repository';
import { SpaceUserRepository } from './repositories/space-user.repository';
import { SpaceGroup } from './entities/space-group.entity';
import { SpaceGroupRepository } from './repositories/space-group.repository';
@Module({
imports: [TypeOrmModule.forFeature([Space, SpaceUser])],
imports: [TypeOrmModule.forFeature([Space, SpaceUser, SpaceGroup])],
controllers: [SpaceController],
providers: [SpaceService, SpaceRepository, SpaceUserRepository],
exports: [SpaceService, SpaceRepository, SpaceUserRepository],
providers: [
SpaceService,
SpaceRepository,
SpaceUserRepository,
SpaceGroupRepository,
],
exports: [SpaceService],
})
export class SpaceModule {}

View File

@ -14,12 +14,16 @@ import { User } from '../user/entities/user.entity';
import { PaginationOptions } from '../../helpers/pagination/pagination-options';
import { PaginationMetaDto } from '../../helpers/pagination/pagination-meta-dto';
import { PaginatedResult } from '../../helpers/pagination/paginated-result';
import { SpaceGroupRepository } from './repositories/space-group.repository';
import { Group } from '../group/entities/group.entity';
import { SpaceGroup } from './entities/space-group.entity';
@Injectable()
export class SpaceService {
constructor(
private spaceRepository: SpaceRepository,
private spaceUserRepository: SpaceUserRepository,
private spaceGroupRepository: SpaceGroupRepository,
private dataSource: DataSource,
) {}
@ -94,7 +98,7 @@ export class SpaceService {
'space.userCount',
'space.spaceUsers',
'spaceUsers',
)
) // TODO: add groups to userCount
.getOne();
if (!space) {
@ -115,7 +119,7 @@ export class SpaceService {
'space.userCount',
'space.spaceUsers',
'spaceUsers',
)
) // TODO: add groups to userCount
.take(paginationOptions.limit)
.skip(paginationOptions.skip)
.getManyAndCount();
@ -178,4 +182,71 @@ export class SpaceService {
const paginationMeta = new PaginationMetaDto({ count, paginationOptions });
return new PaginatedResult(users, paginationMeta);
}
async addGroupToSpace(
groupId: string,
spaceId: string,
role: string,
workspaceId,
manager?: EntityManager,
): Promise<SpaceGroup> {
return await transactionWrapper(
async (manager: EntityManager) => {
const groupExists = await manager.exists(Group, {
where: { id: groupId, workspaceId },
});
if (!groupExists) {
throw new NotFoundException('Group not found');
}
const existingSpaceGroup = await manager.findOneBy(SpaceGroup, {
groupId: groupId,
spaceId: spaceId,
});
if (existingSpaceGroup) {
throw new BadRequestException('Group already added to this space');
}
const spaceGroup = new SpaceGroup();
spaceGroup.groupId = groupId;
spaceGroup.spaceId = spaceId;
spaceGroup.role = role;
await manager.save(spaceGroup);
return spaceGroup;
},
this.dataSource,
manager,
);
}
async getSpaceGroups(
spaceId: string,
workspaceId: string,
paginationOptions: PaginationOptions,
) {
const [spaceGroups, count] = await this.spaceGroupRepository.findAndCount({
relations: ['group'],
where: {
space: {
id: spaceId,
workspaceId,
},
},
take: paginationOptions.limit,
skip: paginationOptions.skip,
});
// TODO: add group userCount
const groups = spaceGroups.map((spaceGroup) => {
return {
...spaceGroup.group,
spaceRole: spaceGroup.role,
};
});
const paginationMeta = new PaginationMetaDto({ count, paginationOptions });
return new PaginatedResult(groups, paginationMeta);
}
}

View File

@ -15,7 +15,6 @@ import { Page } from '../../page/entities/page.entity';
import { Comment } from '../../comment/entities/comment.entity';
import { Space } from '../../space/entities/space.entity';
import { SpaceUser } from '../../space/entities/space-user.entity';
import { Group } from '../../group/entities/group.entity';
@Entity('users')
@Unique(['email', 'workspaceId'])
@ -44,7 +43,9 @@ export class User {
@Column({ nullable: true })
workspaceId: string;
@ManyToOne(() => Workspace, (workspace) => workspace.users)
@ManyToOne(() => Workspace, (workspace) => workspace.users, {
onDelete: 'CASCADE',
})
workspace: Workspace;
@Column({ length: 100, nullable: true })
@ -68,9 +69,6 @@ export class User {
@UpdateDateColumn()
updatedAt: Date;
@OneToMany(() => Group, (group) => group.creator)
groups: Group[];
@OneToMany(() => Page, (page) => page.creator)
createdPages: Page[];

View File

@ -17,7 +17,8 @@ import { UserRepository } from '../../user/repositories/user.repository';
import { SpaceRole, UserRole } from '../../../helpers/types/permission';
import { User } from '../../user/entities/user.entity';
import { EnvironmentService } from '../../../environment/environment.service';
import { Space } from '../../space/entities/space.entity';
import { GroupService } from '../../group/services/group.service';
import { GroupUserService } from '../../group/services/group-user.service';
@Injectable()
export class WorkspaceService {
@ -25,6 +26,8 @@ export class WorkspaceService {
private workspaceRepository: WorkspaceRepository,
private userRepository: UserRepository,
private spaceService: SpaceService,
private groupService: GroupService,
private groupUserService: GroupUserService,
private environmentService: EnvironmentService,
private dataSource: DataSource,
@ -68,12 +71,28 @@ export class WorkspaceService {
workspace.creatorId = user.id;
workspace = await manager.save(workspace);
// create default group
const group = await this.groupService.createDefaultGroup(
workspace.id,
user.id,
manager,
);
// attach user to workspace
user.workspaceId = workspace.id;
user.role = UserRole.OWNER;
await manager.save(user);
// add user to default group
await this.groupUserService.addUserToGroup(
user.id,
group.id,
workspace.id,
manager,
);
// create default space
const spaceData: CreateSpaceDto = {
const spaceInfo: CreateSpaceDto = {
name: 'General',
};
@ -81,11 +100,11 @@ export class WorkspaceService {
const createdSpace = await this.spaceService.create(
user.id,
workspace.id,
spaceData,
spaceInfo,
manager,
);
// and add user to it too.
// and add user to space as owner
await this.spaceService.addUserToSpace(
user.id,
createdSpace.id,
@ -94,6 +113,15 @@ export class WorkspaceService {
manager,
);
// add default group to space as writer
await this.spaceService.addGroupToSpace(
group.id,
createdSpace.id,
SpaceRole.WRITER,
workspace.id,
manager,
);
workspace.defaultSpaceId = createdSpace.id;
await manager.save(workspace);
return workspace;
@ -108,7 +136,7 @@ export class WorkspaceService {
workspaceId,
assignedRole?: UserRole,
manager?: EntityManager,
): Promise<Workspace> {
): Promise<void> {
return await transactionWrapper(
async (manager: EntityManager) => {
const workspace = await manager.findOneBy(Workspace, {
@ -123,25 +151,7 @@ export class WorkspaceService {
user.workspaceId = workspace.id;
await manager.save(user);
const space = await manager.findOneBy(Space, {
id: workspace.defaultSpaceId,
workspaceId,
});
if (!space) {
throw new NotFoundException('Space not found');
}
// add user to default space
await this.spaceService.addUserToSpace(
user.id,
space.id,
space.defaultRole,
workspace.id,
manager,
);
return workspace;
// User is now added to the default space via the default group
},
this.dataSource,
manager,
@ -175,9 +185,6 @@ export class WorkspaceService {
if (!workspace) {
throw new NotFoundException('Workspace not found');
}
//TODO
// remove all existing users from workspace
// delete workspace
// delete
}
}

View File

@ -10,11 +10,14 @@ import { WorkspaceInvitationService } from './services/workspace-invitation.serv
import { WorkspaceInvitationRepository } from './repositories/workspace-invitation.repository';
import { WorkspaceUserService } from './services/workspace-user.service';
import { UserModule } from '../user/user.module';
import { GroupModule } from '../group/group.module';
@Module({
imports: [
TypeOrmModule.forFeature([Workspace, WorkspaceInvitation]),
SpaceModule, UserModule
SpaceModule,
UserModule,
GroupModule,
],
controllers: [WorkspaceController],
providers: [

View File

@ -0,0 +1,22 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class AddDefaultGroup1710886360227 implements MigrationInterface {
name = 'AddDefaultGroup1710886360227'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "groups" ADD "isDefault" boolean NOT NULL DEFAULT false`);
await queryRunner.query(`ALTER TABLE "groups" DROP CONSTRAINT "FK_accb24ba8f4f213f33d08e2a20f"`);
await queryRunner.query(`ALTER TABLE "groups" ALTER COLUMN "creatorId" DROP NOT NULL`);
await queryRunner.query(`ALTER TABLE "groups" ADD CONSTRAINT "UQ_c092c7c01795e6ad7af46bf2d24" UNIQUE ("name", "workspaceId")`);
await queryRunner.query(`ALTER TABLE "groups" ADD CONSTRAINT "FK_accb24ba8f4f213f33d08e2a20f" FOREIGN KEY ("creatorId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "groups" DROP CONSTRAINT "FK_accb24ba8f4f213f33d08e2a20f"`);
await queryRunner.query(`ALTER TABLE "groups" DROP CONSTRAINT "UQ_c092c7c01795e6ad7af46bf2d24"`);
await queryRunner.query(`ALTER TABLE "groups" ALTER COLUMN "creatorId" SET NOT NULL`);
await queryRunner.query(`ALTER TABLE "groups" ADD CONSTRAINT "FK_accb24ba8f4f213f33d08e2a20f" FOREIGN KEY ("creatorId") REFERENCES "users"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "groups" DROP COLUMN "isDefault"`);
}
}

View File

@ -0,0 +1,18 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class SpaceGroupsMembership1710892343941 implements MigrationInterface {
name = 'SpaceGroupsMembership1710892343941'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`CREATE TABLE "space_groups" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "groupId" uuid NOT NULL, "spaceId" uuid NOT NULL, "role" character varying(100), "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_68e59d7b983dfefc7d33febe4c3" UNIQUE ("spaceId", "groupId"), CONSTRAINT "PK_31f9b87a8dced378cb68f04836b" PRIMARY KEY ("id"))`);
await queryRunner.query(`ALTER TABLE "space_groups" ADD CONSTRAINT "FK_b3950d22b51148de9e14a1e5020" FOREIGN KEY ("groupId") REFERENCES "groups"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
await queryRunner.query(`ALTER TABLE "space_groups" ADD CONSTRAINT "FK_80567cbf54af9e8e8ec469d247d" FOREIGN KEY ("spaceId") REFERENCES "spaces"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "space_groups" DROP CONSTRAINT "FK_80567cbf54af9e8e8ec469d247d"`);
await queryRunner.query(`ALTER TABLE "space_groups" DROP CONSTRAINT "FK_b3950d22b51148de9e14a1e5020"`);
await queryRunner.query(`DROP TABLE "space_groups"`);
}
}

View File

@ -0,0 +1,16 @@
import { MigrationInterface, QueryRunner } from "typeorm";
export class AddWorkspaceCascadeToUser1710894465616 implements MigrationInterface {
name = 'AddWorkspaceCascadeToUser1710894465616'
public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "users" DROP CONSTRAINT "FK_949fea12b7977a8b2f483bf802a"`);
await queryRunner.query(`ALTER TABLE "users" ADD CONSTRAINT "FK_949fea12b7977a8b2f483bf802a" FOREIGN KEY ("workspaceId") REFERENCES "workspaces"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
}
public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`ALTER TABLE "users" DROP CONSTRAINT "FK_949fea12b7977a8b2f483bf802a"`);
await queryRunner.query(`ALTER TABLE "users" ADD CONSTRAINT "FK_949fea12b7977a8b2f483bf802a" FOREIGN KEY ("workspaceId") REFERENCES "workspaces"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
}
}