nextjs-cms 0.5.9 → 0.5.11

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.
Files changed (258) hide show
  1. package/dist/api/axios/axiosInstance.d.ts +1 -1
  2. package/dist/api/axios/axiosInstance.js +8 -8
  3. package/dist/api/index.d.ts +855 -855
  4. package/dist/api/index.d.ts.map +1 -1
  5. package/dist/api/index.js +12 -12
  6. package/dist/api/lib/serverActions.d.ts +239 -239
  7. package/dist/api/lib/serverActions.d.ts.map +1 -1
  8. package/dist/api/lib/serverActions.js +834 -834
  9. package/dist/api/root.d.ts +828 -828
  10. package/dist/api/root.js +30 -30
  11. package/dist/api/routers/accountSettings.d.ts +60 -60
  12. package/dist/api/routers/accountSettings.js +108 -108
  13. package/dist/api/routers/admins.d.ts +105 -105
  14. package/dist/api/routers/admins.js +219 -219
  15. package/dist/api/routers/auth.d.ts +47 -47
  16. package/dist/api/routers/auth.js +25 -25
  17. package/dist/api/routers/categorySection.d.ts +103 -103
  18. package/dist/api/routers/categorySection.js +38 -38
  19. package/dist/api/routers/cmsSettings.d.ts +48 -48
  20. package/dist/api/routers/cmsSettings.js +51 -51
  21. package/dist/api/routers/cpanel.d.ts +83 -83
  22. package/dist/api/routers/cpanel.js +216 -216
  23. package/dist/api/routers/files.d.ts +47 -47
  24. package/dist/api/routers/files.js +23 -23
  25. package/dist/api/routers/gallery.d.ts +35 -35
  26. package/dist/api/routers/gallery.js +62 -62
  27. package/dist/api/routers/googleAnalytics.d.ts +30 -30
  28. package/dist/api/routers/googleAnalytics.js +7 -7
  29. package/dist/api/routers/hasItemsSection.d.ts +139 -139
  30. package/dist/api/routers/hasItemsSection.js +34 -34
  31. package/dist/api/routers/navigation.d.ts +51 -51
  32. package/dist/api/routers/navigation.js +11 -11
  33. package/dist/api/routers/simpleSection.d.ts +57 -57
  34. package/dist/api/routers/simpleSection.js +12 -12
  35. package/dist/api/trpc.d.ts +106 -106
  36. package/dist/api/trpc.js +72 -72
  37. package/dist/auth/axios/axiosInstance.d.ts +1 -1
  38. package/dist/auth/axios/axiosInstance.js +8 -8
  39. package/dist/auth/csrf.d.ts +29 -29
  40. package/dist/auth/csrf.js +76 -76
  41. package/dist/auth/hooks/index.d.ts +3 -3
  42. package/dist/auth/hooks/index.d.ts.map +1 -1
  43. package/dist/auth/hooks/index.js +3 -3
  44. package/dist/auth/hooks/useAxiosPrivate.d.ts +4 -4
  45. package/dist/auth/hooks/useAxiosPrivate.js +74 -74
  46. package/dist/auth/hooks/useRefreshToken.d.ts +6 -6
  47. package/dist/auth/hooks/useRefreshToken.js +79 -79
  48. package/dist/auth/index.d.ts +22 -22
  49. package/dist/auth/index.js +44 -44
  50. package/dist/auth/jwt.d.ts +5 -5
  51. package/dist/auth/jwt.js +25 -25
  52. package/dist/auth/lib/actions.d.ts +32 -32
  53. package/dist/auth/lib/actions.d.ts.map +1 -1
  54. package/dist/auth/lib/actions.js +209 -209
  55. package/dist/auth/lib/client.d.ts +3 -3
  56. package/dist/auth/lib/client.js +46 -46
  57. package/dist/auth/lib/index.d.ts +2 -2
  58. package/dist/auth/lib/index.d.ts.map +1 -1
  59. package/dist/auth/lib/index.js +2 -2
  60. package/dist/auth/react.d.ts +105 -105
  61. package/dist/auth/react.d.ts.map +1 -1
  62. package/dist/auth/react.js +347 -347
  63. package/dist/auth/trpc.d.ts +5 -5
  64. package/dist/auth/trpc.d.ts.map +1 -1
  65. package/dist/auth/trpc.js +81 -81
  66. package/dist/core/config/config-loader.d.ts +91 -91
  67. package/dist/core/config/config-loader.js +230 -230
  68. package/dist/core/config/index.d.ts +2 -2
  69. package/dist/core/config/index.d.ts.map +1 -1
  70. package/dist/core/config/index.js +1 -1
  71. package/dist/core/config/loader.d.ts +1 -1
  72. package/dist/core/config/loader.js +42 -42
  73. package/dist/core/db/index.d.ts +1 -1
  74. package/dist/core/db/index.d.ts.map +1 -1
  75. package/dist/core/db/index.js +1 -1
  76. package/dist/core/db/table-checker/DbTable.d.ts +5 -5
  77. package/dist/core/db/table-checker/DbTable.js +5 -5
  78. package/dist/core/db/table-checker/MysqlTable.d.ts +33 -33
  79. package/dist/core/db/table-checker/MysqlTable.d.ts.map +1 -1
  80. package/dist/core/db/table-checker/MysqlTable.js +94 -94
  81. package/dist/core/db/table-checker/index.d.ts +1 -1
  82. package/dist/core/db/table-checker/index.d.ts.map +1 -1
  83. package/dist/core/db/table-checker/index.js +1 -1
  84. package/dist/core/factories/FieldFactory.d.ts +123 -123
  85. package/dist/core/factories/FieldFactory.d.ts.map +1 -1
  86. package/dist/core/factories/FieldFactory.js +411 -411
  87. package/dist/core/factories/SectionFactory.d.ts +109 -109
  88. package/dist/core/factories/SectionFactory.d.ts.map +1 -1
  89. package/dist/core/factories/SectionFactory.js +415 -415
  90. package/dist/core/factories/index.d.ts +2 -2
  91. package/dist/core/factories/index.d.ts.map +1 -1
  92. package/dist/core/factories/index.js +2 -2
  93. package/dist/core/fields/checkbox.d.ts +62 -62
  94. package/dist/core/fields/checkbox.d.ts.map +1 -1
  95. package/dist/core/fields/checkbox.js +62 -62
  96. package/dist/core/fields/color.d.ts +83 -83
  97. package/dist/core/fields/color.d.ts.map +1 -1
  98. package/dist/core/fields/color.js +91 -91
  99. package/dist/core/fields/date.d.ts +99 -99
  100. package/dist/core/fields/date.d.ts.map +1 -1
  101. package/dist/core/fields/date.js +108 -108
  102. package/dist/core/fields/document.d.ts +179 -179
  103. package/dist/core/fields/document.d.ts.map +1 -1
  104. package/dist/core/fields/document.js +277 -277
  105. package/dist/core/fields/field-group.d.ts +17 -17
  106. package/dist/core/fields/field-group.d.ts.map +1 -1
  107. package/dist/core/fields/field-group.js +6 -6
  108. package/dist/core/fields/field.d.ts +125 -125
  109. package/dist/core/fields/field.d.ts.map +1 -1
  110. package/dist/core/fields/field.js +148 -148
  111. package/dist/core/fields/fileField.d.ts +14 -14
  112. package/dist/core/fields/fileField.d.ts.map +1 -1
  113. package/dist/core/fields/fileField.js +5 -5
  114. package/dist/core/fields/index.d.ts +64 -64
  115. package/dist/core/fields/index.d.ts.map +1 -1
  116. package/dist/core/fields/index.js +18 -18
  117. package/dist/core/fields/map.d.ts +166 -166
  118. package/dist/core/fields/map.d.ts.map +1 -1
  119. package/dist/core/fields/map.js +152 -152
  120. package/dist/core/fields/number.d.ts +185 -185
  121. package/dist/core/fields/number.d.ts.map +1 -1
  122. package/dist/core/fields/number.js +241 -241
  123. package/dist/core/fields/password.d.ts +108 -108
  124. package/dist/core/fields/password.d.ts.map +1 -1
  125. package/dist/core/fields/password.js +133 -133
  126. package/dist/core/fields/photo.d.ts +288 -288
  127. package/dist/core/fields/photo.d.ts.map +1 -1
  128. package/dist/core/fields/photo.js +410 -410
  129. package/dist/core/fields/richText.d.ts +294 -294
  130. package/dist/core/fields/richText.d.ts.map +1 -1
  131. package/dist/core/fields/richText.js +338 -338
  132. package/dist/core/fields/select.d.ts +365 -365
  133. package/dist/core/fields/select.d.ts.map +1 -1
  134. package/dist/core/fields/select.js +499 -499
  135. package/dist/core/fields/selectMultiple.d.ts +235 -235
  136. package/dist/core/fields/selectMultiple.d.ts.map +1 -1
  137. package/dist/core/fields/selectMultiple.js +417 -417
  138. package/dist/core/fields/tags.d.ts +130 -130
  139. package/dist/core/fields/tags.d.ts.map +1 -1
  140. package/dist/core/fields/tags.js +105 -105
  141. package/dist/core/fields/text.d.ts +135 -135
  142. package/dist/core/fields/text.d.ts.map +1 -1
  143. package/dist/core/fields/text.js +157 -157
  144. package/dist/core/fields/textArea.d.ts +106 -106
  145. package/dist/core/fields/textArea.d.ts.map +1 -1
  146. package/dist/core/fields/textArea.js +126 -126
  147. package/dist/core/fields/video.d.ts +147 -147
  148. package/dist/core/fields/video.d.ts.map +1 -1
  149. package/dist/core/fields/video.js +248 -248
  150. package/dist/core/helpers/entity.d.ts +7 -7
  151. package/dist/core/helpers/entity.js +27 -27
  152. package/dist/core/helpers/index.d.ts +4 -4
  153. package/dist/core/helpers/index.d.ts.map +1 -1
  154. package/dist/core/helpers/index.js +3 -3
  155. package/dist/core/index.d.ts +7 -7
  156. package/dist/core/index.d.ts.map +1 -1
  157. package/dist/core/index.js +7 -7
  158. package/dist/core/sections/category.d.ts +282 -282
  159. package/dist/core/sections/category.d.ts.map +1 -1
  160. package/dist/core/sections/category.js +147 -147
  161. package/dist/core/sections/hasItems.d.ts +631 -631
  162. package/dist/core/sections/hasItems.d.ts.map +1 -1
  163. package/dist/core/sections/hasItems.js +144 -144
  164. package/dist/core/sections/index.d.ts +4 -4
  165. package/dist/core/sections/index.d.ts.map +1 -1
  166. package/dist/core/sections/index.js +4 -4
  167. package/dist/core/sections/section.d.ts +225 -225
  168. package/dist/core/sections/section.d.ts.map +1 -1
  169. package/dist/core/sections/section.js +341 -341
  170. package/dist/core/sections/simple.d.ts +98 -98
  171. package/dist/core/sections/simple.d.ts.map +1 -1
  172. package/dist/core/sections/simple.js +95 -95
  173. package/dist/core/security/dom.d.ts +10 -10
  174. package/dist/core/security/dom.js +92 -92
  175. package/dist/core/submit/ItemEditSubmit.d.ts +75 -75
  176. package/dist/core/submit/ItemEditSubmit.js +186 -186
  177. package/dist/core/submit/NewItemSubmit.d.ts +13 -13
  178. package/dist/core/submit/NewItemSubmit.js +93 -93
  179. package/dist/core/submit/SimpleSectionSubmit.d.ts +12 -12
  180. package/dist/core/submit/SimpleSectionSubmit.js +93 -93
  181. package/dist/core/submit/index.d.ts +4 -4
  182. package/dist/core/submit/index.js +4 -4
  183. package/dist/core/submit/submit.d.ts +115 -115
  184. package/dist/core/submit/submit.js +479 -479
  185. package/dist/core/types/index.d.ts +279 -279
  186. package/dist/core/types/index.d.ts.map +1 -1
  187. package/dist/core/types/index.js +1 -1
  188. package/dist/db/client.d.ts +8 -8
  189. package/dist/db/client.d.ts.map +1 -1
  190. package/dist/db/client.js +19 -19
  191. package/dist/db/config.d.ts +5 -5
  192. package/dist/db/config.js +22 -22
  193. package/dist/db/drizzle.config.d.ts +5 -5
  194. package/dist/db/drizzle.config.js +18 -18
  195. package/dist/db/index.d.ts +2 -2
  196. package/dist/db/index.js +3 -3
  197. package/dist/db/schema.d.ts +638 -638
  198. package/dist/db/schema.js +73 -73
  199. package/dist/index.d.ts +7 -7
  200. package/dist/index.d.ts.map +1 -1
  201. package/dist/index.js +7 -7
  202. package/dist/translations/index.d.ts +2 -2
  203. package/dist/translations/index.js +15 -15
  204. package/dist/utils/CpanelApi.d.ts +24 -24
  205. package/dist/utils/CpanelApi.js +64 -64
  206. package/dist/utils/constants.d.ts +13 -13
  207. package/dist/utils/constants.js +61 -61
  208. package/dist/utils/index.d.ts +4 -4
  209. package/dist/utils/index.d.ts.map +1 -1
  210. package/dist/utils/index.js +4 -4
  211. package/dist/utils/utils.d.ts +59 -59
  212. package/dist/utils/utils.js +132 -132
  213. package/dist/validators/checkbox.d.ts +3 -3
  214. package/dist/validators/checkbox.d.ts.map +1 -1
  215. package/dist/validators/checkbox.js +12 -12
  216. package/dist/validators/color.d.ts +3 -3
  217. package/dist/validators/color.d.ts.map +1 -1
  218. package/dist/validators/color.js +7 -7
  219. package/dist/validators/date.d.ts +3 -3
  220. package/dist/validators/date.d.ts.map +1 -1
  221. package/dist/validators/date.js +5 -5
  222. package/dist/validators/document.d.ts +3 -3
  223. package/dist/validators/document.d.ts.map +1 -1
  224. package/dist/validators/document.js +57 -57
  225. package/dist/validators/index.d.ts +14 -14
  226. package/dist/validators/index.d.ts.map +1 -1
  227. package/dist/validators/index.js +14 -14
  228. package/dist/validators/map.d.ts +3 -3
  229. package/dist/validators/map.d.ts.map +1 -1
  230. package/dist/validators/map.js +5 -5
  231. package/dist/validators/number.d.ts +3 -3
  232. package/dist/validators/number.d.ts.map +1 -1
  233. package/dist/validators/number.js +20 -20
  234. package/dist/validators/password.d.ts +3 -3
  235. package/dist/validators/password.d.ts.map +1 -1
  236. package/dist/validators/password.js +11 -11
  237. package/dist/validators/photo.d.ts +3 -3
  238. package/dist/validators/photo.d.ts.map +1 -1
  239. package/dist/validators/photo.js +100 -100
  240. package/dist/validators/richText.d.ts +3 -3
  241. package/dist/validators/richText.d.ts.map +1 -1
  242. package/dist/validators/richText.js +8 -8
  243. package/dist/validators/select-multiple.d.ts +9 -9
  244. package/dist/validators/select-multiple.d.ts.map +1 -1
  245. package/dist/validators/select-multiple.js +20 -20
  246. package/dist/validators/select.d.ts +3 -3
  247. package/dist/validators/select.d.ts.map +1 -1
  248. package/dist/validators/select.js +5 -5
  249. package/dist/validators/text.d.ts +3 -3
  250. package/dist/validators/text.d.ts.map +1 -1
  251. package/dist/validators/text.js +7 -7
  252. package/dist/validators/textarea.d.ts +3 -3
  253. package/dist/validators/textarea.d.ts.map +1 -1
  254. package/dist/validators/textarea.js +7 -7
  255. package/dist/validators/video.d.ts +3 -3
  256. package/dist/validators/video.d.ts.map +1 -1
  257. package/dist/validators/video.js +57 -57
  258. package/package.json +4 -5
