Skip to content
Merged
11 changes: 5 additions & 6 deletions server/ai-task/ai-task.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,37 +14,36 @@ import type { UpdateAiTaskDto } from "./dto/update-ai-task.dto";
import { AiTask } from "./schemas/ai-task.schema";
import { AiTaskState } from "./constants/ai-task.constants";
import { ObjectIdValidationPipe } from "./pipes/objectid-validation.pipe";
import { M2MOrAbilities } from "../auth/decorators/m2m-or-abilities.decorator";
import { ADMIN_USER_ABILITY } from "../auth/ability/abilities.constants";
import { AdminOnly } from "../auth/decorators/auth.decorator";

@ApiTags("ai-tasks")
@Controller("api/ai-tasks")
export class AiTaskController {
constructor(private readonly aiTaskService: AiTaskService) {}

@M2MOrAbilities(ADMIN_USER_ABILITY)
@AdminOnly({ allowM2M: true })
@ApiOperation({ summary: "Enqueue a new AI task" })
@Post()
create(@Body() createDto: CreateAiTaskDto) {
return this.aiTaskService.create(createDto);
}

@M2MOrAbilities(ADMIN_USER_ABILITY)
@AdminOnly({ allowM2M: true })
@ApiOperation({ summary: "Get all pending AI tasks" })
@Get("pending")
getPending() {
return this.aiTaskService.findAll(AiTaskState.PENDING);
}

@M2MOrAbilities(ADMIN_USER_ABILITY)
@AdminOnly({ allowM2M: true })
@ApiOperation({ summary: "Get AI tasks by state" })
@Get()
findAll(@Query("state") state?: string) {
const typedState = state as AiTask["state"];
return this.aiTaskService.findAll(typedState);
}

@M2MOrAbilities(ADMIN_USER_ABILITY)
@AdminOnly({ allowM2M: true })
@ApiOperation({
summary: "Update AI task state and optionally dispatch result",
})
Expand Down
17 changes: 5 additions & 12 deletions server/auth/name-space/name-space.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import {
Query,
Req,
Res,
UseGuards,
} from "@nestjs/common";
import { NameSpaceService } from "./name-space.service";
import type { Request, Response } from "express";
Expand All @@ -18,11 +17,7 @@ import { parse } from "url";
import { ViewService } from "../../view/view.service";
import { CreateNameSpaceDTO } from "./dto/create-namespace.dto";
import { UpdateNameSpaceDTO } from "./dto/update-name-space.dto";
import {
AdminUserAbility,
CheckAbilities,
} from "../../auth/ability/ability.decorator";
import { AbilitiesGuard } from "../../auth/ability/abilities.guard";
import { AdminOnly } from "../decorators/auth.decorator";
import { Types } from "mongoose";
import { Roles } from "../../auth/ability/ability.factory";
import { NotificationService } from "../../notifications/notifications.service";
Expand All @@ -37,10 +32,9 @@ export class NameSpaceController {
private notificationService: NotificationService
) {}

@AdminOnly()
@ApiTags("name-space")
@Post("api/name-space")
@UseGuards(AbilitiesGuard)
@CheckAbilities(new AdminUserAbility())
async create(@Body() namespace: CreateNameSpaceDTO) {
namespace.slug = slugify(namespace.name, {
lower: true,
Expand All @@ -55,10 +49,9 @@ export class NameSpaceController {
return await this.nameSpaceService.create(namespace);
}

@AdminOnly()
@ApiTags("name-space")
@Put("api/name-space/:id")
@UseGuards(AbilitiesGuard)
@CheckAbilities(new AdminUserAbility())
async update(@Param("id") id, @Body() namespaceBody: UpdateNameSpaceDTO) {
const nameSpace = await this.nameSpaceService.getById(id);
const newNameSpace = {
Expand Down Expand Up @@ -86,9 +79,8 @@ export class NameSpaceController {
return await this.nameSpaceService.update(id, newNameSpace);
}

@AdminOnly()
@ApiTags("name-space")
@UseGuards(AbilitiesGuard)
@CheckAbilities(new AdminUserAbility())
@Get("api/name-space")
async findAllOrFiltered(
@Query("userId") userId?: string,
Expand All @@ -100,6 +92,7 @@ export class NameSpaceController {
return this.nameSpaceService.listAll();
}

@AdminOnly()
@ApiTags("name-space")
@Get("admin/name-spaces")
public async adminNameSpaces(@Req() req: Request, @Res() res: Response) {
Expand Down
8 changes: 4 additions & 4 deletions server/auth/ory/ory.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type { Request, Response } from "express";
import type { NextApiRequest, NextApiResponse } from "next";
import { parse } from "url";
import { ViewService } from "../../view/view.service";
import { IsPublic } from "../decorators/is-public.decorator";
import { Public } from "../decorators/auth.decorator";
import OryService from "./ory.service";

@Controller("api/.ory")
Expand All @@ -12,7 +12,7 @@ export default class OryController {
private readonly viewService: ViewService,
private readonly oryService: OryService
) {}
@IsPublic()
@Public()
@Get("sessions/whoami")
public async whoAmI(@Req() req: Request, @Res() res: Response) {
try {
Expand All @@ -27,7 +27,7 @@ export default class OryController {
}
}

@IsPublic()
@Public()
@Get("*")
public async getOryPaths(
@Req() req: NextApiRequest,
Expand All @@ -36,7 +36,7 @@ export default class OryController {
await this.oryPaths(req, res);
}

@IsPublic()
@Public()
@Post("*")
public async postOryPaths(
@Req() req: NextApiRequest,
Expand Down
12 changes: 4 additions & 8 deletions server/badge/badge.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import {
Put,
Req,
Res,
UseGuards,
} from "@nestjs/common";
import type { Request, Response } from "express";
import { ImageService } from "../claim/types/image/image.service";
Expand All @@ -20,11 +19,7 @@ import { UsersService } from "../users/users.service";
import { Types } from "mongoose";
import { ApiTags } from "@nestjs/swagger";
import { UtilService } from "../util";
import { AbilitiesGuard } from "../auth/ability/abilities.guard";
import {
AdminUserAbility,
CheckAbilities,
} from "../auth/ability/ability.decorator";
import { AdminOnly } from "../auth/decorators/auth.decorator";

@Controller(":namespace?")
export class BadgeController {
Expand All @@ -36,6 +31,7 @@ export class BadgeController {
private util: UtilService
) {}

@AdminOnly()
@ApiTags("badge")
@Post("api/badge")
public async createBadge(@Body() badge: CreateBadgeDTO, @Req() request) {
Expand Down Expand Up @@ -64,6 +60,7 @@ export class BadgeController {
return createdBadge;
}

@AdminOnly()
@ApiTags("badge")
@Put("api/badge/:id")
public async updateBadge(@Body() badge: UpdateBadgeDTO, @Req() request) {
Expand Down Expand Up @@ -136,10 +133,9 @@ export class BadgeController {
return this.badgeService.listAll();
}

@AdminOnly()
@ApiTags("admin")
@Get("admin/badges")
@UseGuards(AbilitiesGuard)
@CheckAbilities(new AdminUserAbility())
public async adminBadges(@Req() req: Request, @Res() res: Response) {
const badges = await this.badgeService.listAll();
const users = await this.usersService.findAll({
Expand Down
18 changes: 5 additions & 13 deletions server/claim-review/claim-review.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,13 @@ import {
Param,
Put,
Get,
UseGuards,
Header,
Delete,
Query,
} from "@nestjs/common";
import { IsPublic } from "../auth/decorators/is-public.decorator";
import { Public, AdminOnly } from "../auth/decorators/auth.decorator";
import { CaptchaService } from "../captcha/captcha.service";
import { ClaimReviewService } from "./claim-review.service";
import { AbilitiesGuard } from "../auth/ability/abilities.guard";
import {
AdminUserAbility,
CheckAbilities,
} from "../auth/ability/ability.decorator";
import { ApiTags } from "@nestjs/swagger";
import { HistoryService } from "../history/history.service";
import { TargetModel } from "../history/schema/history.schema";
Expand All @@ -31,7 +25,7 @@ export class ClaimReviewController {
private historyService: HistoryService
) {}

@IsPublic()
@Public()
@ApiTags("claim-review")
@Get("api/review")
@Header("Cache-Control", "max-age=60, must-revalidate")
Expand Down Expand Up @@ -67,10 +61,9 @@ export class ClaimReviewController {
});
}

@AdminOnly()
@ApiTags("claim-review")
@Put("api/review/:id")
@UseGuards(AbilitiesGuard)
@CheckAbilities(new AdminUserAbility())
async update(@Param("id") reviewId, @Body() body) {
const validateCaptcha = await this.captchaService.validate(
body.recaptcha
Expand All @@ -85,15 +78,14 @@ export class ClaimReviewController {
);
}

@AdminOnly()
@ApiTags("claim-review")
@Delete("api/review/:id")
@UseGuards(AbilitiesGuard)
@CheckAbilities(new AdminUserAbility())
async delete(@Param("id") reviewId) {
return this.claimReviewService.delete(reviewId);
}

@IsPublic()
@Public()
@ApiTags("claim-review")
@Get("api/review/:data_hash")
@Header("Cache-Control", "max-age=60, must-revalidate")
Expand Down
136 changes: 136 additions & 0 deletions server/claim/claim.controller.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import { Test, TestingModule } from "@nestjs/testing";
import { ClaimController } from "./claim.controller";
import { ImageService } from "./types/image/image.service";
import {
mockClaimService,
mockImageService,
mockPersonalityService,
} from "../mocks/ClaimMock";
import { ClaimService } from "./claim.service";
import { ClaimReviewService } from "../claim-review/claim-review.service";
import { ReviewTaskService } from "../review-task/review-task.service";
import { SentenceService } from "./types/sentence/sentence.service";
import { ConfigService } from "@nestjs/config";
import { ViewService } from "../view/view.service";
import { CaptchaService } from "../captcha/captcha.service";
import { DebateService } from "./types/debate/debate.service";
import { EditorService } from "../editor/editor.service";
import { ParserService } from "./parser/parser.service";
import { HistoryService } from "../history/history.service";
import { ClaimRevisionService } from "./claim-revision/claim-revision.service";
import { FeatureFlagService } from "../feature-flag/feature-flag.service";
import { GroupService } from "../group/group.service";
import { AbilitiesGuard } from "../auth/ability/abilities.guard";
import { GetByDataHashDto } from "./dto/get-by-datahash.dto";

describe("ClaimController (Unit)", () => {
let controller: ClaimController;
let testingModule: TestingModule;
let imageService: ReturnType<typeof mockImageService>;
let claimService: ReturnType<typeof mockClaimService>;
let personalityService: ReturnType<typeof mockPersonalityService>;

beforeEach(async () => {
imageService = mockImageService();
claimService = mockClaimService();
personalityService = mockPersonalityService();

testingModule = await Test.createTestingModule({
controllers: [ClaimController],
providers: [
{ provide: ClaimReviewService, useValue: {} },
{ provide: ReviewTaskService, useValue: {} },
{ provide: "PersonalityService", useValue: personalityService },
{ provide: ClaimService, useValue: claimService },
{ provide: SentenceService, useValue: {} },
{ provide: ConfigService, useValue: {} },
{ provide: ViewService, useValue: {} },
{ provide: CaptchaService, useValue: {} },
{ provide: ImageService, useValue: imageService },
{ provide: DebateService, useValue: {} },
{ provide: EditorService, useValue: {} },
{ provide: ParserService, useValue: {} },
{ provide: HistoryService, useValue: {} },
{ provide: ClaimRevisionService, useValue: {} },
{ provide: FeatureFlagService, useValue: {} },
{ provide: GroupService, useValue: {} },

{ provide: "REQUEST", useValue: {} },
],
})
.overrideGuard(AbilitiesGuard)
.useValue({})
.compile();

controller = testingModule.get<ClaimController>(ClaimController);
});

describe("GetByDataHashDto", () => {
it("should accept valid data_hash", () => {
expect(() =>
GetByDataHashDto.parse({
data_hash: "96cffa6efb4c5732c46dfed98be707a5",
})
).not.toThrow();
});

it("should throw when data_hash is invalid", () => {
expect(() =>
GetByDataHashDto.parse({
data_hash: 123,
})
).toThrow();
});

it("should throw when data_hash is empty", () => {
expect(() =>
GetByDataHashDto.parse({
data_hash: "",
})
).toThrow();
});
});

it("should accept data_hash when it is a string", async () => {
const req = {
params: { data_hash: "96cffa6efb4c5732c46dfed98be707a5" },
} as any;
const res = {} as any;

personalityService.getPersonalityBySlug!.mockResolvedValue({
_id: "507f1f77bcf86cd799439011",
name: "Test Personality",
slug: "test-personality",
description: "Test description",
isHidden: false,
} as any);

claimService.getByPersonalityIdAndClaimSlug.mockResolvedValue({
_id: "507f1f77bcf86cd799439012",
slug: "test-claim",
personalities: ["507f1f77bcf86cd799439011"],
isHidden: false,
nameSpace: "main",
} as any);

imageService.getByDataHash.mockResolvedValue({
_id: "507f1f77bcf86cd799439013",
type: "Image",
data_hash: "96cffa6efb4c5732c46dfed98be707a5",
content: "https://example.com/image.jpg",
props: {
key: "test-image-key",
extension: "jpg",
},
} as any);

jest.spyOn(
controller as any,
"returnClaimReviewPage"
).mockResolvedValue(undefined);

await expect(
controller.getImageClaimReviewPage(req, res)
).resolves.not.toThrow();
});
});
Loading
Loading