mirror of
https://github.com/Shadowfita/docmost.git
synced 2025-11-18 18:51:05 +10:00
Allow creation of space
* other fixes and cleanups
This commit is contained in:
@ -3,7 +3,6 @@ import { TextAlign } from '@tiptap/extension-text-align';
|
||||
import { TaskList } from '@tiptap/extension-task-list';
|
||||
import { TaskItem } from '@tiptap/extension-task-item';
|
||||
import { Underline } from '@tiptap/extension-underline';
|
||||
import { Link } from '@tiptap/extension-link';
|
||||
import { Superscript } from '@tiptap/extension-superscript';
|
||||
import SubScript from '@tiptap/extension-subscript';
|
||||
import { Highlight } from '@tiptap/extension-highlight';
|
||||
@ -17,6 +16,7 @@ import {
|
||||
Details,
|
||||
DetailsContent,
|
||||
DetailsSummary,
|
||||
LinkExtension,
|
||||
MathBlock,
|
||||
MathInline,
|
||||
Table,
|
||||
@ -37,7 +37,7 @@ export const tiptapExtensions = [
|
||||
TaskList,
|
||||
TaskItem,
|
||||
Underline,
|
||||
Link,
|
||||
LinkExtension,
|
||||
Superscript,
|
||||
SubScript,
|
||||
Highlight,
|
||||
|
||||
@ -2,7 +2,7 @@ import { IsOptional, IsString, MaxLength, MinLength } from 'class-validator';
|
||||
|
||||
export class CreateSpaceDto {
|
||||
@MinLength(2)
|
||||
@MaxLength(64)
|
||||
@MaxLength(50)
|
||||
@IsString()
|
||||
name: string;
|
||||
|
||||
@ -11,7 +11,7 @@ export class CreateSpaceDto {
|
||||
description?: string;
|
||||
|
||||
@MinLength(2)
|
||||
@MaxLength(64)
|
||||
@MaxLength(50)
|
||||
@IsString()
|
||||
slug: string;
|
||||
}
|
||||
|
||||
@ -6,14 +6,54 @@ import {
|
||||
import { CreateSpaceDto } from '../dto/create-space.dto';
|
||||
import { PaginationOptions } from '@docmost/db/pagination/pagination-options';
|
||||
import { SpaceRepo } from '@docmost/db/repos/space/space.repo';
|
||||
import { KyselyTransaction } from '@docmost/db/types/kysely.types';
|
||||
import { Space } from '@docmost/db/types/entity.types';
|
||||
import { KyselyDB, KyselyTransaction } from '@docmost/db/types/kysely.types';
|
||||
import { Space, User } from '@docmost/db/types/entity.types';
|
||||
import { PaginationResult } from '@docmost/db/pagination/pagination';
|
||||
import { UpdateSpaceDto } from '../dto/update-space.dto';
|
||||
import { executeTx } from '@docmost/db/utils';
|
||||
import { InjectKysely } from 'nestjs-kysely';
|
||||
import { SpaceMemberService } from './space-member.service';
|
||||
import { SpaceRole } from '../../../common/helpers/types/permission';
|
||||
|
||||
@Injectable()
|
||||
export class SpaceService {
|
||||
constructor(private spaceRepo: SpaceRepo) {}
|
||||
constructor(
|
||||
private spaceRepo: SpaceRepo,
|
||||
private spaceMemberService: SpaceMemberService,
|
||||
@InjectKysely() private readonly db: KyselyDB,
|
||||
) {}
|
||||
|
||||
async createSpace(
|
||||
authUser: User,
|
||||
workspaceId: string,
|
||||
createSpaceDto: CreateSpaceDto,
|
||||
trx?: KyselyTransaction,
|
||||
): Promise<Space> {
|
||||
let space = null;
|
||||
|
||||
await executeTx(
|
||||
this.db,
|
||||
async (trx) => {
|
||||
space = await this.create(
|
||||
authUser.id,
|
||||
workspaceId,
|
||||
createSpaceDto,
|
||||
trx,
|
||||
);
|
||||
|
||||
await this.spaceMemberService.addUserToSpace(
|
||||
authUser.id,
|
||||
space.id,
|
||||
SpaceRole.ADMIN,
|
||||
workspaceId,
|
||||
trx,
|
||||
);
|
||||
},
|
||||
trx,
|
||||
);
|
||||
|
||||
return { ...space, memberCount: 1 };
|
||||
}
|
||||
|
||||
async create(
|
||||
userId: string,
|
||||
@ -28,7 +68,7 @@ export class SpaceService {
|
||||
);
|
||||
if (slugExists) {
|
||||
throw new BadRequestException(
|
||||
'Slug exists. Please use a unique space slug',
|
||||
'Space slug exists. Please use a unique space slug',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@ -28,6 +28,12 @@ import {
|
||||
import { UpdateSpaceDto } from './dto/update-space.dto';
|
||||
import { findHighestUserSpaceRole } from '@docmost/db/repos/space/utils';
|
||||
import { SpaceMemberRepo } from '@docmost/db/repos/space/space-member.repo';
|
||||
import {
|
||||
WorkspaceCaslAction,
|
||||
WorkspaceCaslSubject,
|
||||
} from '../casl/interfaces/workspace-ability.type';
|
||||
import WorkspaceAbilityFactory from '../casl/abilities/workspace-ability.factory';
|
||||
import { CreateSpaceDto } from './dto/create-space.dto';
|
||||
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Controller('spaces')
|
||||
@ -37,6 +43,7 @@ export class SpaceController {
|
||||
private readonly spaceMemberService: SpaceMemberService,
|
||||
private readonly spaceMemberRepo: SpaceMemberRepo,
|
||||
private readonly spaceAbility: SpaceAbilityFactory,
|
||||
private readonly workspaceAbility: WorkspaceAbilityFactory,
|
||||
) {}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@ -86,6 +93,22 @@ export class SpaceController {
|
||||
return { ...space, membership };
|
||||
}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Post('create')
|
||||
createGroup(
|
||||
@Body() createSpaceDto: CreateSpaceDto,
|
||||
@AuthUser() user: User,
|
||||
@AuthWorkspace() workspace: Workspace,
|
||||
) {
|
||||
const ability = this.workspaceAbility.createForUser(user, workspace);
|
||||
if (
|
||||
ability.cannot(WorkspaceCaslAction.Manage, WorkspaceCaslSubject.Space)
|
||||
) {
|
||||
throw new ForbiddenException();
|
||||
}
|
||||
return this.spaceService.createSpace(user, workspace.id, createSpaceDto);
|
||||
}
|
||||
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Post('update')
|
||||
async updateGroup(
|
||||
|
||||
@ -33,7 +33,7 @@ export class SpaceRepo {
|
||||
if (isValidUUID(spaceId)) {
|
||||
query = query.where('id', '=', spaceId);
|
||||
} else {
|
||||
query = query.where('slug', '=', spaceId);
|
||||
query = query.where(sql`LOWER(slug)`, '=', sql`LOWER(${spaceId})`);
|
||||
}
|
||||
return query.executeTakeFirst();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user