1
00:00:02,160 --> 00:00:03,430
Now let's ensure

2
00:00:03,430 --> 00:00:06,800
that submitting this form works.

3
00:00:06,800 --> 00:00:07,930
And for this,

4
00:00:07,930 --> 00:00:10,820
we have to go to the new-product.ejs file

5
00:00:10,820 --> 00:00:12,943
and add a form action and method.

6
00:00:13,940 --> 00:00:18,050
Now the action should be /admin/products.

7
00:00:18,050 --> 00:00:20,880
So that's the path to which the request will be sent.

8
00:00:20,880 --> 00:00:21,870
And the method,

9
00:00:21,870 --> 00:00:25,190
since we wanna create and store new data on the server,

10
00:00:25,190 --> 00:00:26,380
should be Post,

11
00:00:26,380 --> 00:00:28,600
since as you learned multiple times before

12
00:00:28,600 --> 00:00:30,270
that is the convention.

13
00:00:30,270 --> 00:00:33,440
You typically use post requests for submitting data,

14
00:00:33,440 --> 00:00:35,960
and that has the advantage that then the data

15
00:00:35,960 --> 00:00:38,573
is also included in the request body.

16
00:00:39,810 --> 00:00:42,680
Now, there is something special about this form though.

17
00:00:42,680 --> 00:00:45,650
We have this image input in there.

18
00:00:45,650 --> 00:00:48,530
And you did learn before in the course section

19
00:00:48,530 --> 00:00:51,860
about file uploads that in such cases,

20
00:00:51,860 --> 00:00:54,130
you must change the enctype,

21
00:00:54,130 --> 00:00:56,993
the encoding type of the form.

22
00:00:58,440 --> 00:01:03,220
The default is application/x-www-form-urlencoded

23
00:01:03,220 --> 00:01:06,270
and therefore you don't need to set that default.

24
00:01:06,270 --> 00:01:08,453
You use that for all the regular forms

25
00:01:08,453 --> 00:01:11,780
that do not have a file in them.

26
00:01:11,780 --> 00:01:15,000
If you do have input type="file" in a form,

27
00:01:15,000 --> 00:01:16,890
and that file should be submitted

28
00:01:16,890 --> 00:01:19,230
with all the other data to the server,

29
00:01:19,230 --> 00:01:23,443
then you need multipart/form-data as enctype.

30
00:01:24,840 --> 00:01:27,000
Hence, we have to choose this here.

31
00:01:27,000 --> 00:01:29,920
That will ensure that the file is sent to the server

32
00:01:29,920 --> 00:01:33,410
and there in the second step we can extract it.

33
00:01:33,410 --> 00:01:35,350
Now there is one other thing that is important

34
00:01:35,350 --> 00:01:37,040
that we need to do in this form.

35
00:01:37,040 --> 00:01:39,093
And that's our CSRF token.

36
00:01:39,950 --> 00:01:42,360
All the forms where post requests

37
00:01:42,360 --> 00:01:45,400
are sent need a CSRF token;

38
00:01:45,400 --> 00:01:48,093
otherwise, sending that data will fail.

39
00:01:49,259 --> 00:01:52,150
Now previously, we always solved this problem

40
00:01:52,150 --> 00:01:54,160
by adding a hidden input.

41
00:01:54,160 --> 00:01:56,540
This worked, but unfortunately,

42
00:01:56,540 --> 00:01:58,570
this does not work if the enctype

43
00:01:58,570 --> 00:02:00,713
is set to multipart/form-data.

44
00:02:01,751 --> 00:02:05,460
Therefore, we can't add the CSRF token as we did before,

45
00:02:05,460 --> 00:02:08,030
but thankfully the csurf package,

46
00:02:08,030 --> 00:02:10,990
which we are using for handling the CSRF token,

47
00:02:10,990 --> 00:02:13,233
has a plan B for us.

48
00:02:14,100 --> 00:02:15,870
Besides adding such an input

49
00:02:15,870 --> 00:02:17,980
and therefore adding the token into the body

50
00:02:17,980 --> 00:02:20,140
that's submitted with the request,

