Skip to content

Commit a17cd9f

Browse files
authored
Merge branch 'main' into test/ccp-5133
2 parents 6af8855 + b41f3dd commit a17cd9f

93 files changed

Lines changed: 3856 additions & 289 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.devcontainer/chefs_local/local.sample.json

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,13 @@
149149
"enabled": false
150150
},
151151
"submitToEmail": {
152-
"enabled": false
152+
"enabled": true,
153+
"batchSize": 25,
154+
"delivery": "attachment",
155+
"reportSizeLimit": 5000000,
156+
"attachmentsSizeLimit": 10000000,
157+
"attachmentsCountLimit": 10,
158+
"stuckTimeoutMinutes": 30
153159
},
154160
"documentGenerationV3": {
155161
"enabled": false

.devcontainer/devcontainer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@
6262
//"remoteUser": "root",
6363

6464
"containerEnv": {
65-
"NODE_CONFIG_DIR": "${containerWorkspaceFolder}/.devcontainer/chefs_local"
65+
"NODE_CONFIG_DIR": "${containerWorkspaceFolder}/.devcontainer/chefs_local",
66+
"APITOKEN": "local-dev-token"
6667
},
6768
"portsAttributes": {
6869
"4222": {

.vscode/launch.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@
2929
"runtimeExecutable": "npm",
3030
"type": "node",
3131
"env": {
32-
"NODE_CONFIG_DIR": "${workspaceFolder}/.devcontainer/chefs_local"
32+
"NODE_CONFIG_DIR": "${workspaceFolder}/.devcontainer/chefs_local",
33+
"APITOKEN": "local-dev-token"
3334
}
3435
},
3536
{

app/app.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ const DataConnection = require('./src/db/dataConnection');
1919
const dataConnection = new DataConnection();
2020
const { eventStreamService } = require('./src/components/eventStreamService');
2121
const clamAvScanner = require('./src/components/clamAvScanner');
22+
const uploadCleanup = require('./src/forms/file/uploadCleanup');
2223

2324
const statusService = require('./src/components/statusService');
2425
statusService.registerConnection('dataConnection', 'Database', dataConnection, 'checkAll', 'checkConnection');
@@ -56,6 +57,10 @@ if (process.env.NODE_ENV !== 'test') {
5657
// Initialize connections and wait for completion
5758
statusService.initializeAllConnections();
5859
app.use(httpLogger);
60+
61+
if (config.has('files.uploads.cleanup')) {
62+
uploadCleanup.startUploadCleanupScheduler(config.get('files.uploads.cleanup'));
63+
}
5964
}
6065

6166
const statusPath = `${config.get('server.basePath')}${config.get('server.apiPath')}/status`;
@@ -203,6 +208,7 @@ function cleanup() {
203208

204209
log.info('Cleaning up...', { function: 'cleanup' });
205210
clearInterval(probeId);
211+
uploadCleanup.stopUploadCleanupScheduler();
206212

207213
eventStreamService.closeConnection();
208214
dataConnection.close(() => process.exit());

app/config/custom-environment-variables.json

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,13 @@
1414
"fileKey": "FILES_UPLOADS_FILEKEY",
1515
"fileMaxSize": "FILES_UPLOADS_FILEMAXSIZE",
1616
"fileMinSize": "FILES_UPLOADS_FILEMINSIZE",
17-
"path": "FILES_UPLOADS_PATH"
17+
"path": "FILES_UPLOADS_PATH",
18+
"cleanup": {
19+
"enabled": "FILES_UPLOADS_CLEANUP_ENABLED",
20+
"staleAgeMinutes": "FILES_UPLOADS_CLEANUP_STALEAGEMINUTES",
21+
"intervalMinutes": "FILES_UPLOADS_CLEANUP_INTERVALMINUTES",
22+
"batchSize": "FILES_UPLOADS_CLEANUP_BATCHSIZE"
23+
}
1824
},
1925
"permanent": "FILES_PERMANENT",
2026
"localStorage": {
@@ -128,7 +134,14 @@
128134
"enabled": "FEATURES_OFFLINEFORMS_ENABLED"
129135
},
130136
"submitToEmail": {
131-
"enabled": "FEATURES_SUBMITTOEMAIL_ENABLED"
137+
"enabled": "FEATURES_SUBMITTOEMAIL_ENABLED",
138+
"batchSize": "FEATURES_SUBMITTOEMAIL_BATCHSIZE",
139+
"delivery": "FEATURES_SUBMITTOEMAIL_DELIVERY",
140+
"reportSizeLimit": "FEATURES_SUBMITTOEMAIL_REPORTSIZELIMIT",
141+
"attachmentsSizeLimit": "FEATURES_SUBMITTOEMAIL_ATTACHMENTSSIZELIMIT",
142+
"attachmentsCountLimit": "FEATURES_SUBMITTOEMAIL_ATTACHMENTSCOUNTLIMIT",
143+
"stuckTimeoutMinutes": "FEATURES_SUBMITTOEMAIL_STUCKTIMEOUTMINUTES",
144+
"maxAttempts": "FEATURES_SUBMITTOEMAIL_MAXATTEMPTS"
132145
},
133146
"documentGenerationV2": {
134147
"enabled": "FEATURES_DOCUMENTGENERATIONV2_ENABLED"

app/config/default.json

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,13 @@
1313
"fileMaxSize": "25MB",
1414
"fileMaxSizeBytes": "25000000",
1515
"fileMinSize": "0KB",
16-
"path": "files"
16+
"path": "files",
17+
"cleanup": {
18+
"enabled": true,
19+
"staleAgeMinutes": 1440,
20+
"intervalMinutes": 60,
21+
"batchSize": 100
22+
}
1723
},
1824
"permanent": "objectStorage",
1925
"localStorage": {
@@ -142,7 +148,14 @@
142148
"enabled": false
143149
},
144150
"submitToEmail": {
145-
"enabled": false
151+
"enabled": true,
152+
"batchSize": 25,
153+
"delivery": "attachment",
154+
"reportSizeLimit": 5000000,
155+
"attachmentsSizeLimit": 10000000,
156+
"attachmentsCountLimit": 10,
157+
"stuckTimeoutMinutes": 30,
158+
"maxAttempts": 3
146159
},
147160
"documentGenerationV2": {
148161
"enabled": true

app/frontend/src/components/designer/FormDesigner.vue

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import formioIl8next from '~/internationalization/trans/formio/formio.json';
1313
import templateExtensions from '~/plugins/templateExtensions';
1414
import { formService, userService } from '~/services';
1515
import { useAuthStore } from '~/store/auth';
16+
import { useFeatureFlagStore } from '~/store/featureFlags';
1617
import { useFormStore } from '~/store/form';
1718
import { useNotificationStore } from '~/store/notification';
1819
import { FormDesignerBuilderOptions } from '~/utils/constants';
@@ -71,6 +72,7 @@ const savedStatus = ref(properties.isSavedStatus);
7172
const saving = ref(false);
7273
7374
const authStore = useAuthStore();
75+
const featureFlagStore = useFeatureFlagStore();
7476
const formStore = useFormStore();
7577
const notificationStore = useNotificationStore();
7678
@@ -101,6 +103,11 @@ onMounted(async () => {
101103
if (!properties.formId) {
102104
// We are creating a new form, so we obtain the original schema here.
103105
patch.value.originalSchema = deepClone(formSchema.value);
106+
// Resolve feature flags with no form context. A brand-new form is not
107+
// allowlisted, so allowlist-gated features (e.g. submitToEmail) resolve
108+
// inactive. Without this, a stale active map from a previously-opened
109+
// allowlisted form would leak in and show gated controls on a new form.
110+
await featureFlagStore.resolveForContext({});
104111
}
105112
});
106113
@@ -411,6 +418,7 @@ async function schemaCreateNew() {
411418
showAssigneeInSubmissionsTable: form.value.showAssigneeInSubmissionsTable,
412419
showSubmissionConfirmation: form.value.showSubmissionConfirmation,
413420
submissionReceivedEmails: form.value.submissionReceivedEmails,
421+
submissionPackageSettings: form.value.submissionPackageSettings,
414422
reminder_enabled: false,
415423
deploymentLevel: form.value.deploymentLevel,
416424
ministry: form.value.ministry,

app/frontend/src/components/designer/FormSettings.vue

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ const { form, isFormPublished, isRTL } = storeToRefs(useFormStore());
3434
<FormFunctionalitySettings :disabled="disabled" />
3535
</v-col>
3636
<v-col cols="12" md="6">
37-
<FormSubmissionSettings />
37+
<FormSubmissionSettings :disabled="disabled" />
3838
</v-col>
3939
<v-col v-if="form.schedule.enabled && isFormPublished" cols="12" md="6">
4040
<FormScheduleSettings />

app/frontend/src/components/designer/settings/FormSubmissionSettings.vue

Lines changed: 45 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,32 @@
11
<script setup>
22
import { storeToRefs } from 'pinia';
3-
import { ref } from 'vue';
3+
import { computed } from 'vue';
44
import { useI18n } from 'vue-i18n';
55
66
import { useFormStore } from '~/store/form';
77
import { Regex } from '~/utils/constants';
8+
import SubmissionPackageEmailSettings from './SubmissionPackageEmailSettings.vue';
89
910
const { t, locale } = useI18n({ useScope: 'global' });
1011
1112
const { form, isRTL } = storeToRefs(useFormStore());
1213
1314
/* c8 ignore start */
14-
const emailArrayRules = ref([
15-
(v) =>
16-
!form.value.sendSubmissionReceivedEmail ||
15+
const makeEmailArrayRules = (enabledRefOrGetter) => [
16+
(v = []) =>
17+
!enabledRefOrGetter() ||
1718
v.length > 0 ||
1819
t('trans.formSettings.atLeastOneEmailReq'),
19-
(v) =>
20-
!form.value.sendSubmissionReceivedEmail ||
21-
v.every((item) => new RegExp(Regex.EMAIL).test(item)) ||
20+
21+
(v = []) =>
22+
!enabledRefOrGetter() ||
23+
v.every((item) => new RegExp(Regex.EMAIL).test(String(item).trim())) ||
2224
t('trans.formSettings.validEmailRequired'),
23-
]);
25+
];
26+
27+
const submissionReceivedEmailRules = computed(() =>
28+
makeEmailArrayRules(() => form.sendSubmissionReceivedEmail)
29+
);
2430
/* c8 ignore stop */
2531
</script>
2632

@@ -100,35 +106,37 @@ const emailArrayRules = ref([
100106
</div>
101107
</template>
102108
</v-checkbox>
109+
<div v-if="form.sendSubmissionReceivedEmail">
110+
<v-combobox
111+
v-model="form.submissionReceivedEmails"
112+
:hide-no-data="false"
113+
:rules="submissionReceivedEmailRules"
114+
solid
115+
variant="outlined"
116+
hide-selected
117+
clearable
118+
:hint="$t('trans.formSettings.addMoreValidEmailAddrs')"
119+
:label="$t('trans.formSettings.notificationEmailAddrs')"
120+
multiple
121+
chips
122+
closable-chips
123+
:delimiters="[' ', ',']"
124+
append-icon=""
125+
:lang="locale"
126+
>
127+
<template #no-data>
128+
<v-list-item>
129+
<v-list-item-title>
130+
<span
131+
:lang="locale"
132+
v-html="$t('trans.formSettings.pressToAddMultiEmail')"
133+
/>
134+
</v-list-item-title>
135+
</v-list-item>
136+
</template>
137+
</v-combobox>
138+
</div>
103139

104-
<v-combobox
105-
v-if="form.sendSubmissionReceivedEmail"
106-
v-model="form.submissionReceivedEmails"
107-
:hide-no-data="false"
108-
:rules="emailArrayRules"
109-
solid
110-
variant="outlined"
111-
hide-selected
112-
clearable
113-
:hint="$t('trans.formSettings.addMoreValidEmailAddrs')"
114-
:label="$t('trans.formSettings.notificationEmailAddrs')"
115-
multiple
116-
chips
117-
closable-chips
118-
:delimiters="[' ', ',']"
119-
append-icon=""
120-
:lang="locale"
121-
>
122-
<template #no-data>
123-
<v-list-item>
124-
<v-list-item-title>
125-
<span
126-
:lang="locale"
127-
v-html="$t('trans.formSettings.pressToAddMultiEmail')"
128-
/>
129-
</v-list-item-title>
130-
</v-list-item>
131-
</template>
132-
</v-combobox>
140+
<SubmissionPackageEmailSettings />
133141
</BasePanel>
134142
</template>

0 commit comments

Comments
 (0)