fix(api): add WorkspaceGuard to controllers and fix route ordering

This commit is contained in:
Jason Woltje
2026-01-29 20:15:33 -06:00
parent 9977d9bcf4
commit 48abdbba8b
8 changed files with 216 additions and 541 deletions

View File

@@ -7,175 +7,70 @@ import {
Body,
Param,
UseGuards,
Request,
UnauthorizedException,
HttpCode,
HttpStatus,
} from "@nestjs/common";
import { TagsService } from "./tags.service";
import { CreateTagDto, UpdateTagDto } from "./dto";
import { AuthGuard } from "../auth/guards/auth.guard";
import { WorkspaceGuard, PermissionGuard } from "../common/guards";
import { Workspace, Permission, RequirePermission } from "../common/decorators";
/**
* Controller for knowledge tag endpoints
* All endpoints require authentication and operate within workspace context
*/
@Controller("knowledge/tags")
@UseGuards(AuthGuard)
@UseGuards(AuthGuard, WorkspaceGuard, PermissionGuard)
export class TagsController {
constructor(private readonly tagsService: TagsService) {}
/**
* POST /api/knowledge/tags
* Create a new tag
*/
@Post()
@RequirePermission(Permission.WORKSPACE_MEMBER)
async create(
@Body() createTagDto: CreateTagDto,
@Request() req: any
): Promise<{
id: string;
workspaceId: string;
name: string;
slug: string;
color: string | null;
description: string | null;
}> {
const workspaceId = req.user?.workspaceId;
if (!workspaceId) {
throw new UnauthorizedException("Authentication required");
}
@Workspace() workspaceId: string
) {
return this.tagsService.create(workspaceId, createTagDto);
}
/**
* GET /api/knowledge/tags
* List all tags in the workspace
*/
@Get()
async findAll(@Request() req: any): Promise<
Array<{
id: string;
workspaceId: string;
name: string;
slug: string;
color: string | null;
description: string | null;
_count: {
entries: number;
};
}>
> {
const workspaceId = req.user?.workspaceId;
if (!workspaceId) {
throw new UnauthorizedException("Authentication required");
}
@RequirePermission(Permission.WORKSPACE_ANY)
async findAll(@Workspace() workspaceId: string) {
return this.tagsService.findAll(workspaceId);
}
/**
* GET /api/knowledge/tags/:slug
* Get a single tag by slug
*/
@Get(":slug")
@RequirePermission(Permission.WORKSPACE_ANY)
async findOne(
@Param("slug") slug: string,
@Request() req: any
): Promise<{
id: string;
workspaceId: string;
name: string;
slug: string;
color: string | null;
description: string | null;
_count: {
entries: number;
};
}> {
const workspaceId = req.user?.workspaceId;
if (!workspaceId) {
throw new UnauthorizedException("Authentication required");
}
@Workspace() workspaceId: string
) {
return this.tagsService.findOne(slug, workspaceId);
}
/**
* PUT /api/knowledge/tags/:slug
* Update a tag
*/
@Put(":slug")
@RequirePermission(Permission.WORKSPACE_MEMBER)
async update(
@Param("slug") slug: string,
@Body() updateTagDto: UpdateTagDto,
@Request() req: any
): Promise<{
id: string;
workspaceId: string;
name: string;
slug: string;
color: string | null;
description: string | null;
}> {
const workspaceId = req.user?.workspaceId;
if (!workspaceId) {
throw new UnauthorizedException("Authentication required");
}
@Workspace() workspaceId: string
) {
return this.tagsService.update(slug, workspaceId, updateTagDto);
}
/**
* DELETE /api/knowledge/tags/:slug
* Delete a tag
*/
@Delete(":slug")
@HttpCode(HttpStatus.NO_CONTENT)
@RequirePermission(Permission.WORKSPACE_ADMIN)
async remove(
@Param("slug") slug: string,
@Request() req: any
): Promise<void> {
const workspaceId = req.user?.workspaceId;
if (!workspaceId) {
throw new UnauthorizedException("Authentication required");
}
@Workspace() workspaceId: string
) {
await this.tagsService.remove(slug, workspaceId);
}
/**
* GET /api/knowledge/tags/:slug/entries
* Get all entries with this tag
*/
@Get(":slug/entries")
@RequirePermission(Permission.WORKSPACE_ANY)
async getEntries(
@Param("slug") slug: string,
@Request() req: any
): Promise<
Array<{
id: string;
slug: string;
title: string;
summary: string | null;
status: string;
visibility: string;
createdAt: Date;
updatedAt: Date;
}>
> {
const workspaceId = req.user?.workspaceId;
if (!workspaceId) {
throw new UnauthorizedException("Authentication required");
}
@Workspace() workspaceId: string
) {
return this.tagsService.getEntriesWithTag(slug, workspaceId);
}
}