123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453 |
- // db
- import { selPool, updPool } from "#db";
- import { DbSchema } from "#db-schema";
- import { sql } from "slonik";
- // api
- import { api } from "#api";
- // other
- import { z } from "zod";
- import { RouterUtils } from "#utils/router-utils.js";
- import { Request, Response } from "express";
- import sessionService from "#modules/users/auth/services/session-service.js";
- import { apiTypes } from "#api/current-api.js";
- import {
- addDataToValidator,
- validateAct,
- } from "./validators/act-validators.js";
- import {
- CustomFieldWithUserCopyValue,
- CustomFieldWithValidators,
- } from "#api/v_0.1.0/types/custom-fields-types.js";
- import { ApiError } from "#exceptions/api-error.js";
- import { cCustomFieldsValidateService } from "../custom-fields/c-cf-validate-service.js";
- import { v7 } from "uuid";
- class ClientActivitiesController {
- async getEventActivities(
- req: Request,
- res: Response,
- // next: NextFunction
- ) {
- const event = await sessionService.getCurrentEventFromReq(req);
- const categories = await selPool.any(sql.type(
- apiTypes.activities.ActCategory,
- )`
- select
- c.category_id "categoryId" ,
- c.code,
- c."name",
- c.parent_id "parentId",
- p.code "parentCode"
- from
- act.activity_categories c
- left join act.activity_categories p
- on c.parent_id = p.category_id
- where
- c.event_inst_id = ${event.eventInstId}
- and c.parent_id is null
- `);
- const activities = await selPool.any(sql.type(
- z.object({
- activityId: DbSchema.act.activities.activityId,
- code: DbSchema.act.activities.code,
- publicName: DbSchema.act.activities.publicName,
- eventInstId: DbSchema.act.activities.eventInstId,
- categoryId: DbSchema.act.activities.categoryId,
- categoryCode: DbSchema.act.activityCategories.code,
- blockId: DbSchema.act.activities.blockId,
- validators: z.array(apiTypes.activities.ActValidator),
- peTypes: z.array(
- z.object({
- peTypeId: DbSchema.act.peTypes.peTypeId,
- code: DbSchema.act.peTypes.code,
- name: DbSchema.act.peTypes.name,
- }),
- ),
- }),
- )`
- select
- a.activity_id "activityId",
- a.code,
- a.public_name "publicName",
- a.event_inst_id "eventInstId",
- a.category_id "categoryId",
- a.category_code "categoryCode",
- a.block_id "blockId",
- a.validators,
- a.pe_types "peTypes"
- from
- act.act_with_validators a
- where
- a.event_inst_id = ${event.eventInstId}
- and a.category_id is null
- `);
- const activitiesWithValidatorsData = await Promise.all(
- activities.map(async (activity) => {
- return {
- ...activity,
- validators: await Promise.all(
- activity.validators.map(async (validator) =>
- addDataToValidator(validator, activity.activityId),
- ),
- ),
- };
- }),
- );
- RouterUtils.validAndSendResponse(
- api.client.activities.GET_EventActivities.res,
- res,
- {
- code: "success",
- categories: [...categories],
- activities: [...activitiesWithValidatorsData],
- },
- );
- }
- async getCategory(req: Request, res: Response) {
- const { categoryCode } =
- api.client.activities.GET_Category.req.params.parse(req.params);
- const categories = await selPool.any(sql.type(
- apiTypes.activities.ActCategory,
- )`
- select
- c.category_id "categoryId" ,
- c.code,
- c."name",
- c.parent_id "parentId",
- p.code "parentCode"
- from
- act.activity_categories c
- left join act.activity_categories p
- on c.parent_id = p.category_id
- where
- p.code = ${categoryCode}
- `);
- const activities = await selPool.any(sql.type(
- z.object({
- activityId: DbSchema.act.activities.activityId,
- code: DbSchema.act.activities.code,
- publicName: DbSchema.act.activities.publicName,
- eventInstId: DbSchema.act.activities.eventInstId,
- categoryId: DbSchema.act.activities.categoryId,
- categoryCode: DbSchema.act.activityCategories.code,
- blockId: DbSchema.act.activities.blockId,
- validators: z.array(apiTypes.activities.ActValidator),
- peTypes: z.array(
- z.object({
- peTypeId: DbSchema.act.peTypes.peTypeId,
- code: DbSchema.act.peTypes.code,
- name: DbSchema.act.peTypes.name,
- }),
- ),
- }),
- )`
- select
- a.activity_id "activityId",
- a.code,
- a.public_name "publicName",
- a.event_inst_id "eventInstId",
- a.category_id "categoryId",
- a.category_code "categoryCode",
- a.block_id "blockId",
- a.validators,
- a.pe_types "peTypes"
- from
- act.act_with_validators a
- where
- a.category_code = ${categoryCode}
- `);
- const activitiesWithValidatorsData = await Promise.all(
- activities.map(async (activity) => {
- return {
- ...activity,
- validators: await Promise.all(
- activity.validators.map(async (validator) =>
- addDataToValidator(validator, activity.activityId),
- ),
- ),
- };
- }),
- );
- RouterUtils.validAndSendResponse(
- api.client.activities.GET_Category.res,
- res,
- {
- code: "success",
- categories: [...categories],
- activities: [...activitiesWithValidatorsData],
- },
- );
- }
- async getActRegData(req: Request, res: Response) {
- const event = await sessionService.getCurrentEventFromReq(req);
- const user = sessionService.getUserFromReq(req);
- const { activityCode } =
- api.client.activities.GET_ActRegData.req.params.parse(req.params);
- const actRegData = await selPool.maybeOne(sql.type(
- z.object({
- activityId: DbSchema.act.activities.activityId,
- code: DbSchema.act.activities.code,
- publicName: DbSchema.act.activities.publicName,
- eventInstId: DbSchema.act.activities.eventInstId,
- categoryId: DbSchema.act.activities.categoryId,
- categoryCode: DbSchema.act.activityCategories.code,
- validators: z.array(apiTypes.activities.ActValidator),
- peTypes: z.array(
- z.object({
- peTypeId: DbSchema.act.peTypes.peTypeId,
- code: DbSchema.act.peTypes.code,
- name: DbSchema.act.peTypes.name,
- }),
- ),
- fields: z.array(
- CustomFieldWithUserCopyValue.extend({ arffId: z.string() }),
- ),
- }),
- )`
- select
- a.activity_id "activityId",
- a.code,
- a.public_name "publicName",
- a.event_inst_id "eventInstId",
- a.category_id "categoryId",
- a.category_code "categoryCode",
- a.validators,
- a.pe_types "peTypes",
- coalesce(f.fields, '[]'::jsonb) "fields"
- from
- act.act_with_validators a
- left join lateral (
- select
- jsonb_agg(jsonb_build_object(
- 'fieldDefinitionId', f.field_definition_id,
- 'arffId', af.arff_id,
- 'isCopyUserValue', af.is_copy_user_value,
- 'code', f.code,
- 'userCopyValue', ufwv.value,
- 'fieldTypeCode', f.field_type_code,
- 'title', COALESCE(af.field_title_override, f.title),
- 'mask', f.mask,
- 'options', f."options",
- 'validators', f.validators
- )) as fields
- from
- act.activity_reg_form_fields af
- left join cf.custom_fields_with_validators f on
- f.field_definition_id = af.field_definition_id
- -- значение из профиля юзера
- left join ev.user_fields_with_values ufwv on
- af.field_definition_id = ufwv.field_definition_id
- and ufwv.user_id = ${user.userId}
- and ufwv.event_id = ${event.eventId}
- and ufwv.value is not null
- -- только если нужно копировать
- and af.is_copy_user_value = true
- where
- af.activity_id = a.activity_id
- ) f on true
- where a.code = ${activityCode}
- `);
- // TODO: заменить все BadRequest
- if (!actRegData)
- throw ApiError.BadRequest(
- "actRegDataNotFound",
- "Данные для регистрации на мероприятии не найдены",
- );
- RouterUtils.validAndSendResponse(
- api.client.activities.GET_ActRegData.res,
- res,
- {
- code: "success",
- actRegData: actRegData,
- },
- );
- }
- async registerPe(req: Request, res: Response) {
- const { fields, peId } =
- api.client.activities.POST_RegisterPe.req.body.parse(
- JSON.parse(req.body.body),
- );
- const { activityCode } =
- api.client.activities.POST_RegisterPe.req.params.parse(req.params);
- const files = req.files;
- const actRegData = await selPool.maybeOne(sql.type(
- z.object({
- activityId: DbSchema.act.activities.activityId,
- validators: z.array(apiTypes.activities.ActValidator),
- peTypes: z.array(
- z.object({
- peTypeId: DbSchema.act.peTypes.peTypeId,
- code: DbSchema.act.peTypes.code,
- name: DbSchema.act.peTypes.name,
- }),
- ),
- fields: z.array(
- CustomFieldWithValidators.extend({ arffId: z.string() }),
- ),
- }),
- )`
- select
- a.activity_id "activityId",
- a.validators,
- a.pe_types "peTypes",
- coalesce(f.fields, '[]'::jsonb) "fields"
- from
- act.act_with_validators a
- left join lateral (
- select
- jsonb_agg(jsonb_build_object(
- 'fieldDefinitionId', f.field_definition_id,
- 'arffId', af.arff_id,
- 'isCopyUserValue', af.is_copy_user_value,
- 'code', f.code,
- 'fieldTypeCode', f.field_type_code,
- 'title', COALESCE(af.field_title_override, f.title),
- 'mask', f.mask,
- 'options', f."options",
- 'validators', f.validators
- )) as fields
- from
- act.activity_reg_form_fields af
- left join cf.custom_fields_with_validators f on
- f.field_definition_id = af.field_definition_id
- where
- af.activity_id = a.activity_id
- ) f on true
- where a.code = ${activityCode}
- `);
- if (!actRegData)
- throw ApiError.BadRequest(
- "actRegDataNotFound",
- "Данные для регистрации на мероприятии не найдены",
- );
- const validators = await Promise.all(
- actRegData.validators.map(
- async (validator) =>
- await addDataToValidator(validator, actRegData.activityId),
- ),
- );
- // валидация типа pe
- const peTypeCode = await selPool.maybeOneFirst(sql.type(
- z.object({
- code: z.string(),
- }),
- )`
- select
- pt.code
- from
- act.part_entities p
- left join act.pe_types pt on
- p.pe_type_id = pt.pe_type_id
- where
- p.pe_id = ${peId}
- `);
- if (!peTypeCode)
- throw ApiError.BadRequest(
- "peTypeNotFound",
- "Тип сущности участия не найден",
- );
- const isPeTypeValid = actRegData.peTypes.find((t) => t.code === peTypeCode);
- if (!isPeTypeValid)
- throw ApiError.BadRequest(
- "peTypeNotFound",
- `Тип сущности участия ${peTypeCode} не подходит к мероприятию ${activityCode}. Нужны ${actRegData.peTypes.map((v) => v.code).join(", ")}`,
- );
- //
- //
- // валидация активности
- const actValidators = validators.filter(
- (validator) => !validator.isPeValidator,
- );
- for (const validator of actValidators) {
- const result = validateAct(validator);
- if (!result.isValid) {
- throw ApiError.BadRequest("actValidatorFailed", result.message);
- }
- }
- //
- //
- // валидация формы
- const refFields = actRegData.fields.map((f) => ({
- ...f,
- idKey: "arffId",
- }));
- const validationResult =
- await cCustomFieldsValidateService.processAndValidateFields({
- inputFields: fields,
- referenceFields: refFields,
- files,
- idKey: "arffId",
- addOldValue: false,
- });
- if (!validationResult.isValid)
- throw ApiError.BadRequest(
- "fieldsValidationFailed",
- JSON.stringify(validationResult.messages),
- );
- const validatedFields = validationResult.checkedfields;
- //
- //
- // вставляем в базу и сохраняем файлы
- const activityRegId = v7();
- await updPool.transaction(async (tr) => {
- tr.query(sql.unsafe`
- insert into act.activity_regs
- (activity_reg_id, activity_id, pe_id)
- values
- (${activityRegId}, ${actRegData.activityId}, ${peId})
- `);
- await cCustomFieldsValidateService.saveCustomFieldValuesInTransaction({
- tr,
- parentId: activityRegId,
- action: "activityPeReg",
- inputFields: validatedFields,
- files,
- isDeleteBefore: false,
- });
- // TODO: отправка уведомления
- });
- RouterUtils.validAndSendResponse(
- api.client.activities.POST_RegisterPe.res,
- res,
- {
- code: "success",
- activityRegId,
- },
- );
- }
- }
- export const clientActController = new ClientActivitiesController();
|