WEBVTT

1
00:00:01.720 --> 00:00:07.060
At this point we can sign up and log in and we can create events, edit events, delete

2
00:00:07.060 --> 00:00:09.180
events and register for events.

3
00:00:09.380 --> 00:00:14.880
You could add more functionality related to that, but that's all I want for this app.

4
00:00:16.020 --> 00:00:18.520
At least almost all.

5
00:00:18.960 --> 00:00:23.240
One last piece is missing here and that's image upload.

6
00:00:23.320 --> 00:00:29.320
I want to make sure that when we create an event or when we edit an event, we actually

7
00:00:29.900 --> 00:00:37.200
accept and we expect an image to be attached to the request so that we store that image

8
00:00:37.200 --> 00:00:42.580
here and of course so that we can then also later request and serve that image if we needed

9
00:00:42.580 --> 00:00:43.980
it in our frontend.

10
00:00:45.279 --> 00:00:47.180
So how can we do that?

11
00:00:48.359 --> 00:00:54.620
Well ChatGPT already had an answer for me earlier that we can use a library like maltr.

12
00:00:55.820 --> 00:00:59.980
We could also use some cloud storage, but here I want to use local storage and I want

13
00:00:59.980 --> 00:01:01.500
to use this maltr package.

14
00:01:02.920 --> 00:01:08.600
Now I happen to already know how the maltr package is used and I'll use a bit of AI

15
00:01:08.600 --> 00:01:10.500
help to write the code more quickly.

16
00:01:11.020 --> 00:01:15.160
Of course if you would not know that, you could visit the official docs, but you could

17
00:01:15.259 --> 00:01:17.720
also ask your chatbot.

18
00:01:18.940 --> 00:01:24.180
In cursor you could also bring in the maltr documentation as you learned it earlier in

19
00:01:24.180 --> 00:01:24.680
the course.

20
00:01:24.960 --> 00:01:26.160
So plenty of options.

21
00:01:28.060 --> 00:01:30.600
Now as mentioned, I already know what I want to do.

22
00:01:30.740 --> 00:01:35.220
So I'll start by quitting my development server and by running npm install maltr to

23
00:01:35.220 --> 00:01:38.000
install this maltr package as a dependency.

24
00:01:40.200 --> 00:01:45.680
With it installed, I'll add a new folder, or a new file I mean, to the util folder,

25
00:01:46.180 --> 00:01:53.000
the upload.js file, where I want to set up some settings for maltr.

26
00:01:55.230 --> 00:02:02.200
Because in there I want to import maltr from maltr, except this suggestion, and set up

27
00:02:02.200 --> 00:02:05.340
some storage setting as it's suggested here for me.

28
00:02:06.900 --> 00:02:12.240
Because the maltr package can be configured to control where and how incoming files are

29
00:02:12.240 --> 00:02:13.060
going to be stored.

30
00:02:14.620 --> 00:02:19.520
The maltr package itself will simply take a look at incoming requests and evaluate whether

31
00:02:19.520 --> 00:02:21.820
there is a file attached to them or not.

32
00:02:22.160 --> 00:02:26.480
And then it's the settings I'm about to add here that control how such a file would

33
00:02:26.480 --> 00:02:27.020
be stored.

34
00:02:29.100 --> 00:02:34.740
So I'll configure some maltr disk storage and I do want to set up such a destination

35
00:02:35.060 --> 00:02:40.280
function which controls where the files are stored, but I'll tweak the path and store

36
00:02:40.280 --> 00:02:47.480
them in the public slash images folder, so that it's this folder in which my images

37
00:02:47.480 --> 00:02:48.240
will be stored.

38
00:02:50.380 --> 00:02:51.280
That's one thing.

39
00:02:52.060 --> 00:02:57.280
In addition, I'll add this filename function, which is suggested for me here, which can

40
00:02:57.280 --> 00:02:59.900
be used to rename the received file.

41
00:03:02.180 --> 00:03:08.160
And here I'm using the current timestamp in milliseconds and I append the original

42
00:03:08.160 --> 00:03:10.480
filename, which also includes the file extension.

43
00:03:12.620 --> 00:03:19.900
And then I'll close this and also export this upload constant here, which turns out

44
00:03:19.900 --> 00:03:25.280
to hold a middleware that will be configured with these settings, which I can add to any

45
00:03:25.280 --> 00:03:28.060
route that should possibly accept images.

46
00:03:29.620 --> 00:03:38.100
So what I can do here is I can go to my event routes and here it's the post and put routes

47
00:03:38.100 --> 00:03:40.760
where I do expect to get some images.

48
00:03:42.540 --> 00:03:46.960
So after checking for authentication, I'll add another middleware function here.

49
00:03:47.460 --> 00:03:51.040
That's how this express library, which I'm using, works.

50
00:03:51.240 --> 00:03:56.480
You can add multiple middlewares to one route to execute them step by step, one after another.

