Auto-generated transcript Alright is this thing on? I think it's on. Right. Okay guys, welcome back to another video. You guys know we've been building the GoRedis database clone thingy for a very long time now. I've recorded like 20 videos just on that one particular project and I think I'm ready to move on. I think I'm ready to start building another project and as you can see here I've already started without you guys. So this is going to be a and i call this a drive syncer what this is basically going to do is it's going to synchronize upload all of my programming projects to google drive as like a second backup so before any of you smart asses tell me to use git and source control i'm already doing that but uh it's just sometimes i just forget to upload all of my local changes from my machine to GitHub and everything, right? And that's exactly what happened to me very recently, just a couple of weeks ago. What happened was my hard drive basically just completely got corrupted somehow. I don't know what happened. I'm not a hardware engineer or something, but it got corrupted and there was no way to recover all of my data. And a lot of the projects that I built, I had a ton of code in them that I hadn't actually backed up to source control. So it was like you make a change and you edit like 20 different files and you just forget to push that to GitHub or source control or whatever you're using and it just gets lost, right? And that was not a fun experience. It was a terrible experience. And so yeah, I got traumatized and to heal that trauma, I'm going to build this DriveThinker project that's going to automatically upload all of my programming projects to Google Drive. And of course, this is not going to be like you guys know I don't like to build simple projects I like to go above and beyond and build something complicated just for the sake of it this is not going to be just a simple upload folder to Google Drive project right there is going to be a ton of different features over here specifically the most important feature that we need to build first of all I mean not in this video but the one we're going to build in future videos is that we want to be able to upload only the source code and not things like the credentials the environment files right the env files and stuff not the node modules folder not the dot git folder and so on and so forth right not the like this when folder over here that gives us the python virtual environment not these folders basically we don't want to upload all of these other folders that that we wouldn't actually want to back up right and when it comes to github and source control you can easily configure that by by just using this git ignore file over here right you can just put a bunch of file names and folder names in here and source control will ignore all of these files for you automatically nothing needed on your side but when it comes to google drive there is no such feature like you have this um app the google drive desktop app that can basically just select a bunch of folders to upload. Where is it? Yeah, there we go. So you can only select a bunch of folders to upload. You cannot ignore any folders, right? So if I just added a folder over here, which would be my entire programming projects folder, it will just back up every single file in there. All of the git files, all of the node modules, all of everything else, right? And we don't want to do that, obviously. So we need to build our own custom synchronization project over here that's going to do all of those things for us now that's all I'm going to say about this project for now I hope I haven't bored you guys from all of the long intros and stuff but basically we've built or I've built a pretty decent project so far there's a lot of stuff over here and yeah we're going to build all of this from scratch I'm gonna show you how I built all of this stuff and yeah we're gonna have a good time so first things first let's just throw all of this away and start a new project I'm gonna go do that right now and then I'll catch you guys oh and by the way before I actually create a new project let me just show you guys how this current project that I've built actually works so real quick I'm just going to do a quick run of this project and oh my god I'm not in the right folder there we go let's run this and yeah it's going to start the upload process for this folder it's going to try deleting the previous folder so we don't create duplicates on our drive and so on and so forth it's going to upload all the files it's going to skip the files that we want to skip like this when the token dot JSON and this get folder over here and it's going to just upload everything else that we want to upload and if I look here in my Google Drive in this programming folder I have this project over here and these are all the project files the test folder that i have over here all of the files inside it perfect right so this works it uploads all the files i want to upload it um skips the files that i don't want to upload and yeah this is a very nice project that i've built over here so now that i've shown you a quick preview of what i've built so far and by the way we are going to build a ton of other features as well not just what I have right now but yeah we all gotta start somewhere right so let's open up a brand new project and start building this whole thing out okay here we are in a brand new project I've already created a go module over here I'm going to create a main dot go file just to get started package main funk main and yeah that's all we need to do for now and by the way as you guys can see I did change my color theme from the Nord palette to this other thing. I like it and I'm using this IU dark theme and it looks pretty cool. I like it but let me know what you guys think as well. Now the very first thing we need to do is to create a new project in the Google Developer Console and enable the Google Drive API in that project and also download the OAuth credentials from that project and we need to do all these things so that we can actually interact with the google drive api right so this is the go quick start documentation on this on the google dev console docs we're going to just follow all of this step by step and create our project and get the oauth credentials so first of all enable the api just click here it's going to take you to the dev console and once you're here you can select the project or create a new one let's do that as well as you can see i already have this drive syncer project but you probably won't have that so just click over here in the project picker click on new project and then you can just create a new project over here i'm actually going to do that just so you guys can follow along perfectly find with me just give it a name I going to call this Drive Sync or video there no need to give it a location or organization over here this is unnecessary just click create it going to create the project over here and then just click select project over here and you should see up top over here in the project picker that you're using this new project once you're doing that just click Next over here click enable API and it will enable the Google Drive API boom all that's done now we can actually close this go back over here and the next step is to configure the OAuth consent screen. So let's go over to branding over here. Click get started and we just need to add a bunch of stuff over here. So the app name, I'll just again just copy the project name over here. You can obviously put whatever you want. I'm just going to call this DriveSync or Radio. Use the support email. Just add your own personal email over here. That's what I'm going to do as well. The audience you can select as external contact information. Again, just put your own email address over here. I'm going to do the same thing. Next, finish, agree to the terms and service, and continue and create. Okay, now that that's all done, we go over to this clients tab over here in the sidebar and click create client up here. This is going to be a desktop application. I'm going to just call this, yeah, let's just call this desktop client one. We don't really care about the name. It's going to give us all of this data. We can download this. By the way, guys, make sure to keep all of this stuff very safe, all right? Like this is your client secret and you do not want to expose this to any other third-party person, right? Otherwise, they're going to be able to use this project and use the Google Drive API and just modify your files, right? So don't let that happen. Download the JSON and store it safely somewhere on your computer. In my case, I'm going to store it inside the project over here. We're gonna go reveal in file explorer. I'm going to open this up over here and just paste it over here and I'm going to rename this long name just to client.json. Awesome. We can delete this file over here it doesn't mean anything. There we go. Okay so we have this client.json let me format it as well and this is what it looks like and by the way i am going to blur out all of the client id secret and everything else over here because uh we don't want you guys to see this we need to we need to keep this stuff private so yeah but this is what it looks like now that we have our client we can actually get started on coding all right so if you look at the google Drive documentation again. After you've created your client, we've already done this, then you just create a new Go project, download these modules, and then write the code to actually get the Google Drive API access and modify some files. So first of all, we've already created a module and everything. So let's grab these two modules from the Google servers. So open up a terminal over here and just copy paste these commands from the documentation over here all right so that's the first module now let's get the second why did i open up vs obs studio uh open up the browser and uh grab the second module over here there we go boom okay so we have all of the dependencies all of the modules that we need to get started coding so let's start writing some code so first of all let's create a get client function over here and by the way i'm just copying all of the stuff that they have over here in the documentation you can do the same thing or you can just code alongside me as i'm going to explain everything that we're doing as well so a get client function this is going to return a pointer to http.client it's going to take a config which will be a pointer to an oart2.config object and it's also going to take a force refresh which will be a boolean and you'll see why this is important in like after we actually build all of this but basically we want to be able to force refresh the access tokens to the google drive api in case they expire or whatever right so if if our tokens expire we want to be able to force refresh them over here rather than just trying to use the old tokens constantly right so first of all let's add the token file path over here and in our case this is just going to be client.json right this client.json that we downloaded from the google dev console and then we actually want to grab the token right from this file so to do that let's say token and error equals token from file and passing the token file over here now we need to actually implement this function so let's do that as well this will just take a file which will be a string and it will return a pointer to an or2.token object or an error so first of all let's open up the file let's say os.open, pass in the file. If the error does not equal to nil, then return nil and error. And of course, use defer to make sure we close the file. And now let's just say token equals a new oa2.token object. And then let's use JSON, the built-in JSON package, new encoder, or decoder actually new decoder pass in the file and let's say decode and pass in the token over here and then let's just return the token and return nil for the error now we have our um access token over here but what if there's an error in trying to get the token from the file right if we can't get the token from the file then we need to get it from the web right from the google oauth screen where we grant access to the Google Drive API to use our account. So to do that, and by the way, this will all make a lot more sense once we actually run this and you see how it actually looks like and works. So for now, just understand if we can't get the token from the file, the access token, then we need to get it from the web. So let's implement that. Let's say token equals get token from web and pass in the config over here and by the way instead of having to declare two new token variables what we should do is declare one variable over here which will be a ought a lot to dot token pointer and just use that in both places over here right as such now let's implement this get token from web function as well get token from web this is going to take a config which will be a pointer to an or2.config and it will return an or2.token. No errors over here. So first of all, let's get the authorization URL. This is the URL that we need to go to to authorize the Google Drive API to use our account. So we'll say auth url equals config. authcode url For state we pass in the state token Then we say or2 type offline There we go And then we can just say something like fmt Go to the following URL and grant the necessary permissions. Then paste the authorization code below. this is just standard OAuth authentication stuff. If you've worked with OAuth stuff before then this will feel very familiar to you and we can pass in the auth url over here and we can just say a new line then percentage s to print the auth url and then another new line and then let's actually grab the input from the user. So let's say auth code which will be a string and then let's say if underscore error equals fmt.scan, pass in the auth code over here. And if the error is not nil, if there was an error that occurred over here, then obviously we can't actually proceed with the application. So let's just run log.fatal f and say, unable to read authorization code print the actual error message after that as such and then if this was successful let's say token and error equals config dot exchange will run this function this will convert the authorization code that we get over here in this auth code variable into an oauth token that we can use all right so let's do that this takes a couple of arguments first of all the context i'm just going to say context.background over here and then pass in the auth code over here. There we go. Handle the error as well. If there is an error shut down the program and say unable to read auth code or actually unable to retrieve token from web and print the error message over here. And by the way we should probably add a new line after both of these as well. Now if everything went well let's just return the token over here now back up here in the get client function or actually i should probably do a quick recap of this get token from web function uh in this function all we're really doing is we're grabbing the authorization url from this config.authcode url um function this is going to return a url which we can use to grant permissions to that api and then we just say hey go to the following url grant the permissions then paste the authorization code right then we read the authorization code from the fmt.scan function from the standard input then we just run this config.exchange function which will convert that authorization code into an oauth token that we can use and then we just return that oauth token over here all right now back in the get client function we don't want to have to constantly grab the token from the web right once we've grabbed the token from the web we should try to save that token on our disk right into a file so let's run the save token function which we will implement in just a second passing the token file client.json and actually this is a mistake uh we don't want to use this client.json file over here we want to add token.json this will be a new file that will be created so my bad over there but let's pass in the token as well and then let's implement this save token function so let's say save token this will take a path which will be a string and then token which will be an o or two dot token there we go and it doesn't need to return anything obviously let's just say log dot println saving credential file two and then let's print the uh what is it the path over here then let's open up the file let's say os dot open or actually open file pass in the path and then pass in a bunch of flags we'll say os.create so create the file if it doesn't exist open it up in reading and writing both and also pass in os.trunk which will truncate the file basically empty the file every time we open it so we don't have any past data inside that file right we want to completely have a brand new empty file every time we try to save the token we don't want any old data over there and then for the permissions let's say 0600 what this means is that the owner of the file the file that the person who created the file will have the read and write permissions and everyone else no permissions all right so only the owner has the permission to read and write to this file that's what we're saying when we say 0600 over here Now let's handle the error as well. Let's say log.fatal f unable to cache the oauth2 token. Print the error over here and add a new line as well and then make sure to close the file by using defer and then let's use the built-in JSON package again. Let's say new encoder, pass in the file and run and code and then pass in the oauth2 token over here and that's all we need to do awesome now back up in the get client function we should return the http client over here right so let's say config.client pass in a context again i'll just use context.background for now and pass in the token over here and now we're done with this get client function now we can actually start to write the main function and by the way you will see that this is exactly what the google docs say as well that we need to do right so let's actually okay so let's start implementing the um what is it the main function let's say file and error let's say os.read file over here and this is going to return it's going to take the token file or not the token file but the credentials file which is client.json and it's going to return a byte slice and an error so instead of calling this f i should probably call this b right and then let's say if error does not equal to nil then log.fatal f unable to read client secret file print the error add a new line and there we go then let's run google this is one of the packages that we downloaded dot config from json passing the raw bytes over here from the os.readfile method and also pass in scopes. So if you're not familiar with OAuth credentials and OAuth authentication, scope is basically what permissions you want this client to have with whatever API you're trying to use, right? So in our case, we're trying to use the Google Drive API, right? So we can say something like drive. Again, this is also one of the packages that we downloaded dot drive scope there's tons of different scopes over here and you can see what the what each scope will allow you to do the drive scope is basically the the big daddy i guess of all of the scopes it's going to allow you to see edit create and delete all of your google drive files you can also get the drive file scope which will allow you to see edit create and delete only the specific google drive files that you create with this app and you can get all of the other scopes as well like the metadata scope which will allow you to see information about your Google Drive files The metadata scope over here, which will also allow you to manage and modify the metadata files in your Google Drive and all that. So you can pick the specific scopes that you need, the specific permissions and privileges you need in this Google Drive account. For our cases, we're just going to use drive.drivescope, which is the which this is just going to give you all of the privileges on this google drive and for our purposes this is fine so this is going to return a bunch of stuff over here it's going to return a config and an error so let's handle both of them let's say config and error equals this and then let's handle the error as well let's say log.fatal f unable to parse i guess the client secret file print the error add a new line and there we go now we can actually use this config object to get the client so this get client function that we spent so much time implementing we can pass in the config over here and for the force refresh i'm just going to say true for now we're not even using this boolean right now in the in the code we're going to implement that probably in the next video but for now let's just hard code it let's just pass in true over here because this is obviously not going to do anything because this argument is unused in the function but yeah let's grab the client over here and then let's say service and error equals drive dot new service this will create the google drive service again pass in the context i'll just use background for now again and for the options let's pass in option dot with http client and pass in our clients over here handle the error as well let's say log.fatal f unable to retrieve drive client print the error add a new line there we go and now we have the google drive service we can now use this to create whatever files we want like we can just say service.files.create and pass in a file but we're not going to do this in the current video let's for now let's just uh run the list function over here service.files.list and this will basically just give us the um list of files in our google drive so let's also limit that to the first 10 files let's say and then let's run the do function which will actually run this um api request and give us the result so i will say r for response and error equals this function called handle the error as well let's say log.fable f unable to fetch files from drive print the error add a new line there we go and if it was all successful then the r.files key will have the list of files over here it will be a list of drive files so let's loop over this as such and just print the file dot name over here. Now let's try running this. If we coded everything perfectly then this should work fine. So open up a terminal. Let's say go run dot and it should run. Now it's going to tell me to go to this url and grant the necessary permissions so let's do that there we go I'll select my account over here oh okay we also need to do one more thing since this is a new application and we haven't actually published this or submitted this for verification we aren't going to be able to actually connect to this application until we add ourselves as a test user which is why we're getting this access denied error over here so So close this, let's go back to the Google dev console over here, go over to the client, or actually not the client, I forget where was I supposed to add the test users, in audience I think, yeah in audience. Okay so go to the audience tab and down here in this test users section click on add users and then just add the email address of the Google account that you want to use with this app. save come on save there we go awesome and now if i go over to this url again it should work i'll select my account again there we go and it's gonna give me a warning because google hasn't verified this app we haven't submitted this for verification we're just testing this since we're the developer we can just click continue and grant access to this application now it's going to tell us hey this app can see edit create and delete all of your google drive files that's the drive scope that we added over here so let's grant these permissions click continue and it's going to redirect us to localhost we don't really need to worry about that but if you look over here in the url it's going to give you this code parameter which is exactly what we need so let's copy the entire thing right over here and let's paste it over here okay now it's going to save the credential file to token.json over here you can see it created this new file and this is what it looks like it has an access token a refresh token an expiry and this expires in which is the number of seconds after which this token will expire which is 3600 seconds this is again i'm not good with numbers but it's probably an hour and yeah it saved the credential file then it listed all of the files in my google drive right i said only give me the first 10 files that you can find over here page size 10 and it gave those to me awesome so i'm going to stop over there because i've been recording for like 46 minutes oh my god and even even when i cut all this down even when I trim out all the bad parts in this video it's still gonna be like a 25 30 at least a 30 minute video which is insane so yeah let's let's end it over here we built the OAuth 2 authorization stuff and we basically interacted with the Google Drive API just asked it to list out some files from our Drive in the next video we're going to continue with this and implement all of the file uploads and stuff and all the other fancy stuff that we're going to do this video is getting way too long but hey if you if you watch this to the end and respect to you for having the attention span to watch such a long video most people can't even do that trust me they can't watch any video longer than five ten minutes but if you made it this far then you are amazing my friend yeah let's end it over here thank you so much for watching like comment subscribe share the video we are building a new project over here we're done with redis databases we're building something even better now so this was part one follow along because many more parts are coming very soon and yeah thank you for watching and i will see you in the next video guys see ya