51
00:02:20,140 --> 00:02:24,020
we can also add it as a query parameter on the path,

52
00:02:24,020 --> 00:02:26,663
on the URL the request is sent to.

53
00:02:27,510 --> 00:02:30,760
Simply by adding a question mark here after action

54
00:02:30,760 --> 00:02:33,120
or after the path we set up an action

55
00:02:33,120 --> 00:02:37,010
and adding _csrf field here

56
00:02:37,010 --> 00:02:39,030
where I then dynamically inject

57
00:02:39,030 --> 00:02:40,550
with help of EJS,

58
00:02:40,550 --> 00:02:42,623
locals.csrfToken.

59
00:02:43,910 --> 00:02:46,660
So that token that is generated by the package,

60
00:02:46,660 --> 00:02:48,150
the CSRF package,

61
00:02:48,150 --> 00:02:50,080
is added as a query parameter

62
00:02:50,080 --> 00:02:53,663
named _csrf to the outgoing request.

63
00:02:54,520 --> 00:02:57,163
This will make sure that this form can be submitted.

64
00:02:58,760 --> 00:03:01,570
Now, these are the final touches on the frontend.

65
00:03:01,570 --> 00:03:04,110
Of course, now we have to ensure that on the backend

66
00:03:04,110 --> 00:03:06,030
we are receiving that submitted data.

67
00:03:06,030 --> 00:03:07,490
And most importantly,

68
00:03:07,490 --> 00:03:10,280
that we're also receiving that file.

69
00:03:10,280 --> 00:03:12,963
That is the part that is missing right now.

70
00:03:13,860 --> 00:03:16,030
Now in the file upload section,

71
00:03:16,030 --> 00:03:19,060
I introduced you to a package called multer,

72
00:03:19,060 --> 00:03:22,560
which you can use for handling file uploads.

73
00:03:22,560 --> 00:03:24,980
And indeed, that is still the package

74
00:03:24,980 --> 00:03:26,483
I would recommend using.

75
00:03:27,500 --> 00:03:30,360
You can simply visit the Multer NPM

76
00:03:30,360 --> 00:03:34,270
or GitHub page to find detailed instructions on it.

77
00:03:34,270 --> 00:03:37,150
But in the end, we wanna install it and then we will use it

78
00:03:37,150 --> 00:03:40,053
just as we learned it in the file upload section.

79
00:03:41,900 --> 00:03:43,630
Hence here, back on our server,

80
00:03:43,630 --> 00:03:46,540
I'll quit that running server for now,

81
00:03:46,540 --> 00:03:51,370
and run NPM install multer with or without --save.

82
00:03:51,370 --> 00:03:52,540
Doesn't matter too much.

83
00:03:52,540 --> 00:03:54,150
It will be added as a dependency

84
00:03:54,150 --> 00:03:56,780
in package.json either way,

85
00:03:56,780 --> 00:03:58,720
but this will now install it.

86
00:03:58,720 --> 00:03:59,553
And then thereafter,

87
00:03:59,553 --> 00:04:03,420
we can restart this all with NPM start.

88
00:04:03,420 --> 00:04:08,140
And now we got multer added here as a dependency.

89
00:04:08,140 --> 00:04:10,060
Now we can use it as you learn it.

90
00:04:10,060 --> 00:04:12,430
That means we add it as a middleware

91
00:04:12,430 --> 00:04:15,330
to the routes where we expect a file

92
00:04:15,330 --> 00:04:17,433
and where we wanna extract the file.

93
00:04:18,560 --> 00:04:21,019
Now you've also learned in the multer,

94
00:04:21,019 --> 00:04:23,270
or in the file upload core section,

95
00:04:23,270 --> 00:04:26,000
that you often need to configure multer.

96
00:04:26,000 --> 00:04:29,350
Especially so that you are able to rename the file

97
00:04:29,350 --> 00:04:31,003
and keep the file extension.

98
00:04:32,160 --> 00:04:35,230
Therefore, I will actually add a custom middleware

99
00:04:35,230 --> 00:04:38,350
that will take care about the multer configuration.

