c-pe-controller.ts 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842
  1. // db
  2. import { selPool, updPool } from "#db";
  3. import { DbSchema } from "#db-schema";
  4. import { sql } from "slonik";
  5. // api
  6. import { api, apiTypes } 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 { ApiError } from "#exceptions/api-error.js";
  13. import { v4, v7 } from "uuid";
  14. import { cPeService } from "./c-pe-service.js";
  15. import { cCustomFieldsValidateService } from "#modules/client/custom-fields/c-cf-validate-service.js";
  16. import dayjs from "dayjs";
  17. import { cActService } from "../c-act-service.js";
  18. class ClientPeController {
  19. async getEventPeTypes(
  20. req: Request,
  21. res: Response,
  22. // next: NextFunction
  23. ) {
  24. const event = await sessionService.getCurrentEventFromReq(req);
  25. const peTypes = await selPool.any(sql.type(
  26. z.object({
  27. peTypeId: DbSchema.act.peTypes.peTypeId,
  28. code: DbSchema.act.peTypes.code,
  29. name: DbSchema.act.peTypes.name,
  30. }),
  31. )`
  32. select
  33. pe_type_id as "peTypeId",
  34. code,
  35. "name"
  36. from
  37. act.pe_types pt
  38. where
  39. pt.event_inst_id = ${event.eventInstId}
  40. `);
  41. RouterUtils.validAndSendResponse(api.client.pe.GET_EventPeTypes.res, res, {
  42. code: "success",
  43. peTypes: [...peTypes],
  44. });
  45. }
  46. async getPeTypeForCreate(
  47. req: Request,
  48. res: Response,
  49. // next: NextFunction
  50. ) {
  51. const event = await sessionService.getCurrentEventFromReq(req);
  52. const user = sessionService.getUserFromReq(req);
  53. const { peTypeCode } = api.client.pe.GET_PeType.req.parse(req.params);
  54. const eventId = event.eventId;
  55. const userId = user.userId;
  56. const peType = await cPeService.getPeTypeWithFieldsAndUserCopyValues(
  57. userId,
  58. peTypeCode,
  59. eventId,
  60. );
  61. if (!peType)
  62. throw ApiError.BadRequest(
  63. "peTypeNotFound",
  64. "Тип сущности участия не найден",
  65. );
  66. RouterUtils.validAndSendResponse(api.client.pe.GET_PeType.res, res, {
  67. code: "success",
  68. peType: peType,
  69. });
  70. }
  71. async createPe(req: Request, res: Response) {
  72. const event = await sessionService.getCurrentEventFromReq(req);
  73. const user = sessionService.getUserFromReq(req);
  74. const { fields, peTypeCode, name } =
  75. api.client.pe.POST_PartEntity.req.formData.body.parse(
  76. JSON.parse(req.body.body),
  77. );
  78. const files = req.files;
  79. const peType = await cPeService.getPeTypeWithFields(peTypeCode);
  80. if (!peType)
  81. throw ApiError.BadRequest(
  82. "peTypeNotFound",
  83. "Тип сущности участия не найден",
  84. );
  85. const refFields = peType.fields.map((f) => ({
  86. ...f,
  87. idKey: "peFfId",
  88. }));
  89. // валидация
  90. const validationResult =
  91. await cCustomFieldsValidateService.processAndValidateFields({
  92. inputFields: fields,
  93. referenceFields: refFields,
  94. files,
  95. idKey: "peFfId",
  96. addOldValue: false,
  97. });
  98. if (!validationResult.isValid)
  99. throw ApiError.BadRequest(
  100. "fieldsValidationFailed",
  101. JSON.stringify(validationResult.messages),
  102. );
  103. const validatedFields = validationResult.checkedfields;
  104. //
  105. //
  106. // вставляем в базу и сохраняем файлы
  107. const peId = v7();
  108. await updPool.transaction(async (tr) => {
  109. await tr.query(sql.unsafe`
  110. insert into act.part_entities
  111. (pe_id, pe_type_id, event_inst_id, owner_id, name)
  112. values
  113. (${peId}, ${peType.peTypeId}, ${event.eventInstId}, ${user.userId}, ${name})
  114. `);
  115. if (peType.isJoinAfterCreate) {
  116. await tr.query(sql.unsafe`
  117. insert into act.pe_members
  118. (pe_member_id, pe_id, user_id)
  119. values
  120. (${v7()}, ${peId}, ${user.userId})
  121. `);
  122. }
  123. await cCustomFieldsValidateService.saveCustomFieldValuesInTransaction({
  124. tr,
  125. parentId: peId,
  126. action: "peCreate",
  127. inputFields: validatedFields,
  128. files,
  129. isDeleteBefore: false,
  130. });
  131. });
  132. RouterUtils.validAndSendResponse(api.client.pe.POST_PartEntity.res, res, {
  133. code: "success",
  134. peId,
  135. });
  136. }
  137. async getPeForPatch(req: Request, res: Response) {
  138. const { peId } = api.client.pe.GET_PeForPatch.req.parse(req.params);
  139. const user = sessionService.getUserFromReq(req);
  140. const pe = await cPeService.getPeWithValidatorsAndValues(peId);
  141. if (!pe)
  142. throw ApiError.BadRequest("peNotFound", "Сущность участия не найдена");
  143. if (pe.ownerId !== user.userId) throw ApiError.ForbiddenError();
  144. RouterUtils.validAndSendResponse(api.client.pe.GET_PeForPatch.res, res, {
  145. code: "success",
  146. pe: pe,
  147. });
  148. }
  149. async patchPe(req: Request, res: Response) {
  150. const { peId } = api.client.pe.PATCH_PartEntity.req.params.parse(
  151. req.params,
  152. );
  153. const { name, fields } =
  154. api.client.pe.PATCH_PartEntity.req.formData.body.parse(
  155. JSON.parse(req.body.body),
  156. );
  157. const files = req.files;
  158. const user = sessionService.getUserFromReq(req);
  159. const peType = await cPeService.getPeWithValidatorsAndValues(peId);
  160. if (!peType)
  161. throw ApiError.BadRequest(
  162. "peTypeNotFound",
  163. "Тип сущности участия не найден",
  164. );
  165. // проверка доступа
  166. if (peType.ownerId !== user.userId) throw ApiError.ForbiddenError();
  167. const refFields = peType.fields
  168. .map((f) => ({
  169. ...f,
  170. idKey: "peFfId",
  171. }))
  172. // только изменяемые
  173. .filter((f) => fields.some((ff) => ff.peFfId === f.peFfId));
  174. // валидация
  175. const validationResult =
  176. await cCustomFieldsValidateService.processAndValidateFields({
  177. inputFields: fields,
  178. referenceFields: refFields,
  179. files,
  180. idKey: "peFfId",
  181. addOldValue: true,
  182. });
  183. if (!validationResult.isValid)
  184. throw ApiError.BadRequest(
  185. "fieldsValidationFailed",
  186. JSON.stringify(validationResult.messages),
  187. );
  188. const validatedFields = validationResult.checkedfields;
  189. //
  190. //
  191. // вставляем в базу и сохраняем файлы
  192. await updPool.transaction(async (tr) => {
  193. if (name) {
  194. await tr.query(sql.unsafe`
  195. update act.part_entities
  196. set
  197. name = ${name}
  198. where
  199. pe_id = ${peId}
  200. `);
  201. }
  202. await cCustomFieldsValidateService.saveCustomFieldValuesInTransaction({
  203. tr,
  204. parentId: peId,
  205. action: "peCreate",
  206. inputFields: validatedFields,
  207. files,
  208. isDeleteBefore: true,
  209. });
  210. });
  211. RouterUtils.validAndSendResponse(api.client.pe.PATCH_PartEntity.res, res, {
  212. code: "success",
  213. });
  214. }
  215. async getMyPes(req: Request, res: Response) {
  216. const user = sessionService.getUserFromReq(req);
  217. const event = await sessionService.getCurrentEventFromReq(req);
  218. const ownerPes = await selPool.any(sql.type(
  219. z.object({
  220. peId: DbSchema.act.partEntities.peId,
  221. peTypeId: DbSchema.act.partEntities.peTypeId,
  222. peTypeCode: DbSchema.act.peTypes.code,
  223. peTypeName: DbSchema.act.peTypes.name,
  224. eventInstId: DbSchema.act.partEntities.eventInstId,
  225. ownerId: DbSchema.act.partEntities.ownerId,
  226. name: DbSchema.act.partEntities.name,
  227. }),
  228. )`
  229. select
  230. pe.pe_id "peId",
  231. pe.event_inst_id "eventInstId",
  232. pe.owner_id "ownerId",
  233. pe.pe_type_id "peTypeId",
  234. pt.code "peTypeCode",
  235. pt."name" "peTypeName",
  236. pe."name"
  237. from
  238. act.part_entities pe
  239. join act.pe_types pt on
  240. pt.pe_type_id = pe.pe_type_id
  241. where
  242. pe.event_inst_id = ${event.eventInstId}
  243. and pe.owner_id = ${user.userId}
  244. `);
  245. const memberPes = await selPool.any(sql.type(
  246. z.object({
  247. peMemberId: DbSchema.act.peMembers.peMemberId,
  248. peId: DbSchema.act.partEntities.peId,
  249. peTypeId: DbSchema.act.partEntities.peTypeId,
  250. peTypeCode: DbSchema.act.peTypes.code,
  251. peTypeName: DbSchema.act.peTypes.name,
  252. ownerId: DbSchema.act.partEntities.ownerId,
  253. name: DbSchema.act.partEntities.name,
  254. }),
  255. )`
  256. select
  257. pm.pe_member_id "peMemberId",
  258. pe.pe_id "peId",
  259. pe.event_inst_id "peInstId",
  260. pe.owner_id "ownerId",
  261. pe.pe_type_id "peTypeId",
  262. pt.code "peTypeCode",
  263. pt."name" "peTypeName",
  264. pe."name"
  265. from
  266. act.pe_members pm
  267. join act.part_entities pe on
  268. pe.pe_id = pm.pe_id
  269. join act.pe_types pt on
  270. pt.pe_type_id = pe.pe_type_id
  271. where
  272. pe.event_inst_id = ${event.eventInstId}
  273. and pm.user_id = ${user.userId}
  274. and pm.is_active = true
  275. `);
  276. RouterUtils.validAndSendResponse(api.client.pe.GET_MyPes.res, res, {
  277. code: "success",
  278. owner: [...ownerPes],
  279. memeber: [...memberPes],
  280. });
  281. }
  282. async getPe(req: Request, res: Response) {
  283. const user = sessionService.getUserFromReq(req);
  284. const { peId } = api.client.pe.GET_PartEntity.req.parse(req.params);
  285. const isOwner = await selPool.exists(
  286. sql.unsafe`
  287. select
  288. pe_id
  289. from
  290. act.part_entities pe
  291. where
  292. pe.owner_id = ${user.userId}
  293. and pe.pe_id = ${peId}
  294. `,
  295. );
  296. // валделец
  297. if (isOwner) {
  298. const pe = await cPeService.getPeWithValues(peId);
  299. const members = await cPeService.getPeMembersWithFields(peId);
  300. const invites = await cPeService.getInvites(peId);
  301. const peMembersRequests = await cPeService.getPeMembersRequests(peId);
  302. if (!pe)
  303. throw ApiError.BadRequest("peNotFound", "Сущность участия не найдена");
  304. if (pe.ownerId !== user.userId) throw ApiError.ForbiddenError();
  305. RouterUtils.validAndSendResponse(api.client.pe.GET_PartEntity.res, res, {
  306. code: "success",
  307. pe: {
  308. ...pe,
  309. members: [...members],
  310. invites: [...invites],
  311. peMembersRequests: [...peMembersRequests],
  312. userRole: "owner",
  313. },
  314. });
  315. return;
  316. }
  317. // участник
  318. const isMember = await selPool.exists(
  319. sql.unsafe`
  320. select
  321. pm.pe_id
  322. from
  323. act.pe_members pm
  324. where
  325. pm.user_id = ${user.userId}
  326. and pm.pe_id = ${peId}
  327. and pm.is_active = true
  328. `,
  329. );
  330. if (!isMember) throw ApiError.ForbiddenError();
  331. const pe = await cPeService.getPeForMember(peId);
  332. if (!pe)
  333. throw ApiError.BadRequest("peNotFound", "Сущность участия не найдена");
  334. RouterUtils.validAndSendResponse(api.client.pe.GET_PartEntity.res, res, {
  335. code: "success",
  336. pe: { ...pe, userRole: "member" },
  337. });
  338. }
  339. async joinToPe(req: Request, res: Response) {
  340. const user = sessionService.getUserFromReq(req);
  341. const { peId } = api.client.pe.POST_JoinToPe.req.params.parse(req.params);
  342. const isOwner = await cPeService.checkPeOwner(user.userId, peId);
  343. if (!isOwner) throw ApiError.ForbiddenError();
  344. const peMember = await selPool.maybeOne(sql.type(
  345. z.object({
  346. isActive: DbSchema.act.peMembers.isActive,
  347. peMemberId: DbSchema.act.peMembers.peMemberId,
  348. }),
  349. )`
  350. select
  351. pm.pe_member_id "peMemberId",
  352. pm.is_active "isActive"
  353. from
  354. act.pe_members pm
  355. where
  356. pm.pe_id = ${peId} and
  357. pm.user_id = ${user.userId}
  358. `);
  359. if (peMember && peMember.isActive) {
  360. throw ApiError.BadRequest(
  361. "peMemberAlreadyExists",
  362. "Участник уже в сущности участия",
  363. );
  364. }
  365. const memberId = v7();
  366. await updPool.transaction(async (tr) => {
  367. if (peMember) {
  368. await tr.query(sql.unsafe`
  369. update act.pe_members
  370. set
  371. is_active = true
  372. where
  373. pe_member_id = ${peMember.peMemberId}
  374. `);
  375. } else {
  376. await tr.query(sql.unsafe`
  377. insert into act.pe_members
  378. (pe_member_id, pe_id, user_id, is_active)
  379. values
  380. (${memberId}, ${peId}, ${user.userId}, true)
  381. `);
  382. }
  383. await cPeService.updateAllActRegStatusByPe(peId);
  384. });
  385. RouterUtils.validAndSendResponse(api.client.pe.POST_JoinToPe.res, res, {
  386. code: "success",
  387. memberId,
  388. });
  389. }
  390. async createInvite(req: Request, res: Response) {
  391. const user = sessionService.getUserFromReq(req);
  392. const { name, limitVal, expirationDate } =
  393. api.client.pe.POST_Invite.req.body.parse(req.body);
  394. const { peId } = api.client.pe.POST_Invite.req.params.parse(req.params);
  395. const isOwner = await cPeService.checkPeOwner(user.userId, peId);
  396. if (!isOwner) throw ApiError.ForbiddenError();
  397. const peInviteId = v7();
  398. const peInviteUuid = v4();
  399. await updPool.transaction(async (t) => {
  400. await t.query(sql.unsafe`
  401. insert into act.pe_invites
  402. (pe_invite_id, pe_invite_uuid, pe_id, limit_val, name, expiration_date)
  403. values
  404. (${peInviteId}, ${peInviteUuid}, ${peId}, ${limitVal}, ${name}, ${expirationDate})
  405. `);
  406. });
  407. RouterUtils.validAndSendResponse(api.client.pe.POST_Invite.res, res, {
  408. code: "success",
  409. peInviteId,
  410. });
  411. }
  412. async getInvites(req: Request, res: Response) {
  413. const user = sessionService.getUserFromReq(req);
  414. const { peId } = api.client.pe.GET_Invites.req.parse(req.params);
  415. const isOwner = await cPeService.checkPeOwner(user.userId, peId);
  416. if (!isOwner) throw ApiError.ForbiddenError();
  417. const invites = await cPeService.getInvites(peId);
  418. RouterUtils.validAndSendResponse(api.client.pe.GET_Invites.res, res, {
  419. code: "success",
  420. invites: [...invites],
  421. });
  422. }
  423. async getInviteInfo(req: Request, res: Response) {
  424. const { peInviteUuid } = api.client.pe.GET_InviteInfo.req.params.parse(
  425. req.params,
  426. );
  427. const user = sessionService.getUserFromReq(req);
  428. const invite = await cPeService.getInviteInfo(peInviteUuid);
  429. if (!invite)
  430. throw ApiError.BadRequest("inviteNotFound", "Приглашение не найдено");
  431. const request = await cPeService.checkPeMemberInvite({
  432. peInviteId: invite.peInviteId,
  433. userId: user.userId,
  434. });
  435. if (dayjs(invite.expirationDate).isBefore(dayjs()))
  436. throw ApiError.BadRequest("inviteExpired", "Приглашение истекло");
  437. if (request)
  438. throw ApiError.BadRequest("requestAlreadyExists", "Запрос уже отправлен");
  439. RouterUtils.validAndSendResponse(api.client.pe.GET_InviteInfo.res, res, {
  440. code: "success",
  441. invite,
  442. });
  443. }
  444. async acceptInvite(req: Request, res: Response) {
  445. const user = sessionService.getUserFromReq(req);
  446. const { peInviteUuid } = api.client.pe.POST_AcceptInvite.req.params.parse(
  447. req.params,
  448. );
  449. const invite = await cPeService.getInviteInfo(peInviteUuid);
  450. // приглашение не найдено
  451. if (!invite) {
  452. RouterUtils.validAndSendResponse(
  453. api.client.pe.POST_AcceptInvite.res,
  454. res,
  455. {
  456. code: "inviteNotFound",
  457. },
  458. 400,
  459. );
  460. return;
  461. }
  462. const pe = await selPool.maybeOne(sql.unsafe`
  463. select
  464. pe.pe_id,
  465. pt.max_members,
  466. members."membersCount"
  467. from
  468. act.part_entities pe
  469. left join act.pe_types pt on
  470. pt.pe_type_id = pe.pe_type_id
  471. left join (
  472. select
  473. pe_id,
  474. count(*) as "membersCount"
  475. from
  476. act.pe_members
  477. where
  478. is_active = true
  479. group by
  480. pe_id
  481. ) members on
  482. members.pe_id = pe.pe_id
  483. where
  484. pe.pe_id = ${invite.peId}
  485. `);
  486. if (!pe) {
  487. throw ApiError.BadRequest("peNotFound", "Сущность участия не найдена");
  488. }
  489. // лимит превышен
  490. if (
  491. (invite.limitVal && invite.countVal >= invite.limitVal) ||
  492. (pe.maxMembers !== null && pe.membersCount >= pe.maxMembers)
  493. ) {
  494. RouterUtils.validAndSendResponse(
  495. api.client.pe.POST_AcceptInvite.res,
  496. res,
  497. {
  498. code: "inviteLimitExceeded",
  499. },
  500. 400,
  501. );
  502. return;
  503. }
  504. // приглашение истекло
  505. if (
  506. invite.expirationDate &&
  507. dayjs(invite.expirationDate).isBefore(dayjs())
  508. ) {
  509. RouterUtils.validAndSendResponse(
  510. api.client.pe.POST_AcceptInvite.res,
  511. res,
  512. {
  513. code: "inviteExpired",
  514. },
  515. 400,
  516. );
  517. return;
  518. }
  519. // TODO: много лишних данных
  520. // участник уже в pe
  521. const peMembers = await cPeService.getPeMembersWithFields(invite.peId);
  522. const isFound = peMembers.find((m) => m.userId === user.userId);
  523. if (isFound) {
  524. RouterUtils.validAndSendResponse(
  525. api.client.pe.POST_AcceptInvite.res,
  526. res,
  527. {
  528. code: "peMemberAlreadyExists",
  529. },
  530. 400,
  531. );
  532. return;
  533. }
  534. // запрос уже отправлен
  535. const isPending = await cPeService.checkPeMemberInvite({
  536. peInviteId: invite.peInviteId,
  537. userId: user.userId,
  538. });
  539. if (isPending) {
  540. RouterUtils.validAndSendResponse(
  541. api.client.pe.POST_AcceptInvite.res,
  542. res,
  543. {
  544. code: "peMemberInviteAlreadyExists",
  545. },
  546. 400,
  547. );
  548. return;
  549. }
  550. await updPool.transaction(async (t) => {
  551. const id = v7();
  552. await t.query(sql.unsafe`
  553. insert into act.pe_members_requests
  554. (pe_member_request_id, pe_invite_id, user_id, status)
  555. values
  556. (${id}, ${invite.peInviteId}, ${user.userId}, 'PENDING')
  557. `);
  558. await t.query(sql.unsafe`
  559. update act.pe_invites
  560. set
  561. count_val = count_val + 1
  562. where
  563. pe_id = ${invite.peId}
  564. `);
  565. });
  566. RouterUtils.validAndSendResponse(api.client.pe.POST_AcceptInvite.res, res, {
  567. code: "success",
  568. peId: invite.peId,
  569. });
  570. }
  571. async patchPeMembersRequests(req: Request, res: Response) {
  572. const requests = api.client.pe.PATCH_PeMembersRequests.req.body.parse(
  573. req.body,
  574. );
  575. const user = sessionService.getUserFromReq(req);
  576. const peIdsToRecheck: Set<string> = new Set();
  577. await updPool.transaction(async (t) => {
  578. for (const r of requests) {
  579. const request = await cPeService.getPeMemberRequest(
  580. r.peMemberRequestId,
  581. );
  582. if (!request)
  583. throw ApiError.BadRequest("requestNotFound", "Запрос не найден");
  584. const pe = await cPeService.getPeForMember(request.peId);
  585. if (!pe)
  586. throw ApiError.BadRequest(
  587. "peNotFound",
  588. "Сущность участия не найдена",
  589. );
  590. if (pe.ownerId !== user.userId) throw ApiError.ForbiddenError();
  591. // участник уже в pe
  592. const peMembers = await cPeService.getPeMembersWithFields(pe.peId);
  593. const isFound = peMembers.find((m) => m.userId === request.userId);
  594. if (isFound)
  595. throw ApiError.BadRequest(
  596. "memberAlreadyInPe",
  597. "Участник уже добавлен",
  598. );
  599. peIdsToRecheck.add(pe.peId);
  600. await t.query(sql.unsafe`
  601. update act.pe_members_requests
  602. set
  603. status = ${r.status}
  604. where
  605. pe_member_request_id = ${r.peMemberRequestId}
  606. `);
  607. if (r.status === "ACCEPTED") {
  608. await t.query(sql.unsafe`
  609. insert into act.pe_members
  610. (pe_id, user_id)
  611. values
  612. (${pe.peId}, ${request.userId})
  613. `);
  614. }
  615. }
  616. });
  617. for (const peId of peIdsToRecheck) {
  618. await cPeService.updateAllActRegStatusByPe(peId);
  619. }
  620. RouterUtils.validAndSendResponse(
  621. api.client.pe.PATCH_PeMembersRequests.res,
  622. res,
  623. {
  624. code: "success",
  625. },
  626. );
  627. }
  628. async getMyPesForActivity(req: Request, res: Response) {
  629. const user = sessionService.getUserFromReq(req);
  630. const event = await sessionService.getCurrentEventFromReq(req);
  631. const pes = await selPool.any(sql.type(apiTypes.activities.PeForActivity)`
  632. select
  633. pe.pe_id "peId",
  634. pe.event_inst_id "eventInstId",
  635. pe.owner_id "ownerId",
  636. pe.pe_type_id "peTypeId",
  637. pt.code "peTypeCode",
  638. pt."name" "peTypeName",
  639. pe."name",
  640. coalesce(m.members, '[]'::jsonb) members,
  641. v.fields
  642. from
  643. act.part_entities pe
  644. join act.pe_types pt on
  645. pt.pe_type_id = pe.pe_type_id
  646. -- members
  647. left join lateral (
  648. select
  649. jsonb_agg(jsonb_build_object(
  650. 'peMemberId', m.pe_member_id,
  651. 'userId', m.user_id,
  652. 'email', m.email,
  653. 'fields', m.fields
  654. )) as members
  655. from
  656. act.pe_members_with_fields_and_values m
  657. where
  658. m.pe_id = pe.pe_id
  659. ) m on
  660. true
  661. -- fields
  662. left join act.pe_with_fields_and_values v on
  663. v.pe_id = pe.pe_id
  664. where
  665. pe.event_inst_id = ${event.eventInstId}
  666. and pe.owner_id = ${user.userId}
  667. `);
  668. RouterUtils.validAndSendResponse(
  669. api.client.pe.GET_MyPesForActivity.res,
  670. res,
  671. {
  672. code: "success",
  673. pes: [...pes],
  674. },
  675. );
  676. }
  677. async excludeMemberFromPe(req: Request, res: Response) {
  678. const user = sessionService.getUserFromReq(req);
  679. const { peMemberId } = api.client.pe.DELETE_PeMember.req.params.parse(
  680. req.params,
  681. );
  682. const peMember = await cPeService.getPeMember(peMemberId);
  683. if (!peMember)
  684. throw ApiError.BadRequest("peMemberNotFound", "Участник не найден");
  685. const pe = await cPeService.getPeForMember(peMember.peId);
  686. if (!pe)
  687. throw ApiError.BadRequest("peNotFound", "Сущность участия не найдена");
  688. if (pe.ownerId !== user.userId) throw ApiError.ForbiddenError();
  689. await updPool.transaction(async (t) => {
  690. await cActService.refundByPeMemberId({
  691. peMemberId,
  692. peId: pe.peId,
  693. userId: user.userId,
  694. });
  695. await t.query(sql.unsafe`
  696. update act.pe_members
  697. set
  698. is_active = false
  699. where
  700. pe_member_id = ${peMemberId}
  701. `);
  702. });
  703. RouterUtils.validAndSendResponse(api.client.pe.DELETE_PeMember.res, res, {
  704. code: "success",
  705. });
  706. }
  707. async getRelatedActivityRegsToPe(req: Request, res: Response) {
  708. const user = sessionService.getUserFromReq(req);
  709. const { peId } = api.client.pe.GET_RelatedActivityRegsToPe.req.params.parse(
  710. req.params,
  711. );
  712. const pe = await cPeService.getPeForMember(peId);
  713. if (!pe)
  714. throw ApiError.BadRequest("peNotFound", "Сущность участия не найдена");
  715. if (pe.ownerId !== user.userId) throw ApiError.ForbiddenError();
  716. const activityRegs = await cActService.getActivityRegsByPeId(peId);
  717. RouterUtils.validAndSendResponse(
  718. api.client.pe.GET_RelatedActivityRegsToPe.res,
  719. res,
  720. {
  721. code: "success",
  722. activityRegs: [...activityRegs],
  723. },
  724. );
  725. }
  726. }
  727. export const clientPeController = new ClientPeController();