mirror of
https://github.com/Shadowfita/docmost.git
synced 2025-11-12 15:52:32 +10:00
Use polymorphic table for space membership
This commit is contained in:
@ -8,7 +8,7 @@ import { WorkspaceRepository } from '../../workspace/repositories/workspace.repo
|
||||
import { WorkspaceService } from '../../workspace/services/workspace.service';
|
||||
import { CreateWorkspaceDto } from '../../workspace/dto/create-workspace.dto';
|
||||
import { Workspace } from '../../workspace/entities/workspace.entity';
|
||||
import { SpaceService } from '../../space/space.service';
|
||||
import { SpaceService } from '../../space/services/space.service';
|
||||
import { CreateAdminUserDto } from '../dto/create-admin-user.dto';
|
||||
import { GroupUserService } from '../../group/services/group-user.service';
|
||||
|
||||
|
||||
@ -15,16 +15,16 @@ import { Group } from '../../group/entities/group.entity';
|
||||
import { GroupUser } from '../../group/entities/group-user.entity';
|
||||
import { Attachment } from '../../attachment/entities/attachment.entity';
|
||||
import { Space } from '../../space/entities/space.entity';
|
||||
import { SpaceUser } from '../../space/entities/space-user.entity';
|
||||
import { Page } from '../../page/entities/page.entity';
|
||||
import { Comment } from '../../comment/entities/comment.entity';
|
||||
import { SpaceMember } from '../../space/entities/space-member.entity';
|
||||
|
||||
export type Subjects =
|
||||
| InferSubjects<
|
||||
| typeof Workspace
|
||||
| typeof WorkspaceInvitation
|
||||
| typeof Space
|
||||
| typeof SpaceUser
|
||||
| typeof SpaceMember
|
||||
| typeof Group
|
||||
| typeof GroupUser
|
||||
| typeof Attachment
|
||||
|
||||
@ -12,7 +12,7 @@ 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';
|
||||
import { SpaceMember } from '../../space/entities/space-member.entity';
|
||||
|
||||
@Entity('groups')
|
||||
@Unique(['name', 'workspaceId'])
|
||||
@ -54,8 +54,8 @@ export class Group {
|
||||
@OneToMany(() => GroupUser, (groupUser) => groupUser.group)
|
||||
groupUsers: GroupUser[];
|
||||
|
||||
@OneToMany(() => SpaceGroup, (spaceGroup) => spaceGroup.group)
|
||||
spaces: SpaceGroup[];
|
||||
@OneToMany(() => SpaceMember, (spaceMembership) => spaceMembership.group)
|
||||
spaces: SpaceMember[];
|
||||
|
||||
userCount?: number;
|
||||
memberCount?: number;
|
||||
}
|
||||
|
||||
@ -89,12 +89,6 @@ export class GroupUserService {
|
||||
throw new NotFoundException('Group not found');
|
||||
}
|
||||
|
||||
const find = await manager.findOne(User, {
|
||||
where: { id: userId },
|
||||
});
|
||||
|
||||
console.log(find);
|
||||
|
||||
const userExists = await manager.exists(User, {
|
||||
where: { id: userId, workspaceId },
|
||||
});
|
||||
|
||||
@ -119,7 +119,7 @@ export class GroupService {
|
||||
.where('group.id = :groupId', { groupId })
|
||||
.andWhere('group.workspaceId = :workspaceId', { workspaceId })
|
||||
.loadRelationCountAndMap(
|
||||
'group.userCount',
|
||||
'group.memberCount',
|
||||
'group.groupUsers',
|
||||
'groupUsers',
|
||||
)
|
||||
@ -140,7 +140,7 @@ export class GroupService {
|
||||
.createQueryBuilder('group')
|
||||
.where('group.workspaceId = :workspaceId', { workspaceId })
|
||||
.loadRelationCountAndMap(
|
||||
'group.userCount',
|
||||
'group.memberCount',
|
||||
'group.groupUsers',
|
||||
'groupUsers',
|
||||
)
|
||||
|
||||
@ -1,45 +0,0 @@
|
||||
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;
|
||||
}
|
||||
69
apps/server/src/core/space/entities/space-member.entity.ts
Normal file
69
apps/server/src/core/space/entities/space-member.entity.ts
Normal file
@ -0,0 +1,69 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
Unique,
|
||||
Check,
|
||||
} from 'typeorm';
|
||||
import { User } from '../../user/entities/user.entity';
|
||||
import { Space } from './space.entity';
|
||||
import { Group } from '../../group/entities/group.entity';
|
||||
|
||||
@Entity('space_members')
|
||||
// allow either userId or groupId
|
||||
@Check(
|
||||
'CHK_allow_userId_or_groupId',
|
||||
`("userId" IS NOT NULL AND "groupId" IS NULL) OR ("userId" IS NULL AND "groupId" IS NOT NULL)`,
|
||||
)
|
||||
@Unique(['spaceId', 'userId'])
|
||||
@Unique(['spaceId', 'groupId'])
|
||||
export class SpaceMember {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
userId: string;
|
||||
|
||||
@ManyToOne(() => User, (user) => user.spaces, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn({ name: 'userId' })
|
||||
user: User;
|
||||
|
||||
@Column({ nullable: true })
|
||||
groupId: string;
|
||||
|
||||
@ManyToOne(() => Group, (group) => group.spaces, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn({ name: 'groupId' })
|
||||
group: Group;
|
||||
|
||||
@Column()
|
||||
spaceId: string;
|
||||
|
||||
@ManyToOne(() => Space, (space) => space.spaceMembers, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
space: Space;
|
||||
|
||||
@Column({ length: 100 })
|
||||
role: string;
|
||||
|
||||
@Column({ nullable: true })
|
||||
creatorId: string;
|
||||
|
||||
@ManyToOne(() => User)
|
||||
@JoinColumn({ name: 'creatorId' })
|
||||
creator: User;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updatedAt: Date;
|
||||
}
|
||||
@ -1,45 +0,0 @@
|
||||
import {
|
||||
Entity,
|
||||
PrimaryGeneratedColumn,
|
||||
Column,
|
||||
CreateDateColumn,
|
||||
UpdateDateColumn,
|
||||
ManyToOne,
|
||||
JoinColumn,
|
||||
Unique,
|
||||
} from 'typeorm';
|
||||
import { User } from '../../user/entities/user.entity';
|
||||
import { Space } from './space.entity';
|
||||
|
||||
@Entity('space_users')
|
||||
@Unique(['spaceId', 'userId'])
|
||||
export class SpaceUser {
|
||||
@PrimaryGeneratedColumn('uuid')
|
||||
id: string;
|
||||
|
||||
@Column()
|
||||
userId: string;
|
||||
|
||||
@ManyToOne(() => User, (user) => user.spaces, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
@JoinColumn({ name: 'userId' })
|
||||
user: User;
|
||||
|
||||
@Column()
|
||||
spaceId: string;
|
||||
|
||||
@ManyToOne(() => Space, (space) => space.spaceUsers, {
|
||||
onDelete: 'CASCADE',
|
||||
})
|
||||
space: Space;
|
||||
|
||||
@Column({ length: 100, nullable: true })
|
||||
role: string;
|
||||
|
||||
@CreateDateColumn()
|
||||
createdAt: Date;
|
||||
|
||||
@UpdateDateColumn()
|
||||
updatedAt: Date;
|
||||
}
|
||||
@ -11,10 +11,9 @@ import {
|
||||
} from 'typeorm';
|
||||
import { User } from '../../user/entities/user.entity';
|
||||
import { Workspace } from '../../workspace/entities/workspace.entity';
|
||||
import { SpaceUser } from './space-user.entity';
|
||||
import { Page } from '../../page/entities/page.entity';
|
||||
import { SpaceVisibility, SpaceRole } from '../../../helpers/types/permission';
|
||||
import { SpaceGroup } from './space-group.entity';
|
||||
import { SpaceMember } from './space-member.entity';
|
||||
|
||||
@Entity('spaces')
|
||||
@Unique(['slug', 'workspaceId'])
|
||||
@ -56,11 +55,8 @@ export class Space {
|
||||
@JoinColumn({ name: 'workspaceId' })
|
||||
workspace: Workspace;
|
||||
|
||||
@OneToMany(() => SpaceUser, (spaceUser) => spaceUser.space)
|
||||
spaceUsers: SpaceUser[];
|
||||
|
||||
@OneToMany(() => SpaceGroup, (spaceGroup) => spaceGroup.space)
|
||||
spaceGroups: SpaceGroup[];
|
||||
@OneToMany(() => SpaceMember, (spaceMember) => spaceMember.space)
|
||||
spaceMembers: SpaceMember[];
|
||||
|
||||
@OneToMany(() => Page, (page) => page.space)
|
||||
pages: Page[];
|
||||
|
||||
@ -1,10 +0,0 @@
|
||||
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());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,10 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { SpaceMember } from '../entities/space-member.entity';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceMemberRepository extends Repository<SpaceMember> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(SpaceMember, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { DataSource, Repository } from 'typeorm';
|
||||
import { SpaceUser } from '../entities/space-user.entity';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceUserRepository extends Repository<SpaceUser> {
|
||||
constructor(private dataSource: DataSource) {
|
||||
super(SpaceUser, dataSource.createEntityManager());
|
||||
}
|
||||
}
|
||||
230
apps/server/src/core/space/services/space-member.service.ts
Normal file
230
apps/server/src/core/space/services/space-member.service.ts
Normal file
@ -0,0 +1,230 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { SpaceRepository } from '../repositories/space.repository';
|
||||
import { transactionWrapper } from '../../../helpers/db.helper';
|
||||
import { DataSource, EntityManager, IsNull, Not } from 'typeorm';
|
||||
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 { Group } from '../../group/entities/group.entity';
|
||||
import { SpaceMemberRepository } from '../repositories/space-member.repository';
|
||||
import { SpaceMember } from '../entities/space-member.entity';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceMemberService {
|
||||
constructor(
|
||||
private spaceRepository: SpaceRepository,
|
||||
private spaceMemberRepository: SpaceMemberRepository,
|
||||
private dataSource: DataSource,
|
||||
) {}
|
||||
|
||||
async addUserToSpace(
|
||||
userId: string,
|
||||
spaceId: string,
|
||||
role: string,
|
||||
workspaceId,
|
||||
manager?: EntityManager,
|
||||
): Promise<SpaceMember> {
|
||||
return await transactionWrapper(
|
||||
async (manager: EntityManager) => {
|
||||
const userExists = await manager.exists(User, {
|
||||
where: { id: userId, workspaceId },
|
||||
});
|
||||
if (!userExists) {
|
||||
throw new NotFoundException('User not found');
|
||||
}
|
||||
|
||||
const existingSpaceUser = await manager.findOneBy(SpaceMember, {
|
||||
userId: userId,
|
||||
spaceId: spaceId,
|
||||
});
|
||||
|
||||
if (existingSpaceUser) {
|
||||
throw new BadRequestException('User already added to this space');
|
||||
}
|
||||
|
||||
const spaceMember = new SpaceMember();
|
||||
spaceMember.userId = userId;
|
||||
spaceMember.spaceId = spaceId;
|
||||
spaceMember.role = role;
|
||||
await manager.save(spaceMember);
|
||||
|
||||
return spaceMember;
|
||||
},
|
||||
this.dataSource,
|
||||
manager,
|
||||
);
|
||||
}
|
||||
|
||||
async getUserSpaces(
|
||||
userId: string,
|
||||
workspaceId: string,
|
||||
paginationOptions: PaginationOptions,
|
||||
) {
|
||||
const [userSpaces, count] = await this.spaceMemberRepository
|
||||
.createQueryBuilder('spaceMember')
|
||||
.leftJoinAndSelect('spaceMember.space', 'space')
|
||||
.where('spaceMember.userId = :userId', { userId })
|
||||
.andWhere('space.workspaceId = :workspaceId', { workspaceId })
|
||||
.loadRelationCountAndMap(
|
||||
'space.memberCount',
|
||||
'space.spaceMembers',
|
||||
'spaceMembers',
|
||||
)
|
||||
.take(paginationOptions.limit)
|
||||
.skip(paginationOptions.skip)
|
||||
.getManyAndCount();
|
||||
|
||||
/*
|
||||
const getUserSpacesViaGroup = this.spaceRepository
|
||||
.createQueryBuilder('space')
|
||||
.leftJoin('space.spaceGroups', 'spaceGroup')
|
||||
.leftJoin('spaceGroup.group', 'group')
|
||||
.leftJoin('group.groupUsers', 'groupUser')
|
||||
.where('groupUser.userId = :userId', { userId })
|
||||
.andWhere('space.workspaceId = :workspaceId', { workspaceId })
|
||||
.getManyAndCount();
|
||||
|
||||
console.log(await getUserSpacesViaGroup);
|
||||
*/
|
||||
|
||||
const spaces = userSpaces.map((userSpace) => userSpace.space);
|
||||
|
||||
const paginationMeta = new PaginationMetaDto({ count, paginationOptions });
|
||||
return new PaginatedResult(spaces, paginationMeta);
|
||||
}
|
||||
|
||||
async getSpaceMembers(
|
||||
spaceId: string,
|
||||
workspaceId: string,
|
||||
paginationOptions: PaginationOptions,
|
||||
) {
|
||||
const [spaceMembers, count] = await this.spaceMemberRepository.findAndCount(
|
||||
{
|
||||
relations: ['user', 'group'],
|
||||
where: {
|
||||
space: {
|
||||
id: spaceId,
|
||||
workspaceId,
|
||||
},
|
||||
},
|
||||
order: {
|
||||
createdAt: 'ASC',
|
||||
},
|
||||
take: paginationOptions.limit,
|
||||
skip: paginationOptions.skip,
|
||||
},
|
||||
);
|
||||
|
||||
const members = await Promise.all(
|
||||
spaceMembers.map(async (member) => {
|
||||
let memberInfo = {};
|
||||
|
||||
if (member.user) {
|
||||
memberInfo = {
|
||||
id: member.user.id,
|
||||
name: member.user.name,
|
||||
email: member.user.email,
|
||||
avatarUrl: member.user.avatarUrl,
|
||||
type: 'user',
|
||||
};
|
||||
} else if (member.group) {
|
||||
const memberCount = await this.dataSource.getRepository(Group).count({
|
||||
where: {
|
||||
id: member.groupId,
|
||||
workspaceId,
|
||||
},
|
||||
});
|
||||
|
||||
memberInfo = {
|
||||
id: member.group.id,
|
||||
name: member.group.name,
|
||||
isDefault: member.group.isDefault,
|
||||
memberCount: memberCount,
|
||||
type: 'group',
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...memberInfo,
|
||||
role: member.role,
|
||||
};
|
||||
}),
|
||||
);
|
||||
|
||||
const paginationMeta = new PaginationMetaDto({ count, paginationOptions });
|
||||
return new PaginatedResult(members, paginationMeta);
|
||||
}
|
||||
|
||||
async addGroupToSpace(
|
||||
groupId: string,
|
||||
spaceId: string,
|
||||
role: string,
|
||||
workspaceId,
|
||||
manager?: EntityManager,
|
||||
): Promise<SpaceMember> {
|
||||
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(SpaceMember, {
|
||||
groupId: groupId,
|
||||
spaceId: spaceId,
|
||||
});
|
||||
|
||||
if (existingSpaceGroup) {
|
||||
throw new BadRequestException('Group already added to this space');
|
||||
}
|
||||
|
||||
const spaceMember = new SpaceMember();
|
||||
spaceMember.groupId = groupId;
|
||||
spaceMember.spaceId = spaceId;
|
||||
spaceMember.role = role;
|
||||
await manager.save(spaceMember);
|
||||
|
||||
return spaceMember;
|
||||
},
|
||||
this.dataSource,
|
||||
manager,
|
||||
);
|
||||
}
|
||||
|
||||
async getSpaceGroup(
|
||||
spaceId: string,
|
||||
workspaceId: string,
|
||||
paginationOptions: PaginationOptions,
|
||||
) {
|
||||
const [spaceGroups, count] = await this.spaceMemberRepository.findAndCount({
|
||||
relations: ['group'],
|
||||
where: {
|
||||
groupId: Not(IsNull()),
|
||||
space: {
|
||||
id: spaceId,
|
||||
workspaceId,
|
||||
},
|
||||
},
|
||||
take: paginationOptions.limit,
|
||||
skip: paginationOptions.skip,
|
||||
});
|
||||
|
||||
// TODO: add group memberCount
|
||||
const groups = spaceGroups.map((spaceGroup) => {
|
||||
return {
|
||||
...spaceGroup.group,
|
||||
spaceRole: spaceGroup.role,
|
||||
};
|
||||
});
|
||||
|
||||
const paginationMeta = new PaginationMetaDto({ count, paginationOptions });
|
||||
return new PaginatedResult(groups, paginationMeta);
|
||||
}
|
||||
}
|
||||
84
apps/server/src/core/space/services/space.service.ts
Normal file
84
apps/server/src/core/space/services/space.service.ts
Normal file
@ -0,0 +1,84 @@
|
||||
import { Injectable, NotFoundException } from '@nestjs/common';
|
||||
import { CreateSpaceDto } from '../dto/create-space.dto';
|
||||
import { Space } from '../entities/space.entity';
|
||||
import { SpaceRepository } from '../repositories/space.repository';
|
||||
import { transactionWrapper } from '../../../helpers/db.helper';
|
||||
import { DataSource, EntityManager } from 'typeorm';
|
||||
import { PaginationOptions } from '../../../helpers/pagination/pagination-options';
|
||||
import { PaginationMetaDto } from '../../../helpers/pagination/pagination-meta-dto';
|
||||
import { PaginatedResult } from '../../../helpers/pagination/paginated-result';
|
||||
import { SpaceMemberRepository } from '../repositories/space-member.repository';
|
||||
import slugify from 'slugify';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceService {
|
||||
constructor(
|
||||
private spaceRepository: SpaceRepository,
|
||||
private spaceMemberRepository: SpaceMemberRepository,
|
||||
private dataSource: DataSource,
|
||||
) {}
|
||||
|
||||
async create(
|
||||
userId: string,
|
||||
workspaceId: string,
|
||||
createSpaceDto?: CreateSpaceDto,
|
||||
manager?: EntityManager,
|
||||
): Promise<Space> {
|
||||
return await transactionWrapper(
|
||||
async (manager: EntityManager) => {
|
||||
const space = new Space();
|
||||
space.name = createSpaceDto.name ?? 'untitled space ';
|
||||
space.description = createSpaceDto.description ?? '';
|
||||
space.creatorId = userId;
|
||||
space.workspaceId = workspaceId;
|
||||
|
||||
space.slug = slugify(space.name.toLowerCase()); // TODO: check for duplicate
|
||||
|
||||
await manager.save(space);
|
||||
return space;
|
||||
},
|
||||
this.dataSource,
|
||||
manager,
|
||||
);
|
||||
}
|
||||
|
||||
async getSpaceInfo(spaceId: string, workspaceId: string): Promise<Space> {
|
||||
const space = await this.spaceRepository
|
||||
.createQueryBuilder('space')
|
||||
.where('space.id = :spaceId', { spaceId })
|
||||
.andWhere('space.workspaceId = :workspaceId', { workspaceId })
|
||||
.loadRelationCountAndMap(
|
||||
'space.memberCount',
|
||||
'space.spaceMembers',
|
||||
'spaceMembers',
|
||||
) // TODO: add groups to memberCount
|
||||
.getOne();
|
||||
|
||||
if (!space) {
|
||||
throw new NotFoundException('Space not found');
|
||||
}
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
async getWorkspaceSpaces(
|
||||
workspaceId: string,
|
||||
paginationOptions: PaginationOptions,
|
||||
): Promise<PaginatedResult<Space>> {
|
||||
const [spaces, count] = await this.spaceRepository
|
||||
.createQueryBuilder('space')
|
||||
.where('space.workspaceId = :workspaceId', { workspaceId })
|
||||
.loadRelationCountAndMap(
|
||||
'space.memberCount',
|
||||
'space.spaceMembers',
|
||||
'spaceMembers',
|
||||
) // TODO: add groups to memberCount
|
||||
.take(paginationOptions.limit)
|
||||
.skip(paginationOptions.skip)
|
||||
.getManyAndCount();
|
||||
|
||||
const paginationMeta = new PaginationMetaDto({ count, paginationOptions });
|
||||
|
||||
return new PaginatedResult(spaces, paginationMeta);
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,6 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { SpaceController } from './space.controller';
|
||||
import { SpaceService } from './space.service';
|
||||
import { SpaceService } from './services/space.service';
|
||||
|
||||
describe('SpaceController', () => {
|
||||
let controller: SpaceController;
|
||||
|
||||
@ -6,7 +6,7 @@ import {
|
||||
Post,
|
||||
UseGuards,
|
||||
} from '@nestjs/common';
|
||||
import { SpaceService } from './space.service';
|
||||
import { SpaceService } from './services/space.service';
|
||||
import { AuthUser } from '../../decorators/auth-user.decorator';
|
||||
import { User } from '../user/entities/user.entity';
|
||||
import { AuthWorkspace } from '../../decorators/auth-workspace.decorator';
|
||||
@ -14,11 +14,15 @@ import { Workspace } from '../workspace/entities/workspace.entity';
|
||||
import { JwtAuthGuard } from '../../guards/jwt-auth.guard';
|
||||
import { SpaceIdDto } from './dto/space-id.dto';
|
||||
import { PaginationOptions } from '../../helpers/pagination/pagination-options';
|
||||
import { SpaceMemberService } from './services/space-member.service';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Controller('spaces')
|
||||
export class SpaceController {
|
||||
constructor(private readonly spaceService: SpaceService) {}
|
||||
constructor(
|
||||
private readonly spaceService: SpaceService,
|
||||
private readonly spaceMemberService: SpaceMemberService,
|
||||
) {}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Post('/')
|
||||
@ -41,7 +45,11 @@ export class SpaceController {
|
||||
@AuthUser() user: User,
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
) {
|
||||
return this.spaceService.getUserSpaces(user.id, workspace.id, pagination);
|
||||
return this.spaceMemberService.getUserSpaces(
|
||||
user.id,
|
||||
workspace.id,
|
||||
pagination,
|
||||
);
|
||||
}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ -64,7 +72,7 @@ export class SpaceController {
|
||||
@AuthUser() user: User,
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
) {
|
||||
return this.spaceService.getSpaceUsers(
|
||||
return this.spaceMemberService.getSpaceMembers(
|
||||
spaceIdDto.spaceId,
|
||||
workspace.id,
|
||||
pagination,
|
||||
|
||||
@ -1,23 +1,22 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
import { SpaceService } from './space.service';
|
||||
import { SpaceService } from './services/space.service';
|
||||
import { SpaceController } from './space.controller';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
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';
|
||||
import { SpaceMember } from './entities/space-member.entity';
|
||||
import { SpaceMemberRepository } from './repositories/space-member.repository';
|
||||
import { SpaceMemberService } from './services/space-member.service';
|
||||
|
||||
@Module({
|
||||
imports: [TypeOrmModule.forFeature([Space, SpaceUser, SpaceGroup])],
|
||||
imports: [TypeOrmModule.forFeature([Space, SpaceMember])],
|
||||
controllers: [SpaceController],
|
||||
providers: [
|
||||
SpaceService,
|
||||
SpaceMemberService,
|
||||
SpaceRepository,
|
||||
SpaceUserRepository,
|
||||
SpaceGroupRepository,
|
||||
SpaceMemberRepository,
|
||||
],
|
||||
exports: [SpaceService],
|
||||
exports: [SpaceService, SpaceMemberService],
|
||||
})
|
||||
export class SpaceModule {}
|
||||
|
||||
@ -1,263 +0,0 @@
|
||||
import {
|
||||
BadRequestException,
|
||||
Injectable,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { CreateSpaceDto } from './dto/create-space.dto';
|
||||
import { Space } from './entities/space.entity';
|
||||
import { SpaceRepository } from './repositories/space.repository';
|
||||
import { SpaceUserRepository } from './repositories/space-user.repository';
|
||||
import { SpaceUser } from './entities/space-user.entity';
|
||||
import { transactionWrapper } from '../../helpers/db.helper';
|
||||
import { DataSource, EntityManager } from 'typeorm';
|
||||
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,
|
||||
) {}
|
||||
|
||||
async create(
|
||||
userId: string,
|
||||
workspaceId: string,
|
||||
createSpaceDto?: CreateSpaceDto,
|
||||
manager?: EntityManager,
|
||||
): Promise<Space> {
|
||||
return await transactionWrapper(
|
||||
async (manager: EntityManager) => {
|
||||
const space = new Space();
|
||||
space.name = createSpaceDto.name ?? 'untitled space ';
|
||||
space.description = createSpaceDto.description ?? '';
|
||||
space.creatorId = userId;
|
||||
space.workspaceId = workspaceId;
|
||||
|
||||
space.slug = space.name.toLowerCase(); // TODO: fix
|
||||
|
||||
await manager.save(space);
|
||||
return space;
|
||||
},
|
||||
this.dataSource,
|
||||
manager,
|
||||
);
|
||||
}
|
||||
|
||||
async addUserToSpace(
|
||||
userId: string,
|
||||
spaceId: string,
|
||||
role: string,
|
||||
workspaceId,
|
||||
manager?: EntityManager,
|
||||
): Promise<SpaceUser> {
|
||||
return await transactionWrapper(
|
||||
async (manager: EntityManager) => {
|
||||
const userExists = await manager.exists(User, {
|
||||
where: { id: userId, workspaceId },
|
||||
});
|
||||
if (!userExists) {
|
||||
throw new NotFoundException('User not found');
|
||||
}
|
||||
|
||||
const existingSpaceUser = await manager.findOneBy(SpaceUser, {
|
||||
userId: userId,
|
||||
spaceId: spaceId,
|
||||
});
|
||||
|
||||
if (existingSpaceUser) {
|
||||
throw new BadRequestException('User already added to this space');
|
||||
}
|
||||
|
||||
const spaceUser = new SpaceUser();
|
||||
spaceUser.userId = userId;
|
||||
spaceUser.spaceId = spaceId;
|
||||
spaceUser.role = role;
|
||||
await manager.save(spaceUser);
|
||||
|
||||
return spaceUser;
|
||||
},
|
||||
this.dataSource,
|
||||
manager,
|
||||
);
|
||||
}
|
||||
|
||||
async getSpaceInfo(spaceId: string, workspaceId: string): Promise<Space> {
|
||||
const space = await this.spaceRepository
|
||||
.createQueryBuilder('space')
|
||||
.where('space.id = :spaceId', { spaceId })
|
||||
.andWhere('space.workspaceId = :workspaceId', { workspaceId })
|
||||
.loadRelationCountAndMap(
|
||||
'space.userCount',
|
||||
'space.spaceUsers',
|
||||
'spaceUsers',
|
||||
) // TODO: add groups to userCount
|
||||
.getOne();
|
||||
|
||||
if (!space) {
|
||||
throw new NotFoundException('Space not found');
|
||||
}
|
||||
|
||||
return space;
|
||||
}
|
||||
|
||||
async getWorkspaceSpaces(
|
||||
workspaceId: string,
|
||||
paginationOptions: PaginationOptions,
|
||||
): Promise<PaginatedResult<Space>> {
|
||||
const [spaces, count] = await this.spaceRepository
|
||||
.createQueryBuilder('space')
|
||||
.where('space.workspaceId = :workspaceId', { workspaceId })
|
||||
.loadRelationCountAndMap(
|
||||
'space.userCount',
|
||||
'space.spaceUsers',
|
||||
'spaceUsers',
|
||||
) // TODO: add groups to userCount
|
||||
.take(paginationOptions.limit)
|
||||
.skip(paginationOptions.skip)
|
||||
.getManyAndCount();
|
||||
|
||||
const paginationMeta = new PaginationMetaDto({ count, paginationOptions });
|
||||
|
||||
return new PaginatedResult(spaces, paginationMeta);
|
||||
}
|
||||
|
||||
async getUserSpaces(
|
||||
userId: string,
|
||||
workspaceId: string,
|
||||
paginationOptions: PaginationOptions,
|
||||
) {
|
||||
const [userSpaces, count] = await this.spaceUserRepository
|
||||
.createQueryBuilder('spaceUser')
|
||||
.leftJoinAndSelect('spaceUser.space', 'space')
|
||||
.where('spaceUser.userId = :userId', { userId })
|
||||
.andWhere('space.workspaceId = :workspaceId', { workspaceId })
|
||||
.loadRelationCountAndMap(
|
||||
'space.userCount',
|
||||
'space.spaceUsers',
|
||||
'spaceUsers',
|
||||
)
|
||||
.take(paginationOptions.limit)
|
||||
.skip(paginationOptions.skip)
|
||||
.getManyAndCount();
|
||||
|
||||
|
||||
const getUserSpacesViaGroup = this.spaceRepository
|
||||
.createQueryBuilder('space')
|
||||
.leftJoin('space.spaceGroups', 'spaceGroup')
|
||||
.leftJoin('spaceGroup.group', 'group')
|
||||
.leftJoin('group.groupUsers', 'groupUser')
|
||||
.where('groupUser.userId = :userId', { userId })
|
||||
.andWhere('space.workspaceId = :workspaceId', { workspaceId }).getManyAndCount();
|
||||
|
||||
console.log(await getUserSpacesViaGroup);
|
||||
|
||||
const spaces = userSpaces.map((userSpace) => userSpace.space);
|
||||
|
||||
const paginationMeta = new PaginationMetaDto({ count, paginationOptions });
|
||||
return new PaginatedResult(spaces, paginationMeta);
|
||||
}
|
||||
|
||||
async getSpaceUsers(
|
||||
spaceId: string,
|
||||
workspaceId: string,
|
||||
paginationOptions: PaginationOptions,
|
||||
) {
|
||||
const [spaceUsers, count] = await this.spaceUserRepository.findAndCount({
|
||||
relations: ['user'],
|
||||
where: {
|
||||
space: {
|
||||
id: spaceId,
|
||||
workspaceId,
|
||||
},
|
||||
},
|
||||
take: paginationOptions.limit,
|
||||
skip: paginationOptions.skip,
|
||||
});
|
||||
|
||||
const users = spaceUsers.map((spaceUser) => {
|
||||
delete spaceUser.user.password;
|
||||
return {
|
||||
...spaceUser.user,
|
||||
spaceRole: spaceUser.role,
|
||||
};
|
||||
});
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
@ -14,7 +14,7 @@ import { Workspace } from '../../workspace/entities/workspace.entity';
|
||||
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 { SpaceMember } from '../../space/entities/space-member.entity';
|
||||
|
||||
@Entity('users')
|
||||
@Unique(['email', 'workspaceId'])
|
||||
@ -78,8 +78,8 @@ export class User {
|
||||
@OneToMany(() => Space, (space) => space.creator)
|
||||
createdSpaces: Space[];
|
||||
|
||||
@OneToMany(() => SpaceUser, (spaceUser) => spaceUser.user)
|
||||
spaces: SpaceUser[];
|
||||
@OneToMany(() => SpaceMember, (spaceMembership) => spaceMembership.user)
|
||||
spaces: SpaceMember[];
|
||||
|
||||
toJSON() {
|
||||
delete this.password;
|
||||
|
||||
@ -9,7 +9,7 @@ import { Workspace } from '../entities/workspace.entity';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import { UpdateWorkspaceDto } from '../dto/update-workspace.dto';
|
||||
import { DeleteWorkspaceDto } from '../dto/delete-workspace.dto';
|
||||
import { SpaceService } from '../../space/space.service';
|
||||
import { SpaceService } from '../../space/services/space.service';
|
||||
import { DataSource, EntityManager } from 'typeorm';
|
||||
import { transactionWrapper } from '../../../helpers/db.helper';
|
||||
import { CreateSpaceDto } from '../../space/dto/create-space.dto';
|
||||
@ -19,6 +19,7 @@ import { User } from '../../user/entities/user.entity';
|
||||
import { EnvironmentService } from '../../../integrations/environment/environment.service';
|
||||
import { GroupService } from '../../group/services/group.service';
|
||||
import { GroupUserService } from '../../group/services/group-user.service';
|
||||
import { SpaceMemberService } from '../../space/services/space-member.service';
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceService {
|
||||
@ -26,6 +27,7 @@ export class WorkspaceService {
|
||||
private workspaceRepository: WorkspaceRepository,
|
||||
private userRepository: UserRepository,
|
||||
private spaceService: SpaceService,
|
||||
private spaceMemberService: SpaceMemberService,
|
||||
private groupService: GroupService,
|
||||
private groupUserService: GroupUserService,
|
||||
private environmentService: EnvironmentService,
|
||||
@ -42,7 +44,7 @@ export class WorkspaceService {
|
||||
.createQueryBuilder('workspace')
|
||||
.where('workspace.id = :workspaceId', { workspaceId })
|
||||
.loadRelationCountAndMap(
|
||||
'workspace.userCount',
|
||||
'workspace.memberCount',
|
||||
'workspace.users',
|
||||
'workspaceUsers',
|
||||
)
|
||||
@ -105,7 +107,7 @@ export class WorkspaceService {
|
||||
);
|
||||
|
||||
// and add user to space as owner
|
||||
await this.spaceService.addUserToSpace(
|
||||
await this.spaceMemberService.addUserToSpace(
|
||||
user.id,
|
||||
createdSpace.id,
|
||||
SpaceRole.OWNER,
|
||||
@ -114,7 +116,7 @@ export class WorkspaceService {
|
||||
);
|
||||
|
||||
// add default group to space as writer
|
||||
await this.spaceService.addGroupToSpace(
|
||||
await this.spaceMemberService.addGroupToSpace(
|
||||
group.id,
|
||||
createdSpace.id,
|
||||
SpaceRole.WRITER,
|
||||
|
||||
@ -1,18 +0,0 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class AddSpacesUsers1708941651476 implements MigrationInterface {
|
||||
name = 'AddSpacesUsers1708941651476'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`CREATE TABLE "space_users" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "userId" 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_5819a4f6b83e86596c57c19e39f" UNIQUE ("spaceId", "userId"), CONSTRAINT "PK_8d03fbe7f6bc26f9ac665250e1d" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`ALTER TABLE "space_users" ADD CONSTRAINT "FK_e735cdb3781f344a2dff3083fd5" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "space_users" ADD CONSTRAINT "FK_dae4f7e55306bdcec6ac8f602c1" 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_users" DROP CONSTRAINT "FK_dae4f7e55306bdcec6ac8f602c1"`);
|
||||
await queryRunner.query(`ALTER TABLE "space_users" DROP CONSTRAINT "FK_e735cdb3781f344a2dff3083fd5"`);
|
||||
await queryRunner.query(`DROP TABLE "space_users"`);
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
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"`);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,22 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class PolymorphicSpaceMembers1711054895950 implements MigrationInterface {
|
||||
name = 'PolymorphicSpaceMembers1711054895950'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`CREATE TABLE "space_members" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "userId" uuid, "groupId" uuid, "spaceId" uuid NOT NULL, "role" character varying(100) NOT NULL, "creatorId" uuid, "createdAt" TIMESTAMP NOT NULL DEFAULT now(), "updatedAt" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "UQ_07add45942b705c4b8c6c88013d" UNIQUE ("spaceId", "groupId"), CONSTRAINT "UQ_e91b442c5a1c7aa13c767c88363" UNIQUE ("spaceId", "userId"), CONSTRAINT "PK_5aaa6440d7f1e8b8c051df43d5e" PRIMARY KEY ("id"))`);
|
||||
await queryRunner.query(`ALTER TABLE "space_members" ADD CONSTRAINT "FK_6b3b64db93d9a721ff7005eb6a3" FOREIGN KEY ("userId") REFERENCES "users"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "space_members" ADD CONSTRAINT "FK_1677eab7e3f6602e13ca23418f5" FOREIGN KEY ("groupId") REFERENCES "groups"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "space_members" ADD CONSTRAINT "FK_25571cab1e221c0278499f4e801" FOREIGN KEY ("spaceId") REFERENCES "spaces"("id") ON DELETE CASCADE ON UPDATE NO ACTION`);
|
||||
await queryRunner.query(`ALTER TABLE "space_members" ADD CONSTRAINT "FK_63ce441685d52339875a4a33b7e" 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 "space_members" DROP CONSTRAINT "FK_63ce441685d52339875a4a33b7e"`);
|
||||
await queryRunner.query(`ALTER TABLE "space_members" DROP CONSTRAINT "FK_25571cab1e221c0278499f4e801"`);
|
||||
await queryRunner.query(`ALTER TABLE "space_members" DROP CONSTRAINT "FK_1677eab7e3f6602e13ca23418f5"`);
|
||||
await queryRunner.query(`ALTER TABLE "space_members" DROP CONSTRAINT "FK_6b3b64db93d9a721ff7005eb6a3"`);
|
||||
await queryRunner.query(`DROP TABLE "space_members"`);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,14 @@
|
||||
import { MigrationInterface, QueryRunner } from "typeorm";
|
||||
|
||||
export class SpaceMemberEntityConstraint1711059108729 implements MigrationInterface {
|
||||
name = 'SpaceMemberEntityConstraint1711059108729'
|
||||
|
||||
public async up(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "space_members" ADD CONSTRAINT "CHK_allow_userId_or_groupId" CHECK (("userId" IS NOT NULL AND "groupId" IS NULL) OR ("userId" IS NULL AND "groupId" IS NOT NULL))`);
|
||||
}
|
||||
|
||||
public async down(queryRunner: QueryRunner): Promise<void> {
|
||||
await queryRunner.query(`ALTER TABLE "space_members" DROP CONSTRAINT "CHK_allow_userId_or_groupId"`);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user