100
00:04:38,350 --> 00:04:41,653
I'll name it image-upload.js.

101
00:04:42,490 --> 00:04:46,500
In there I wanna start by requiring multer,

102
00:04:46,500 --> 00:04:48,403
this package we just installed.

103
00:04:49,480 --> 00:04:53,320
And you might recall that you then need to,

104
00:04:53,320 --> 00:04:56,653
in the end, execute multer as a function.

105
00:04:58,430 --> 00:05:01,780
This gives you back an upload object,

106
00:05:01,780 --> 00:05:04,370
which you can then use to access different

107
00:05:04,370 --> 00:05:07,350
pre-configured middlewares that could be added

108
00:05:07,350 --> 00:05:08,403
to your routes.

109
00:05:09,450 --> 00:05:13,050
Now multer takes a object with configuration options,

110
00:05:13,050 --> 00:05:14,750
but I'll come back to those later.

111
00:05:15,930 --> 00:05:19,860
Now, upload this object you get back after calling multer

112
00:05:19,860 --> 00:05:22,330
has various methods for extracting

113
00:05:22,330 --> 00:05:25,150
different kinds of files from requests.

114
00:05:25,150 --> 00:05:28,230
And we need the single method because that allows us

115
00:05:28,230 --> 00:05:31,430
to extract a single file by field name

116
00:05:31,430 --> 00:05:33,710
from the incoming request.

117
00:05:33,710 --> 00:05:35,530
And here I'll pass the field name

118
00:05:35,530 --> 00:05:37,830
as a parameter value to signal.

119
00:05:37,830 --> 00:05:39,870
And in my case, that's image,

120
00:05:39,870 --> 00:05:43,010
because that is the name I assigned

121
00:05:43,010 --> 00:05:46,300
in the new-product-ejs file to this input.

122
00:05:46,300 --> 00:05:48,730
It has a name of image here

123
00:05:48,730 --> 00:05:51,300
and therefore that is the name, image,

124
00:05:51,300 --> 00:05:53,320
for which we have to look with help

125
00:05:53,320 --> 00:05:54,633
of the multer middleware.

126
00:05:56,440 --> 00:06:00,400
Now this gives me then the configured multer middleware

127
00:06:00,400 --> 00:06:02,550
because upload.single will return

128
00:06:02,550 --> 00:06:04,750
the actual middleware function.

129
00:06:04,750 --> 00:06:07,500
And therefore it's this configuredMulterMiddleware,

130
00:06:07,500 --> 00:06:09,320
which I now want to export

131
00:06:09,320 --> 00:06:14,320
with module.exports = configuredMulterMiddleware.

132
00:06:16,340 --> 00:06:18,670
But this is not all we need to do.

133
00:06:18,670 --> 00:06:20,670
This would extract the image,

134
00:06:20,670 --> 00:06:23,060
but it would store it in the wrong path

135
00:06:23,060 --> 00:06:25,403
and it would store it under the wrong name.

136
00:06:26,690 --> 00:06:29,050
Now you did learn in the file upload section

137
00:06:29,050 --> 00:06:33,340
that on multer you can actually set a storage option

138
00:06:34,380 --> 00:06:37,970
and this then takes a disk storage object

139
00:06:37,970 --> 00:06:39,820
as expected by multer.

140
00:06:39,820 --> 00:06:43,270
You can create such a multer disk storage object

141
00:06:43,270 --> 00:06:44,910
by accessing multer

142
00:06:44,910 --> 00:06:47,337
which I'm importing here .diskStorage.

143
00:06:49,640 --> 00:06:51,570
This is a function you can execute

144
00:06:51,570 --> 00:06:53,360
or a method you can execute,

145
00:06:53,360 --> 00:06:56,790
which itself takes a configuration object.

146
00:06:56,790 --> 00:06:58,900
And then this configuration object,

147
00:06:58,900 --> 00:07:01,190
which you pass to disk storage,

148
00:07:01,190 --> 00:07:05,823
you can configure the destination and the file name.

149
00:07:06,780 --> 00:07:09,230
Now destination can be a function

