At this point we can sign up and log in and we can create events, edit events, delete
events and register for events.
You could add more functionality related to that, but that's all I want for this app.
At least almost all.
One last piece is missing here and that's image upload.
I want to make sure that when we create an event or when we edit an event, we actually
accept and we expect an image to be attached to the request so that we store that image
here and of course so that we can then also later request and serve that image if we needed
it in our frontend.
So how can we do that?
Well ChatGPT already had an answer for me earlier that we can use a library like maltr.
We could also use some cloud storage, but here I want to use local storage and I want
to use this maltr package.
Now I happen to already know how the maltr package is used and I'll use a bit of AI
help to write the code more quickly.
Of course if you would not know that, you could visit the official docs, but you could
also ask your chatbot.
In cursor you could also bring in the maltr documentation as you learned it earlier in
the course.
So plenty of options.
Now as mentioned, I already know what I want to do.
So I'll start by quitting my development server and by running npm install maltr to
install this maltr package as a dependency.
With it installed, I'll add a new folder, or a new file I mean, to the util folder,
the upload.js file, where I want to set up some settings for maltr.
Because in there I want to import maltr from maltr, except this suggestion, and set up
some storage setting as it's suggested here for me.
Because the maltr package can be configured to control where and how incoming files are
going to be stored.
The maltr package itself will simply take a look at incoming requests and evaluate whether
there is a file attached to them or not.
And then it's the settings I'm about to add here that control how such a file would
be stored.
So I'll configure some maltr disk storage and I do want to set up such a destination
function which controls where the files are stored, but I'll tweak the path and store
them in the public slash images folder, so that it's this folder in which my images
will be stored.
That's one thing.
In addition, I'll add this filename function, which is suggested for me here, which can
be used to rename the received file.
And here I'm using the current timestamp in milliseconds and I append the original
filename, which also includes the file extension.
And then I'll close this and also export this upload constant here, which turns out
to hold a middleware that will be configured with these settings, which I can add to any
route that should possibly accept images.
So what I can do here is I can go to my event routes and here it's the post and put routes
where I do expect to get some images.
So after checking for authentication, I'll add another middleware function here.
That's how this express library, which I'm using, works.
You can add multiple middlewares to one route to execute them step by step, one after another.
And here it's this upload function, which is imported from my util folder and the upload.js file.
And there specifically, technically upload is not a middleware itself.
It is an object instead, which provides multiple middlewares.
And here it's the single middleware, which must be called like this to enable it.
And then you simply specify what the name of the field that carries the image will be
in the incoming request body.
And here I expect to get a request body field named image, which should contain the image
file.
And you'll see how it's submitted soon once we test this route.
So that's how we can use this configured malter middleware to extract images or one image
for this create route.
And it's the same code I'll use down here for the put route.
And that will ensure that we do extract an image stored under the key.
image from the incoming request body here. Now for this to work, the code in the EventsController.js
file also must be tweaked for both the create function and the edit function. Because I'm no
longer just getting title, description and so on from this request, instead I also get that file.
And that file is made available on rec.file. This file property is a property that's added
to this request object by the malter package. So I can get my image by accessing rec.file.
That will be this one single file which I expect to get and which I extracted.
Now, of course, I also want to verify whether we got an image file. So we need an extra check here
in this long validation if statement and check if this is maybe not truthy, if it's null,
if it's not set, in which case I would return this invalid input data response.
And it's the same approach down here in this edit route. Extract the image file just as before
and then also add this extra check here.
Here, GitHub Copilot actually suggests a more sophisticated check,
whether it's really an image. But here to keep things simple, I'll just check if I maybe don't
have an image, just as when creating the event. So that will extract the image. It will also be
stored thanks to this malter configuration. This will automatically ensure that images that are
attached to requests where this malter middleware is enabled will be stored in this path
by using this name. So the storage will be taken care of. But of course, I do need to make sure
that I also store that image file name in the database when I create a new event.
Because at the moment, that's not happening. I'm getting hold of that image that was uploaded here.
But technically, that's just an object with information about that image file that has
been stored by malter. For example, this image object here will contain the name of the image
file. And it's that name which I want to store together with all the other event data in the
database so that when I later query for all the events, I know which image belongs to which event.
Therefore, of course, I want to pass that image to create event.
So that image object or to be precise, image.filename. This image thing here will be an
object that has a file name property which includes or which contains the file name of
the image as it has been stored by malter. The same is of course also true for the edit function.
When I call edit event, I also want to pass the image file name here
to this object which is passed as a second argument to edit event.
And with that, of course, I now need to tweak
create event and edit event in the models folder in the events function there.
And here when I call create event, I actually also must give this a key name
which will be image here. But still, I need to tweak create event and edit event
to make sure that they use this received image name and that they really store it in the database.