51
00:03:58.540 --> 00:04:04.100
And here it's this upload function, which is imported from my util folder and the upload.js file.

52
00:04:05.940 --> 00:04:09.520
And there specifically, technically upload is not a middleware itself.

53
00:04:09.660 --> 00:04:13.140
It is an object instead, which provides multiple middlewares.

54
00:04:13.500 --> 00:04:17.860
And here it's the single middleware, which must be called like this to enable it.

55
00:04:19.149 --> 00:04:25.540
And then you simply specify what the name of the field that carries the image will be

56
00:04:25.460 --> 00:04:27.160
in the incoming request body.

57
00:04:28.500 --> 00:04:34.740
And here I expect to get a request body field named image, which should contain the image

58
00:04:34.740 --> 00:04:35.320
file.

59
00:04:35.560 --> 00:04:39.040
And you'll see how it's submitted soon once we test this route.

60
00:04:40.780 --> 00:04:47.460
So that's how we can use this configured malter middleware to extract images or one image

61
00:04:47.460 --> 00:04:49.440
for this create route.

62
00:04:51.300 --> 00:04:54.500
And it's the same code I'll use down here for the put route.

63
00:04:55.360 --> 00:05:00.000
And that will ensure that we do extract an image stored under the key.

64
00:05:00.000 --> 00:05:10.240
image from the incoming request body here. Now for this to work, the code in the EventsController.js

65
00:05:10.240 --> 00:05:17.860
file also must be tweaked for both the create function and the edit function. Because I'm no

66
00:05:17.860 --> 00:05:25.000
longer just getting title, description and so on from this request, instead I also get that file.

67
00:05:26.540 --> 00:05:34.560
And that file is made available on rec.file. This file property is a property that's added

68
00:05:34.560 --> 00:05:42.980
to this request object by the malter package. So I can get my image by accessing rec.file.

69
00:05:43.300 --> 00:05:48.060
That will be this one single file which I expect to get and which I extracted.

70
00:05:49.700 --> 00:05:58.340
Now, of course, I also want to verify whether we got an image file. So we need an extra check here

71
00:05:58.340 --> 00:06:05.480
in this long validation if statement and check if this is maybe not truthy, if it's null,

72
00:06:05.580 --> 00:06:10.900
if it's not set, in which case I would return this invalid input data response.

73
00:06:12.760 --> 00:06:20.580
And it's the same approach down here in this edit route. Extract the image file just as before

74
00:06:21.960 --> 00:06:24.960
and then also add this extra check here.

75
00:06:27.540 --> 00:06:33.140
Here, GitHub Copilot actually suggests a more sophisticated check,

76
00:06:34.120 --> 00:06:39.900
whether it's really an image. But here to keep things simple, I'll just check if I maybe don't

77
00:06:39.760 --> 00:06:50.140
have an image, just as when creating the event. So that will extract the image. It will also be

78
00:06:50.140 --> 00:06:57.640
stored thanks to this malter configuration. This will automatically ensure that images that are

79
00:06:57.640 --> 00:07:03.720
attached to requests where this malter middleware is enabled will be stored in this path

80
00:07:05.420 --> 00:07:12.820
by using this name. So the storage will be taken care of. But of course, I do need to make sure

81
00:07:12.820 --> 00:07:19.060
that I also store that image file name in the database when I create a new event.

82
00:07:21.120 --> 00:07:27.360
Because at the moment, that's not happening. I'm getting hold of that image that was uploaded here.

83
00:07:27.480 --> 00:07:32.360
But technically, that's just an object with information about that image file that has

84
00:07:32.360 --> 00:07:39.720
been stored by malter. For example, this image object here will contain the name of the image

85
00:07:39.720 --> 00:07:46.000
file. And it's that name which I want to store together with all the other event data in the

86
00:07:46.000 --> 00:07:52.280
database so that when I later query for all the events, I know which image belongs to which event.

87
00:07:54.039 --> 00:07:58.220
Therefore, of course, I want to pass that image to create event.

88
00:07:58.940 --> 00:08:08.220
So that image object or to be precise, image.filename. This image thing here will be an

89
00:08:08.220 --> 00:08:14.560
object that has a file name property which includes or which contains the file name of

90
00:08:14.560 --> 00:08:23.240
the image as it has been stored by malter. The same is of course also true for the edit function.

91
00:08:23.460 --> 00:08:29.520
When I call edit event, I also want to pass the image file name here

92
00:08:30.960 --> 00:08:35.480
to this object which is passed as a second argument to edit event.

93
00:08:37.760 --> 00:08:40.120
And with that, of course, I now need to tweak

94
00:08:41.860 --> 00:08:46.480
create event and edit event in the models folder in the events function there.

95
00:08:47.860 --> 00:08:52.840
And here when I call create event, I actually also must give this a key name

96
00:08:52.840 --> 00:08:59.600
which will be image here. But still, I need to tweak create event and edit event

97
00:08:59.600 --> 00:09:05.680
to make sure that they use this received image name and that they really store it in the database.