150
00:07:09,230 --> 00:07:11,130
where you run your own logic

151
00:07:11,130 --> 00:07:13,210
for determining the destination.

152
00:07:13,210 --> 00:07:16,820
Alternatively, you can just specify a path here.

153
00:07:16,820 --> 00:07:21,820
In my case, I'll choose product-data/images as a path here.

154
00:07:23,610 --> 00:07:26,550
Now we just have to make sure that we have such a folder

155
00:07:26,550 --> 00:07:28,840
in our project here then.

156
00:07:28,840 --> 00:07:29,673
So therefore,

157
00:07:31,740 --> 00:07:33,370
I will quickly

158
00:07:33,370 --> 00:07:36,760
add a product-data folder

159
00:07:36,760 --> 00:07:38,860
and in there an images folder,

160
00:07:38,860 --> 00:07:41,010
which initially of course is empty,

161
00:07:41,010 --> 00:07:43,670
but that is the path at which I'm pointing here

162
00:07:43,670 --> 00:07:47,470
where finally the images, the uploaded images,

163
00:07:47,470 --> 00:07:48,583
should be stored in.

164
00:07:50,480 --> 00:07:53,100
Now, the second option we can add for disk storage

165
00:07:53,100 --> 00:07:55,470
is the file name option.

166
00:07:55,470 --> 00:07:58,050
And here we can provide a function,

167
00:07:58,050 --> 00:08:00,330
an anonymous function here in this case,

168
00:08:00,330 --> 00:08:02,310
but you could of course also use a function

169
00:08:02,310 --> 00:08:05,023
that you define somewhere else at which you now point,

170
00:08:05,910 --> 00:08:07,380
which takes the request,

171
00:08:07,380 --> 00:08:10,090
the file extracted by multer

172
00:08:10,090 --> 00:08:13,220
and a callback function which you have to call

173
00:08:13,220 --> 00:08:15,460
in your function once you're done

174
00:08:15,460 --> 00:08:17,163
coming up with a file name.

175
00:08:18,740 --> 00:08:20,750
And I will call that function right away

176
00:08:20,750 --> 00:08:22,390
and queue that function.

177
00:08:22,390 --> 00:08:24,560
You then first pass information

178
00:08:24,560 --> 00:08:27,060
about a potential error you faced.

179
00:08:27,060 --> 00:08:28,270
If you've got no error,

180
00:08:28,270 --> 00:08:31,570
you pass null and here we have no error.

181
00:08:31,570 --> 00:08:34,659
And then the second value you pass to call callback

182
00:08:34,659 --> 00:08:37,773
is the file name you wanna use for the uploaded file.

183
00:08:38,809 --> 00:08:40,495
And here I will actually install

184
00:08:40,495 --> 00:08:42,950
another third-party package.

185
00:08:42,950 --> 00:08:46,120
And that is the uuid package,

186
00:08:46,120 --> 00:08:50,060
which I can use for generating unique identifiers

187
00:08:50,060 --> 00:08:53,360
so that I don't have any clashing file names later,

188
00:08:53,360 --> 00:08:56,530
but every file gets its own file name.

189
00:08:56,530 --> 00:08:59,560
And this package will generate them for me.

190
00:08:59,560 --> 00:09:03,850
For this I'll just import uuid by requiring uuid.

191
00:09:03,850 --> 00:09:05,660
And then on this required package

192
00:09:05,660 --> 00:09:08,460
we should access the v4 version.

193
00:09:08,460 --> 00:09:09,693
So version four.

194
00:09:10,930 --> 00:09:14,800
And then uuid here actually is a function you can execute,

195
00:09:14,800 --> 00:09:17,753
which will give you a string that contains a unique ID.

196
00:09:19,130 --> 00:09:21,950
Now I will concatenate that with a dash

197
00:09:21,950 --> 00:09:24,030
and then with the original file name,

198
00:09:24,030 --> 00:09:26,890
which will contain the file extension.

199
00:09:26,890 --> 00:09:30,790
We can access this on the file identified by multer.

200
00:09:30,790 --> 00:09:34,070
This file object holds information about that file.

