@flusys/nestjs-form-builder 8.0.3 → 8.1.1

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.
@@ -4,16 +4,17 @@ import * as __rspack_external__flusys_nestjs_shared_classes_6076a329 from "@flus
4
4
  import * as __rspack_external__flusys_nestjs_shared_decorators_c129b601 from "@flusys/nestjs-shared/decorators";
5
5
  import * as __rspack_external__flusys_nestjs_shared_dtos_c4585026 from "@flusys/nestjs-shared/dtos";
6
6
  import * as __rspack_external__flusys_nestjs_shared_modules_24702bee from "@flusys/nestjs-shared/modules";
7
+ import * as __rspack_external__flusys_nestjs_shared_utils_9125c1f1 from "@flusys/nestjs-shared/utils";
7
8
  import * as __rspack_external__nestjs_common_a04939da from "@nestjs/common";
8
9
  import * as __rspack_external__nestjs_swagger_7cd450b5 from "@nestjs/swagger";
9
10
  import * as __rspack_external_class_transformer_c5a479fb from "class-transformer";
10
11
  import * as __rspack_external_class_validator_7b99ef4d from "class-validator";
11
12
  import * as __rspack_external_typeorm from "typeorm";
12
- import * as __rspack_external__flusys_nestjs_core_ff4ca4e2 from "@flusys/nestjs-core";
13
- import * as __rspack_external__flusys_nestjs_shared_utils_9125c1f1 from "@flusys/nestjs-shared/utils";
13
+ import * as __rspack_external_crypto from "crypto";
14
14
  import * as __rspack_external__nestjs_core_d7b00a1a from "@nestjs/core";
15
- export const __rspack_esm_id = 262;
16
- export const __rspack_esm_ids = [262];
15
+ import * as __rspack_external__flusys_nestjs_core_ff4ca4e2 from "@flusys/nestjs-core";
16
+ export const __rspack_esm_id = 432;
17
+ export const __rspack_esm_ids = [432];
17
18
  export const __webpack_modules__ = {
18
19
  769(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
19
20
  /**
@@ -58,7 +59,15 @@ const FORM_MESSAGES = {
58
59
  INVALID_ACCESS_TYPE: 'form.invalid.access.type',
59
60
  PERMISSION_CHECK_FAILED: 'form.permission.check.failed',
60
61
  GET_SUCCESS: 'form.get.success',
61
- GET_ACCESS_INFO_SUCCESS: 'form.get.access.info.success'
62
+ GET_ACCESS_INFO_SUCCESS: 'form.get.access.info.success',
63
+ EMAIL_NOT_CONFIGURED: 'form.email.not.configured',
64
+ EMAIL_VERIFICATION_REQUIRED: 'form.email.verification.required',
65
+ OTP_SENT: 'form.email.otp.sent',
66
+ OTP_SEND_FAILED: 'form.email.otp.send.failed',
67
+ OTP_INVALID: 'form.email.otp.invalid',
68
+ OTP_EXPIRED: 'form.email.otp.expired',
69
+ OTP_TOO_MANY_ATTEMPTS: 'form.email.otp.too.many.attempts',
70
+ OTP_VERIFIED: 'form.email.otp.verified'
62
71
  };
63
72
  const FORM_RESULT_MESSAGES = {
64
73
  GET_ALL_SUCCESS: 'form.result.get.all.success',
@@ -67,7 +76,8 @@ const FORM_RESULT_MESSAGES = {
67
76
  HAS_NOT_SUBMITTED_SUCCESS: 'form.result.has.not.submitted.success',
68
77
  SUBMIT_SUCCESS: 'form.result.submit.success',
69
78
  DRAFT_GET_SUCCESS: 'form.result.draft.get.success',
70
- DRAFT_UPDATE_SUCCESS: 'form.result.draft.update.success'
79
+ DRAFT_UPDATE_SUCCESS: 'form.result.draft.update.success',
80
+ ALREADY_SUBMITTED: 'form.result.already.submitted'
71
81
  };
72
82
 
73
83
  __webpack_require__.d(__webpack_exports__, {
@@ -109,6 +119,7 @@ class SubmitFormDto {
109
119
  formId;
110
120
  data;
111
121
  isDraft;
122
+ accessToken;
112
123
  }
113
124
  _ts_decorate([
114
125
  (0,_nestjs_swagger__rspack_import_1.ApiProperty)({
@@ -141,6 +152,15 @@ _ts_decorate([
141
152
  (0,class_validator__rspack_import_3.IsOptional)(),
142
153
  _ts_metadata("design:type", Boolean)
143
154
  ], SubmitFormDto.prototype, "isDraft", void 0);
155
+ _ts_decorate([
156
+ (0,_nestjs_swagger__rspack_import_1.ApiProperty)({
157
+ description: 'Access token from email verification (only used for EMAIL_VERIFIED forms submitted anonymously)',
158
+ required: false
159
+ }),
160
+ (0,class_validator__rspack_import_3.IsString)(),
161
+ (0,class_validator__rspack_import_3.IsOptional)(),
162
+ _ts_metadata("design:type", String)
163
+ ], SubmitFormDto.prototype, "accessToken", void 0);
144
164
  class CreateFormResultDto extends SubmitFormDto {
145
165
  schemaVersionSnapshot;
146
166
  schemaVersion;
@@ -250,6 +270,7 @@ class FormResultResponseDto extends _flusys_nestjs_shared_dtos__rspack_import_0.
250
270
  schemaVersion;
251
271
  data;
252
272
  submittedById;
273
+ submitterEmail;
253
274
  submittedAt;
254
275
  isDraft;
255
276
  }
@@ -278,6 +299,11 @@ _ts_decorate([
278
299
  (0,_nestjs_swagger__rspack_import_1.ApiProperty)(),
279
300
  _ts_metadata("design:type", Object)
280
301
  ], FormResultResponseDto.prototype, "submittedById", void 0);
302
+ _ts_decorate([
303
+ (0,class_transformer__rspack_import_2.Expose)(),
304
+ (0,_nestjs_swagger__rspack_import_1.ApiProperty)(),
305
+ _ts_metadata("design:type", Object)
306
+ ], FormResultResponseDto.prototype, "submitterEmail", void 0);
281
307
  _ts_decorate([
282
308
  (0,class_transformer__rspack_import_2.Expose)(),
283
309
  (0,_nestjs_swagger__rspack_import_1.ApiProperty)(),
@@ -301,7 +327,7 @@ __webpack_require__.d(__webpack_exports__, {
301
327
 
302
328
 
303
329
  },
304
- 532(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
330
+ 814(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
305
331
 
306
332
  // EXPORTS
307
333
  __webpack_require__.d(__webpack_exports__, {
@@ -309,6 +335,7 @@ __webpack_require__.d(__webpack_exports__, {
309
335
  C7: () => (/* reexport */ Form),
310
336
  Xl: () => (/* binding */ FormCompanyEntities),
311
337
  t$: () => (/* binding */ FormCoreEntities),
338
+ Kr: () => (/* reexport */ FormEmailVerification),
312
339
  ez: () => (/* reexport */ FormResult),
313
340
  Wl: () => (/* reexport */ FormWithCompany),
314
341
  getFormBuilderEntitiesByConfig: () => (/* binding */ getFormBuilderEntitiesByConfig)
@@ -470,6 +497,7 @@ class FormResult extends Identity {
470
497
  schemaVersion;
471
498
  data;
472
499
  submittedById;
500
+ submitterEmail;
473
501
  submittedAt;
474
502
  isDraft;
475
503
  }
@@ -513,6 +541,15 @@ form_result_entity_ts_decorate([
513
541
  }),
514
542
  form_result_entity_ts_metadata("design:type", Object)
515
543
  ], FormResult.prototype, "submittedById", void 0);
