‫Let's now actually configure Multer to our needs.
‫First giving images a better filename,
‫then second allowing only image files
‫to be uploaded onto our server.
‫And to start, let's actually move
‫all the Multer-related stuff
‫from this router to the controller.
‫So let's cut this here,
‫and I'm gonna put it right here at the end,
‫or actually at the top, all right?
‫So everything related to Multer,
‫we're going to put it right here at the top.
‫Then we also need of course to import this Multer package.
‫And now we also need to create a middleware with this.
‫So exports.uploadUserPhoto
‫will be equal to this.
‫All right, and so we still have a middleware function,
‫but now it's got its own easier to use name, all right?
‫And so here, userController.uploadPhoto, all right?
‫So that looks much nicer,
‫and of course it makes sense
‫that this code is in the controller.
‫And so now this is nice and clean,
‫and we can actually close it now.
‫Great, and so now let's actually go ahead
‫and configure our Multer upload to our needs.
‫And so for that we are going to create one Multer storage
‫and one Multer filter, all right?
‫And then we're going to use that storage and the filter
‫to then create the upload from there, all right?
‫So let's do that here.
‫So a multerStorage, we use multer.diskStorage.
‫All right, and we could also choose
‫to store the file in memory as a buffer,
‫so that we could then use it later by other processes.
‫And actually we're gonna do that a bit later,
‫but for now of course we want to really store the file
‫as it is in our file system, okay?
‫So for disk storage we'll take a couple of options,
‫and the first one is the destination.
‫But now we cannot simply set it to this path
‫like we did before.
‫No, this is a bit more complex, all right?
‫And so really this destination here is a callback function
‫which goes like this.
‫So this callback function has access to the current request,
‫to the currently uploaded file,
‫and also to a callback function.
‫And this callback function is a bit
‫like the next function in Express.
‫But I'm calling it cb here, which stands for callback,
‫so that it's a different name than next,
‫because actually it doesn't come from Express, okay?
‫But it's similar in that we can pass errors in here
‫and other stuff, as you will see in a second.
‫So to now define the destination,
‫we actually need to call that callback.
‫So callback, and then the first argument is an error
‫if there is one.
‫And if not, then just null.
‫And the second argument is then the actual destination.
‫So let's copy that from here,
‫and paste it here.
‫All right, and again this all looks a bit weird and complex,
‫and let's actually take a look
‫at the Multer documentation on GitHub.
‫Okay, and so if you need to learn more,
‫you can take a look at this documentation here.
‫And as you see, with 6,000 stars,
‫it's actually a pretty popular package.
‫So here you can learn how to use it.
‫But in fact what you will find here
‫is kind of what we're gonna do
‫throughout the next couple of lectures, okay?
‫So this looks way more confusing
‫than what we're going to do, all right?
‫But you see that this is actually
‫what we're doing currently, so we're setting the destination
‫and next we will actually also set the filename.
‫So let's do that, and again, if you want to learn more
‫just take a look at that documentation.
‫But for now I want to now set the filename property.
‫So not that, simply filename.
‫And again, that's a very similar callback function
‫with a similar signature, request, file and callback.
‫And now we want to give our files some unique filenames.
‫And the way I'm going to do that
‫is to call them user-userid- the current timestamp.
‫So something like this: so user-,
‫and then the ID which is this weird, something like this.
‫Right, and then the current timestamp,
‫which is going to be a huge number, something like this,
‫and then of course the file extension, okay?
‫And with this we can basically guarantee
‫that there won't be two images with the same filename.
‫If we used only the user ID,
‫then of course multiple uploads by the same user
‫would override the previous image.
‫And if we only used user with the timestamp, well,
‫then if two users were uploading an image at the same time,
‫they would then get the exact same filename,
‫which does not make sense.
‫All right, so first of all,
‫let's actually extract the filename from the uploaded file.
‫And how do we get that?
‫Well let's take a look at our console output here,
‫where we had the request.file a long time ago.
‫So here it is, so remember that this object here
‫was request.file, and so that is exactly
‫what this file here is, okay?
‫And so here we have the mimetype,
‫and so that JPEG is stored right here, okay?
‫And so this is where we're gonna get
‫the file extension from.
‫So extension equals the file.mimetype,
‫and then let's split that string by the slash,
‫and take the second element of the resulting array.
‫And so that will then be only this part, so only this.
‫All right, so that is the extension.
‫And so now just like before,
‫we need to call the callback function with no error,
‫and then the filename that we want to specify.
‫So, that will be user-, then the user ID, remember?
‫And so since we have access to the request here,
‫that's very simple, request.user.id.
‫And so as you know, that's the ID
‫from the currently logged in user.
‫Then the timestamp, so Date.now, okay,
‫and then dot the extension that we just created, all right?
‫So let's get rid of this comment,
‫and so that is actually our storage.
‫And so basically a complete definition
‫of how we want to store our files,
‫with the destination and the filename.
‫Next up, let's create a Multer filter.
‫So let's call it exactly that.
‫And the filter in Multer is simply, again,
‫a callback function, similar to the ones we had before,
‫accessing the request, file, and a callback function.
‫And in this function, the goal is basically
‫to test if the uploaded file is an image.
‫And if it is so, then we pass true
‫into the callback function,
‫and if it's not we pass false into the callback function,
‫along with an error.
‫Because again, we do not want to allow files
‫to be uploaded that are not images.
‫And so that's exactly what this filter is for.
‫Now, if in your own application
‫you want to upload something else, let's say CSV files,
‫when then of course you can test for that instead of images.
‫So all the stuff that we're doing here
‫works not only for images,
‫but really for all kinds of files
‫that you want to upload, all right?
‫Now again, in this case we are really talking about images,
‫and so let's test if the uploaded file is an image.
‫And for that we will once more use the mimetype,
‫because whatever image type is uploaded,
‫so no matter if it's a JPEG, or a PNG, or a bitmap,
‫or a TIFF, or really anything,
‫the mimetype will always start with image.
‫And so now we can test for that.
‫So if file.mimetype.startsWith,
‫image, and so I'm not sure if we have used this one before,
‫but it is a fairly new and very useful string method
‫that is available in JavaScript,
‫so in all JavaScript in general.
‫So in case that we actually have an image, well,
‫then again there is no error and we pass true,
‫as I said in the beginning.
‫But otherwise, we will then actually pass an error,
‫and then false.
‫So let's just put an x here, and false.
‫So for this x here, we will now create an AppError,
‫just like we've been doing all along.
‫And actually we already have that here.
‫So let's say new AppError,
‫not an image,
‫please upload only images, all right?
‫And then a 400 for a bad request.
‫Great, so we have our storage, we have our filter,
‫now it's time to actually use them
‫in order to create the upload.
‫All right, so the upload will now not look like this,
‫but instead we will pass in these variables.
‫So in Multer we can specify the storage,
‫and so that is our multerStorage.
‫And then the fileFilter,
‫which is the variable that we called multerFilter.
‫Okay, and that's it.
‫And of course we could've put all of this here
‫directly into this options object here.
‫But I usually prefer to do these outside
‫and then simply pass the variables into an options object.
‫So that then looks a bit cleaner.
‫So this is a lot of steps that we need to take
‫in order to really create our Multer middleware.
‫But finally we then of course,
‫just like we did in the last video,
‫use this upload, and on that we call single,
‫with the name of the field.
‫So photo, and then from there we create an export,
‫or middleware, which we actually already included
‫into our router.
‫So let's now delete this old kind of image
‫that we had here before.
‫No, that didn't work.
‫And now let's actually test it here again.
‫So back in Postman, we still have our name here
‫and the Leo image, and so let's go.
‫And we got no error, which is good.
‫And let's see our output here again.
‫So everything here in the beginning is the same,
‫but then you see that our filename is actually now correct.
‫And if you take a look here at our folder,
‫then indeed there is our image.
‫And so that's exactly the one that we uploaded.
‫So that is in dev-data, images, Leo.
‫And indeed, that is exactly the same.
‫Great, that's awesome.
‫Now just to test this filter here as well,
‫let's try to upload some other file that is not an image.
‫So let's select something else here from our dev-data,
‫and let's say simply some JSON data.
‫And so let's wait if we get an error here.
‫And indeed we get one.
‫So not an image, please upload only images.
‫And so it means that that also works.
‫So perfect, all of our Multer configuration
‫now works really fine, but of course
‫there's still one step missing.
‫And that is to actually link the user
‫to the newly-updated image, right?
‫Because right now in the database,
‫we obviously still have the path,
‫or actually the name of the old image,
‫because nowhere in our code we specified
‫that we wanted to update the user document itself, right?
‫And so let's fix that in the next video.