201
00:09:34,070 --> 00:09:36,760
And it does, for example, holds the original name,

202
00:09:36,760 --> 00:09:38,713
which includes the file extension.

203
00:09:39,660 --> 00:09:41,870
And this then generates a unique file name

204
00:09:41,870 --> 00:09:45,263
with the file extension that gets stored in this folder.

205
00:09:46,490 --> 00:09:48,030
Now, with all of that done,

206
00:09:48,030 --> 00:09:50,760
we can apply this image upload middleware

207
00:09:50,760 --> 00:09:54,510
to the route we want to use for handling

208
00:09:54,510 --> 00:09:57,750
the submitted new product form.

209
00:09:57,750 --> 00:10:01,010
So that's in admin routes there.

210
00:10:01,010 --> 00:10:05,160
I will import the imageUploadMiddleware

211
00:10:05,160 --> 00:10:10,037
by requiring ../middlewares/image-upload like this.

212
00:10:12,340 --> 00:10:15,460
And then here we need to register a post route

213
00:10:17,130 --> 00:10:19,030
for /products

214
00:10:20,030 --> 00:10:23,790
because in the new-product.ejs file

215
00:10:23,790 --> 00:10:28,400
we are sending a request to /admin/products.

216
00:10:28,400 --> 00:10:31,180
As you learned, /admin can be omitted

217
00:10:31,180 --> 00:10:32,810
in the admin.routes.js files.

218
00:10:32,810 --> 00:10:35,970
So it's just /products, but a post request,

219
00:10:35,970 --> 00:10:37,203
that's very important.

220
00:10:38,260 --> 00:10:39,780
And then here,

221
00:10:39,780 --> 00:10:43,600
I wanna point at adminController.createNewProduct,

222
00:10:43,600 --> 00:10:46,740
but you also learned that these

223
00:10:46,740 --> 00:10:51,740
router middleware registration methods get posts and so on,

224
00:10:51,880 --> 00:10:56,380
take multiple parameter values, at least optionally,

225
00:10:56,380 --> 00:11:00,160
and you can specify a list of middleware functions here,

226
00:11:00,160 --> 00:11:03,023
which will then be executed from left to right.

227
00:11:04,160 --> 00:11:06,770
And here, before we reach create new product

228
00:11:06,770 --> 00:11:08,350
in my admin controller,

229
00:11:08,350 --> 00:11:12,187
I actually want to execute imageUploadMiddleware.

230
00:11:13,649 --> 00:11:16,300
And I don't execute it myself here like this.

231
00:11:16,300 --> 00:11:19,100
Instead I just point at this middleware function,

232
00:11:19,100 --> 00:11:21,870
this configured multer middleware function,

233
00:11:21,870 --> 00:11:24,270
because express will then execute it for me

234
00:11:24,270 --> 00:11:25,903
for the incoming requests.

235
00:11:26,820 --> 00:11:29,510
But this middleware function, which we wrote ourselves,

236
00:11:29,510 --> 00:11:32,610
is now basically the multer middleware function

237
00:11:32,610 --> 00:11:35,753
with some preconfiguration from our site.

238
00:11:36,940 --> 00:11:39,700
And that ensures that the uploaded files

239
00:11:39,700 --> 00:11:40,963
should be extracted.

240
00:11:41,930 --> 00:11:44,140
It should be extracted and stored,

241
00:11:44,140 --> 00:11:47,670
but we can't test this yet because in the admin.controller

242
00:11:47,670 --> 00:11:50,960
createNewProduct, doesn't do anything.

243
00:11:50,960 --> 00:11:54,430
Of course, we should be able to create a new product here

244
00:11:54,430 --> 00:11:57,710
and therefore again in this administration controller,

245
00:11:57,710 --> 00:12:00,000
createNewProduct action,

246
00:12:00,000 --> 00:12:02,990
we should accept the request and response,

247
00:12:02,990 --> 00:12:07,350
and then we should get all the entered data

248
00:12:07,350 --> 00:12:09,743
and store that in the database.

249
00:12:10,830 --> 00:12:14,300
We'll do that database storing with help of a model,