@@ -1,479 +1,479 @@
1
- import { sql } from 'drizzle-orm';
2
- import { db } from "../../db/client.js";
3
- import { SectionFactory } from "../factories.js";
4
- import { entityKind, is } from "../helpers.js";
5
- import { NumberField, PhotoField, SelectField, TextField } from "../fields.js";
6
- import { MysqlTableChecker } from "../db.js";
7
- export class Submit {
8
- static [entityKind] = 'Submit';
9
- user;
10
- _itemId = undefined;
11
- _error = false;
12
- _errorMessage = '';
13
- _notices = null;
14
- sectionName;
15
- _postData;
16
- _sectionInfo;
17
- preSubmit = false;
18
- sqlNamesAndValues = {};
19
- fields = [];
20
- /**
21
- * Constructor
22
- */
23
- constructor({ preSubmit, sectionName, user, postData }) {
24
- this.sectionName = sectionName;
25
- this.user = user;
26
- this._postData = postData;
27
- this.preSubmit = preSubmit ?? false;
28
- }
29
- /**
30
- * Run custom hooks after the item is updated
31
- * @protected
32
- */
33
- async runPostSubmitHooks() {
34
- try {
35
- await this._sectionInfo.hooks?.afterUpdate?.({
36
- itemId: this._itemId,
37
- values: this.sqlNamesAndValues,
38
- section: this._sectionInfo,
39
- });
40
- }
41
- catch (e) {
42
- // Do not break the submit flow if a hook throws
43
- console.error('afterUpdate hook failed:', e);
44
- }
45
- }
46
- /**
47
- * Log operation to the database
48
- */
49
- async logOperation({ operation, message }) {
50
- // TODO: Log the operation to the database,
51
- // get the heading input name and its value to identify the item,
52
- // then generate the log message
53
- }
54
- /**
55
- * Must be called after the constructor
56
- */
57
- async initialize(requiredRole = 'C') {
58
- await this.initializeSectionInfo(this.user, requiredRole);
59
- }
60
- /**
61
- * Gets the section info and assigns it to the `sectionInfo` property
62
- * @param user
63
- * @param requiredRole
64
- * @private
65
- */
66
- async initializeSectionInfo(user, requiredRole) {
67
- /**
68
- * First, let's get the section details, and then get the section input fields
69
- */
70
- const s = await SectionFactory.getSectionForAdmin({
71
- name: this.sectionName,
72
- admin: {
73
- id: user.id,
74
- requiredRole: requiredRole,
75
- },
76
- });
77
- if (!s || !s.name) {
78
- this._error = true;
79
- this._errorMessage = 'Section not found or you do not have access to this operation';
80
- return undefined;
81
- }
82
- /**
83
- * Build the section from config when we need to use it
84
- */
85
- this._sectionInfo = s.build();
86
- /**
87
- * Build the fields from the field configs
88
- */
89
- this._sectionInfo.buildFields();
90
- }
91
- /**
92
- * Perform post submit operations
93
- * This will initiate the post submit operations for each field (if any)
94
- * @private
95
- */
96
- async postSubmit() {
97
- try {
98
- /**
99
- * Perform post submit operations
100
- */
101
- for (const field of this._sectionInfo?.fields ?? []) {
102
- let variable = undefined;
103
- /**
104
- * Figure out the variable to pass to the post submit function
105
- */
106
- switch (field.type) {
107
- case 'photo':
108
- case 'document':
109
- case 'video':
110
- /**
111
- * File fields need the section name to save the file in the correct folder
112
- */
113
- variable = this._sectionInfo?.name;
114
- break;
115
- case 'select_multiple':
116
- case 'select':
117
- /**
118
- * Select multiple fields need the itemId,
119
- * to save the selected values in the correct table with the correct item id
120
- */
121
- variable = this._itemId;
122
- break;
123
- case 'rich_text':
124
- /**
125
- * Rich text fields need the section name to save the file in the correct folder,
126
- * and the itemId to save inline images with the correct item id in the `editor_photos` table
127
- */
128
- variable = {
129
- sectionName: this._sectionInfo?.name,
130
- itemId: this._itemId,
131
- };
132
- break;
133
- default:
134
- break;
135
- }
136
- /**
137
- * Call the post submit function
138
- */
139
- await field.postSubmit(variable);
140
- }
141
- }
142
- catch (e) {
143
- this._error = true;
144
- this._errorMessage = e.message;
145
- return;
146
- }
147
- }
148
- /**
149
- * Rollback post submit operations.<br>
150
- * This will rollback the post submit operations for each field (if any)
151
- * @private
152
- */
153
- async postSubmitRollback() {
154
- for (const field of this._sectionInfo?.fields ?? []) {
155
- await field.postSubmitRollback();
156
- }
157
- }
158
- /**
159
- * Check if the conditional field conditions are met for a field.
160
- * @param field
161
- * @private
162
- */
163
- checkConditionalField(field) {
164
- /**
165
- * Check if the conditions are met
166
- */
167
- let status = false;
168
- field.conditionalRules?.map((rule) => {
169
- switch (rule.condition) {
170
- case 'equals':
171
- status = this._postData.get(rule.field.name)?.toString() === `${rule.value}`;
172
- break;
173
- case 'notEquals':
174
- status = this._postData.get(rule.field.name)?.toString() !== `${rule.value}`;
175
- break;
176
- default:
177
- break;
178
- }
179
- });
180
- return status;
181
- }
182
- /**
183
- * Check if the field is required and perform the required checks.
184
- * @param field
185
- * @protected
186
- */
187
- checkRequired(field) {
188
- field.checkRequired();
189
- }
190
- /**
191
- * Set the field value.
192
- * @param field
193
- * @protected
194
- */
195
- setFieldValue(field) {
196
- let value;
197
- /**
198
- * Check if the field is a select field that has depth (selecting from category section with depth > 1)
199
- */
200
- if (is(field, SelectField)) {
201
- /**
202
- * If true, value can be an array of values
203
- */
204
- value = this._postData.getAll(field.name).filter(Boolean);
205
- field.setValue(value.map((v) => {
206
- return { value: v.toString(), label: '' };
207
- }));
208
- }
209
- else {
210
- value = this._postData.get(field.name);
211
- if (value)
212
- field.setValue(value);
213
- }
214
- }
215
- updateSqlNamesAndValues(field) {
216
- if (field.hasSqlNameAndValue()) {
217
- this.sqlNamesAndValues[field.name] = field.getSubmitValue();
218
- }
219
- }
220
- assignItemIdValue(field) {
221
- if (!this._itemId &&
222
- field.name === this._sectionInfo.db.identifier.name &&
223
- (is(field, NumberField) || is(field, TextField))) {
224
- this._itemId = field.getValue();
225
- }
226
- }
227
- /**
228
- * Handle the field
229
- * @param field
230
- * @protected
231
- */
232
- async handleField(field) {
233
- /**
234
- * Get the value from the post request,
235
- * and assign it to the field object
236
- */
237
- this.setFieldValue(field);
238
- /**
239
- * Check if field is conditional, and check if the conditions are met.
240
- * If the conditions are met, continue with the field.
241
- * If the field is not conditional, skip the field, because it will not be included in the sql query.
242
- */
243
- if (field.isConditional()) {
244
- /**
245
- * Check if the conditions are met
246
- */
247
- if (!this.checkConditionalField(field)) {
248
- /**
249
- * Conditions are not met, skip the field
250
- */
251
- return;
252
- }
253
- }
254
- try {
255
- /**
256
- * Check if the field is required,
257
- * This will throw an error if the field is required and the value is not present
258
- */
259
- this.checkRequired(field);
260
- /**
261
- * Prepare the field for submission,
262
- * this will throw an error if the checks fail
263
- */
264
- await field.prepareForSubmission();
265
- }
266
- catch (e) {
267
- this._error = true;
268
- this._errorMessage = e.message;
269
- return;
270
- }
271
- /**
272
- * Add the sql name and value to the sqlNamesAndValues object
273
- */
274
- this.updateSqlNamesAndValues(field);
275
- /**
276
- * Assign the itemId value
277
- */
278
- this.assignItemIdValue(field);
279
- }
280
- async handleFields() {
281
- if (this._error)
282
- return;
283
- if (!this._sectionInfo)
284
- return;
285
- for (const field of this._sectionInfo.fields ?? []) {
286
- if (field) {
287
- await this.handleField(field);
288
- }
289
- }
290
- }
291
- /**
292
- * Execute the sql query.
293
- * @param sqlQuery
294
- * @private
295
- */
296
- async executeQuery(sqlQuery) {
297
- if (this._error)
298
- return;
299
- /**
300
- * If there is a sql query, let's execute it
301
- */
302
- if (!sqlQuery) {
303
- this._error = true;
304
- this._errorMessage = 'SQL query is not defined';
305
- return;
306
- }
307
- try {
308
- const [submit, fields] = await db.execute(sqlQuery);
309
- /**
310
- * If there is no itemId,
311
- * there should be an auto increment field in the table
312
- * assign the insertId to the itemId property
313
- */
314
- if (!this._itemId) {
315
- this._itemId = submit.insertId;
316
- }
317
- }
318
- catch (e) {
319
- this._error = true;
320
- this._errorMessage = e.message;
321
- return;
322
- }
323
- }
324
- /**
325
- * Try to submit the form.
326
- */
327
- async submit() {
328
- /**
329
- * Assign the values to the fields
330
- */
331
- await this.handleFields();
332
- /**
333
- * If this is a pre-submit operation, don't submit the form
334
- */
335
- if (this.preSubmit) {
336
- return;
337
- }
338
- /**
339
- * Build the sql query
340
- */
341
- const sqlQuery = this.buildSqlQuery();
342
- /**
343
- * Execute the sql query
344
- */
345
- await this.executeQuery(sqlQuery);
346
- /**
347
- * Just return if there is an error,
348
- * because post submit operations did not run yet
349
- */
350
- if (this._error) {
351
- return;
352
- }
353
- /**
354
- * Perform post submit operations
355
- */
356
- await this.postSubmit();
357
- /**
358
- * If there is an error in any of the post submit operations,
359
- * rollback the submit and post submit operations
360
- */
361
- if (this._error) {
362
- try {
363
- /**
364
- * Rollback the submit operation
365
- */
366
- await this.submitRollback();
367
- /**
368
- * Rollback the post submit operations for each field (if any)
369
- */
370
- await this.postSubmitRollback();
371
- }
372
- catch (e) {
373
- /**
374
- * Those errors can be ignored
375
- */
376
- }
377
- }
378
- // Only when there was no error, trigger post submit hooks
379
- if (!this._error) {
380
- // console.log('Running post submit hooks...')
381
- await this.runPostSubmitHooks();
382
- }
383
- /**
384
- * Handle gallery photos
385
- */
386
- await this.handleGallery();
387
- return true;
388
- }
389
- async handleGallery() {
390
- if (!this._sectionInfo.gallery ||
391
- !this._sectionInfo.gallery.db ||
392
- !this._sectionInfo.gallery.db.tableName ||
393
- !this._sectionInfo.gallery.db.referenceIdentifierField ||
394
- !this._sectionInfo.gallery.db.metaField) {
395
- /**
396
- * The gallery table is not set up correctly, add it to the notices array
397
- */
398
- this.addNotice('Gallery table is not set up correctly, gallery photos were not saved.');
399
- return;
400
- }
401
- const columns = await MysqlTableChecker.getColumns(this._sectionInfo.gallery.db.tableName);
402
- if (!columns.includes(this._sectionInfo.gallery.db.referenceIdentifierField) ||
403
- !columns.includes(this._sectionInfo.gallery.db.metaField) ||
404
- !columns.includes(this._sectionInfo.gallery.db.photoNameField)) {
405
- /**
406
- * The gallery table is not set up correctly, add it to the notices array
407
- */
408
- this.addNotice('Gallery table is not set up correctly, gallery photos were not saved.');
409
- return;
410
- }
411
- /**
412
- * Gallery photos are sent as `dropzoneFiles` in the post request
413
- */
414
- const galleryPhotos = this._postData.getAll('dropzoneFiles');
415
- /**
416
- * Loop through the gallery photos and create a new PhotoField for each photo
417
- */
418
- for (const photo of galleryPhotos) {
419
- /**
420
- * Create a photo field instance for the gallery photo
421
- */
422
- const photoField = new PhotoField({
423
- name: 'dropzonePhoto',
424
- label: 'Photo',
425
- required: false,
426
- order: 0,
427
- type: ['jpg', 'jpeg', 'png'],
428
- watermark: this._sectionInfo.gallery.watermark,
429
- thumbnail: this._sectionInfo.gallery.thumbnail,
430
- });
431
- /**
432
- * Set the value of the photo field
433
- */
434
- photoField.setValue(photo);
435
- try {
436
- /**
437
- * Prepare the photo field for submission
438
- */
439
- await photoField.prepareForSubmission();
440
- /**
441
- * Perform post submit operations for the photo field
442
- */
443
- await photoField.postSubmit(this._sectionInfo.name);
444
- /**
445
- * Prepare the sql statement to insert the photo into the gallery table
446
- */
447
- const sqlChunks = [];
448
- sqlChunks.push(sql `INSERT INTO \`${sql.raw(this._sectionInfo.gallery.db.tableName)}\` (\`${sql.raw(this._sectionInfo.gallery.db.referenceIdentifierField)}\`, \`${sql.raw(this._sectionInfo.gallery.db.photoNameField)}\`, \`created_by\`) VALUES (${this._itemId}, ${photoField.getValue()}, ${this.user.name})`);
449
- const sqlQuery = sql.join(sqlChunks);
450
- /**
451
- * Execute the sql query
452
- */
453
- await db.execute(sqlQuery);
454
- }
455
- catch (e) {
456
- // It's not logical to roll back the whole operation.
457
- // The admin can try again in the `edit` page.
458
- // Add the error message to the notices array
459
- this.addNotice(e.message);
460
- console.log(e);
461
- }
462
- }
463
- }
464
- get errorMessage() {
465
- return this._errorMessage;
466
- }
467
- get error() {
468
- return this._error;
469
- }
470
- get notices() {
471
- return this._notices;
472
- }
473
- addNotice(notice) {
474
- if (!this._notices) {
475
- this._notices = [];
476
- }
477
- this._notices.push(notice);
478
- }
479
- }
1
+ import { sql } from 'drizzle-orm';
2
+ import { db } from '../../db/client';
3
+ import { SectionFactory } from '../factories';
4
+ import { entityKind, is } from '../helpers';
5
+ import { NumberField, PhotoField, SelectField, TextField } from '../fields';
6
+ import { MysqlTableChecker } from '../db';
7
+ export class Submit {
8
+ static [entityKind] = 'Submit';
9
+ user;
10
+ _itemId = undefined;
11
+ _error = false;
12
+ _errorMessage = '';
13
+ _notices = null;
14
+ sectionName;
15
+ _postData;
16
+ _sectionInfo;
17
+ preSubmit = false;
18
+ sqlNamesAndValues = {};
19
+ fields = [];
20
+ /**
21
+ * Constructor
22
+ */
23
+ constructor({ preSubmit, sectionName, user, postData }) {
24
+ this.sectionName = sectionName;
25
+ this.user = user;
26
+ this._postData = postData;
27
+ this.preSubmit = preSubmit ?? false;
28
+ }
29
+ /**
30
+ * Run custom hooks after the item is updated
31
+ * @protected
32
+ */
33
+ async runPostSubmitHooks() {
34
+ try {
35
+ await this._sectionInfo.hooks?.afterUpdate?.({
36
+ itemId: this._itemId,
37
+ values: this.sqlNamesAndValues,
38
+ section: this._sectionInfo,
39
+ });
40
+ }
41
+ catch (e) {
42
+ // Do not break the submit flow if a hook throws
43
+ console.error('afterUpdate hook failed:', e);
44
+ }
45
+ }
46
+ /**
47
+ * Log operation to the database
48
+ */
49
+ async logOperation({ operation, message }) {
50
+ // TODO: Log the operation to the database,
51
+ // get the heading input name and its value to identify the item,
52
+ // then generate the log message
53
+ }
54
+ /**
55
+ * Must be called after the constructor
56
+ */
57
+ async initialize(requiredRole = 'C') {
58
+ await this.initializeSectionInfo(this.user, requiredRole);
59
+ }
60
+ /**
61
+ * Gets the section info and assigns it to the `sectionInfo` property
62
+ * @param user
63
+ * @param requiredRole
64
+ * @private
65
+ */
66
+ async initializeSectionInfo(user, requiredRole) {
67
+ /**
68
+ * First, let's get the section details, and then get the section input fields
69
+ */
70
+ const s = await SectionFactory.getSectionForAdmin({
71
+ name: this.sectionName,
72
+ admin: {
73
+ id: user.id,
74
+ requiredRole: requiredRole,
75
+ },
76
+ });
77
+ if (!s || !s.name) {
78
+ this._error = true;
79
+ this._errorMessage = 'Section not found or you do not have access to this operation';
80
+ return undefined;
81
+ }
82
+ /**
83
+ * Build the section from config when we need to use it
84
+ */
85
+ this._sectionInfo = s.build();
86
+ /**
87
+ * Build the fields from the field configs
88
+ */
89
+ this._sectionInfo.buildFields();
90
+ }
91
+ /**
92
+ * Perform post submit operations
93
+ * This will initiate the post submit operations for each field (if any)
94
+ * @private
95
+ */
96
+ async postSubmit() {
97
+ try {
98
+ /**
99
+ * Perform post submit operations
100
+ */
101
+ for (const field of this._sectionInfo?.fields ?? []) {
102
+ let variable = undefined;
103
+ /**
104
+ * Figure out the variable to pass to the post submit function
105
+ */
106
+ switch (field.type) {
107
+ case 'photo':
108
+ case 'document':
109
+ case 'video':
110
+ /**
111
+ * File fields need the section name to save the file in the correct folder
112
+ */
113
+ variable = this._sectionInfo?.name;
114
+ break;
115
+ case 'select_multiple':
116
+ case 'select':
117
+ /**
118
+ * Select multiple fields need the itemId,
119
+ * to save the selected values in the correct table with the correct item id
120
+ */
121
+ variable = this._itemId;
122
+ break;
123
+ case 'rich_text':
124
+ /**
125
+ * Rich text fields need the section name to save the file in the correct folder,
126
+ * and the itemId to save inline images with the correct item id in the `editor_photos` table
127
+ */
128
+ variable = {
129
+ sectionName: this._sectionInfo?.name,
130
+ itemId: this._itemId,
131
+ };
132
+ break;
133
+ default:
134
+ break;
135
+ }
136
+ /**
137
+ * Call the post submit function
138
+ */
139
+ await field.postSubmit(variable);
140
+ }
141
+ }
142
+ catch (e) {
143
+ this._error = true;
144
+ this._errorMessage = e.message;
145
+ return;
146
+ }
147
+ }
148
+ /**
149
+ * Rollback post submit operations.<br>
150
+ * This will rollback the post submit operations for each field (if any)
151
+ * @private
152
+ */
153
+ async postSubmitRollback() {
154
+ for (const field of this._sectionInfo?.fields ?? []) {
155
+ await field.postSubmitRollback();
156
+ }
157
+ }
158
+ /**
159
+ * Check if the conditional field conditions are met for a field.
160
+ * @param field
161
+ * @private
162
+ */
163
+ checkConditionalField(field) {
164
+ /**
165
+ * Check if the conditions are met
166
+ */
167
+ let status = false;
168
+ field.conditionalRules?.map((rule) => {
169
+ switch (rule.condition) {
170
+ case 'equals':
171
+ status = this._postData.get(rule.field.name)?.toString() === `${rule.value}`;
172
+ break;
173
+ case 'notEquals':
174
+ status = this._postData.get(rule.field.name)?.toString() !== `${rule.value}`;
175
+ break;
176
+ default:
177
+ break;
178
+ }
179
+ });
180
+ return status;
181
+ }
182
+ /**
183
+ * Check if the field is required and perform the required checks.
184
+ * @param field
185
+ * @protected
186
+ */
187
+ checkRequired(field) {
188
+ field.checkRequired();
189
+ }
190
+ /**
191
+ * Set the field value.
192
+ * @param field
193
+ * @protected
194
+ */
195
+ setFieldValue(field) {
196
+ let value;
197
+ /**
198
+ * Check if the field is a select field that has depth (selecting from category section with depth > 1)
199
+ */
200
+ if (is(field, SelectField)) {
201
+ /**
202
+ * If true, value can be an array of values
203
+ */
204
+ value = this._postData.getAll(field.name).filter(Boolean);
205
+ field.setValue(value.map((v) => {
206
+ return { value: v.toString(), label: '' };
207
+ }));
208
+ }
209
+ else {
210
+ value = this._postData.get(field.name);
211
+ if (value)
212
+ field.setValue(value);
213
+ }
214
+ }
215
+ updateSqlNamesAndValues(field) {
216
+ if (field.hasSqlNameAndValue()) {
217
+ this.sqlNamesAndValues[field.name] = field.getSubmitValue();
218
+ }
219
+ }
220
+ assignItemIdValue(field) {
221
+ if (!this._itemId &&
222
+ field.name === this._sectionInfo.db.identifier.name &&
223
+ (is(field, NumberField) || is(field, TextField))) {
224
+ this._itemId = field.getValue();
225
+ }
226
+ }
227
+ /**
228
+ * Handle the field
229
+ * @param field
230
+ * @protected
231
+ */
232
+ async handleField(field) {
233
+ /**
234
+ * Get the value from the post request,
235
+ * and assign it to the field object
236
+ */
237
+ this.setFieldValue(field);
238
+ /**
239
+ * Check if field is conditional, and check if the conditions are met.
240
+ * If the conditions are met, continue with the field.
241
+ * If the field is not conditional, skip the field, because it will not be included in the sql query.
242
+ */
243
+ if (field.isConditional()) {
244
+ /**
245
+ * Check if the conditions are met
246
+ */
247
+ if (!this.checkConditionalField(field)) {
248
+ /**
249
+ * Conditions are not met, skip the field
250
+ */
251
+ return;
252
+ }
253
+ }
254
+ try {
255
+ /**
256
+ * Check if the field is required,
257
+ * This will throw an error if the field is required and the value is not present
258
+ */
259
+ this.checkRequired(field);
260
+ /**
261
+ * Prepare the field for submission,
262
+ * this will throw an error if the checks fail
263
+ */
264
+ await field.prepareForSubmission();
265
+ }
266
+ catch (e) {
267
+ this._error = true;
268
+ this._errorMessage = e.message;
269
+ return;
270
+ }
271
+ /**
272
+ * Add the sql name and value to the sqlNamesAndValues object
273
+ */
274
+ this.updateSqlNamesAndValues(field);
275
+ /**
276
+ * Assign the itemId value
277
+ */
278
+ this.assignItemIdValue(field);
279
+ }
280
+ async handleFields() {
281
+ if (this._error)
282
+ return;
283
+ if (!this._sectionInfo)
284
+ return;
285
+ for (const field of this._sectionInfo.fields ?? []) {
286
+ if (field) {
287
+ await this.handleField(field);
288
+ }
289
+ }
290
+ }
291
+ /**
292
+ * Execute the sql query.
293
+ * @param sqlQuery
294
+ * @private
295
+ */
296
+ async executeQuery(sqlQuery) {
297
+ if (this._error)
298
+ return;
299
+ /**
300
+ * If there is a sql query, let's execute it
301
+ */
302
+ if (!sqlQuery) {
303
+ this._error = true;
304
+ this._errorMessage = 'SQL query is not defined';
305
+ return;
306
+ }
307
+ try {
308
+ const [submit, fields] = await db.execute(sqlQuery);
309
+ /**
310
+ * If there is no itemId,
311
+ * there should be an auto increment field in the table
312
+ * assign the insertId to the itemId property
313
+ */
314
+ if (!this._itemId) {
315
+ this._itemId = submit.insertId;
316
+ }
317
+ }
318
+ catch (e) {
319
+ this._error = true;
320
+ this._errorMessage = e.message;
321
+ return;
322
+ }
323
+ }
324
+ /**
325
+ * Try to submit the form.
326
+ */
327
+ async submit() {
328
+ /**
329
+ * Assign the values to the fields
330
+ */
331
+ await this.handleFields();
332
+ /**
333
+ * If this is a pre-submit operation, don't submit the form
334
+ */
335
+ if (this.preSubmit) {
336
+ return;
337
+ }
338
+ /**
339
+ * Build the sql query
340
+ */
341
+ const sqlQuery = this.buildSqlQuery();
342
+ /**
343
+ * Execute the sql query
344
+ */
345
+ await this.executeQuery(sqlQuery);
346
+ /**
347
+ * Just return if there is an error,
348
+ * because post submit operations did not run yet
349
+ */
350
+ if (this._error) {
351
+ return;
352
+ }
353
+ /**
354
+ * Perform post submit operations
355
+ */
356
+ await this.postSubmit();
357
+ /**
358
+ * If there is an error in any of the post submit operations,
359
+ * rollback the submit and post submit operations
360
+ */
361
+ if (this._error) {
362
+ try {
363
+ /**
364
+ * Rollback the submit operation
365
+ */
366
+ await this.submitRollback();
367
+ /**
368
+ * Rollback the post submit operations for each field (if any)
369
+ */
370
+ await this.postSubmitRollback();
371
+ }
372
+ catch (e) {
373
+ /**
374
+ * Those errors can be ignored
375
+ */
376
+ }
377
+ }
378
+ // Only when there was no error, trigger post submit hooks
379
+ if (!this._error) {
380
+ // console.log('Running post submit hooks...')
381
+ await this.runPostSubmitHooks();
382
+ }
383
+ /**
384
+ * Handle gallery photos
385
+ */
386
+ await this.handleGallery();
387
+ return true;
388
+ }
389
+ async handleGallery() {
390
+ if (!this._sectionInfo.gallery ||
391
+ !this._sectionInfo.gallery.db ||
392
+ !this._sectionInfo.gallery.db.tableName ||
393
+ !this._sectionInfo.gallery.db.referenceIdentifierField ||
394
+ !this._sectionInfo.gallery.db.metaField) {
395
+ /**
396
+ * The gallery table is not set up correctly, add it to the notices array
397
+ */
398
+ this.addNotice('Gallery table is not set up correctly, gallery photos were not saved.');
399
+ return;
400
+ }
401
+ const columns = await MysqlTableChecker.getColumns(this._sectionInfo.gallery.db.tableName);
402
+ if (!columns.includes(this._sectionInfo.gallery.db.referenceIdentifierField) ||
403
+ !columns.includes(this._sectionInfo.gallery.db.metaField) ||
404
+ !columns.includes(this._sectionInfo.gallery.db.photoNameField)) {
405
+ /**
406
+ * The gallery table is not set up correctly, add it to the notices array
407
+ */
408
+ this.addNotice('Gallery table is not set up correctly, gallery photos were not saved.');
409
+ return;
410
+ }
411
+ /**
412
+ * Gallery photos are sent as `dropzoneFiles` in the post request
413
+ */
414
+ const galleryPhotos = this._postData.getAll('dropzoneFiles');
415
+ /**
416
+ * Loop through the gallery photos and create a new PhotoField for each photo
417
+ */
418
+ for (const photo of galleryPhotos) {
419
+ /**
420
+ * Create a photo field instance for the gallery photo
421
+ */
422
+ const photoField = new PhotoField({
423
+ name: 'dropzonePhoto',
424
+ label: 'Photo',
425
+ required: false,
426
+ order: 0,
427
+ type: ['jpg', 'jpeg', 'png'],
428
+ watermark: this._sectionInfo.gallery.watermark,
429
+ thumbnail: this._sectionInfo.gallery.thumbnail,
430
+ });
431
+ /**
432
+ * Set the value of the photo field
433
+ */
434
+ photoField.setValue(photo);
435
+ try {
436
+ /**
437
+ * Prepare the photo field for submission
438
+ */
439
+ await photoField.prepareForSubmission();
440
+ /**
441
+ * Perform post submit operations for the photo field
442
+ */
443
+ await photoField.postSubmit(this._sectionInfo.name);
444
+ /**
445
+ * Prepare the sql statement to insert the photo into the gallery table
446
+ */
447
+ const sqlChunks = [];
448
+ sqlChunks.push(sql `INSERT INTO \`${sql.raw(this._sectionInfo.gallery.db.tableName)}\` (\`${sql.raw(this._sectionInfo.gallery.db.referenceIdentifierField)}\`, \`${sql.raw(this._sectionInfo.gallery.db.photoNameField)}\`, \`created_by\`) VALUES (${this._itemId}, ${photoField.getValue()}, ${this.user.name})`);
449
+ const sqlQuery = sql.join(sqlChunks);
450
+ /**
451
+ * Execute the sql query
452
+ */
453
+ await db.execute(sqlQuery);
454
+ }
455
+ catch (e) {
456
+ // It's not logical to roll back the whole operation.
457
+ // The admin can try again in the `edit` page.
458
+ // Add the error message to the notices array
459
+ this.addNotice(e.message);
460
+ console.log(e);
461
+ }
462
+ }
463
+ }
464
+ get errorMessage() {
465
+ return this._errorMessage;
466
+ }
467
+ get error() {
468
+ return this._error;
469
+ }
470
+ get notices() {
471
+ return this._notices;
472
+ }
473
+ addNotice(notice) {
474
+ if (!this._notices) {
475
+ this._notices = [];
476
+ }
477
+ this._notices.push(notice);
478
+ }
479
+ }