c-pe-controller.ts 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. // db
  2. import { selPool, updPool } from "#db";
  3. import { DbSchema } from "#db-schema";
  4. import { sql } from "slonik";
  5. // api
  6. import { api } from "#api";
  7. // other
  8. import { z } from "zod";
  9. import { RouterUtils } from "#utils/router-utils.js";
  10. import { Request, Response } from "express";
  11. import sessionService from "#modules/users/auth/services/session-service.js";
  12. import { CustomFieldWithUserCopyValue } from "#api/v_0.1.0/types/pe-types.js";
  13. import { ApiError } from "#exceptions/api-error.js";
  14. import { v7 } from "uuid";
  15. class ClientPeController {
  16. async getEventPeTypes(
  17. req: Request,
  18. res: Response,
  19. // next: NextFunction
  20. ) {
  21. const event = await sessionService.getCurrentEventFromReq(req);
  22. const peTypes = await selPool.any(sql.type(
  23. z.object({
  24. peTypeId: DbSchema.act.peTypes.peTypeId,
  25. code: DbSchema.act.peTypes.code,
  26. name: DbSchema.act.peTypes.name,
  27. }),
  28. )`
  29. select
  30. pe_type_id as "peTypeId",
  31. code,
  32. "name"
  33. from
  34. act.pe_types pt
  35. where
  36. pt.event_inst_id = ${event.eventInstId}
  37. `);
  38. RouterUtils.validAndSendResponse(api.client.pe.GET_EventPeTypes.res, res, {
  39. code: "success",
  40. peTypes: [...peTypes],
  41. });
  42. }
  43. async getPeTypeForCreate(
  44. req: Request,
  45. res: Response,
  46. // next: NextFunction
  47. ) {
  48. const event = await sessionService.getCurrentEventFromReq(req);
  49. const user = sessionService.getUserFromReq(req);
  50. const { peTypeCode } = api.client.pe.GET_PeType.req.parse(req.params);
  51. const eventId = event.eventId;
  52. const userId = user.userId;
  53. const peType = await selPool.maybeOne(sql.type(
  54. z.object({
  55. peTypeId: z.string(),
  56. code: z.string(),
  57. name: z.string(),
  58. eventInstId: z.string(),
  59. fields: z.array(
  60. CustomFieldWithUserCopyValue.extend({ isCopyUserValue: z.boolean() }),
  61. ),
  62. }),
  63. )`
  64. select
  65. pt.pe_type_id as "peTypeId",
  66. pt.code,
  67. pt.name,
  68. pt.event_inst_id as "eventInstId",
  69. coalesce(json_agg(jsonb_build_object(
  70. 'fieldDefinitionId',
  71. cfwv.field_definition_id,
  72. 'peFfId',
  73. pff.pe_ff_id,
  74. 'isCopyUserValue',
  75. pff.is_copy_user_value,
  76. 'code',
  77. cfwv.code,
  78. 'userCopyValue',
  79. ufwv.value,
  80. 'fieldTypeCode',
  81. cfwv.field_type_code,
  82. 'title',
  83. COALESCE(pff.field_title_override, cfwv.title),
  84. 'mask',
  85. cfwv.mask,
  86. 'options',
  87. cfwv.options,
  88. 'validators',
  89. cfwv.validators)) filter (
  90. where
  91. cfwv.field_definition_id is not null),
  92. '[]'::json) as fields
  93. from
  94. act.pe_types pt
  95. -- необходимые поля
  96. left join act.pe_form_fields pff on
  97. pff.pe_type_id = pt.pe_type_id
  98. -- значение из профиля юзера
  99. left join ev.user_fields_with_values ufwv on
  100. pff.field_definition_id = ufwv.field_definition_id
  101. and ufwv.user_id = ${userId}
  102. and ufwv.event_id = ${eventId}
  103. and ufwv.value is not null
  104. -- только если нужно копировать
  105. and pff.is_copy_user_value = true
  106. left join cf.custom_fields_with_validators cfwv on
  107. pff.field_definition_id = cfwv.field_definition_id
  108. where
  109. pt.code = ${peTypeCode}
  110. group by
  111. pt.pe_type_id,
  112. pt.code,
  113. pt.name,
  114. pt.event_inst_id
  115. `);
  116. if (!peType)
  117. throw ApiError.BadRequest(
  118. "peTypeNotFound",
  119. "Тип сущности участия не найден",
  120. );
  121. RouterUtils.validAndSendResponse(api.client.pe.GET_PeType.res, res, {
  122. code: "success",
  123. peType: peType,
  124. });
  125. }
  126. async createPeType(req: Request, res: Response) {
  127. const event = await sessionService.getCurrentEventFromReq(req);
  128. const user = sessionService.getUserFromReq(req);
  129. const { form, peTypeId } = api.client.pe.POST_PartEntity.req.parse(
  130. req.body,
  131. );
  132. await updPool.transaction(async (t) => {
  133. const peId = v7();
  134. await t.query(sql.unsafe`
  135. insert into act.part_entities
  136. (pe_id, pe_type_id, event_inst_id, owner_id)
  137. values
  138. (${peId}, ${peTypeId}, ${event.eventInstId}, ${user.userId})
  139. `);
  140. for (const field of form) {
  141. await t.query(sql.unsafe`
  142. insert into act.pe_field_values
  143. (pe_ff_id, pe_id, value)
  144. values
  145. (${field.peFfId}, ${peId}, ${field.value})
  146. `);
  147. }
  148. RouterUtils.validAndSendResponse(api.client.pe.POST_PartEntity.res, res, {
  149. code: "success",
  150. peId,
  151. });
  152. });
  153. }
  154. async getOwnerPe(req: Request, res: Response) {
  155. const user = sessionService.getUserFromReq(req);
  156. const { peId } = api.client.pe.GET_OwnerPartEntity.req.parse(req.body);
  157. // TODO: заменить типы бд
  158. const pe = await selPool.maybeOne(sql.type(
  159. z.object({
  160. peTypeId: z.string().uuid(),
  161. code: z.string(),
  162. name: z.string(),
  163. eventInstId: z.string().uuid(),
  164. ownerId: z.string().uuid(),
  165. fields: z.array(
  166. CustomFieldWithUserCopyValue.extend({ isCopyUserValue: z.boolean() }),
  167. ),
  168. }),
  169. )`
  170. select
  171. pt.pe_type_id as "peTypeId",
  172. pt.code,
  173. pt.name,
  174. pt.event_inst_id as "eventInstId",
  175. pe.owner_id as "ownerId",
  176. coalesce(json_agg(jsonb_build_object(
  177. 'fieldDefinitionId',
  178. cfwv.field_definition_id,
  179. 'peFfId',
  180. pff.pe_ff_id,
  181. 'isCopyUserValue',
  182. pff.is_copy_user_value,
  183. 'code',
  184. cfwv.code,
  185. 'value',
  186. pfv.value,
  187. 'fieldTypeCode',
  188. cfwv.field_type_code,
  189. 'title',
  190. COALESCE(pff.field_title_override, cfwv.title),
  191. 'mask',
  192. cfwv.mask,
  193. 'options',
  194. cfwv.options,
  195. 'validators',
  196. cfwv.validators)) filter (
  197. where
  198. cfwv.field_definition_id is not null),
  199. '[]'::json) as fields
  200. from
  201. act.part_entities pe
  202. join act.pe_types pt on
  203. pt.pe_type_id = pe.pe_type_id
  204. -- необходимые поля
  205. left join act.pe_form_fields pff on
  206. pff.pe_type_id = pt.pe_type_id
  207. -- значения
  208. left join act.pe_field_values pfv on
  209. pff.pe_ff_id = pfv.pe_ff_id
  210. and
  211. pff.pe_type_id = pt.pe_type_id
  212. left join cf.custom_fields_with_validators cfwv on
  213. pff.field_definition_id = cfwv.field_definition_id
  214. where pe.pe_id = ${peId}
  215. group by
  216. pt.pe_type_id,
  217. pt.code,
  218. pt.name,
  219. pt.event_inst_id,
  220. pe.owner_id
  221. `);
  222. if (!pe)
  223. throw ApiError.BadRequest("peNotFound", "Сущность участия не найдена");
  224. RouterUtils.validAndSendResponse(
  225. api.client.pe.GET_OwnerPartEntity.res,
  226. res,
  227. {
  228. code: "success",
  229. pe: pe,
  230. },
  231. );
  232. }
  233. }
  234. export const clientPeController = new ClientPeController();