@cyberismo/backend 0.0.27 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.d.ts +1 -1
- package/dist/app.js +10 -4
- package/dist/app.js.map +1 -1
- package/dist/auth/index.d.ts +1 -1
- package/dist/auth/index.js +1 -1
- package/dist/auth/index.js.map +1 -1
- package/dist/auth/keycloak.js +3 -0
- package/dist/auth/keycloak.js.map +1 -1
- package/dist/auth/mock.d.ts +8 -1
- package/dist/auth/mock.js +51 -2
- package/dist/auth/mock.js.map +1 -1
- package/dist/common/validationSchemas.d.ts +3 -1
- package/dist/common/validationSchemas.js +1 -0
- package/dist/common/validationSchemas.js.map +1 -1
- package/dist/domain/calculations/index.js +1 -1
- package/dist/domain/calculations/index.js.map +1 -1
- package/dist/domain/cardTypes/service.d.ts +1 -1
- package/dist/domain/cardTypes/service.js +26 -4
- package/dist/domain/cardTypes/service.js.map +1 -1
- package/dist/domain/cards/lib.js +7 -5
- package/dist/domain/cards/lib.js.map +1 -1
- package/dist/domain/cards/service.js +3 -6
- package/dist/domain/cards/service.js.map +1 -1
- package/dist/domain/project/index.js +32 -1
- package/dist/domain/project/index.js.map +1 -1
- package/dist/domain/project/schema.d.ts +11 -0
- package/dist/domain/project/schema.js +20 -0
- package/dist/domain/project/schema.js.map +1 -1
- package/dist/domain/project/service.d.ts +23 -1
- package/dist/domain/project/service.js +52 -1
- package/dist/domain/project/service.js.map +1 -1
- package/dist/domain/projects/index.d.ts +1 -1
- package/dist/domain/projects/index.js +66 -3
- package/dist/domain/projects/index.js.map +1 -1
- package/dist/domain/projects/schema.d.ts +22 -0
- package/dist/domain/projects/schema.js +40 -0
- package/dist/domain/projects/schema.js.map +1 -0
- package/dist/domain/projects/service.d.ts +37 -0
- package/dist/domain/projects/service.js +53 -0
- package/dist/domain/projects/service.js.map +1 -0
- package/dist/domain/resources/index.js +1 -1
- package/dist/domain/resources/index.js.map +1 -1
- package/dist/domain/resources/schema.d.ts +4 -1
- package/dist/domain/resources/schema.js +4 -2
- package/dist/domain/resources/schema.js.map +1 -1
- package/dist/domain/resources/service.d.ts +1 -1
- package/dist/domain/resources/service.js +7 -2
- package/dist/domain/resources/service.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/main.js +0 -4
- package/dist/main.js.map +1 -1
- package/dist/middleware/auth.d.ts +5 -3
- package/dist/middleware/auth.js +7 -4
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/zvalidator.d.ts +1 -1
- package/dist/project-registry.d.ts +2 -1
- package/dist/project-registry.js +4 -2
- package/dist/project-registry.js.map +1 -1
- package/dist/public/THIRD-PARTY.txt +932 -1022
- package/dist/public/assets/abnfDiagram-VRR7QNED-Djr4KJ5E.js +1 -0
- package/dist/public/assets/arc-DrR4k_H-.js +1 -0
- package/dist/public/assets/architecture-TIHT7OUA-XL6N-4o9.js +1 -0
- package/dist/public/assets/architectureDiagram-ZJ3FMSHR-DsMU2Uwa.js +36 -0
- package/dist/public/assets/blockDiagram-677ZJIJ3-DRBmQUQJ.js +132 -0
- package/dist/public/assets/c4Diagram-LMCZKHZV-E0rM02LD.js +10 -0
- package/dist/public/assets/channel-D5fnImJy.js +1 -0
- package/dist/public/assets/chunk-2Q5K7J3B-C1jixKkw.js +1 -0
- package/dist/public/assets/chunk-32BRIVSS-BnDY0aSV.js +1 -0
- package/dist/public/assets/chunk-52WLFC77-N5YugKaZ.js +10 -0
- package/dist/public/assets/chunk-5FCAYU7R-I3_t_Ic_.js +1 -0
- package/dist/public/assets/chunk-5HE753X5-Dxz40rzH.js +1 -0
- package/dist/public/assets/chunk-5JV3BV7I-CNwCKRLH.js +1 -0
- package/dist/public/assets/chunk-5TONJI2A-ezWQ_Z2j.js +2 -0
- package/dist/public/assets/{chunk-FMBD7UC4-Cgl-u-NC.js → chunk-5VM5RSS4-ZNzvKenW.js} +1 -1
- package/dist/public/assets/chunk-7BUUIJ7U-Bb538aSH.js +1 -0
- package/dist/public/assets/chunk-BIQX33UG-DS132-R_.js +1 -0
- package/dist/public/assets/chunk-C7G6YPKG-BN-cNjoj.js +1 -0
- package/dist/public/assets/chunk-CQNSW5MT-D8Mn1I73.js +1 -0
- package/dist/public/assets/chunk-CYSBUYHQ-Dc64Dwdo.js +1 -0
- package/dist/public/assets/chunk-EMLP6XTP-aIK0V8GX.js +1 -0
- package/dist/public/assets/chunk-EX3LRPZG-Db0XYyxy.js +231 -0
- package/dist/public/assets/chunk-FWX5IMBZ-BF_P2-Do.js +2 -0
- package/dist/public/assets/chunk-HOUHSVGY-L35GPy9G.js +1 -0
- package/dist/public/assets/chunk-ICXQ74PX-Bb8zaHde.js +2 -0
- package/dist/public/assets/chunk-JG7HCLWE-BtAXK3iQ.js +2 -0
- package/dist/public/assets/chunk-JWPE2WC7-DVXcaiue.js +1 -0
- package/dist/public/assets/chunk-KEIR6QF5-DEvma7oi.js +161 -0
- package/dist/public/assets/chunk-MOJQB5TN-D1shKbMs.js +88 -0
- package/dist/public/assets/chunk-MOZMSUNE-5FIqIBsY.js +1 -0
- package/dist/public/assets/chunk-OGEWGWER-BVIFy9xz.js +1 -0
- package/dist/public/assets/chunk-OSBZ3O6U-Cfd7kf1R.js +1 -0
- package/dist/public/assets/chunk-PUDLZKDR-Db3FSNR9.js +156 -0
- package/dist/public/assets/chunk-Q4XR5HBZ-BuKFRUzR.js +70 -0
- package/dist/public/assets/chunk-QBLGF6JB-DUGZXFh-.js +1 -0
- package/dist/public/assets/chunk-R7FJI6CG-D7mUd-qN.js +1 -0
- package/dist/public/assets/chunk-RYQCIY6F-C_3rESBd.js +1 -0
- package/dist/public/assets/chunk-U6XO7XAA-C3UhlwA1.js +2 -0
- package/dist/public/assets/chunk-V7JOEXUC-71b0ABpv.js +206 -0
- package/dist/public/assets/chunk-VAUOI2AC-C-GBw18h.js +1 -0
- package/dist/public/assets/chunk-VR4S4FIN-tUhbELKr.js +1 -0
- package/dist/public/assets/chunk-WYO6CB5R-BQoO62-B.js +127 -0
- package/dist/public/assets/chunk-XXDRQBXY-Co8n4ZHT.js +1 -0
- package/dist/public/assets/chunk-Y2CYZVJY-DsF7k-Jl.js +1 -0
- package/dist/public/assets/chunk-YOTPTUD7-DhCRKU1A.js +1 -0
- package/dist/public/assets/chunk-ZGVPDNZ5-hpz2Ryq5.js +62 -0
- package/dist/public/assets/chunk-ZIRB5QZD-BpeS1aZ7.js +32 -0
- package/dist/public/assets/classDiagram-OUVF2IWQ-CXdVorPK.js +1 -0
- package/dist/public/assets/classDiagram-v2-EOCWNBFH-CXdVorPK.js +1 -0
- package/dist/public/assets/colors-Cg5Vh3br.js +1 -0
- package/dist/public/assets/cose-bilkent-JH36ORCC-4GoRbloS.js +1 -0
- package/dist/public/assets/cynefin-VYW2F7L2-BPH-25fI.js +1 -0
- package/dist/public/assets/cynefinDiagram-TSTJHNR4-PEf16euv.js +62 -0
- package/dist/public/assets/cytoscape.esm-C3UvhD5t.js +321 -0
- package/dist/public/assets/dagre-Buvkdvvj.js +1 -0
- package/dist/public/assets/dagre-VKFMJZFB-DPsCMBF1.js +4 -0
- package/dist/public/assets/defaultLocale-CNPGWpMu.js +1 -0
- package/dist/public/assets/diagram-FQU43EPY-DS-ryuRg.js +3 -0
- package/dist/public/assets/diagram-G47NLZAW-CzUoYkFf.js +24 -0
- package/dist/public/assets/diagram-NH7WQ7WH-MhGnE2fh.js +24 -0
- package/dist/public/assets/diagram-OA4YK3LP-CsQ9aFR_.js +30 -0
- package/dist/public/assets/diagram-WEI45ONY-Er3q49ew.js +41 -0
- package/dist/public/assets/dist-BzwexiH1.js +1 -0
- package/dist/public/assets/ebnfDiagram-CCIWWBDH-AnJAsk14.js +1 -0
- package/dist/public/assets/erDiagram-Q63AITRT-DulA16my.js +85 -0
- package/dist/public/assets/eventmodeling-45OFAUF4-CoIhTpHU.js +1 -0
- package/dist/public/assets/flowDiagram-23GEKE2U-BGMXUq18.js +1 -0
- package/dist/public/assets/ganttDiagram-NO4QXBWP-DAvCPT7_.js +292 -0
- package/dist/public/assets/gitGraph-TEB2WS4Q-BcPsZts5.js +1 -0
- package/dist/public/assets/gitGraphDiagram-IHSO6WYX-CksvJvsQ.js +106 -0
- package/dist/public/assets/{graphlib-B8gBHxth.js → graphlib-DS17s2tU.js} +1 -1
- package/dist/public/assets/index-H1CkT-JT.js +447 -0
- package/dist/public/assets/info-DKCQHKI2-7VGzrAVB.js +1 -0
- package/dist/public/assets/infoDiagram-FWYZ7A6U-D_by7lSL.js +2 -0
- package/dist/public/assets/init-ZlXS9mIS.js +1 -0
- package/dist/public/assets/{ishikawaDiagram-YF4QCWOH-D5HGS4h9.js → ishikawaDiagram-FXEZZL3T-CiLpASIW.js} +6 -6
- package/dist/public/assets/journeyDiagram-5HDEW3XC-DpvFmk7c.js +139 -0
- package/dist/public/assets/kanban-definition-HUTT4EX6-DYP_x6zD.js +89 -0
- package/dist/public/assets/{katex-Vhh-h91d.js → katex-DolUETbr.js} +3 -3
- package/dist/public/assets/{line-DNZMOnJ3.js → line-C8Sfsgt8.js} +1 -1
- package/dist/public/assets/linear-BWTvbP1l.js +1 -0
- package/dist/public/assets/map-BaFkSB1l.js +1 -0
- package/dist/public/assets/mermaid-parser.core--8614tkK.js +4 -0
- package/dist/public/assets/mindmap-definition-LN4V7U3C-3IAd4gp3.js +96 -0
- package/dist/public/assets/ordinal-BdBDtYTt.js +1 -0
- package/dist/public/assets/packet-7NZHBO7P-KYt33H0C.js +1 -0
- package/dist/public/assets/pegDiagram-2B236MQR-BQNFxYz2.js +1 -0
- package/dist/public/assets/pie-RZYD4A2V-xKz9s9I4.js +1 -0
- package/dist/public/assets/pieDiagram-ENE6RG2P-Cy13tg8_.js +39 -0
- package/dist/public/assets/quadrantDiagram-ABIIQ3AL-B3czMbdS.js +7 -0
- package/dist/public/assets/radar-I7S5WNFK-B4QTX-fX.js +1 -0
- package/dist/public/assets/railroad-3IZDKUUU-Co_9rPVC.js +1 -0
- package/dist/public/assets/railroad-abnf-AHOZXSZD-Bhy_c3ol.js +1 -0
- package/dist/public/assets/railroad-ebnf-EBAXGLYW-B9ENjG34.js +1 -0
- package/dist/public/assets/railroad-peg-LSFZ7HO6-CyJxDBsB.js +1 -0
- package/dist/public/assets/railroadDiagram-RFXS5EU6-M2j5SJF2.js +1 -0
- package/dist/public/assets/range-EplFIxc7.js +1 -0
- package/dist/public/assets/requirementDiagram-TGXJPOKE-CmvJWy_S.js +84 -0
- package/dist/public/assets/{rough.esm-CSKSodPl.js → rough.esm-By172zw-.js} +1 -1
- package/dist/public/assets/sankeyDiagram-HTMAVEWB-tAeOzMTn.js +40 -0
- package/dist/public/assets/sequenceDiagram-DBY2YBRQ-r0pwijM4.js +162 -0
- package/dist/public/assets/sizeCapture-X5ZJPWSS-B0uUizjq.js +1 -0
- package/dist/public/assets/src-DOh7_en_.js +1 -0
- package/dist/public/assets/stateDiagram-2N3HPSRC-a9IdkSQG.js +1 -0
- package/dist/public/assets/stateDiagram-v2-6OUMAXLB-s2blPtZ-.js +1 -0
- package/dist/public/assets/swimlanes-5IMT3BWC-5w0Cdxk6.js +2 -0
- package/dist/public/assets/swimlanesDiagram-G3AALYLV-BWa-KRed.js +8 -0
- package/dist/public/assets/time-BM2d9MsQ.js +1 -0
- package/dist/public/assets/timeline-definition-FHXFAJF6-CvXlv_4Y.js +120 -0
- package/dist/public/assets/treeView-QDETBFTQ-B9cxjfpB.js +1 -0
- package/dist/public/assets/treemap-6X3UGDF4-BplEq4hB.js +1 -0
- package/dist/public/assets/treemap-BfjIY-m6.js +1 -0
- package/dist/public/assets/vennDiagram-L72KCM5P-ti2qNcvo.js +34 -0
- package/dist/public/assets/wardley-OPB4EBWU-BX2ghg5e.js +1 -0
- package/dist/public/assets/wardleyDiagram-EHGQE667-C8lblm8x.js +78 -0
- package/dist/public/assets/xychartDiagram-FW5EYKEG-US-_k5eu.js +7 -0
- package/dist/public/index.html +31 -12
- package/dist/types.d.ts +4 -1
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -1
- package/package.json +11 -10
- package/src/app.ts +11 -4
- package/src/auth/index.ts +1 -1
- package/src/auth/keycloak.ts +3 -0
- package/src/auth/mock.ts +54 -2
- package/src/common/validationSchemas.ts +1 -0
- package/src/domain/calculations/index.ts +1 -1
- package/src/domain/cardTypes/service.ts +26 -21
- package/src/domain/cards/lib.ts +11 -4
- package/src/domain/cards/service.ts +4 -5
- package/src/domain/project/index.ts +54 -0
- package/src/domain/project/schema.ts +23 -0
- package/src/domain/project/service.ts +89 -1
- package/src/domain/projects/index.ts +115 -3
- package/src/domain/projects/schema.ts +42 -0
- package/src/domain/projects/service.ts +98 -0
- package/src/domain/resources/index.ts +1 -1
- package/src/domain/resources/schema.ts +4 -2
- package/src/domain/resources/service.ts +5 -4
- package/src/index.ts +11 -6
- package/src/main.ts +0 -6
- package/src/middleware/auth.ts +10 -4
- package/src/project-registry.ts +7 -2
- package/src/types.ts +3 -0
- package/dist/public/assets/architecture-7EHR7CIX-CHU1xuYF.js +0 -1
- package/dist/public/assets/architectureDiagram-3BPJPVTR--CSL9yP4.js +0 -36
- package/dist/public/assets/blockDiagram-GPEHLZMM-KVU5YZg5.js +0 -132
- package/dist/public/assets/c4Diagram-AAUBKEIU-CKZoRo4y.js +0 -10
- package/dist/public/assets/channel-DylEVeTd.js +0 -1
- package/dist/public/assets/chunk-2J33WTMH-3csjo24p.js +0 -1
- package/dist/public/assets/chunk-3OPIFGDE-BKzRNP07.js +0 -62
- package/dist/public/assets/chunk-4BX2VUAB-ClBqZOcE.js +0 -1
- package/dist/public/assets/chunk-55IACEB6-Bgi2dUOh.js +0 -1
- package/dist/public/assets/chunk-5ZQYHXKU-CECM_AkK.js +0 -2
- package/dist/public/assets/chunk-727SXJPM-DwCEXlGv.js +0 -206
- package/dist/public/assets/chunk-AQP2D5EJ-4K2xdOIK.js +0 -231
- package/dist/public/assets/chunk-BSJP7CBP-ByoKnyMP.js +0 -1
- package/dist/public/assets/chunk-CSCIHK7Q-DPeQmPB5.js +0 -124
- package/dist/public/assets/chunk-L5ZTLDWV-pkYUefHU.js +0 -1
- package/dist/public/assets/chunk-ND2GUHAM-BbBhIALU.js +0 -1
- package/dist/public/assets/chunk-NNHCCRGN-DlpIbxXb.js +0 -159
- package/dist/public/assets/chunk-NZK2D7GU-Bsg3s0FQ.js +0 -1
- package/dist/public/assets/chunk-O5CBEL6O-CLKEM0Ng.js +0 -70
- package/dist/public/assets/chunk-QZHKN3VN-DYbrfjC5.js +0 -1
- package/dist/public/assets/classDiagram-4FO5ZUOK-BJy5zoel.js +0 -1
- package/dist/public/assets/classDiagram-v2-Q7XG4LA2-BJy5zoel.js +0 -1
- package/dist/public/assets/cose-bilkent-S5V4N54A-BW2eHW0s.js +0 -1
- package/dist/public/assets/cytoscape.esm-FqbQrHcz.js +0 -321
- package/dist/public/assets/dagre-BM42HDAG-BthzRaVA.js +0 -4
- package/dist/public/assets/dagre-Bx709z4p.js +0 -1
- package/dist/public/assets/diagram-2AECGRRQ-CQJQx4k6.js +0 -43
- package/dist/public/assets/diagram-5GNKFQAL-DZn5aW7S.js +0 -10
- package/dist/public/assets/diagram-KO2AKTUF-C-khQZwA.js +0 -3
- package/dist/public/assets/diagram-LMA3HP47-DgWJfUcV.js +0 -24
- package/dist/public/assets/diagram-OG6HWLK6-44JZNjGl.js +0 -24
- package/dist/public/assets/dist-Dek0Yhn0.js +0 -1
- package/dist/public/assets/erDiagram-TEJ5UH35-BVkYJRJ3.js +0 -85
- package/dist/public/assets/eventmodeling-FCH6USID-C_5XBe82.js +0 -1
- package/dist/public/assets/flowDiagram-I6XJVG4X-DanY8_jA.js +0 -162
- package/dist/public/assets/ganttDiagram-6RSMTGT7-DD1Pw4Yz.js +0 -292
- package/dist/public/assets/gitGraph-WXDBUCRP-D4dBNuhe.js +0 -1
- package/dist/public/assets/gitGraphDiagram-PVQCEYII-BPrVPTyG.js +0 -106
- package/dist/public/assets/index-CKFcPbR1.js +0 -729
- package/dist/public/assets/info-J43DQDTF-D7lvZ6o6.js +0 -1
- package/dist/public/assets/infoDiagram-5YYISTIA-t6t0skjQ.js +0 -2
- package/dist/public/assets/journeyDiagram-JHISSGLW-DZle34fL.js +0 -139
- package/dist/public/assets/kanban-definition-UN3LZRKU-DvUHZ0z2.js +0 -89
- package/dist/public/assets/mermaid-parser.core-DFZGVidJ.js +0 -4
- package/dist/public/assets/mindmap-definition-RKZ34NQL-Lmrs6IX6.js +0 -96
- package/dist/public/assets/packet-YPE3B663-AbbU2Ze4.js +0 -1
- package/dist/public/assets/pie-LRSECV5Y-DN4QBmSF.js +0 -1
- package/dist/public/assets/pieDiagram-4H26LBE5-BwD91PEd.js +0 -30
- package/dist/public/assets/quadrantDiagram-W4KKPZXB-DXCkBrKi.js +0 -7
- package/dist/public/assets/radar-GUYGQ44K-ej308gGR.js +0 -1
- package/dist/public/assets/requirementDiagram-4Y6WPE33-jDFKiwdn.js +0 -84
- package/dist/public/assets/sankeyDiagram-5OEKKPKP-D9xT2nUr.js +0 -40
- package/dist/public/assets/sequenceDiagram-3UESZ5HK-Bmko-3_U.js +0 -162
- package/dist/public/assets/src-CqxF9LGw.js +0 -1
- package/dist/public/assets/stateDiagram-AJRCARHV-DjPm6sNG.js +0 -1
- package/dist/public/assets/stateDiagram-v2-BHNVJYJU-B-cimf9q.js +0 -1
- package/dist/public/assets/timeline-definition-PNZ67QCA-nKPLYYzI.js +0 -120
- package/dist/public/assets/treeView-BLDUP644--ooV0k8a.js +0 -1
- package/dist/public/assets/treemap-LRROVOQU-BKq-VDOX.js +0 -1
- package/dist/public/assets/vennDiagram-CIIHVFJN-DHORAsW0.js +0 -34
- package/dist/public/assets/wardley-L42UT6IY-VU5ormp0.js +0 -1
- package/dist/public/assets/wardleyDiagram-YWT4CUSO-DwqR74vk.js +0 -78
- package/dist/public/assets/xychartDiagram-2RQKCTM6-CUU1IRcn.js +0 -7
package/src/auth/mock.ts
CHANGED
|
@@ -11,6 +11,8 @@
|
|
|
11
11
|
License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
+
import type { MiddlewareHandler } from 'hono';
|
|
15
|
+
import { setCookie } from 'hono/cookie';
|
|
14
16
|
import { UserRole } from '../types.js';
|
|
15
17
|
import type { UserInfo } from '../types.js';
|
|
16
18
|
import type { AuthProvider } from './types.js';
|
|
@@ -20,6 +22,32 @@ export interface MockUserConfig {
|
|
|
20
22
|
email?: string;
|
|
21
23
|
}
|
|
22
24
|
|
|
25
|
+
export const MOCK_ROLE_COOKIE = 'mock-role';
|
|
26
|
+
const ROLE_RESET_VALUE = 'default';
|
|
27
|
+
|
|
28
|
+
const ROLE_ALIASES: Record<string, UserRole> = {
|
|
29
|
+
reader: UserRole.Reader,
|
|
30
|
+
editor: UserRole.Editor,
|
|
31
|
+
admin: UserRole.Admin,
|
|
32
|
+
connector: UserRole.Connector,
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function parseRole(value: string | null | undefined): UserRole | null {
|
|
36
|
+
if (!value) return null;
|
|
37
|
+
return ROLE_ALIASES[value.toLowerCase()] ?? null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readCookie(header: string | null, name: string): string | undefined {
|
|
41
|
+
if (!header) return undefined;
|
|
42
|
+
for (const part of header.split(';')) {
|
|
43
|
+
const eq = part.indexOf('=');
|
|
44
|
+
if (eq === -1) continue;
|
|
45
|
+
if (part.slice(0, eq).trim() !== name) continue;
|
|
46
|
+
return decodeURIComponent(part.slice(eq + 1).trim());
|
|
47
|
+
}
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
23
51
|
export class MockAuthProvider implements AuthProvider {
|
|
24
52
|
private readonly userConfig: MockUserConfig;
|
|
25
53
|
|
|
@@ -27,12 +55,36 @@ export class MockAuthProvider implements AuthProvider {
|
|
|
27
55
|
this.userConfig = config ?? {};
|
|
28
56
|
}
|
|
29
57
|
|
|
30
|
-
async authenticate(): Promise<UserInfo> {
|
|
58
|
+
async authenticate(req: Request): Promise<UserInfo> {
|
|
59
|
+
const cookieRole = parseRole(
|
|
60
|
+
readCookie(req.headers.get('cookie'), MOCK_ROLE_COOKIE),
|
|
61
|
+
);
|
|
31
62
|
return {
|
|
32
63
|
id: 'mock-user',
|
|
33
64
|
email: this.userConfig.email ?? 'admin@cyberismo.local',
|
|
34
65
|
name: this.userConfig.name ?? 'Local Admin',
|
|
35
|
-
role: UserRole.Admin,
|
|
66
|
+
role: cookieRole ?? UserRole.Admin,
|
|
36
67
|
};
|
|
37
68
|
}
|
|
38
69
|
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Dev-only middleware that turns `?role=<reader|editor|admin>` into a persistent
|
|
73
|
+
* `mock-role` cookie, and clears it on `?role=default`.
|
|
74
|
+
*/
|
|
75
|
+
export function mockRoleCookieMiddleware(): MiddlewareHandler {
|
|
76
|
+
return async (c, next) => {
|
|
77
|
+
const override = new URL(c.req.url).searchParams.get('role');
|
|
78
|
+
if (override) {
|
|
79
|
+
if (override.toLowerCase() === ROLE_RESET_VALUE) {
|
|
80
|
+
setCookie(c, MOCK_ROLE_COOKIE, '', { path: '/', maxAge: 0 });
|
|
81
|
+
} else if (parseRole(override)) {
|
|
82
|
+
setCookie(c, MOCK_ROLE_COOKIE, override.toLowerCase(), {
|
|
83
|
+
path: '/',
|
|
84
|
+
sameSite: 'Lax',
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
await next();
|
|
89
|
+
};
|
|
90
|
+
}
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import type
|
|
14
|
+
import { resourceName, type CommandManager } from '@cyberismo/data-handler';
|
|
15
15
|
import type { VisibilityGroup, FieldVisibilityBody } from './schema.js';
|
|
16
16
|
|
|
17
17
|
export async function getCardTypes(commands: CommandManager) {
|
|
@@ -53,6 +53,7 @@ export async function updateFieldVisibility(
|
|
|
53
53
|
body: FieldVisibilityBody,
|
|
54
54
|
): Promise<void> {
|
|
55
55
|
const { fieldName, group: targetGroup, index: targetIndex } = body;
|
|
56
|
+
const target = resourceName(cardTypeName);
|
|
56
57
|
|
|
57
58
|
await commands.atomic(async () => {
|
|
58
59
|
// Read is now inside the write lock
|
|
@@ -87,38 +88,42 @@ export async function updateFieldVisibility(
|
|
|
87
88
|
// If same group, just handle reordering
|
|
88
89
|
if (currentGroup === targetGroup) {
|
|
89
90
|
if (targetGroup !== 'hidden' && targetIndex !== undefined) {
|
|
90
|
-
await commands.updateCmd.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
91
|
+
await commands.updateCmd.apply({
|
|
92
|
+
kind: 'edit',
|
|
93
|
+
target,
|
|
94
|
+
updateKey: { key: groupToKey[targetGroup] },
|
|
95
|
+
operation: { name: 'rank', target: fieldName, newIndex: targetIndex },
|
|
96
|
+
});
|
|
95
97
|
}
|
|
96
98
|
return;
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
// Remove from current group (if not hidden)
|
|
100
102
|
if (currentGroup !== 'hidden') {
|
|
101
|
-
await commands.updateCmd.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
await commands.updateCmd.apply({
|
|
104
|
+
kind: 'edit',
|
|
105
|
+
target,
|
|
106
|
+
updateKey: { key: groupToKey[currentGroup] },
|
|
107
|
+
operation: { name: 'remove', target: fieldName },
|
|
108
|
+
});
|
|
106
109
|
}
|
|
107
110
|
|
|
108
111
|
// Add to new group (if not hidden)
|
|
109
112
|
if (targetGroup !== 'hidden') {
|
|
110
|
-
await commands.updateCmd.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
113
|
+
await commands.updateCmd.apply({
|
|
114
|
+
kind: 'edit',
|
|
115
|
+
target,
|
|
116
|
+
updateKey: { key: groupToKey[targetGroup] },
|
|
117
|
+
operation: { name: 'add', target: fieldName },
|
|
118
|
+
});
|
|
115
119
|
|
|
116
120
|
if (targetIndex !== undefined) {
|
|
117
|
-
await commands.updateCmd.
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
121
|
+
await commands.updateCmd.apply({
|
|
122
|
+
kind: 'edit',
|
|
123
|
+
target,
|
|
124
|
+
updateKey: { key: groupToKey[targetGroup] },
|
|
125
|
+
operation: { name: 'rank', target: fieldName, newIndex: targetIndex },
|
|
126
|
+
});
|
|
122
127
|
}
|
|
123
128
|
}
|
|
124
129
|
}, `Update field visibility for ${cardTypeName}`);
|
package/src/domain/cards/lib.ts
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import
|
|
14
|
+
import { convert } from '@asciidoctor/core';
|
|
15
15
|
import type { Card } from '@cyberismo/data-handler/interfaces/project-interfaces';
|
|
16
16
|
import { type CommandManager, evaluateMacros } from '@cyberismo/data-handler';
|
|
17
17
|
import { preprocessMermaidBlocksForHtml } from '@cyberismo/data-handler/utils/mermaid-renderer';
|
|
@@ -71,15 +71,15 @@ export async function getCardDetails(
|
|
|
71
71
|
);
|
|
72
72
|
|
|
73
73
|
const projectPrefix = commands.project.projectPrefix;
|
|
74
|
-
const htmlContent =
|
|
75
|
-
|
|
74
|
+
const htmlContent = (
|
|
75
|
+
await convert(asciidocContent, {
|
|
76
76
|
safe: 'safe',
|
|
77
77
|
attributes: {
|
|
78
78
|
imagesdir: `/api/projects/${projectPrefix}/cards/${key}/a`,
|
|
79
79
|
icons: 'font',
|
|
80
80
|
},
|
|
81
81
|
})
|
|
82
|
-
|
|
82
|
+
).toString();
|
|
83
83
|
|
|
84
84
|
if (raw) {
|
|
85
85
|
if (!cardDetailsResponse.metadata) {
|
|
@@ -105,6 +105,13 @@ export async function getCardDetails(
|
|
|
105
105
|
fieldDescription: fieldType.description,
|
|
106
106
|
dataType: fieldType.dataType,
|
|
107
107
|
isCalculated: customField.isCalculated,
|
|
108
|
+
isOverridable: !!(
|
|
109
|
+
customField.isCalculated && customField.enableOverride
|
|
110
|
+
),
|
|
111
|
+
overrideValue:
|
|
112
|
+
customField.isCalculated && customField.enableOverride
|
|
113
|
+
? cardDetailsResponse.metadata[customField.name]
|
|
114
|
+
: undefined,
|
|
108
115
|
value: cardDetailsResponse.metadata[customField.name],
|
|
109
116
|
enumValues: fieldType.enumValues ?? [],
|
|
110
117
|
});
|
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
-
import
|
|
14
|
+
import { convert } from '@asciidoctor/core';
|
|
15
15
|
import type {
|
|
16
16
|
ExportPdfOptions,
|
|
17
17
|
MetadataContent,
|
|
@@ -181,17 +181,16 @@ export async function parseContent(
|
|
|
181
181
|
'inject',
|
|
182
182
|
);
|
|
183
183
|
|
|
184
|
-
const processor = Processor();
|
|
185
184
|
const projectPrefix = commands.project.projectPrefix;
|
|
186
|
-
const parsedContent =
|
|
187
|
-
|
|
185
|
+
const parsedContent = (
|
|
186
|
+
await convert(asciidocContent, {
|
|
188
187
|
safe: 'safe',
|
|
189
188
|
attributes: {
|
|
190
189
|
imagesdir: `/api/projects/${projectPrefix}/cards/${key}/a`,
|
|
191
190
|
icons: 'font',
|
|
192
191
|
},
|
|
193
192
|
})
|
|
194
|
-
|
|
193
|
+
).toString();
|
|
195
194
|
|
|
196
195
|
return { parsedContent };
|
|
197
196
|
});
|
|
@@ -14,8 +14,11 @@
|
|
|
14
14
|
import { Hono } from 'hono';
|
|
15
15
|
import { zValidator } from '../../middleware/zvalidator.js';
|
|
16
16
|
import {
|
|
17
|
+
addHubSchema,
|
|
18
|
+
cleanSchema,
|
|
17
19
|
importModuleSchema,
|
|
18
20
|
moduleParamSchema,
|
|
21
|
+
removeHubSchema,
|
|
19
22
|
updateProjectSchema,
|
|
20
23
|
} from './schema.js';
|
|
21
24
|
import * as projectService from './service.js';
|
|
@@ -92,4 +95,55 @@ router.delete(
|
|
|
92
95
|
},
|
|
93
96
|
);
|
|
94
97
|
|
|
98
|
+
router.get('/hubs', requireRole(UserRole.Reader), async (c) => {
|
|
99
|
+
const commands = c.get('commands');
|
|
100
|
+
const hubs = await projectService.getHubs(commands);
|
|
101
|
+
return c.json(hubs);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
router.post(
|
|
105
|
+
'/hubs',
|
|
106
|
+
requireRole(UserRole.Admin),
|
|
107
|
+
zValidator('json', addHubSchema),
|
|
108
|
+
async (c) => {
|
|
109
|
+
const commands = c.get('commands');
|
|
110
|
+
const { location } = c.req.valid('json');
|
|
111
|
+
const unreachable = await projectService.addHub(commands, location);
|
|
112
|
+
return c.json({ message: 'Hub added', unreachable });
|
|
113
|
+
},
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
router.delete(
|
|
117
|
+
'/hubs',
|
|
118
|
+
requireRole(UserRole.Admin),
|
|
119
|
+
zValidator('query', removeHubSchema),
|
|
120
|
+
async (c) => {
|
|
121
|
+
const commands = c.get('commands');
|
|
122
|
+
const { location } = c.req.valid('query');
|
|
123
|
+
await projectService.removeHub(commands, location);
|
|
124
|
+
return c.json({ message: 'Hub removed' });
|
|
125
|
+
},
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
router.post('/hubs/fetch', requireRole(UserRole.Admin), async (c) => {
|
|
129
|
+
const commands = c.get('commands');
|
|
130
|
+
const unreachable = await projectService.fetchHubs(commands);
|
|
131
|
+
return c.json({ message: 'Hubs fetched', unreachable });
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
// A non-empty 'failedCards' in the response is a partial success, not an error:
|
|
135
|
+
// the command collects per-card failures instead of throwing, so the report of
|
|
136
|
+
// what was and was not removed is returned with 200.
|
|
137
|
+
router.post(
|
|
138
|
+
'/clean',
|
|
139
|
+
requireRole(UserRole.Admin),
|
|
140
|
+
zValidator('json', cleanSchema),
|
|
141
|
+
async (c) => {
|
|
142
|
+
const commands = c.get('commands');
|
|
143
|
+
const { dryRun } = c.req.valid('json');
|
|
144
|
+
const result = await projectService.cleanProject(commands, dryRun);
|
|
145
|
+
return c.json(result);
|
|
146
|
+
},
|
|
147
|
+
);
|
|
148
|
+
|
|
95
149
|
export default router;
|
|
@@ -20,6 +20,8 @@ export const moduleParamSchema = z.object({
|
|
|
20
20
|
export const updateProjectSchema = z.object({
|
|
21
21
|
name: z.string().optional(),
|
|
22
22
|
cardKeyPrefix: z.string().optional(),
|
|
23
|
+
description: z.string().optional(),
|
|
24
|
+
category: z.string().optional(),
|
|
23
25
|
gitRemoteUrl: z
|
|
24
26
|
.string()
|
|
25
27
|
.refine((s) => s.startsWith('https://') || s.startsWith('git@'), {
|
|
@@ -28,6 +30,27 @@ export const updateProjectSchema = z.object({
|
|
|
28
30
|
.optional(),
|
|
29
31
|
});
|
|
30
32
|
|
|
33
|
+
export const addHubSchema = z.object({
|
|
34
|
+
location: z.url({
|
|
35
|
+
protocol: /^https?$/,
|
|
36
|
+
error: 'Hub location must be a valid HTTP or HTTPS URL',
|
|
37
|
+
}),
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Removal accepts any stored location: configurations written before locations
|
|
41
|
+
// were validated may hold entries this schema would otherwise refuse, and those
|
|
42
|
+
// have to stay removable.
|
|
43
|
+
export const removeHubSchema = z.object({
|
|
44
|
+
location: z.string().min(1),
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// 'dryRun' is required so that a request whose body did not arrive fails with
|
|
48
|
+
// 400 instead of defaulting into the destructive real clean. The command's
|
|
49
|
+
// 'cardType' narrowing is deliberately not exposed yet.
|
|
50
|
+
export const cleanSchema = z.object({
|
|
51
|
+
dryRun: z.boolean(),
|
|
52
|
+
});
|
|
53
|
+
|
|
31
54
|
export const importModuleSchema = z.object({
|
|
32
55
|
source: z
|
|
33
56
|
.string()
|
|
@@ -12,10 +12,14 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import {
|
|
15
|
+
type CleanResult,
|
|
15
16
|
type CommandManager,
|
|
17
|
+
type HubFetchFailure,
|
|
16
18
|
type ModuleSettingFromHub,
|
|
17
19
|
} from '@cyberismo/data-handler';
|
|
18
20
|
|
|
21
|
+
export type { CleanResult } from '@cyberismo/data-handler';
|
|
22
|
+
|
|
19
23
|
export interface ProjectModule {
|
|
20
24
|
name: string;
|
|
21
25
|
cardKeyPrefix: string;
|
|
@@ -24,6 +28,8 @@ export interface ProjectModule {
|
|
|
24
28
|
export interface ProjectInfo {
|
|
25
29
|
name: string;
|
|
26
30
|
cardKeyPrefix: string;
|
|
31
|
+
description: string;
|
|
32
|
+
category: string;
|
|
27
33
|
modules: ProjectModule[];
|
|
28
34
|
gitRemoteUrl: string | null;
|
|
29
35
|
}
|
|
@@ -31,9 +37,25 @@ export interface ProjectInfo {
|
|
|
31
37
|
export interface ProjectUpdatePayload {
|
|
32
38
|
name?: string;
|
|
33
39
|
cardKeyPrefix?: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
category?: string;
|
|
34
42
|
gitRemoteUrl?: string;
|
|
35
43
|
}
|
|
36
44
|
|
|
45
|
+
export interface HubModuleInfo {
|
|
46
|
+
name: string;
|
|
47
|
+
displayName?: string;
|
|
48
|
+
location: string;
|
|
49
|
+
imported: boolean;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface HubInfo {
|
|
53
|
+
location: string;
|
|
54
|
+
displayName?: string;
|
|
55
|
+
description?: string;
|
|
56
|
+
modules: HubModuleInfo[];
|
|
57
|
+
}
|
|
58
|
+
|
|
37
59
|
async function toModuleInfo(
|
|
38
60
|
commands: CommandManager,
|
|
39
61
|
moduleName: string,
|
|
@@ -67,6 +89,8 @@ export async function getProject(
|
|
|
67
89
|
return {
|
|
68
90
|
name: project.name,
|
|
69
91
|
cardKeyPrefix: project.prefix,
|
|
92
|
+
description: project.description ?? '',
|
|
93
|
+
category: project.category ?? '',
|
|
70
94
|
modules: moduleDetails,
|
|
71
95
|
gitRemoteUrl,
|
|
72
96
|
};
|
|
@@ -77,7 +101,7 @@ export async function updateProject(
|
|
|
77
101
|
commands: CommandManager,
|
|
78
102
|
updates: ProjectUpdatePayload,
|
|
79
103
|
): Promise<ProjectInfo> {
|
|
80
|
-
const { name, cardKeyPrefix, gitRemoteUrl } = updates;
|
|
104
|
+
const { name, cardKeyPrefix, description, category, gitRemoteUrl } = updates;
|
|
81
105
|
|
|
82
106
|
await commands.atomic(async () => {
|
|
83
107
|
if (cardKeyPrefix) {
|
|
@@ -86,6 +110,12 @@ export async function updateProject(
|
|
|
86
110
|
if (name) {
|
|
87
111
|
await commands.project.configuration.setProjectName(name);
|
|
88
112
|
}
|
|
113
|
+
if (description !== undefined) {
|
|
114
|
+
await commands.project.configuration.setDescription(description);
|
|
115
|
+
}
|
|
116
|
+
if (category !== undefined) {
|
|
117
|
+
await commands.project.configuration.setCategory(category);
|
|
118
|
+
}
|
|
89
119
|
}, 'Update project settings');
|
|
90
120
|
|
|
91
121
|
if (gitRemoteUrl !== undefined) {
|
|
@@ -107,9 +137,21 @@ export async function deleteModule(commands: CommandManager, module: string) {
|
|
|
107
137
|
await commands.removeCmd.remove('module', module);
|
|
108
138
|
}
|
|
109
139
|
|
|
140
|
+
// Hub data is only refreshed on demand, so a project that has never fetched
|
|
141
|
+
// would otherwise show an empty catalogue until the user asks for a refresh.
|
|
142
|
+
async function populateHubCache(commands: CommandManager) {
|
|
143
|
+
try {
|
|
144
|
+
await commands.fetchCmd.ensureModuleListExists();
|
|
145
|
+
} catch (error) {
|
|
146
|
+
// An unreachable hub must not fail listing the hubs we already know about.
|
|
147
|
+
console.warn('Failed to populate the hub cache', error);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
110
151
|
export async function getImportableModules(
|
|
111
152
|
commands: CommandManager,
|
|
112
153
|
): Promise<ModuleSettingFromHub[]> {
|
|
154
|
+
await populateHubCache(commands);
|
|
113
155
|
return commands.showCmd.showImportableModules(false, true);
|
|
114
156
|
}
|
|
115
157
|
|
|
@@ -119,3 +161,49 @@ export async function importModule(
|
|
|
119
161
|
): Promise<void> {
|
|
120
162
|
await commands.importCmd.importModule(source);
|
|
121
163
|
}
|
|
164
|
+
|
|
165
|
+
export async function getHubs(commands: CommandManager): Promise<HubInfo[]> {
|
|
166
|
+
await populateHubCache(commands);
|
|
167
|
+
const hubs = await commands.showCmd.showHubDetails();
|
|
168
|
+
const importedModules = new Set(
|
|
169
|
+
(await commands.showCmd.showModules()).map((mod) => mod.name),
|
|
170
|
+
);
|
|
171
|
+
return hubs.map((hub) => ({
|
|
172
|
+
location: hub.location,
|
|
173
|
+
displayName: hub.displayName,
|
|
174
|
+
description: hub.description,
|
|
175
|
+
modules: hub.modules.map((mod) => ({
|
|
176
|
+
name: mod.name,
|
|
177
|
+
displayName: mod.displayName,
|
|
178
|
+
location: mod.location,
|
|
179
|
+
imported: importedModules.has(mod.name),
|
|
180
|
+
})),
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export async function addHub(
|
|
185
|
+
commands: CommandManager,
|
|
186
|
+
location: string,
|
|
187
|
+
): Promise<HubFetchFailure[]> {
|
|
188
|
+
await commands.createCmd.addHubLocation(location);
|
|
189
|
+
// The hub is configured even when it cannot be reached right now; its
|
|
190
|
+
// modules appear once a later refresh succeeds.
|
|
191
|
+
return commands.fetchCmd.fetchHubs(true);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export async function removeHub(commands: CommandManager, location: string) {
|
|
195
|
+
await commands.removeCmd.remove('hub', location);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export async function fetchHubs(
|
|
199
|
+
commands: CommandManager,
|
|
200
|
+
): Promise<HubFetchFailure[]> {
|
|
201
|
+
return commands.fetchCmd.fetchHubs(true);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
export async function cleanProject(
|
|
205
|
+
commands: CommandManager,
|
|
206
|
+
dryRun: boolean,
|
|
207
|
+
): Promise<CleanResult> {
|
|
208
|
+
return commands.cleanCmd.clean(dryRun);
|
|
209
|
+
}
|
|
@@ -12,11 +12,17 @@
|
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
14
|
import { Hono } from 'hono';
|
|
15
|
+
import { zValidator } from '../../middleware/zvalidator.js';
|
|
15
16
|
import type { ProjectRegistry } from '../../project-registry.js';
|
|
16
|
-
import { requireRole } from '../../middleware/auth.js';
|
|
17
|
+
import { requireRole, getCurrentUser } from '../../middleware/auth.js';
|
|
17
18
|
import { UserRole } from '../../types.js';
|
|
19
|
+
import { createProjectSchema, cloneProjectSchema } from './schema.js';
|
|
20
|
+
import * as projectsService from './service.js';
|
|
18
21
|
|
|
19
|
-
export function createProjectsRouter(
|
|
22
|
+
export function createProjectsRouter(
|
|
23
|
+
registry: ProjectRegistry,
|
|
24
|
+
multiProjectRoot?: string,
|
|
25
|
+
) {
|
|
20
26
|
const router = new Hono();
|
|
21
27
|
|
|
22
28
|
/**
|
|
@@ -32,8 +38,114 @@ export function createProjectsRouter(registry: ProjectRegistry) {
|
|
|
32
38
|
* description: Unauthorized
|
|
33
39
|
*/
|
|
34
40
|
router.get('/', requireRole(UserRole.Reader), (c) => {
|
|
35
|
-
return c.json(
|
|
41
|
+
return c.json({
|
|
42
|
+
projects: registry.list(),
|
|
43
|
+
canCreateProjects: !!multiProjectRoot,
|
|
44
|
+
});
|
|
36
45
|
});
|
|
37
46
|
|
|
47
|
+
/**
|
|
48
|
+
* @swagger
|
|
49
|
+
* /api/projects:
|
|
50
|
+
* post:
|
|
51
|
+
* summary: Create a new project
|
|
52
|
+
* description: Creates a new project on disk, initializes git, adds default hub
|
|
53
|
+
*/
|
|
54
|
+
router.post(
|
|
55
|
+
'/',
|
|
56
|
+
requireRole(UserRole.Editor),
|
|
57
|
+
zValidator('json', createProjectSchema),
|
|
58
|
+
async (c) => {
|
|
59
|
+
if (!multiProjectRoot) {
|
|
60
|
+
return c.json(
|
|
61
|
+
{ error: 'Project creation is not available in single-project mode' },
|
|
62
|
+
403,
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const params = c.req.valid('json');
|
|
67
|
+
|
|
68
|
+
if (registry.has(params.prefix)) {
|
|
69
|
+
return c.json(
|
|
70
|
+
{ error: `Project with prefix '${params.prefix}' already exists` },
|
|
71
|
+
409,
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
try {
|
|
76
|
+
const result = await projectsService.createProject(
|
|
77
|
+
registry,
|
|
78
|
+
multiProjectRoot,
|
|
79
|
+
params,
|
|
80
|
+
getCurrentUser(c),
|
|
81
|
+
);
|
|
82
|
+
return c.json(result, 201);
|
|
83
|
+
} catch (error) {
|
|
84
|
+
return c.json(
|
|
85
|
+
{
|
|
86
|
+
error:
|
|
87
|
+
error instanceof Error
|
|
88
|
+
? error.message
|
|
89
|
+
: 'Failed to create project',
|
|
90
|
+
},
|
|
91
|
+
500,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* @swagger
|
|
99
|
+
* /api/projects/clone:
|
|
100
|
+
* post:
|
|
101
|
+
* summary: Clone a project from a git repository
|
|
102
|
+
* description: Clones a git repo and registers discovered projects
|
|
103
|
+
*/
|
|
104
|
+
router.post(
|
|
105
|
+
'/clone',
|
|
106
|
+
requireRole(UserRole.Editor),
|
|
107
|
+
zValidator('json', cloneProjectSchema),
|
|
108
|
+
async (c) => {
|
|
109
|
+
if (!multiProjectRoot) {
|
|
110
|
+
return c.json(
|
|
111
|
+
{ error: 'Project cloning is not available in single-project mode' },
|
|
112
|
+
403,
|
|
113
|
+
);
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
const { url } = c.req.valid('json');
|
|
117
|
+
|
|
118
|
+
try {
|
|
119
|
+
const result = await projectsService.cloneProject(
|
|
120
|
+
registry,
|
|
121
|
+
multiProjectRoot,
|
|
122
|
+
url,
|
|
123
|
+
);
|
|
124
|
+
|
|
125
|
+
if (result.projects.length === 0) {
|
|
126
|
+
return c.json(
|
|
127
|
+
{
|
|
128
|
+
error: 'All projects in the cloned repository already exist',
|
|
129
|
+
skippedDuplicates: result.skippedDuplicates,
|
|
130
|
+
},
|
|
131
|
+
409,
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return c.json(result, 201);
|
|
136
|
+
} catch (error) {
|
|
137
|
+
return c.json(
|
|
138
|
+
{
|
|
139
|
+
error:
|
|
140
|
+
error instanceof Error
|
|
141
|
+
? error.message
|
|
142
|
+
: 'Failed to clone repository',
|
|
143
|
+
},
|
|
144
|
+
500,
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
);
|
|
149
|
+
|
|
38
150
|
return router;
|
|
39
151
|
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
Cyberismo
|
|
3
|
+
Copyright © Cyberismo Ltd and contributors 2026
|
|
4
|
+
This program is free software: you can redistribute it and/or modify it under
|
|
5
|
+
the terms of the GNU Affero General Public License version 3 as published by
|
|
6
|
+
the Free Software Foundation.
|
|
7
|
+
This program is distributed in the hope that it will be useful, but WITHOUT
|
|
8
|
+
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
9
|
+
FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
10
|
+
details. You should have received a copy of the GNU Affero General Public
|
|
11
|
+
License along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { z } from 'zod';
|
|
15
|
+
import { Validate } from '@cyberismo/data-handler';
|
|
16
|
+
|
|
17
|
+
export const createProjectSchema = z.object({
|
|
18
|
+
name: z
|
|
19
|
+
.string()
|
|
20
|
+
.min(1, 'Project name is required')
|
|
21
|
+
.refine((s) => Validate.isValidProjectName(s), {
|
|
22
|
+
message: 'Invalid project name',
|
|
23
|
+
}),
|
|
24
|
+
prefix: z
|
|
25
|
+
.string()
|
|
26
|
+
.min(3, 'Prefix must be at least 3 characters')
|
|
27
|
+
.max(10, 'Prefix must be at most 10 characters')
|
|
28
|
+
.refine((s) => Validate.validatePrefix(s), {
|
|
29
|
+
message: 'Prefix must contain only lowercase letters',
|
|
30
|
+
}),
|
|
31
|
+
category: z.string().optional().default(''),
|
|
32
|
+
description: z.string().optional().default(''),
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
export const cloneProjectSchema = z.object({
|
|
36
|
+
url: z
|
|
37
|
+
.string()
|
|
38
|
+
.min(1, 'Repository URL is required')
|
|
39
|
+
.refine((s) => s.startsWith('https://') || s.startsWith('git@'), {
|
|
40
|
+
message: 'URL must start with https:// or git@',
|
|
41
|
+
}),
|
|
42
|
+
});
|