544
+ form_result_entity_ts_decorate([
545
+ (0,external_typeorm_.Column)({
546
+ type: 'varchar',
547
+ length: 255,
548
+ nullable: true,
549
+ name: 'submitter_email'
550
+ }),
551
+ form_result_entity_ts_metadata("design:type", Object)
552
+ ], FormResult.prototype, "submitterEmail", void 0);
516
553
  form_result_entity_ts_decorate([
517
554
  (0,external_typeorm_.Column)({
518
555
  type: 'timestamp',
@@ -532,9 +569,122 @@ form_result_entity_ts_decorate([
532
569
  FormResult = form_result_entity_ts_decorate([
533
570
  (0,external_typeorm_.Entity)({
534
571
  name: 'form_result'
535
- })
572
+ }),
573
+ (0,external_typeorm_.Index)([
574
+ 'formId',
575
+ 'submitterEmail'
576
+ ])
536
577
  ], FormResult);
537
578
 
579
+ ;// CONCATENATED MODULE: ./projects/nestjs-form-builder/src/entities/form-email-verification.entity.ts
580
+ function form_email_verification_entity_ts_decorate(decorators, target, key, desc) {
581
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
582
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
583
+ r = Reflect.decorate(decorators, target, key, desc);
584
+ } else {
585
+ for(var i = decorators.length - 1; i >= 0; i--){
586
+ if (d = decorators[i]) {
587
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
588
+ }
589
+ }
590
+ }
591
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
592
+ }
593
+ function form_email_verification_entity_ts_metadata(metadataKey, metadataValue) {
594
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
595
+ return Reflect.metadata(metadataKey, metadataValue);
596
+ }
597
+ }
598
+
599
+
600
+ class FormEmailVerification extends Identity {
601
+ formId;
602
+ email;
603
+ otpHash;
604
+ otpExpiresAt;
605
+ otpAttempts;
606
+ verifiedAt;
607
+ accessTokenHash;
608
+ accessTokenExpiresAt;
609
+ }
610
+ form_email_verification_entity_ts_decorate([
611
+ (0,external_typeorm_.Column)({
612
+ type: 'uuid',
613
+ nullable: false,
614
+ name: 'form_id'
615
+ }),
616
+ form_email_verification_entity_ts_metadata("design:type", String)
617
+ ], FormEmailVerification.prototype, "formId", void 0);
618
+ form_email_verification_entity_ts_decorate([
619
+ (0,external_typeorm_.Column)({
620
+ type: 'varchar',
621
+ length: 255,
622
+ nullable: false
623
+ }),
624
+ form_email_verification_entity_ts_metadata("design:type", String)
625
+ ], FormEmailVerification.prototype, "email", void 0);
626
+ form_email_verification_entity_ts_decorate([
627
+ (0,external_typeorm_.Column)({
628
+ type: 'varchar',
629
+ length: 64,
630
+ nullable: true,
631
+ name: 'otp_hash'
632
+ }),
633
+ form_email_verification_entity_ts_metadata("design:type", Object)
634
+ ], FormEmailVerification.prototype, "otpHash", void 0);
635
+ form_email_verification_entity_ts_decorate([
636
+ (0,external_typeorm_.Column)({
637
+ type: 'timestamp',
638
+ nullable: true,
639
+ name: 'otp_expires_at'
640
+ }),
641
+ form_email_verification_entity_ts_metadata("design:type", Object)
642
+ ], FormEmailVerification.prototype, "otpExpiresAt", void 0);
643
+ form_email_verification_entity_ts_decorate([
644
+ (0,external_typeorm_.Column)({
645
+ type: 'int',
646
+ nullable: false,
647
+ default: 0,
648
+ name: 'otp_attempts'
649
+ }),
650
+ form_email_verification_entity_ts_metadata("design:type", Number)
651
+ ], FormEmailVerification.prototype, "otpAttempts", void 0);
652
+ form_email_verification_entity_ts_decorate([
653
+ (0,external_typeorm_.Column)({
654
+ type: 'timestamp',
655
+ nullable: true,
656
+ name: 'verified_at'
657
+ }),
658
+ form_email_verification_entity_ts_metadata("design:type", Object)
659
+ ], FormEmailVerification.prototype, "verifiedAt", void 0);
660
+ form_email_verification_entity_ts_decorate([
661
+ (0,external_typeorm_.Index)(),
662
+ (0,external_typeorm_.Column)({
663
+ type: 'varchar',
664
+ length: 64,
665
+ nullable: true,
666
+ name: 'access_token_hash'
667
+ }),
668
+ form_email_verification_entity_ts_metadata("design:type", Object)
669
+ ], FormEmailVerification.prototype, "accessTokenHash", void 0);
670
+ form_email_verification_entity_ts_decorate([
671
+ (0,external_typeorm_.Column)({
672
+ type: 'timestamp',
673
+ nullable: true,
674
+ name: 'access_token_expires_at'
675
+ }),
676
+ form_email_verification_entity_ts_metadata("design:type", Object)
677
+ ], FormEmailVerification.prototype, "accessTokenExpiresAt", void 0);
678
+ FormEmailVerification = form_email_verification_entity_ts_decorate([
679
+ (0,external_typeorm_.Entity)({
680
+ name: 'form_email_verification'
681
+ }),
682
+ (0,external_typeorm_.Unique)([
683
+ 'formId',
684
+ 'email'
685
+ ])
686
+ ], FormEmailVerification);
687
+
538
688
  ;// CONCATENATED MODULE: ./projects/nestjs-form-builder/src/entities/form-with-company.entity.ts
539
689
  function form_with_company_entity_ts_decorate(decorators, target, key, desc) {
540
690
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -590,20 +740,24 @@ FormWithCompany = form_with_company_entity_ts_decorate([
590
740
  // Entities without company feature
591
741
 
592
742
 
743
+
593
744
  // Entities with company feature
594
745
 
595
746
 
596
747
 
597
748
 
749
+
598
750
  // Core entities (no company feature)
599
751
  const FormCoreEntities = [
600
752
  Form,
601
- FormResult
753
+ FormResult,
754
+ FormEmailVerification
602
755
  ];
603
756
  // Company-specific entities
604
757
  const FormCompanyEntities = [
605
758
  FormWithCompany,
606
- FormResult
759
+ FormResult,
760
+ FormEmailVerification
607
761
  ];
608
762
  function getFormBuilderEntitiesByConfig(enableCompanyFeature) {
609
763
  return enableCompanyFeature ? FormCompanyEntities : FormCoreEntities;
@@ -621,6 +775,7 @@ function getFormBuilderEntitiesByConfig(enableCompanyFeature) {
621
775
  /** No authentication required - anyone can submit */ FormAccessType["PUBLIC"] = "public";
622
776
  /** Any authenticated user can submit */ FormAccessType["AUTHENTICATED"] = "authenticated";
623
777
  /** Only users with specific action permissions can submit */ FormAccessType["ACTION_GROUP"] = "action_group";
778
+ /** Anonymous visitors verify a one-time email code before submitting (already-logged-in users are auto-identified by their account email) */ FormAccessType["EMAIL_VERIFIED"] = "email_verified";
624
779
  return FormAccessType;
625
780
  }({});
626
781
 
@@ -629,6 +784,20 @@ __webpack_require__.d(__webpack_exports__, {
629
784
  });
630
785
 
631
786
 
787
+ },
788
+ 341(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
789
+ /**
790
+ * Provider Interface for sending form-submission verification emails.
791
+ * Implemented at the app level (composition root) using the email module,
792
+ * so nestjs-form-builder never depends on nestjs-email directly.
793
+ */ const FORM_BUILDER_EMAIL_PROVIDER = 'FORM_BUILDER_EMAIL_PROVIDER';
794
+
795
+ __webpack_require__.d(__webpack_exports__, {
796
+ }, {
797
+ Q: FORM_BUILDER_EMAIL_PROVIDER
798
+ });
799
+
800
+
632
801
  },
633
802
  781(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
634
803
  /* import */ var _nestjs_common__rspack_import_0 = __webpack_require__(157);
@@ -758,7 +927,7 @@ class FormBuilderDataSourceProvider extends modules_.MultiTenantDataSourceServic
758
927
  }
759
928
  async getFormBuilderEntities(enableCompanyFeature) {
760
929
  const enable = enableCompanyFeature ?? this.configService.isCompanyFeatureEnabled();
761
- const { getFormBuilderEntitiesByConfig } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 532));
930
+ const { getFormBuilderEntitiesByConfig } = await Promise.resolve(/* import() */).then(__webpack_require__.bind(__webpack_require__, 814));
762
931
  return getFormBuilderEntitiesByConfig(enable);
763
932
  }
764
933
  async createDataSourceFromConfig(config) {
@@ -782,6 +951,219 @@ FormBuilderDataSourceProvider = _ts_decorate([
782
951
  ], FormBuilderDataSourceProvider);
783
952
 
784
953
 
954
+ },
955
+ 474(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
956
+
957
+ // EXPORTS
958
+ __webpack_require__.d(__webpack_exports__, {
959
+ w: () => (/* binding */ FormEmailAuthService)
960
+ });
961
+
962
+ // EXTERNAL MODULE: external "@flusys/nestjs-shared/utils"
963
+ var utils_ = __webpack_require__(216);
964
+ // EXTERNAL MODULE: external "@nestjs/common"
965
+ var common_ = __webpack_require__(157);
966
+ ;// CONCATENATED MODULE: external "crypto"
967
+
968
+ // EXTERNAL MODULE: ./projects/nestjs-form-builder/src/config/message-keys.ts
969
+ var message_keys = __webpack_require__(137);
970
+ // EXTERNAL MODULE: ./projects/nestjs-form-builder/src/entities/index.ts + 6 modules
971
+ var entities = __webpack_require__(814);
972
+ // EXTERNAL MODULE: ./projects/nestjs-form-builder/src/interfaces/form-builder-email-provider.interface.ts
973
+ var form_builder_email_provider_interface = __webpack_require__(341);
974
+ // EXTERNAL MODULE: ./projects/nestjs-form-builder/src/services/form-builder-datasource.provider.ts + 1 modules
975
+ var form_builder_datasource_provider = __webpack_require__(593);
976
+ ;// CONCATENATED MODULE: ./projects/nestjs-form-builder/src/services/form-email-auth.service.ts
977
+ function _ts_decorate(decorators, target, key, desc) {
978
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
979
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
980
+ r = Reflect.decorate(decorators, target, key, desc);
981
+ } else {
982
+ for(var i = decorators.length - 1; i >= 0; i--){
983
+ if (d = decorators[i]) {
984
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
985
+ }
986
+ }
987
+ }
988
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
989
+ }
990
+ function _ts_metadata(metadataKey, metadataValue) {
991
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
992
+ return Reflect.metadata(metadataKey, metadataValue);
993
+ }
994
+ }
995
+ function _ts_param(paramIndex, decorator) {
996
+ return function(target, key) {
997
+ decorator(target, key, paramIndex);
998
+ };
999
+ }
1000
+
1001
+
1002
+
1003
+
1004
+
1005
+
1006
+
1007
+ class FormEmailAuthService {
1008
+ dataSourceProvider;
1009
+ emailProvider;
1010
+ OTP_EXPIRY_MS = 10 * 60 * 1000;
1011
+ ACCESS_TOKEN_EXPIRY_MS = 30 * 24 * 60 * 60 * 1000;
1012
+ MAX_OTP_ATTEMPTS = 5;
1013
+ repository = null;
1014
+ constructor(dataSourceProvider, emailProvider){
1015
+ this.dataSourceProvider = dataSourceProvider;
1016
+ this.emailProvider = emailProvider;
1017
+ }
1018
+ async ensureRepository() {
1019
+ if (!this.repository) {
1020
+ this.repository = await this.dataSourceProvider.getRepository(entities/* .FormEmailVerification */.Kr);
1021
+ }
1022
+ return this.repository;
1023
+ }
1024
+ generateOtp() {
1025
+ return __rspack_external_crypto.randomInt(100000, 1000000).toString();
1026
+ }
1027
+ generateAccessToken() {
1028
+ return (0,utils_.generateSecureToken)();
1029
+ }
1030
+ hashValue(value) {
1031
+ return (0,utils_.hashToken)(value);
1032
+ }
1033
+ normalizeEmail(email) {
1034
+ return email.trim().toLowerCase();
1035
+ }
1036
+ assertEmailEnabled() {
1037
+ if (!this.emailProvider) {
1038
+ throw new common_.BadRequestException({
1039
+ message: 'Email service is not configured for this form',
1040
+ messageKey: message_keys/* .FORM_MESSAGES.EMAIL_NOT_CONFIGURED */.Q.EMAIL_NOT_CONFIGURED
1041
+ });
1042
+ }
1043
+ }
1044
+ async requestOtp(formId, email, formTitle) {
1045
+ this.assertEmailEnabled();
1046
+ const repository = await this.ensureRepository();
1047
+ email = this.normalizeEmail(email);
1048
+ const otp = this.generateOtp();
1049
+ const record = await repository.findOne({
1050
+ where: {
1051
+ formId,
1052
+ email
1053
+ }
1054
+ }) ?? repository.create({
1055
+ formId,
1056
+ email
1057
+ });
1058
+ Object.assign(record, {
1059
+ otpHash: this.hashValue(otp),
1060
+ otpExpiresAt: new Date(Date.now() + this.OTP_EXPIRY_MS),
1061
+ otpAttempts: 0
1062
+ });
1063
+ await repository.save(record);
1064
+ try {
1065
+ await this.emailProvider.sendOtpEmail(email, otp, formTitle, this.OTP_EXPIRY_MS / 60000);
1066
+ } catch {
1067
+ throw new common_.BadRequestException({
1068
+ message: 'Failed to send verification code. Please try again.',
1069
+ messageKey: message_keys/* .FORM_MESSAGES.OTP_SEND_FAILED */.Q.OTP_SEND_FAILED
1070
+ });
1071
+ }
1072
+ return {
1073
+ success: true,
1074
+ message: 'Verification code sent to your email',
1075
+ messageKey: message_keys/* .FORM_MESSAGES.OTP_SENT */.Q.OTP_SENT
1076
+ };
1077
+ }
1078
+ async verifyOtp(formId, email, code) {
1079
+ const repository = await this.ensureRepository();
1080
+ email = this.normalizeEmail(email);
1081
+ const record = await repository.findOne({
1082
+ where: {
1083
+ formId,
1084
+ email
1085
+ }
1086
+ });
1087
+ if (!record?.otpHash || !record.otpExpiresAt) {
1088
+ throw new common_.BadRequestException({
1089
+ message: 'Invalid or expired verification code',
1090
+ messageKey: message_keys/* .FORM_MESSAGES.OTP_INVALID */.Q.OTP_INVALID
1091
+ });
1092
+ }
1093
+ if (record.otpAttempts >= this.MAX_OTP_ATTEMPTS) {
1094
+ throw new common_.BadRequestException({
1095
+ message: 'Too many incorrect attempts. Please request a new code.',
1096
+ messageKey: message_keys/* .FORM_MESSAGES.OTP_TOO_MANY_ATTEMPTS */.Q.OTP_TOO_MANY_ATTEMPTS
1097
+ });
1098
+ }
1099
+ if ((0,utils_.isExpired)(record.otpExpiresAt)) {
1100
+ throw new common_.BadRequestException({
1101
+ message: 'Verification code has expired. Please request a new one.',
1102
+ messageKey: message_keys/* .FORM_MESSAGES.OTP_EXPIRED */.Q.OTP_EXPIRED
1103
+ });
1104
+ }
1105
+ if (record.otpHash !== this.hashValue(code)) {
1106
+ record.otpAttempts += 1;
1107
+ await repository.save(record);
1108
+ throw new common_.BadRequestException({
1109
+ message: 'Invalid verification code',
1110
+ messageKey: message_keys/* .FORM_MESSAGES.OTP_INVALID */.Q.OTP_INVALID
1111
+ });
1112
+ }
1113
+ const accessToken = this.generateAccessToken();
1114
+ const accessTokenExpiresAt = new Date(Date.now() + this.ACCESS_TOKEN_EXPIRY_MS);
1115
+ Object.assign(record, {
1116
+ verifiedAt: record.verifiedAt ?? new Date(),
1117
+ accessTokenHash: this.hashValue(accessToken),
1118
+ accessTokenExpiresAt,
1119
+ otpHash: null,
1120
+ otpExpiresAt: null,
1121
+ otpAttempts: 0
1122
+ });
1123
+ await repository.save(record);
1124
+ return {
1125
+ accessToken,
1126
+ expiresAt: accessTokenExpiresAt
1127
+ };
1128
+ }
1129
+ // Slides the token's expiry forward on every use so an active repeat-filler
1130
+ // on a 'multiple' response-mode form never needs to re-verify.
1131
+ async resolveAccessToken(formId, accessToken) {
1132
+ if (!accessToken) return null;
1133
+ const repository = await this.ensureRepository();
1134
+ const record = await repository.findOne({
1135
+ where: {
1136
+ formId,
1137
+ accessTokenHash: this.hashValue(accessToken)
1138
+ }
1139
+ });
1140
+ if (!record?.accessTokenExpiresAt || (0,utils_.isExpired)(record.accessTokenExpiresAt)) {
1141
+ return null;
1142
+ }
1143
+ record.accessTokenExpiresAt = new Date(Date.now() + this.ACCESS_TOKEN_EXPIRY_MS);
1144
+ await repository.save(record);
1145
+ return record.email;
1146
+ }
1147
+ async resolveSubmitterEmail(formId, user, accessToken) {
1148
+ if (user?.email) return this.normalizeEmail(user.email);
1149
+ return this.resolveAccessToken(formId, accessToken);
1150
+ }
1151
+ }
1152
+ FormEmailAuthService = _ts_decorate([
1153
+ (0,common_.Injectable)({
1154
+ scope: common_.Scope.REQUEST
1155
+ }),
1156
+ _ts_param(0, (0,common_.Inject)(form_builder_datasource_provider/* .FormBuilderDataSourceProvider */._)),
1157
+ _ts_param(1, (0,common_.Optional)()),
1158
+ _ts_param(1, (0,common_.Inject)(form_builder_email_provider_interface/* .FORM_BUILDER_EMAIL_PROVIDER */.Q)),
1159
+ _ts_metadata("design:type", Function),
1160
+ _ts_metadata("design:paramtypes", [
1161
+ typeof form_builder_datasource_provider/* .FormBuilderDataSourceProvider */._ === "undefined" ? Object : form_builder_datasource_provider/* .FormBuilderDataSourceProvider */._,
1162
+ typeof IFormBuilderEmailProvider === "undefined" ? Object : IFormBuilderEmailProvider
1163
+ ])
1164
+ ], FormEmailAuthService);
1165
+
1166
+
785
1167
  },
786
1168
  160(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
787
1169
  /* import */ var _flusys_nestjs_shared_classes__rspack_import_0 = __webpack_require__(937);
@@ -789,15 +1171,16 @@ FormBuilderDataSourceProvider = _ts_decorate([
789
1171
  /* import */ var _flusys_nestjs_shared_modules__rspack_import_2 = __webpack_require__(236);
790
1172
  /* import */ var _nestjs_common__rspack_import_3 = __webpack_require__(157);
791
1173
  /* import */ var typeorm__rspack_import_4 = __webpack_require__(158);
792
- /* import */ var _config_index_js__rspack_import_10 = __webpack_require__(769);
793
- /* import */ var _config_index_js__rspack_import_11 = __webpack_require__(137);
1174
+ /* import */ var _config_index_js__rspack_import_11 = __webpack_require__(769);
1175
+ /* import */ var _config_index_js__rspack_import_12 = __webpack_require__(137);
794
1176
  /* import */ var _dtos_form_result_dto_js__rspack_import_5 = __webpack_require__(788);
795
- /* import */ var _entities_index_js__rspack_import_6 = __webpack_require__(532);
796
- /* import */ var _enums_form_access_type_enum_js__rspack_import_12 = __webpack_require__(376);
797
- /* import */ var _utils_computed_field_utils_js__rspack_import_13 = __webpack_require__(801);
1177
+ /* import */ var _entities_index_js__rspack_import_6 = __webpack_require__(814);
1178
+ /* import */ var _enums_form_access_type_enum_js__rspack_import_13 = __webpack_require__(376);
1179
+ /* import */ var _utils_computed_field_utils_js__rspack_import_14 = __webpack_require__(801);
798
1180
  /* import */ var _utils_permission_utils_js__rspack_import_7 = __webpack_require__(988);
799
1181
  /* import */ var _form_builder_config_service_js__rspack_import_8 = __webpack_require__(781);
800
1182
  /* import */ var _form_builder_datasource_provider_js__rspack_import_9 = __webpack_require__(593);
1183
+ /* import */ var _form_email_auth_service_js__rspack_import_10 = __webpack_require__(474);
801
1184
  function _ts_decorate(decorators, target, key, desc) {
802
1185
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
803
1186
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -834,14 +1217,22 @@ function _ts_param(paramIndex, decorator) {
834
1217
 
835
1218
 
836
1219
 
1220
+
837
1221
  class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.ApiService {
838
1222
  cacheManager;
839
1223
  utilsService;
840
1224
  formBuilderConfig;
841
1225
  dataSourceProvider;
1226
+ formEmailAuthService;
842
1227
  formRepository = null;
843
- constructor(cacheManager, utilsService, formBuilderConfig, dataSourceProvider){
844
- super(_config_index_js__rspack_import_10/* .FORM_BUILDER_EVENT_ENTITIES.FORM_RESULT */.eF.FORM_RESULT, cacheManager, utilsService, FormResultService.name, true, _config_index_js__rspack_import_10/* .FORM_BUILDER_EVENT_MODULE */.T$, dataSourceProvider, _entities_index_js__rspack_import_6/* .FormResult */.ez), this.cacheManager = cacheManager, this.utilsService = utilsService, this.formBuilderConfig = formBuilderConfig, this.dataSourceProvider = dataSourceProvider;
1228
+ // Serializes the single-response check-then-insert per (formId, email) within
1229
+ // this process, so a double-click/two-tab submission can't both pass the check
1230
+ // before either has saved. Static because the service is REQUEST-scoped - a
1231
+ // per-instance lock would never be shared between the two racing requests.
1232
+ // Does not span multiple app instances; see withSubmissionLock().
1233
+ static submissionLocks = new Map();
1234
+ constructor(cacheManager, utilsService, formBuilderConfig, dataSourceProvider, formEmailAuthService){
1235
+ super(_config_index_js__rspack_import_11/* .FORM_BUILDER_EVENT_ENTITIES.FORM_RESULT */.eF.FORM_RESULT, cacheManager, utilsService, FormResultService.name, true, _config_index_js__rspack_import_11/* .FORM_BUILDER_EVENT_MODULE */.T$, dataSourceProvider, _entities_index_js__rspack_import_6/* .FormResult */.ez), this.cacheManager = cacheManager, this.utilsService = utilsService, this.formBuilderConfig = formBuilderConfig, this.dataSourceProvider = dataSourceProvider, this.formEmailAuthService = formEmailAuthService;
845
1236
  }
846
1237
  async ensureFormRepositoryInitialized() {
847
1238
  if (!this.formRepository) {
@@ -850,6 +1241,23 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
850
1241
  this.formRepository = await this.dataSourceProvider.getRepository(formEntity);
851
1242
  }
852
1243
  }
1244
+ async withSubmissionLock(key, fn) {
1245
+ const prior = FormResultService.submissionLocks.get(key) ?? Promise.resolve();
1246
+ let release;
1247
+ const current = new Promise((resolve)=>{
1248
+ release = resolve;
1249
+ });
1250
+ FormResultService.submissionLocks.set(key, current);
1251
+ await prior;
1252
+ try {
1253
+ return await fn();
1254
+ } finally{
1255
+ release();
1256
+ if (FormResultService.submissionLocks.get(key) === current) {
1257
+ FormResultService.submissionLocks.delete(key);
1258
+ }
1259
+ }
1260
+ }
853
1261
  async getActiveForm(formId) {
854
1262
  await this.ensureFormRepositoryInitialized();
855
1263
  const form = await this.formRepository.findOne({
@@ -862,7 +1270,7 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
862
1270
  if (!form) {
863
1271
  throw new _nestjs_common__rspack_import_3.NotFoundException({
864
1272
  message: 'Form not found or inactive',
865
- messageKey: _config_index_js__rspack_import_11/* .FORM_MESSAGES.NOT_FOUND */.Q.NOT_FOUND
1273
+ messageKey: _config_index_js__rspack_import_12/* .FORM_MESSAGES.NOT_FOUND */.Q.NOT_FOUND
866
1274
  });
867
1275
  }
868
1276
  return form;
@@ -874,35 +1282,85 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
874
1282
  });
875
1283
  }
876
1284
  }
1285
+ static PUBLICLY_SUBMITTABLE_ACCESS_TYPES = new Set([
1286
+ _enums_form_access_type_enum_js__rspack_import_13/* .FormAccessType.PUBLIC */.h.PUBLIC,
1287
+ _enums_form_access_type_enum_js__rspack_import_13/* .FormAccessType.EMAIL_VERIFIED */.h.EMAIL_VERIFIED
1288
+ ]);
877
1289
  async validateSubmissionAccess(form, user, isPublic) {
878
1290
  if (isPublic) {
879
- if (form.accessType !== _enums_form_access_type_enum_js__rspack_import_12/* .FormAccessType.PUBLIC */.h.PUBLIC) {
1291
+ if (!FormResultService.PUBLICLY_SUBMITTABLE_ACCESS_TYPES.has(form.accessType)) {
880
1292
  throw new _nestjs_common__rspack_import_3.UnauthorizedException({
881
1293
  message: 'This form is not available for public submission',
882
- messageKey: _config_index_js__rspack_import_11/* .FORM_MESSAGES.NOT_PUBLIC */.Q.NOT_PUBLIC
1294
+ messageKey: _config_index_js__rspack_import_12/* .FORM_MESSAGES.NOT_PUBLIC */.Q.NOT_PUBLIC
883
1295
  });
884
1296
  }
885
1297
  return;
886
1298
  }
887
- if (form.accessType === _enums_form_access_type_enum_js__rspack_import_12/* .FormAccessType.PUBLIC */.h.PUBLIC) return;
1299
+ switch(form.accessType){
1300
+ case _enums_form_access_type_enum_js__rspack_import_13/* .FormAccessType.PUBLIC */.h.PUBLIC:
1301
+ return;
1302
+ case _enums_form_access_type_enum_js__rspack_import_13/* .FormAccessType.EMAIL_VERIFIED */.h.EMAIL_VERIFIED:
1303
+ throw new _nestjs_common__rspack_import_3.BadRequestException({
1304
+ message: 'Email-verified forms must be submitted through the public endpoint',
1305
+ messageKey: _config_index_js__rspack_import_12/* .FORM_MESSAGES.INVALID_ACCESS_TYPE */.Q.INVALID_ACCESS_TYPE
1306
+ });
1307
+ case _enums_form_access_type_enum_js__rspack_import_13/* .FormAccessType.ACTION_GROUP */.h.ACTION_GROUP:
1308
+ case _enums_form_access_type_enum_js__rspack_import_13/* .FormAccessType.AUTHENTICATED */.h.AUTHENTICATED:
1309
+ break;
1310
+ default:
1311
+ throw new _nestjs_common__rspack_import_3.BadRequestException({
1312
+ message: 'Invalid form access type',
1313
+ messageKey: _config_index_js__rspack_import_12/* .FORM_MESSAGES.INVALID_ACCESS_TYPE */.Q.INVALID_ACCESS_TYPE
1314
+ });
1315
+ }
888
1316
  if (!user) {
889
1317
  throw new _nestjs_common__rspack_import_3.UnauthorizedException({
890
1318
  message: 'Authentication required to submit this form',
891
- messageKey: _config_index_js__rspack_import_11/* .FORM_MESSAGES.AUTH_REQUIRED */.Q.AUTH_REQUIRED
1319
+ messageKey: _config_index_js__rspack_import_12/* .FORM_MESSAGES.AUTH_REQUIRED */.Q.AUTH_REQUIRED
892
1320
  });
893
1321
  }
894
- if (form.accessType === _enums_form_access_type_enum_js__rspack_import_12/* .FormAccessType.ACTION_GROUP */.h.ACTION_GROUP && form.actionGroups?.length) {
1322
+ if (form.accessType === _enums_form_access_type_enum_js__rspack_import_13/* .FormAccessType.ACTION_GROUP */.h.ACTION_GROUP && form.actionGroups?.length) {
895
1323
  const hasPermission = await (0,_utils_permission_utils_js__rspack_import_7/* .validateUserPermissions */.i)(user, form.actionGroups, this.cacheManager, this.formBuilderConfig.isCompanyFeatureEnabled());
896
1324
  if (!hasPermission) {
897
1325
  throw new _nestjs_common__rspack_import_3.ForbiddenException({
898
1326
  message: 'You do not have permission to submit this form',
899
- messageKey: _config_index_js__rspack_import_11/* .FORM_MESSAGES.ACCESS_DENIED */.Q.ACCESS_DENIED
1327
+ messageKey: _config_index_js__rspack_import_12/* .FORM_MESSAGES.ACCESS_DENIED */.Q.ACCESS_DENIED
900
1328
  });
901
1329
  }
902
- } else if (form.accessType !== _enums_form_access_type_enum_js__rspack_import_12/* .FormAccessType.AUTHENTICATED */.h.AUTHENTICATED) {
1330
+ } else if (form.accessType !== _enums_form_access_type_enum_js__rspack_import_13/* .FormAccessType.AUTHENTICATED */.h.AUTHENTICATED) {
903
1331
  throw new _nestjs_common__rspack_import_3.BadRequestException({
904
1332
  message: 'Invalid form access type',
905
- messageKey: _config_index_js__rspack_import_11/* .FORM_MESSAGES.INVALID_ACCESS_TYPE */.Q.INVALID_ACCESS_TYPE
1333
+ messageKey: _config_index_js__rspack_import_12/* .FORM_MESSAGES.INVALID_ACCESS_TYPE */.Q.INVALID_ACCESS_TYPE
1334
+ });
1335
+ }
1336
+ }
1337
+ async resolveEmailVerifiedSubmitter(form, user, accessToken) {
1338
+ if (form.accessType !== _enums_form_access_type_enum_js__rspack_import_13/* .FormAccessType.EMAIL_VERIFIED */.h.EMAIL_VERIFIED) return null;
1339
+ const email = await this.formEmailAuthService.resolveSubmitterEmail(form.id, user ?? undefined, accessToken);
1340
+ if (!email) {
1341
+ throw new _nestjs_common__rspack_import_3.UnauthorizedException({
1342
+ message: 'Email verification required to submit this form',
1343
+ messageKey: _config_index_js__rspack_import_12/* .FORM_MESSAGES.EMAIL_VERIFICATION_REQUIRED */.Q.EMAIL_VERIFICATION_REQUIRED
1344
+ });
1345
+ }
1346
+ return email;
1347
+ }
1348
+ async assertSingleResponseNotExceeded(form, submitterEmail) {
1349
+ if (!submitterEmail) return;
1350
+ const settings = form.schema?.settings;
1351
+ if (settings?.responseMode !== 'single') return;
1352
+ const count = await this.repository.count({
1353
+ where: {
1354
+ formId: form.id,
1355
+ submitterEmail,
1356
+ isDraft: false,
1357
+ deletedAt: (0,typeorm__rspack_import_4.IsNull)()
1358
+ }
1359
+ });
1360
+ if (count > 0) {
1361
+ throw new _nestjs_common__rspack_import_3.ConflictException({
1362
+ message: 'You have already submitted a response to this form',
1363
+ messageKey: _config_index_js__rspack_import_12/* .FORM_RESULT_MESSAGES.ALREADY_SUBMITTED */.y.ALREADY_SUBMITTED
906
1364
  });
907
1365
  }
908
1366
  }
@@ -924,6 +1382,7 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
924
1382
  'schemaVersion',
925
1383
  'data',
926
1384
  'submittedById',
1385
+ 'submitterEmail',
927
1386
  'submittedAt',
928
1387
  'isDraft',
929
1388
  'createdAt',
@@ -952,7 +1411,7 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
952
1411
  if (!computedFields || computedFields.length === 0) {
953
1412
  return data;
954
1413
  }
955
- const computedValues = (0,_utils_computed_field_utils_js__rspack_import_13/* .calculateComputedFields */.X)(data, computedFields);
1414
+ const computedValues = (0,_utils_computed_field_utils_js__rspack_import_14/* .calculateComputedFields */.X)(data, computedFields);
956
1415
  return {
957
1416
  ...data,
958
1417
  _computed: computedValues
@@ -966,6 +1425,7 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
966
1425
  schemaVersion: entity.schemaVersion,
967
1426
  data: entity.data,
968
1427
  submittedById: entity.submittedById,
1428
+ submitterEmail: entity.submitterEmail,
969
1429
  submittedAt: entity.submittedAt,
970
1430
  isDraft: entity.isDraft,
971
1431
  createdAt: entity.createdAt,
@@ -981,7 +1441,21 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
981
1441
  await this.ensureDataSourceRepository();
982
1442
  const form = await this.getActiveForm(dto.formId);
983
1443
  await this.validateSubmissionAccess(form, user, isPublic);
1444
+ const submitterEmail = await this.resolveEmailVerifiedSubmitter(form, user, dto.accessToken);
984
1445
  const isDraft = dto.isDraft ?? false;
1446
+ const persist = ()=>this.persistSubmission(form, dto, user, submitterEmail, isDraft);
1447
+ // Only a non-draft submission is subject to the single-response check, so
1448
+ // only that path needs serializing against a concurrent duplicate for the
1449
+ // same form + email (see withSubmissionLock()).
1450
+ if (!isDraft && submitterEmail) {
1451
+ return this.withSubmissionLock(`${form.id}:${submitterEmail}`, persist);
1452
+ }
1453
+ return persist();
1454
+ }
1455
+ async persistSubmission(form, dto, user, submitterEmail, isDraft) {
1456
+ if (!isDraft) {
1457
+ await this.assertSingleResponseNotExceeded(form, submitterEmail);
1458
+ }
985
1459
  const staleResults = [];
986
1460
  // Handle existing draft for authenticated users
987
1461
  if (user?.id) {
@@ -1013,6 +1487,7 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
1013
1487
  schemaVersion: form.schemaVersion,
1014
1488
  data: this.applyComputedFields(dto.data, form, isDraft),
1015
1489
  submittedById: user?.id ?? null,
1490
+ submitterEmail,
1016
1491
  submittedAt: new Date(),
1017
1492
  isDraft
1018
1493
  });
@@ -1045,7 +1520,7 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
1045
1520
  if (!draft) {
1046
1521
  throw new _nestjs_common__rspack_import_3.NotFoundException({
1047
1522
  message: 'Draft not found',
1048
- messageKey: _config_index_js__rspack_import_11/* .FORM_RESULT_MESSAGES.NOT_FOUND */.y.NOT_FOUND
1523
+ messageKey: _config_index_js__rspack_import_12/* .FORM_RESULT_MESSAGES.NOT_FOUND */.y.NOT_FOUND
1049
1524
  });
1050
1525
  }
1051
1526
  const form = await this.getActiveForm(dto.formId);
@@ -1065,7 +1540,7 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
1065
1540
  return this.convertEntityToResponseDto(saved, false);
1066
1541
  }
1067
1542
  async publishSubmissionEvent(result, formId, isDraft, user) {
1068
- await this.publishDomainAction(isDraft ? _config_index_js__rspack_import_10/* .FORM_BUILDER_EVENT_ACTIONS.DRAFT_SAVED */.ov.DRAFT_SAVED : _config_index_js__rspack_import_10/* .FORM_BUILDER_EVENT_ACTIONS.SUBMITTED */.ov.SUBMITTED, {
1543
+ await this.publishDomainAction(isDraft ? _config_index_js__rspack_import_11/* .FORM_BUILDER_EVENT_ACTIONS.DRAFT_SAVED */.ov.DRAFT_SAVED : _config_index_js__rspack_import_11/* .FORM_BUILDER_EVENT_ACTIONS.SUBMITTED */.ov.SUBMITTED, {
1069
1544
  ids: [
1070
1545
  result.id
1071
1546
  ],
@@ -1111,6 +1586,20 @@ class FormResultService extends _flusys_nestjs_shared_classes__rspack_import_0.A
1111
1586
  });
1112
1587
  return count > 0;
1113
1588
  }
1589
+ // Anonymous-path counterpart to hasUserSubmitted, keyed by a resolved
1590
+ // EMAIL_VERIFIED submitter email instead of a user id.
1591
+ async hasSubmittedByEmail(formId, email) {
1592
+ await this.ensureDataSourceRepository();
1593
+ const count = await this.repository.count({
1594
+ where: {
1595
+ formId,
1596
+ submitterEmail: email,
1597
+ isDraft: false,
1598
+ deletedAt: (0,typeorm__rspack_import_4.IsNull)()
1599
+ }
1600
+ });
1601
+ return count > 0;
1602
+ }
1114
1603
  }
1115
1604
  _ts_decorate([
1116
1605
  (0,_flusys_nestjs_shared_decorators__rspack_import_1.LogAction)({
@@ -1146,12 +1635,14 @@ FormResultService = _ts_decorate([
1146
1635
  _ts_param(1, (0,_nestjs_common__rspack_import_3.Inject)(_flusys_nestjs_shared_modules__rspack_import_2.UtilsService)),
1147
1636
  _ts_param(2, (0,_nestjs_common__rspack_import_3.Inject)(_form_builder_config_service_js__rspack_import_8/* .FormBuilderConfigService */.j)),
1148
1637
  _ts_param(3, (0,_nestjs_common__rspack_import_3.Inject)(_form_builder_datasource_provider_js__rspack_import_9/* .FormBuilderDataSourceProvider */._)),
1638
+ _ts_param(4, (0,_nestjs_common__rspack_import_3.Inject)(_form_email_auth_service_js__rspack_import_10/* .FormEmailAuthService */.w)),
1149
1639
  _ts_metadata("design:type", Function),
1150
1640
  _ts_metadata("design:paramtypes", [
1151
1641
  typeof _flusys_nestjs_shared_classes__rspack_import_0.HybridCache === "undefined" ? Object : _flusys_nestjs_shared_classes__rspack_import_0.HybridCache,
1152
1642
  typeof _flusys_nestjs_shared_modules__rspack_import_2.UtilsService === "undefined" ? Object : _flusys_nestjs_shared_modules__rspack_import_2.UtilsService,
1153
1643
  typeof _form_builder_config_service_js__rspack_import_8/* .FormBuilderConfigService */.j === "undefined" ? Object : _form_builder_config_service_js__rspack_import_8/* .FormBuilderConfigService */.j,
1154
- typeof _form_builder_datasource_provider_js__rspack_import_9/* .FormBuilderDataSourceProvider */._ === "undefined" ? Object : _form_builder_datasource_provider_js__rspack_import_9/* .FormBuilderDataSourceProvider */._
1644
+ typeof _form_builder_datasource_provider_js__rspack_import_9/* .FormBuilderDataSourceProvider */._ === "undefined" ? Object : _form_builder_datasource_provider_js__rspack_import_9/* .FormBuilderDataSourceProvider */._,
1645
+ typeof _form_email_auth_service_js__rspack_import_10/* .FormEmailAuthService */.w === "undefined" ? Object : _form_email_auth_service_js__rspack_import_10/* .FormEmailAuthService */.w
1155
1646
  ])
1156
1647
  ], FormResultService);
1157
1648
 
@@ -1161,7 +1652,7 @@ __webpack_require__.d(__webpack_exports__, {
1161
1652
 
1162
1653
 
1163
1654
  },
1164
- 148(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1655
+ 134(__unused_rspack_module, __webpack_exports__, __webpack_require__) {
1165
1656
 
1166
1657
  // EXPORTS
1167
1658
  __webpack_require__.d(__webpack_exports__, {
@@ -1174,8 +1665,8 @@ __webpack_require__.d(__webpack_exports__, {
1174
1665
  var classes_ = __webpack_require__(937);
1175
1666
  // EXTERNAL MODULE: external "@flusys/nestjs-shared/modules"
1176
1667
  var modules_ = __webpack_require__(236);
1177
- ;// CONCATENATED MODULE: external "@flusys/nestjs-shared/utils"
1178
-
1668
+ // EXTERNAL MODULE: external "@flusys/nestjs-shared/utils"
1669
+ var utils_ = __webpack_require__(216);
1179
1670
  // EXTERNAL MODULE: external "@nestjs/common"
1180
1671
  var common_ = __webpack_require__(157);
1181
1672
  // EXTERNAL MODULE: external "typeorm"
@@ -1184,8 +1675,8 @@ var external_typeorm_ = __webpack_require__(158);
1184
1675
  var event_actions = __webpack_require__(769);
1185
1676
  // EXTERNAL MODULE: ./projects/nestjs-form-builder/src/config/message-keys.ts
1186
1677
  var message_keys = __webpack_require__(137);
1187
- // EXTERNAL MODULE: ./projects/nestjs-form-builder/src/entities/index.ts + 5 modules
1188
- var entities = __webpack_require__(532);
1678
+ // EXTERNAL MODULE: ./projects/nestjs-form-builder/src/entities/index.ts + 6 modules
1679
+ var entities = __webpack_require__(814);
1189
1680
  // EXTERNAL MODULE: ./projects/nestjs-form-builder/src/enums/form-access-type.enum.ts
1190
1681
  var form_access_type_enum = __webpack_require__(376);
1191
1682
  // EXTERNAL MODULE: ./projects/nestjs-form-builder/src/utils/permission.utils.ts
@@ -1348,7 +1839,7 @@ class FormService extends classes_.ApiService {
1348
1839
  async getExtraManipulateQuery(query, filterDto, user) {
1349
1840
  const result = await super.getExtraManipulateQuery(query, filterDto, user);
1350
1841
  // Apply company filter using shared utility
1351
- (0,__rspack_external__flusys_nestjs_shared_utils_9125c1f1.applyCompanyFilter)(query, {
1842
+ (0,utils_.applyCompanyFilter)(query, {
1352
1843
  isCompanyFeatureEnabled: this.formBuilderConfig.isCompanyFeatureEnabled(),
1353
1844
  entityAlias: 'form'
1354
1845
  }, user);
@@ -1494,6 +1985,33 @@ class FormService extends classes_.ApiService {
1494
1985
  isActive: form.isActive
1495
1986
  };
1496
1987
  }
1988
+ async getEmailVerifiedFormEntity(formId) {
1989
+ await this.ensureDataSourceRepository();
1990
+ const form = await this.repository.findOne({
1991
+ where: {
1992
+ id: formId,
1993
+ isActive: true,
1994
+ deletedAt: (0,external_typeorm_.IsNull)()
1995
+ }
1996
+ });
1997
+ if (!form) {
1998
+ throw new common_.NotFoundException({
1999
+ message: 'Form not found or inactive',
2000
+ messageKey: message_keys/* .FORM_MESSAGES.NOT_FOUND */.Q.NOT_FOUND
2001
+ });
2002
+ }
2003
+ if (form.accessType !== form_access_type_enum/* .FormAccessType.EMAIL_VERIFIED */.h.EMAIL_VERIFIED) {
2004
+ throw new common_.BadRequestException({
2005
+ message: 'This form does not use email verification',
2006
+ messageKey: message_keys/* .FORM_MESSAGES.INVALID_ACCESS_TYPE */.Q.INVALID_ACCESS_TYPE
2007
+ });
2008
+ }
2009
+ return form;
2010
+ }
2011
+ async getEmailVerifiedForm(formId) {
2012
+ const form = await this.getEmailVerifiedFormEntity(formId);
2013
+ return this.toPublicForm(form);
2014
+ }
1497
2015
  async getAuthenticatedForm(formId, user) {
1498
2016
  const form = await this.getFormForSubmission(formId, user);
1499
2017
  // For action_group access, check permissions from cache
@@ -1806,6 +2324,12 @@ module.exports = __rspack_external__flusys_nestjs_shared_dtos_c4585026;
1806
2324
  module.exports = __rspack_external__flusys_nestjs_shared_modules_24702bee;
1807
2325
 
1808
2326
 
2327
+ },
2328
+ 216(module) {
2329
+
2330
+ module.exports = __rspack_external__flusys_nestjs_shared_utils_9125c1f1;
2331
+
2332
+
1809
2333
  },
1810
2334
  157(module) {
1811
2335