250
00:12:14,300 --> 00:12:15,560
which we'll create soon.

251
00:12:15,560 --> 00:12:20,560
For the moment I just want to console log my request body

252
00:12:21,700 --> 00:12:23,510
and after that,

253
00:12:23,510 --> 00:12:28,320
also console log request file.

254
00:12:28,320 --> 00:12:32,210
The file field should be available thanks to multer

255
00:12:32,210 --> 00:12:35,840
and it should contain information about the stored file.

256
00:12:35,840 --> 00:12:40,840
And I will then simply redirect to /admin/products.

257
00:12:41,210 --> 00:12:42,650
That's all I do for now.

258
00:12:42,650 --> 00:12:45,783
Of course, this will soon change so that we can do more.

259
00:12:47,290 --> 00:12:48,890
With that however,

260
00:12:48,890 --> 00:12:51,980
if you now reload this add new product page,

261
00:12:51,980 --> 00:12:55,860
and we give this a try and I enter test here

262
00:12:55,860 --> 00:12:57,453
and I choose a file.

263
00:12:58,660 --> 00:13:01,730
And for this simply I prepared a basic image of the keyboard

264
00:13:01,730 --> 00:13:04,290
I'm using for recording this very video.

265
00:13:04,290 --> 00:13:06,260
And at the moment we have no preview.

266
00:13:06,260 --> 00:13:08,450
We'll add one later.

267
00:13:08,450 --> 00:13:09,930
Then I can add a summary.

268
00:13:09,930 --> 00:13:13,907
This is a summary and the price like this.

269
00:13:15,940 --> 00:13:19,280
And then, this is a detailed description

270
00:13:21,920 --> 00:13:26,090
will become important later.

271
00:13:26,090 --> 00:13:27,750
At the moment this doesn't matter too much

272
00:13:27,750 --> 00:13:30,473
because it won't be saved to a database anyways.

273
00:13:31,490 --> 00:13:33,510
I could show you that the reset button works,

274
00:13:33,510 --> 00:13:35,380
but I don't want to enter it all again,

275
00:13:35,380 --> 00:13:37,360
so I'll just click save.

276
00:13:37,360 --> 00:13:41,260
I'm redirected, and here on the server side in the log,

277
00:13:41,260 --> 00:13:43,830
we now see that logged data.

278
00:13:43,830 --> 00:13:45,200
We see the request body,

279
00:13:45,200 --> 00:13:48,140
which contains all the form data I entered.

280
00:13:48,140 --> 00:13:50,890
And then here, we see the image data

281
00:13:50,890 --> 00:13:53,670
that is provided by multer.

282
00:13:53,670 --> 00:13:56,930
We can also see that in the product data images folder,

283
00:13:56,930 --> 00:13:58,640
this image is saved.

284
00:13:58,640 --> 00:14:01,270
It has this unique ID, dash,

285
00:14:01,270 --> 00:14:04,510
and then the original file name with the extension.

286
00:14:04,510 --> 00:14:05,620
And if I click on it,

287
00:14:05,620 --> 00:14:09,260
we can see the image here in VS Code in the preview.

288
00:14:09,260 --> 00:14:10,900
So this was saved here.

289
00:14:10,900 --> 00:14:12,230
And then here in the console,

290
00:14:12,230 --> 00:14:15,230
we got all the details multer provides to us.

291
00:14:15,230 --> 00:14:17,550
Information about the type of image,

292
00:14:17,550 --> 00:14:19,840
the path where it was stored,

293
00:14:19,840 --> 00:14:23,350
the file name and the full path to the image

294
00:14:23,350 --> 00:14:25,690
and the size of the image as well.

295
00:14:25,690 --> 00:14:27,570
So that is all working.

296
00:14:27,570 --> 00:14:30,050
We are getting that data on the server side,

297
00:14:30,050 --> 00:14:31,340
which is amazing.

298
00:14:31,340 --> 00:14:33,530
Now, of course, we don't want to log it.

299
00:14:33,530 --> 00:14:35,723
Instead we want to save it in a database.

