Updated 057 Drag and Drop Upload functionality in JCB (markdown)
parent
d2b0610ed3
commit
895afc333c
@ -157,7 +157,7 @@ This '`setFile`' is what we are moving towards, because we want to make sure tha
|
|||||||
|
|
||||||
[00:39:16](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h39m16s)
|
[00:39:16](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h39m16s)
|
||||||
|
|
||||||
We want to look at the getFileJS which has a different implementation and as you can see it is in the view footer. We have PHP in that area of the JavaScript. This is the getFile. In the getFile there is again a link that was echoed which will be used to load the file, to make it that it can be downloaded. [00:39:44](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h39m44s) If it is a document or if it is media, we do not want to display it but we want to have you to be able to download it. There are different behaviors for image and images, as well as for documents and for media. [00:40:04](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h40m04s) It has different behaviors. It continues building buttons and displays. I will pop this code out on the Gits, and you can look at it, and see if you can make sense out of it. The `DOCLINK` or the `DOCBUTTON` is the potential idea about this if we go to the Document Manager. [00:40:26](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h40m26s) In the Document Manager, when you create a document, you will have what is called 'Description'. If you add a document you can use those placeholders in the description. It is the beginning of using these documents across the website, and not just in the component. We will eventually write a little plugin, and if you use this placeholder which it generates. If you use that anywhere the plugin will identify it and will load either a link or a button depending on which one you are using, the button or the link. That is what it is doing. You might say I do not need placeholders and you can grab that part and take it out also then wherever the '`var placeholder`' is being used and need to be removed for example over there. [00:41:36](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h41m36s) There is a '`fileBox`' that we are building. It is getting the placeholders, the download and the delete buttons, all of them get loaded into the '`fileBox`'. [00:41:53](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h41m53s) If we are having more than one file, we are treating it differently than just having one file. That is what we are doing here, the document has a little different behavior but somewhat the same. That is what the final stretch is, it is like a relay race, one carries it this far and then the other one takes it over, carries it a little further. [00:42:17](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h42m17s) This one is at the very last end of the track, where it is finally putting the image back into the page, and all of the nice little thrills, bells and whistles take place here. This is where you can enhance it with some JavaScript. [00:42:37](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h42m37s) You can see I am using Uikit to deal with most of the styling. Now you have seen the front-end as we would call it of the behavior of our Drag an Drop. [00:42:53](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h42m53s) You've seen how I set up the field. You've seen when the Ajax has finished its request. It runs this `setFilekey` which triggers a whole bunch of things that ends up adding the file to the page. <<<<<<<<<<<<<<<<
|
We want to look at the getFileJS which has a different implementation and as you can see it is in the view footer. We have PHP in that area of the JavaScript. This is the getFile. In the getFile there is again a link that was echoed which will be used to load the file, to make it that it can be downloaded. [00:39:44](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h39m44s) If it is a document or if it is media, we do not want to display it but we want to have you to be able to download it. There are different behaviors for image and images, as well as for documents and for media. [00:40:04](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h40m04s) It has different behaviors. It continues building buttons and displays. I will pop this code out on the Gits, and you can look at it, and see if you can make sense out of it. The `DOCLINK` or the `DOCBUTTON` is the potential idea about this if we go to the Document Manager. [00:40:26](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h40m26s) In the Document Manager, when you create a document, you will have what is called 'Description'. If you add a document you can use those placeholders in the description. It is the beginning of using these documents across the website, and not just in the component. We will eventually write a little plugin, and if you use this placeholder which it generates. If you use that anywhere the plugin will identify it and will load either a link or a button depending on which one you are using, the button or the link. That is what it is doing. You might say I do not need placeholders and you can grab that part and take it out also then wherever the '`var placeholder`' is being used and need to be removed for example over there. [00:41:36](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h41m36s) There is a '`fileBox`' that we are building. It is getting the placeholders, the download and the delete buttons, all of them get loaded into the '`fileBox`'. [00:41:53](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h41m53s) If we are having more than one file, we are treating it differently than just having one file. That is what we are doing here, the document has a little different behavior but somewhat the same. That is what the final stretch is, it is like a relay race, one carries it this far and then the other one takes it over, carries it a little further. [00:42:17](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h42m17s) This one is at the very last end of the track, where it is finally putting the image back into the page, and all of the nice little thrills, bells and whistles take place here. This is where you can enhance it with some JavaScript. [00:42:37](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h42m37s) You can see I am using Uikit to deal with most of the styling. Now you have seen the front-end as we would call it of the behavior of our Drag an Drop. [00:42:53](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h42m53s) You've seen how I set up the field. You've seen when the Ajax has finished its request. It runs this `setFilekey` which triggers a whole bunch of things that end up adding the file to the page.
|
||||||
|
|
||||||
### Demostration - Uploading An Image (see video)
|
### Demostration - Uploading An Image (see video)
|
||||||
|
|
||||||
@ -177,39 +177,35 @@ With the uploading of a document, it is more or less the same. If you have a doc
|
|||||||
|
|
||||||
How the download works here with the document, I'm using a controller. If we hovered over this link, it is not visable. So I have to copy the link, it is long because we are using an encrypted path to the file.[00:47:25](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h47m25s) It could sometimes being encrypted or sometimes just be basic64 encrypted. But the point is we have what we see here as a task and download document. There is a controller called '`download`' in my component, This is how this download document [00:47:54](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h47m54s) concept works, but you will have to write that. You need to figure that one out if you want people to download your documents. If it is just to upload images of course you do not need any of this. But it is only when you are going to have a downloadable file or media.
|
How the download works here with the document, I'm using a controller. If we hovered over this link, it is not visable. So I have to copy the link, it is long because we are using an encrypted path to the file.[00:47:25](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h47m25s) It could sometimes being encrypted or sometimes just be basic64 encrypted. But the point is we have what we see here as a task and download document. There is a controller called '`download`' in my component, This is how this download document [00:47:54](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h47m54s) concept works, but you will have to write that. You need to figure that one out if you want people to download your documents. If it is just to upload images of course you do not need any of this. But it is only when you are going to have a downloadable file or media.
|
||||||
|
|
||||||
### Demostration - Uploading A Media File (see video)
|
### Demostration - Uploading A Media File
|
||||||
|
|
||||||
[00:48:17](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h48m17s)
|
[00:48:17](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h48m17s)
|
||||||
|
|
||||||
Next one is how to upload some media files. I have a bunch of audio files, and I am going to upload them. What I am going to do, is to select a whole bunch of them, and then upload them all at once. This is what the Uploader can do. After it is dropped it will upload. The page needs to be refreshed and a name given to it. [00:49:01](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h49m01s) The Document. In Description say: 'More Soon'. Save this. [00:49:24](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h49m24s) If it did not upload all of them, try again. I have 6 of them uploaded. There are 6 documents and you can download them and test them. See if they are still fine. 'Why the home?', 'The order of the home'. The media is working. Let us also do that with documents and add some more documents. [00:49:57](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h49m57s)<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
Next is how to upload some media files. I have a bunch of audio files, and I am going to upload them. What I am going to do, is to select a whole bunch of them, and then upload them all at once. This is what the Uploader can do. After it is dropped it will upload. The page needs to be refreshed and a name given to it. [00:49:01](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h49m01s) The 'Document. Description' say: 'More Soon'. Save this. [00:49:24](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h49m24s) If it did not upload all of them, try again. I have 6 of them uploaded. There are 6 documents and you can download them and test them. See if they are still fine. 'Why the home?', 'The order of the home'. The media is working. Let us also do that with documents and add some more documents. [00:49:57](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h49m57s)
|
||||||
|
|
||||||
|
I've got a few selected and drag and drop them and it is uploaded. I need to check some of the JavaScript. I see it did not add the download button. Without saving, if we refresh the page, you will see that it has all those documents there because it used Ajax to store them in the database. At the end of day that is the behavior we wanted here in our component. We wanted the option to upload multiple documents to one document, and multiple media files. [00:50:31](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h50m31s) To be able to test them in the back-end, if you want to test any of them. Even be able to remove any of them at any time, just click on remove and it will be removed. In the front we will be able to use the file names, and the user would be able to identify the one he want. [00:50:59](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h50m59s) The filenames get preserved while it is being stored in the server with this hash behind it. We are seeing the JavaScript we looked at earlier in action, it is uploading, it is deleting. This one is cropping which we will deal with a bit more. That is our drag and drop options in action.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
I've got a few selected and drag and drop them there. 123 and is uploaded. I need to check some of the JavaScript. I see it didn't add the download button. Without saving, if we refresh the page, you'll see that it has all those documents there. Because it used Ajax to store them in the database. At the end of day that is the behavior we wanted here in our component. We wanted the option to upload multiple [00:50:31](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h50m31s) documents to one document, and multiple media files. To be able to test them in the back-end, if you wanted to test any of them. Even be able to remove any of them at any time, just click on remove and it will be removed. In the front we'll be able to use the file names, and the user would be able to identify this is what I want. [00:50:59](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h50m59s) The filenames get preserved while it is being stored in the server with this hash behind it. We are seeing the JavaScript we looked at earlier in action, it is uploading, it is deleting. This one is cropping which we will look at it a little more. That is seeing our drag and drop options in action.
|
|
||||||
|
|
||||||
### Server Side Of Implementation
|
### Server Side Of Implementation
|
||||||
|
|
||||||
[00:51:28](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h51m28s)
|
[00:51:28](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h51m28s)
|
||||||
|
|
||||||
Now let's go look at the server side of this implementation. The server side we have in the documents Admin View. We're opening the PHP tab, have this Ajax area. Like I showed before you would need to set up the Ajax in this area, targets the controller. In the controller it creates all these necessary script [00:51:54](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h51m54s) to make this method. We are going to look at the inside of that custom code. Make this method available to the Ajax call. There are some values that we set because every component I used, this stuff is different. For some we're using images, documents and media as the types. For some [00:52:23](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h52m23s) target the main and doc. The allowedView, there's only one view in this component that is allowed to use in the Uploader and that is the document view. The getViewID is the function which I get the actual view name and ID. It is using the session to throw that around to insure that nobody is able to tamper with that value through the front. Little extra little gymnastics to add another layer there.
|
Now let's go look at the server side of this implementation. The server side is in the documents Admin View. On opening the PHP tab, we have this Ajax area. Like I showed before you need to set up the Ajax where this area targets the controller. In the controller it creates all these necessary script [00:51:54](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h51m54s) to make this method. We are going to look at the inside of that custom code to make this method available to the Ajax call. There are some values that we set because every component I use this stuff in is different, so for some we are using `images`, `documents` and `media` as the types and for some targets the `main` and `doc`.[00:52:23](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h52m23s) Regarding the `allowedView`; there is only one view in this component that is allowed to use in the Uploader and that is the document view. The `getViewID` is the function which I get the actual view name and ID. It is using the session to throw that around to insure that nobody is able to tamper with that value through the front. So that is just extra gymnastics to add another layer.
|
||||||
|
|
||||||
### phpAjaxUploader - Custom Code Area
|
### phpAjaxUploader - Custom Code Area
|
||||||
|
|
||||||
[00:53:01](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h53m01s)
|
[00:53:01](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h53m01s)
|
||||||
|
|
||||||
We are going to look at this phpAjaxUploader in the custom codes area. Let's Search for it in the custom code area. Why am I using custom code? Because I'm reusing this. At the moment it doesn't look like I'm reusing it many places, it only says it's used in component. This is not the area where I'm doing my work, this is just for tutorials. I'm using a whole different developing environment [00:53:33](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h53m33s) or rather a developing system Joomla website than this one. This one is explaining and demonstrating. I'm reusing this code in many components and we have image formats that are allowed in the system. Document formats that are allowed in the system. [00:53:57](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h53m57s) Media formats that are allowed in the system. You can adapt this to whatever you need. At the end of the day it is up to you to decide what you want to allow and what you wouldn't. The reality is this is the available formats. If you remember in the options area of our component, it has a media area and there we have allowed documents, allowed media formats, and allowed image formats. These should be the same. It should be the same list, having the same values. But these are a field we created in Joomla, a List field. We manually added this to the components configuration area.
|
We are going to look at this `phpAjaxUploader` in the custom codes area. Let's Search for it in the custom code area. I am using custom code because I am reusing it. At the moment it does not look like I am reusing it in many places, it only says it is used in component. This is not the area where I am doing my work, this is just for tutorials. I am using a different Joomla website than this one. This one is only for demonstration. I am reusing this code in many components and we have `image` formats that are allowed in the system, `Document` formats that are allowed in the system and `Media` formats that are allowed in the system.[00:53:57](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h53m57s) You can adapt this to allow whatever you like. This is the available formats. Remember in the options area of our component, it has a media area and there we have allowed documents, allowed media formats, and allowed image formats. These should be the same. It should be the same list, having the same values. But these are a field we created in Joomla, a List field. This is manually added to the components configuration area.
|
||||||
|
|
||||||
### Quick Demonstration How add A List Field To The Components Configuration Area
|
### Quick Demonstration How add A List Field To The Components Configuration Area
|
||||||
|
|
||||||
[00:54:48](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h54m48s)
|
[00:54:48](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h54m48s)
|
||||||
|
|
||||||
If you don't know what that is, let me quickly show you. In the component it has this component config. If your component doesn't show one like this, Hello World, it doesn't show a component config, you can go into the component and then in [00:55:16](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h55m16s) settings there is this button create component config for this Joomla component. I'm going to close out, I don't want to do Hello World, I can show you with the Document Manager. We could use the same button in settings. We can edit if it hasn't have one, you can create one. You select fields [00:55:50](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h55m50s) with their custom values and the tabs in which they should be display. As you can see I've selected Allowed Document Formats(list), which is just a list of the formats and I set it to allow multiple selection. That's how I'm doing this Allowed Media, Allowed Image, and Allowed Documents. Then here's the crop document image. If you do not know how to create a field, and how to set radio buttons, or list, then go review the videos about that. I'm not going to explain that now. That's how we deal with that and that list we have looked at now [00:56:29](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h56m29s) is the same list as what we see here. It should be the same. Because this is the allowed, and that list shows the user what is allowed for the system. [00:57:03](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h57m03s) This is what you could say as available formats, and then those drop downs is what you as the owner of this website, where this application will run, is what you will allow. This list should be the same as the one there, but it also is going to be use if people post a specific type, [00:57:38](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h57m38s) as if it is allowed. We're going to be able to bounce this and make sure that security wise we are safe.
|
If you don't know what that is, let me quickly show you. In the component it has this component config. If your component doesn't show one like this, Hello World, it doesn't show a component config, you can go into the component and then in [00:55:16](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h55m16s) settings there is this button '_Create component config for this Joomla component_'. Close, I do not want to do Hello World, I can show you with the Document Manager. We could use the same button in Settings. We can edit it if it has not have one, you can create one. You select fields with their custom values and the tabs in which they should be displayed.[00:55:50](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h55m50s) I have selected 'Allowed Document Formats(list)', which is just a list of the formats and I set it to allow multiple selection. That is how this Allowed Media, Allowed Image, and Allowed Documents are done. Then there is the crop document image. If you do not know how to create a field, and how to set radio buttons, or list, then go review the videos about that. That is how we deal with that and that list we have looked at now is the same list as what we see here. [00:56:29](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h56m29s) It should be the same because this is the allowed, and that list shows the user what is allowed for the system. [00:57:03](https://www.youtube.com/watch?v=UvzDyVQyHDI&list=PLQRGFI8XZ_wtGvPQZWBfDzzlERLQgpMRE&t=00h57m03s) This is what you could say is available formats, and then those drop-downs is what you as the owner of this website, where this application will run, will allow. This list should be the same as the one there, but it also is going to be used if people post a specific type, as if it is allowed. We are going to be able to bounce this and make sure that security wise we are safe. <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### uploadFile Function
|
### uploadFile Function
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user