Skip to content

Commit

Permalink
Merge pull request #34 from apostrophecms/feature/add-limit-support
Browse files Browse the repository at this point in the history
Feature/add limit support
  • Loading branch information
haroun authored Oct 9, 2023
2 parents a8816c0 + 4abb057 commit cb72eff
Show file tree
Hide file tree
Showing 6 changed files with 108 additions and 3 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

### Adds

* File upload can now be limited in size (frontend only) by setting the max file size per file upload field.
On the server, there are many factors that can influence this rule (for example proxies and servers used
between Apostrophe and the end-user). That is why this rule is not enforced on the server side.
We use the default express connect-multiparty size limits. The rule is checked before submit.
* Allow to configure file field `multiple` attribute. By default, file field allow the user to select multiple files.
This can now be disabled.
* Add divider widget (`<hr>` tag) to form widgets.

## 1.1.1 (2023-02-17)
Expand Down
9 changes: 9 additions & 0 deletions i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,16 @@
"fieldNameHelp": "No spaces or punctuation other than dashes. If left blank, the form will populate this with a simplified form of the label. Changing this field after a form is in use may cause problems with any integrations.",
"fieldRequired": "Is this field required?",
"file": "File attachment",
"fileAllowMultiple": "Allow multiple file attachments",
"fileLimitSize": "Limit file size?",
"fileMaxSize": "Max file attachment size",
"fileMaxSizeError": "File is too large '%1$s' (max size: %2$s).",
"fileMaxSizeHelp": "In Bytes",
"fileMissingEarly": "Uploaded temporary file {{ path }} was already removed, this should have been the responsibility of the upload route",
"fileSizeUnitB": "B",
"fileSizeUnitGB": "GB",
"fileSizeUnitKB": "KB",
"fileSizeUnitMB": "MB",
"fileUploadError": "An error occurred uploading the file. It may be too large or of an inappropriate type.",
"fileUploading": "Uploading...",
"form": "Form",
Expand Down
3 changes: 2 additions & 1 deletion index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const fs = require('fs');
const path = require('path');
const connectMultiparty = require('connect-multiparty');
const fields = require('./lib/fields');

module.exports = {
Expand Down Expand Up @@ -246,7 +247,7 @@ module.exports = {
post: {
// Route to accept the submitted form.
submit: [
require('connect-multiparty')(),
connectMultiparty(),
async function (req) {
try {
await self.submitForm(req);
Expand Down
43 changes: 43 additions & 0 deletions modules/@apostrophecms/form-file-field-widget/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,28 @@ module.exports = {
icons: {
'file-upload-outline-icon': 'FileUploadOutline'
},
fields: {
add: {
allowMultiple: {
label: 'aposForm:fileAllowMultiple',
type: 'boolean',
def: true
},
limitSize: {
label: 'aposForm:fileLimitSize',
type: 'boolean',
def: false
},
maxSize: {
label: 'aposForm:fileMaxSize',
help: 'aposForm:fileMaxSizeHelp',
type: 'integer',
if: {
limitSize: true
}
}
}
},
methods (self) {
return {
async sanitizeFormField (widget, input, output) {
Expand All @@ -28,5 +50,26 @@ module.exports = {
}
}
};
},
extendMethods (self) {
return {
async output(_super, req, widget, options, _with) {
return _super(
req,
{
...widget,
allowMultiple: widget.allowMultiple ?? true,
fileSizeUnits: {
B: req.t('aposForm:fileSizeUnitB'),
KB: req.t('aposForm:fileSizeUnitKB'),
MB: req.t('aposForm:fileSizeUnitMB'),
GB: req.t('aposForm:fileSizeUnitGB')
}
},
options,
_with
);
}
};
}
};
40 changes: 40 additions & 0 deletions modules/@apostrophecms/form-file-field-widget/ui/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,50 @@ const WIDGET_NAME = '@apostrophecms/form-file-field';
const WIDGET_SELECTOR = '[data-apos-form-file]';

export default () => {
const readableSize = ({ units, size }) => {
return size < 1000
? `${size} ${units.B}`
: size < 1000 * 1000
? `${(size / 1000).toFixed(2)} ${units.KB}`
: size < 1000 * 1000 * 1000
? `${(size / (1000 * 1000)).toFixed(2)} ${units.MB}`
: `${(size / (1000 * 1000 * 1000)).toFixed(2)} ${units.GB}`;
};

const sizeLimiter = (input) => {
const { files } = input;
const totalSize = Array.from(files || []).reduce((sum, { size }) => sum + size, 0);

const units = JSON.parse(input.dataset.fileSizeUnits) || {};
const maxSize = input.dataset.maxSize;
const maxSizeError = (input.dataset.maxSizeError || '').replace(
'%2$s',
readableSize({
size: maxSize,
units
})
);
if (maxSize && totalSize > maxSize) {
const error = new Error(
maxSizeError.replace(
'%1$s',
readableSize({
size: totalSize,
units
})
)
);
error.field = input.getAttribute('name');

throw error;
}
};

apos.aposForm.collectors[WIDGET_NAME] = {
selector: WIDGET_SELECTOR,
collector (el) {
const input = el.querySelector('input[type="file"]');
sizeLimiter(input);

return {
field: input.getAttribute('name'),
Expand Down
10 changes: 8 additions & 2 deletions modules/@apostrophecms/form-file-field-widget/views/widget.html
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@
</label>
<input
class="apos-form-input {{ prependIfPrefix('__input') }}"
type="file" id="{{ id }}" multiple
type="file" id="{{ id }}"
{% if widget.allowMultiple %}multiple{% endif %}
{% if widget.limitSize and widget.maxSize %}
data-max-size="{{ widget.maxSize }}"
data-max-size-error="{{ __t('aposForm:fileMaxSizeError') }}"
data-file-size-units="{{ widget.fileSizeUnits | jsonAttribute }}"
{% endif %}
name="{{ widget.fieldName}}" {% if widget.required %}required{% endif %}>
</div>
</div>

0 comments on commit cb72eff

Please sign in to comment.