You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/file_uploads.md
+80-43Lines changed: 80 additions & 43 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1,18 +1,32 @@
1
1
# File uploads in BCIERS app
2
2
3
-
Could use some optimization: https://github.com/bcgov/cas-registration/issues/2123
4
-
5
3
Two methods are available:
6
4
7
5
- with RJSF
8
6
- without RJSF using `FormData`
9
7
10
-
## With RJSF (using data-urls)
8
+
#### Model
9
+
10
+
The `FileField` is where django does the magic, along with the `STORAGES` configuration in settings.py.
11
+
More documentation [here](https://docs.djangoproject.com/en/5.1/ref/models/fields/#filefield)
12
+
13
+
```python
14
+
classDocument(TimeStampedModel):
15
+
file= models.FileField(upload_to="documents", db_comment="The file format, metadata, etc.")
16
+
```
17
+
18
+
#### Connection with GCS
19
+
20
+
- Some setup is done in cas-registration/bc_obps/bc_obps/settings.py, will need env variables
21
+
- GCS is not set up in CI so we skip endpoint tests related to files, and we don't have any file stuff in our mock data
22
+
23
+
## With RJSF
24
+
25
+
Because files can be large and slow to process, we only pass the file from the front end to the back end when the user first uploads it. We never pass the file itself from back to front; instead we pass a url where the user can download it.
11
26
12
27
### Frontend
13
28
14
-
- RJSF supports file with data-urls: https://rjsf-team.github.io/react-jsonschema-form/docs/usage/widgets/#file-widgets
15
-
-`FileWidget`: this started as a copy/paste from RJSF's [FileWidget](https://github.com/rjsf-team/react-jsonschema-form/blob/main/packages/core/src/components/widgets/FileWidget.tsx) and @marcelmueller did some styling to match the designs. It now additionally includes a check for max file size, and possibly other stuff including state mgt.
29
+
We send files to the backend using FormData. Because RJSF stores data as json, in the handleSubmit, we have to convert to FormData (see `convertRjsfFormData` from "@/registration/app/components/operations/registration/OperationInformationForm"). The conversion happens in the form component (e.g. `OperationInformationForm`). The `FileWidget` handles previewing and downloading the file, and additionally includes a check for max file size.
16
30
17
31
In the rjsf schema:
18
32
@@ -21,76 +35,99 @@ In the rjsf schema:
21
35
statutory_declaration: {
22
36
type: "string",
23
37
title: "Statutory Declaration",
24
-
format: "data-url",
25
38
}
26
39
27
40
# uiSchema
28
41
statutory_declaration: {
29
42
"ui:widget": "FileWidget",
30
43
"ui:options": {
31
-
filePreview: true,
32
44
accept: ".pdf",
33
45
}
34
46
}
35
47
```
36
48
37
49
### Backend
38
50
39
-
#### Ninja field validator
51
+
#### Endpoints
52
+
53
+
To make django ninja happy, we have to separate out form data and file data. There are a few ways to do this, see the docs, and we've chosen to go with this for a POST endpoint:
54
+
55
+
```python
56
+
defupdate_operation(
57
+
request: HttpRequest, operation_id: UUID,
58
+
details: Form[OperationAdminstrationIn], # OperationAdminstrationIn is a ModelSchema or Schema
payload.boundary_map, # type:ignore# mypy is not aware of the schema validator
76
-
'boundary_map',
77
-
),
78
-
```
95
+
We have mock files in both our FE and BE constants.
79
96
80
-
#### Model
97
+
In vitests, we have to mock `createObjectURL`, which is used in the `FileWidget` (e.g. `global.URL.createObjectURL = vi.fn(() => "this is the link to download the File",);`).
81
98
82
-
The `FileField` is where django does the magic, along with the `STORAGES` configuration in settings.py.
83
-
More documentation [here](https://docs.djangoproject.com/en/5.1/ref/models/fields/#filefield)
99
+
We check mocked calls like this:
84
100
85
-
```python
86
-
classDocument(TimeStampedModel):
87
-
file= models.FileField(upload_to="documents", db_comment="The file format, metadata, etc.")
0 commit comments