feat: v2 routing forms responses endpoints (#19319)
* wip: routing forms responses * refactor structure * Revert "refactor structure" This reverts commit b641c06592cd9314008e81c4584039bd42393ac7. * routing forms * remove unused file
This commit is contained in:
@@ -0,0 +1,40 @@
|
||||
import { RoutingFormsRepository } from "@/modules/routing-forms/routing-forms.repository";
|
||||
import {
|
||||
Injectable,
|
||||
CanActivate,
|
||||
ExecutionContext,
|
||||
ForbiddenException,
|
||||
NotFoundException,
|
||||
} from "@nestjs/common";
|
||||
import { Request } from "express";
|
||||
|
||||
import { Team } from "@calcom/prisma/client";
|
||||
|
||||
@Injectable()
|
||||
export class IsRoutingFormInTeam implements CanActivate {
|
||||
constructor(private routingFormsRepository: RoutingFormsRepository) {}
|
||||
|
||||
async canActivate(context: ExecutionContext): Promise<boolean> {
|
||||
const request = context.switchToHttp().getRequest<Request & { team: Team }>();
|
||||
const teamId: string = request.params.teamId;
|
||||
const routingFormId: string = request.params.routingFormId;
|
||||
|
||||
if (!routingFormId) {
|
||||
throw new ForbiddenException("No routing form id found in request params.");
|
||||
}
|
||||
|
||||
if (!teamId) {
|
||||
throw new ForbiddenException("No team id found in request params.");
|
||||
}
|
||||
|
||||
const routingForm = await this.routingFormsRepository.getTeamRoutingForm(Number(teamId), routingFormId);
|
||||
|
||||
if (!routingForm) {
|
||||
throw new NotFoundException(
|
||||
`Team with id=(${teamId}) routing form with id=(${routingFormId}) not found.`
|
||||
);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -41,6 +41,7 @@ import { OrganizationsTeamsService } from "@/modules/organizations/services/orga
|
||||
import { OrganizationsUsersService } from "@/modules/organizations/services/organizations-users-service";
|
||||
import { OrganizationsWebhooksService } from "@/modules/organizations/services/organizations-webhooks.service";
|
||||
import { OrganizationsService } from "@/modules/organizations/services/organizations.service";
|
||||
import { OrganizationsTeamsRoutingFormsModule } from "@/modules/organizations/teams/routing-forms/organizations-teams-routing-forms-responses.module";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { RedisModule } from "@/modules/redis/redis.module";
|
||||
import { StripeModule } from "@/modules/stripe/stripe.module";
|
||||
@@ -62,6 +63,7 @@ import { Module } from "@nestjs/common";
|
||||
EventTypesModule_2024_06_14,
|
||||
TeamsEventTypesModule,
|
||||
TeamsModule,
|
||||
OrganizationsTeamsRoutingFormsModule,
|
||||
],
|
||||
providers: [
|
||||
OrganizationsRepository,
|
||||
|
||||
+197
@@ -0,0 +1,197 @@
|
||||
import { bootstrap } from "@/app";
|
||||
import { AppModule } from "@/app.module";
|
||||
import { GetRoutingFormResponsesOutput } from "@/modules/organizations/teams/routing-forms/outputs/get-routing-form-responses.output";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { TokensModule } from "@/modules/tokens/tokens.module";
|
||||
import { UsersModule } from "@/modules/users/users.module";
|
||||
import { INestApplication } from "@nestjs/common";
|
||||
import { NestExpressApplication } from "@nestjs/platform-express";
|
||||
import { Test } from "@nestjs/testing";
|
||||
import { User } from "@prisma/client";
|
||||
import * as request from "supertest";
|
||||
import { ApiKeysRepositoryFixture } from "test/fixtures/repository/api-keys.repository.fixture";
|
||||
import { MembershipRepositoryFixture } from "test/fixtures/repository/membership.repository.fixture";
|
||||
import { OrganizationRepositoryFixture } from "test/fixtures/repository/organization.repository.fixture";
|
||||
import { ProfileRepositoryFixture } from "test/fixtures/repository/profiles.repository.fixture";
|
||||
import { RoutingFormsRepositoryFixture } from "test/fixtures/repository/routing-forms.repository.fixture";
|
||||
import { TeamRepositoryFixture } from "test/fixtures/repository/team.repository.fixture";
|
||||
import { UserRepositoryFixture } from "test/fixtures/repository/users.repository.fixture";
|
||||
import { randomString } from "test/utils/randomString";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { Team } from "@calcom/prisma/client";
|
||||
|
||||
describe("Organizations Teams Routing Forms Responses", () => {
|
||||
let app: INestApplication;
|
||||
|
||||
let userRepositoryFixture: UserRepositoryFixture;
|
||||
let organizationsRepositoryFixture: OrganizationRepositoryFixture;
|
||||
|
||||
let teamsRepositoryFixture: TeamRepositoryFixture;
|
||||
let profileRepositoryFixture: ProfileRepositoryFixture;
|
||||
let routingFormsRepositoryFixture: RoutingFormsRepositoryFixture;
|
||||
let apiKeysRepositoryFixture: ApiKeysRepositoryFixture;
|
||||
let membershipsRepositoryFixture: MembershipRepositoryFixture;
|
||||
|
||||
let org: Team;
|
||||
let orgTeam: Team;
|
||||
|
||||
const authEmail = `organizations-teams-routing-forms-responses-user-${randomString()}@api.com`;
|
||||
let user: User;
|
||||
let apiKeyString: string;
|
||||
|
||||
let routingFormId: string;
|
||||
const routingFormResponses = [
|
||||
{
|
||||
id: 1,
|
||||
formFillerId: "cm78tvkvd0001kh8jq0tu5iq9",
|
||||
response: {
|
||||
"participant-field": {
|
||||
label: "participant",
|
||||
value: "mamut",
|
||||
},
|
||||
},
|
||||
createdAt: new Date("2025-02-17T09:03:18.121Z"),
|
||||
},
|
||||
];
|
||||
|
||||
beforeAll(async () => {
|
||||
const moduleRef = await Test.createTestingModule({
|
||||
imports: [AppModule, PrismaModule, UsersModule, TokensModule],
|
||||
}).compile();
|
||||
|
||||
userRepositoryFixture = new UserRepositoryFixture(moduleRef);
|
||||
organizationsRepositoryFixture = new OrganizationRepositoryFixture(moduleRef);
|
||||
teamsRepositoryFixture = new TeamRepositoryFixture(moduleRef);
|
||||
profileRepositoryFixture = new ProfileRepositoryFixture(moduleRef);
|
||||
routingFormsRepositoryFixture = new RoutingFormsRepositoryFixture(moduleRef);
|
||||
apiKeysRepositoryFixture = new ApiKeysRepositoryFixture(moduleRef);
|
||||
membershipsRepositoryFixture = new MembershipRepositoryFixture(moduleRef);
|
||||
|
||||
org = await organizationsRepositoryFixture.create({
|
||||
name: `organizations-teams-routing-forms-responses-organization-${randomString()}`,
|
||||
isOrganization: true,
|
||||
});
|
||||
|
||||
user = await userRepositoryFixture.create({
|
||||
email: authEmail,
|
||||
username: authEmail,
|
||||
});
|
||||
|
||||
const { keyString } = await apiKeysRepositoryFixture.createApiKey(user.id, null);
|
||||
apiKeyString = keyString;
|
||||
|
||||
orgTeam = await teamsRepositoryFixture.create({
|
||||
name: `organizations-teams-routing-forms-responses-team-${randomString()}`,
|
||||
isOrganization: false,
|
||||
parent: { connect: { id: org.id } },
|
||||
});
|
||||
|
||||
await membershipsRepositoryFixture.create({
|
||||
role: "ADMIN",
|
||||
user: { connect: { id: user.id } },
|
||||
team: { connect: { id: org.id } },
|
||||
});
|
||||
|
||||
await membershipsRepositoryFixture.create({
|
||||
role: "ADMIN",
|
||||
user: { connect: { id: user.id } },
|
||||
team: { connect: { id: orgTeam.id } },
|
||||
});
|
||||
|
||||
await profileRepositoryFixture.create({
|
||||
uid: `usr-${user.id}`,
|
||||
username: authEmail,
|
||||
organization: {
|
||||
connect: {
|
||||
id: org.id,
|
||||
},
|
||||
},
|
||||
user: {
|
||||
connect: {
|
||||
id: user.id,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const routingForm = await routingFormsRepositoryFixture.create({
|
||||
name: "Test Routing Form",
|
||||
description: null,
|
||||
position: 0,
|
||||
disabled: false,
|
||||
fields: JSON.stringify([
|
||||
{
|
||||
type: "text",
|
||||
label: "participant",
|
||||
required: true,
|
||||
},
|
||||
]),
|
||||
routes: JSON.stringify([
|
||||
{
|
||||
action: { type: "customPageMessage", value: "Thank you for your response" },
|
||||
},
|
||||
]),
|
||||
user: {
|
||||
connect: {
|
||||
id: user.id,
|
||||
},
|
||||
},
|
||||
team: {
|
||||
connect: {
|
||||
id: orgTeam.id,
|
||||
},
|
||||
},
|
||||
responses: {
|
||||
create: routingFormResponses,
|
||||
},
|
||||
});
|
||||
routingFormId = routingForm.id;
|
||||
|
||||
app = moduleRef.createNestApplication();
|
||||
bootstrap(app as NestExpressApplication);
|
||||
|
||||
await app.init();
|
||||
});
|
||||
|
||||
it("should not get routing form responses for non existing org", async () => {
|
||||
return request(app.getHttpServer())
|
||||
.get(`/v2/organizations/99999/teams/${orgTeam.id}/routing-forms/${routingFormId}/responses`)
|
||||
.expect(401);
|
||||
});
|
||||
|
||||
it("should not get routing form responses for non existing team", async () => {
|
||||
return request(app.getHttpServer())
|
||||
.get(`/v2/organizations/${org.id}/teams/99999/routing-forms/${routingFormId}/responses`)
|
||||
.expect(401);
|
||||
});
|
||||
|
||||
it("should not get routing form responses for non existing routing form", async () => {
|
||||
return request(app.getHttpServer())
|
||||
.get(`/v2/organizations/${org.id}/teams/${orgTeam.id}/routing-forms/99999/responses`)
|
||||
.expect(401);
|
||||
});
|
||||
|
||||
it("should get routing form responses", async () => {
|
||||
return request(app.getHttpServer())
|
||||
.get(`/v2/organizations/${org.id}/teams/${orgTeam.id}/routing-forms/${routingFormId}/responses`)
|
||||
.set({ Authorization: `Bearer cal_test_${apiKeyString}` })
|
||||
.expect(200)
|
||||
.then((response) => {
|
||||
const responseBody: GetRoutingFormResponsesOutput = response.body;
|
||||
expect(responseBody.status).toEqual(SUCCESS_STATUS);
|
||||
const responseData = responseBody.data;
|
||||
expect(responseData).toBeDefined();
|
||||
expect(responseData.length).toEqual(1);
|
||||
expect(responseData[0].id).toEqual(routingFormResponses[0].id);
|
||||
expect(responseData[0].response).toEqual(routingFormResponses[0].response);
|
||||
expect(responseData[0].formFillerId).toEqual(routingFormResponses[0].formFillerId);
|
||||
expect(responseData[0].createdAt).toEqual(routingFormResponses[0].createdAt.toISOString());
|
||||
});
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await userRepositoryFixture.deleteByEmail(user.email);
|
||||
await organizationsRepositoryFixture.delete(org.id);
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
import { API_VERSIONS_VALUES } from "@/lib/api-versions";
|
||||
import { PlatformPlan } from "@/modules/auth/decorators/billing/platform-plan.decorator";
|
||||
import { Roles } from "@/modules/auth/decorators/roles/roles.decorator";
|
||||
import { ApiAuthGuard } from "@/modules/auth/guards/api-auth/api-auth.guard";
|
||||
import { PlatformPlanGuard } from "@/modules/auth/guards/billing/platform-plan.guard";
|
||||
import { IsAdminAPIEnabledGuard } from "@/modules/auth/guards/organizations/is-admin-api-enabled.guard";
|
||||
import { IsOrgGuard } from "@/modules/auth/guards/organizations/is-org.guard";
|
||||
import { IsRoutingFormInTeam } from "@/modules/auth/guards/routing-forms/is-routing-form-in-team.guard";
|
||||
import { IsTeamInOrg } from "@/modules/auth/guards/teams/is-team-in-org.guard";
|
||||
import { Controller, Get, Param, UseGuards } from "@nestjs/common";
|
||||
import { ApiOperation, ApiTags } from "@nestjs/swagger";
|
||||
import { plainToClass } from "class-transformer";
|
||||
|
||||
import { SUCCESS_STATUS } from "@calcom/platform-constants";
|
||||
import { RoutingFormResponseOutput } from "@calcom/platform-types";
|
||||
|
||||
import { RoutingFormsResponsesService } from "../../../../routing-forms-responses/services/routing-forms-responses.service";
|
||||
import { GetRoutingFormResponsesOutput } from "../outputs/get-routing-form-responses.output";
|
||||
|
||||
@Controller({
|
||||
path: "/v2/organizations/:orgId/teams/:teamId/routing-forms/:routingFormId/responses",
|
||||
version: API_VERSIONS_VALUES,
|
||||
})
|
||||
@ApiTags("Orgs / Teams / Routing forms / Responses")
|
||||
@UseGuards(
|
||||
ApiAuthGuard,
|
||||
IsOrgGuard,
|
||||
IsTeamInOrg,
|
||||
IsRoutingFormInTeam,
|
||||
PlatformPlanGuard,
|
||||
IsAdminAPIEnabledGuard
|
||||
)
|
||||
export class OrganizationsTeamsRoutingFormsResponsesController {
|
||||
constructor(private readonly routingFormsResponsesService: RoutingFormsResponsesService) {}
|
||||
|
||||
@Get()
|
||||
@ApiOperation({ summary: "Get routing form responses" })
|
||||
@Roles("ORG_ADMIN")
|
||||
@PlatformPlan("ESSENTIALS")
|
||||
async getRoutingFormResponses(
|
||||
@Param("routingFormId") routingFormId: string
|
||||
): Promise<GetRoutingFormResponsesOutput> {
|
||||
const routingFormResponses = await this.routingFormsResponsesService.getRoutingFormResponses(
|
||||
routingFormId
|
||||
);
|
||||
|
||||
return {
|
||||
status: SUCCESS_STATUS,
|
||||
data: routingFormResponses,
|
||||
};
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import { OrganizationsRepository } from "@/modules/organizations/organizations.repository";
|
||||
import { OrganizationsTeamsRepository } from "@/modules/organizations/repositories/organizations-teams.repository";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { RedisModule } from "@/modules/redis/redis.module";
|
||||
import { RoutingFormsResponsesModule } from "@/modules/routing-forms-responses/routing-forms-responses.module";
|
||||
import { RoutingFormsModule } from "@/modules/routing-forms/routing-forms.module";
|
||||
import { StripeModule } from "@/modules/stripe/stripe.module";
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
import { OrganizationsTeamsRoutingFormsResponsesController } from "./controllers/organizations-teams-routing-forms-responses.controller";
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule, StripeModule, RedisModule, RoutingFormsResponsesModule, RoutingFormsModule],
|
||||
providers: [OrganizationsRepository, OrganizationsTeamsRepository],
|
||||
controllers: [OrganizationsTeamsRoutingFormsResponsesController],
|
||||
})
|
||||
export class OrganizationsTeamsRoutingFormsModule {}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import { ApiProperty } from "@nestjs/swagger";
|
||||
import { Expose, Type } from "class-transformer";
|
||||
import { IsEnum } from "class-validator";
|
||||
|
||||
import { SUCCESS_STATUS, ERROR_STATUS } from "@calcom/platform-constants";
|
||||
import { RoutingFormResponseOutput } from "@calcom/platform-types";
|
||||
|
||||
export class GetRoutingFormResponsesOutput {
|
||||
@ApiProperty({ example: SUCCESS_STATUS, enum: [SUCCESS_STATUS, ERROR_STATUS] })
|
||||
@IsEnum([SUCCESS_STATUS, ERROR_STATUS])
|
||||
status!: typeof SUCCESS_STATUS | typeof ERROR_STATUS;
|
||||
|
||||
@ApiProperty({ type: [RoutingFormResponseOutput] })
|
||||
@Expose()
|
||||
@Type(() => RoutingFormResponseOutput)
|
||||
data!: RoutingFormResponseOutput[];
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
import { OrganizationsRepository } from "@/modules/organizations/organizations.repository";
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { RoutingFormsResponsesRepository } from "@/modules/routing-forms-responses/routing-forms-responses.repository";
|
||||
import { RoutingFormsResponsesOutputService } from "@/modules/routing-forms-responses/services/routing-forms-responses-output.service";
|
||||
import { RoutingFormsResponsesService } from "@/modules/routing-forms-responses/services/routing-forms-responses.service";
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule],
|
||||
providers: [
|
||||
RoutingFormsResponsesService,
|
||||
RoutingFormsResponsesRepository,
|
||||
RoutingFormsResponsesOutputService,
|
||||
],
|
||||
exports: [
|
||||
RoutingFormsResponsesService,
|
||||
RoutingFormsResponsesRepository,
|
||||
RoutingFormsResponsesOutputService,
|
||||
],
|
||||
})
|
||||
export class RoutingFormsResponsesModule {}
|
||||
@@ -0,0 +1,18 @@
|
||||
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
@Injectable()
|
||||
export class RoutingFormsResponsesRepository {
|
||||
constructor(private readonly dbRead: PrismaReadService) {}
|
||||
|
||||
async getRoutingFormResponses(routingFormId: string) {
|
||||
return this.dbRead.prisma.app_RoutingForms_FormResponse.findMany({
|
||||
where: {
|
||||
formId: routingFormId,
|
||||
},
|
||||
orderBy: {
|
||||
createdAt: "desc",
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
import { Injectable } from "@nestjs/common";
|
||||
import { plainToClass } from "class-transformer";
|
||||
|
||||
import { RoutingFormResponseOutput, RoutingFormResponseResponseOutput } from "@calcom/platform-types";
|
||||
import { App_RoutingForms_FormResponse } from "@calcom/prisma/client";
|
||||
|
||||
@Injectable()
|
||||
export class RoutingFormsResponsesOutputService {
|
||||
getRoutingFormResponses(
|
||||
dbRoutingFormResponses: App_RoutingForms_FormResponse[]
|
||||
): RoutingFormResponseOutput[] {
|
||||
return dbRoutingFormResponses.map((response) => {
|
||||
const parsed = plainToClass(RoutingFormResponseOutput, response, { strategy: "excludeAll" });
|
||||
|
||||
// note(Lauris): I don't know why plainToClass(RoutingFormResponseOutput)
|
||||
// erases nested "response" object so parsing and attaching it manually
|
||||
const parsedResponse: Record<string, RoutingFormResponseResponseOutput> = {};
|
||||
const responseData = response.response || {};
|
||||
for (const [key, value] of Object.entries(responseData)) {
|
||||
parsedResponse[key] = plainToClass(RoutingFormResponseResponseOutput, value, {
|
||||
strategy: "excludeAll",
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
...parsed,
|
||||
response: parsedResponse,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
import { RoutingFormsResponsesOutputService } from "@/modules/routing-forms-responses/services/routing-forms-responses-output.service";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
import { RoutingFormsResponsesRepository } from "../routing-forms-responses.repository";
|
||||
|
||||
@Injectable()
|
||||
export class RoutingFormsResponsesService {
|
||||
constructor(
|
||||
private readonly routingFormsRepository: RoutingFormsResponsesRepository,
|
||||
private readonly routingFormsResponsesOutputService: RoutingFormsResponsesOutputService
|
||||
) {}
|
||||
|
||||
async getRoutingFormResponses(routingFormId: string) {
|
||||
const responses = await this.routingFormsRepository.getRoutingFormResponses(routingFormId);
|
||||
return this.routingFormsResponsesOutputService.getRoutingFormResponses(responses);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
import { PrismaModule } from "@/modules/prisma/prisma.module";
|
||||
import { RoutingFormsRepository } from "@/modules/routing-forms/routing-forms.repository";
|
||||
import { Module } from "@nestjs/common";
|
||||
|
||||
@Module({
|
||||
imports: [PrismaModule],
|
||||
providers: [RoutingFormsRepository],
|
||||
exports: [RoutingFormsRepository],
|
||||
})
|
||||
export class RoutingFormsModule {}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
|
||||
import { Injectable } from "@nestjs/common";
|
||||
|
||||
@Injectable()
|
||||
export class RoutingFormsRepository {
|
||||
constructor(private readonly dbRead: PrismaReadService) {}
|
||||
|
||||
async getTeamRoutingForm(teamId: number, routingFormId: string) {
|
||||
return this.dbRead.prisma.app_RoutingForms_Form.findFirst({
|
||||
where: {
|
||||
id: routingFormId,
|
||||
teamId,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -2557,6 +2557,37 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v2/organizations/{orgId}/teams/{teamId}/routing-forms/{routing}-formId/responses": {
|
||||
"get": {
|
||||
"operationId": "OrganizationsTeamsRoutingFormsResponsesController_getRoutingFormResponses",
|
||||
"summary": "Get routing form responses",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "routing-formId",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/GetRoutingFormResponsesOutput"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": [
|
||||
"Orgs / Teams / Routing forms / Responses"
|
||||
]
|
||||
}
|
||||
},
|
||||
"/v2/organizations/{orgId}/teams/{teamId}/users/{userId}/schedules": {
|
||||
"get": {
|
||||
"operationId": "OrganizationsTeamsSchedulesController_getUserSchedules",
|
||||
@@ -14323,6 +14354,67 @@
|
||||
"data"
|
||||
]
|
||||
},
|
||||
"RoutingFormResponseOutput": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"formId": {
|
||||
"type": "string"
|
||||
},
|
||||
"formFillerId": {
|
||||
"type": "string"
|
||||
},
|
||||
"routedToBookingUid": {
|
||||
"type": "string"
|
||||
},
|
||||
"response": {
|
||||
"type": "object",
|
||||
"example": {
|
||||
"f00b26df-f54b-4985-8d98-17c5482c6a24": {
|
||||
"label": "participant",
|
||||
"value": "mamut"
|
||||
}
|
||||
}
|
||||
},
|
||||
"createdAt": {
|
||||
"format": "date-time",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"id",
|
||||
"formId",
|
||||
"formFillerId",
|
||||
"routedToBookingUid",
|
||||
"response",
|
||||
"createdAt"
|
||||
]
|
||||
},
|
||||
"GetRoutingFormResponsesOutput": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"example": "success",
|
||||
"enum": [
|
||||
"success",
|
||||
"error"
|
||||
]
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/RoutingFormResponseOutput"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"status",
|
||||
"data"
|
||||
]
|
||||
},
|
||||
"ProviderVerifyClientData": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import { PrismaReadService } from "@/modules/prisma/prisma-read.service";
|
||||
import { PrismaWriteService } from "@/modules/prisma/prisma-write.service";
|
||||
import { TestingModule } from "@nestjs/testing";
|
||||
import { Prisma, App_RoutingForms_Form } from "@prisma/client";
|
||||
|
||||
export class RoutingFormsRepositoryFixture {
|
||||
private prismaReadClient: PrismaReadService["prisma"];
|
||||
private prismaWriteClient: PrismaWriteService["prisma"];
|
||||
|
||||
constructor(private readonly module: TestingModule) {
|
||||
this.prismaReadClient = module.get(PrismaReadService).prisma;
|
||||
this.prismaWriteClient = module.get(PrismaWriteService).prisma;
|
||||
}
|
||||
|
||||
async get(routingFormId: App_RoutingForms_Form["id"]) {
|
||||
return this.prismaReadClient.app_RoutingForms_Form.findUnique({ where: { id: routingFormId } });
|
||||
}
|
||||
|
||||
async create(data: Prisma.App_RoutingForms_FormCreateInput) {
|
||||
return this.prismaWriteClient.app_RoutingForms_Form.create({ data });
|
||||
}
|
||||
|
||||
async delete(routingFormId: App_RoutingForms_Form["id"]) {
|
||||
return this.prismaWriteClient.app_RoutingForms_Form.delete({ where: { id: routingFormId } });
|
||||
}
|
||||
}
|
||||
@@ -2422,6 +2422,35 @@
|
||||
"tags": ["Orgs / Teams / Memberships"]
|
||||
}
|
||||
},
|
||||
"/v2/organizations/{orgId}/teams/{teamId}/routing-forms/{routing}-formId/responses": {
|
||||
"get": {
|
||||
"operationId": "OrganizationsTeamsRoutingFormsResponsesController_getRoutingFormResponses",
|
||||
"summary": "Get routing form responses",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "routing-formId",
|
||||
"required": true,
|
||||
"in": "path",
|
||||
"schema": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"description": "",
|
||||
"content": {
|
||||
"application/json": {
|
||||
"schema": {
|
||||
"$ref": "#/components/schemas/GetRoutingFormResponsesOutput"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tags": ["Orgs / Teams / Routing forms / Responses"]
|
||||
}
|
||||
},
|
||||
"/v2/organizations/{orgId}/teams/{teamId}/users/{userId}/schedules": {
|
||||
"get": {
|
||||
"operationId": "OrganizationsTeamsSchedulesController_getUserSchedules",
|
||||
@@ -12917,6 +12946,54 @@
|
||||
},
|
||||
"required": ["status", "data"]
|
||||
},
|
||||
"RoutingFormResponseOutput": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"id": {
|
||||
"type": "string"
|
||||
},
|
||||
"formId": {
|
||||
"type": "string"
|
||||
},
|
||||
"formFillerId": {
|
||||
"type": "string"
|
||||
},
|
||||
"routedToBookingUid": {
|
||||
"type": "string"
|
||||
},
|
||||
"response": {
|
||||
"type": "object",
|
||||
"example": {
|
||||
"f00b26df-f54b-4985-8d98-17c5482c6a24": {
|
||||
"label": "participant",
|
||||
"value": "mamut"
|
||||
}
|
||||
}
|
||||
},
|
||||
"createdAt": {
|
||||
"format": "date-time",
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"required": ["id", "formId", "formFillerId", "routedToBookingUid", "response", "createdAt"]
|
||||
},
|
||||
"GetRoutingFormResponsesOutput": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"status": {
|
||||
"type": "string",
|
||||
"example": "success",
|
||||
"enum": ["success", "error"]
|
||||
},
|
||||
"data": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/components/schemas/RoutingFormResponseOutput"
|
||||
}
|
||||
}
|
||||
},
|
||||
"required": ["status", "data"]
|
||||
},
|
||||
"ProviderVerifyClientData": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
@@ -13856,6 +13933,10 @@
|
||||
"key": "value"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"type": "number",
|
||||
"example": 4
|
||||
},
|
||||
"attendees": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -13996,6 +14077,10 @@
|
||||
"key": "value"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"type": "number",
|
||||
"example": 4
|
||||
},
|
||||
"attendees": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -14232,6 +14317,10 @@
|
||||
"key": "value"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"type": "number",
|
||||
"example": 4
|
||||
},
|
||||
"seatUid": {
|
||||
"type": "string",
|
||||
"example": "3be561a9-31f1-4b8e-aefc-9d9a085f0dd1"
|
||||
@@ -14362,6 +14451,10 @@
|
||||
"key": "value"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"type": "number",
|
||||
"example": 4
|
||||
},
|
||||
"seatUid": {
|
||||
"type": "string",
|
||||
"example": "3be561a9-31f1-4b8e-aefc-9d9a085f0dd1"
|
||||
@@ -14531,6 +14624,10 @@
|
||||
"key": "value"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"type": "number",
|
||||
"example": 4
|
||||
},
|
||||
"attendees": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
@@ -14656,6 +14753,10 @@
|
||||
"key": "value"
|
||||
}
|
||||
},
|
||||
"rating": {
|
||||
"type": "number",
|
||||
"example": 4
|
||||
},
|
||||
"attendees": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
||||
@@ -10,3 +10,4 @@ export * from "./event-types";
|
||||
export * from "./organizations";
|
||||
export * from "./teams";
|
||||
export * from "./embed";
|
||||
export * from "./routing-forms";
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./responses";
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./routing-form-response.output";
|
||||
@@ -0,0 +1,54 @@
|
||||
import { ApiProperty, ApiPropertyOptional } from "@nestjs/swagger";
|
||||
import { Expose } from "class-transformer";
|
||||
import { IsDate, IsInt, IsString, IsObject } from "class-validator";
|
||||
|
||||
export class RoutingFormResponseResponseOutput {
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@Expose()
|
||||
label!: string;
|
||||
|
||||
@ApiPropertyOptional()
|
||||
@IsString()
|
||||
@Expose()
|
||||
identifier?: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@Expose()
|
||||
value!: string | number | string[];
|
||||
}
|
||||
|
||||
export class RoutingFormResponseOutput {
|
||||
@ApiProperty()
|
||||
@IsInt()
|
||||
@Expose()
|
||||
id!: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsInt()
|
||||
@Expose()
|
||||
formId!: string;
|
||||
|
||||
@ApiProperty()
|
||||
@IsString()
|
||||
@Expose()
|
||||
formFillerId!: string;
|
||||
|
||||
@ApiProperty()
|
||||
@Expose()
|
||||
@IsString()
|
||||
routedToBookingUid!: string;
|
||||
|
||||
@ApiProperty({
|
||||
example: { "f00b26df-f54b-4985-8d98-17c5482c6a24": { label: "participant", value: "mamut" } },
|
||||
})
|
||||
@IsObject()
|
||||
@Expose()
|
||||
response!: Record<string, RoutingFormResponseResponseOutput>;
|
||||
|
||||
@ApiProperty()
|
||||
@Expose()
|
||||
@IsDate()
|
||||
createdAt!: Date;
|
||||
}
|
||||
Reference in New Issue
Block a user