How to get the FolderID from Google Drive folders using Chilkat DLL - vb.net

Im using the ChilKat to develop a tool using VB.NET, that performs a single file upload to my google drive account.
Im able to get the folderID within a root folder, but im struggling to get the folderID if there is a path of folders.
At this moment the argument FolderPath is not being used (i will, when i uncover how to properly get the FolderID). For now, i can get the "Nova" folder id, but none of the other folders within the following tree:
Is there an easier way to get the folderID from GoogleDrive?
I would also like to create the path of folders on Google Drive, in case they dont exist.
I never worked with JSON or HTTP requests, so im kind of lost here.
Any help would be mostly appreciated!
Thanks in advance!
Private Function FolderID(ByVal FolderPath As String) As String
Dim rest As New Chilkat.Rest
' Connect using TLS.
Dim success As Boolean = rest.Connect("www.googleapis.com", 443, True, True)
' Provide the authentication credentials (i.e. the access token)
Dim gAuth As New Chilkat.AuthGoogle
gAuth.AccessToken = M_AccessToken
rest.SetAuthGoogle(gAuth)
Dim json As New Chilkat.JsonObject
json.EmitCompact = False
' Get the folder Testes folder that is in the Google Drive root.
rest.AddQueryParam("q", "'root' in parents and name='Testes'")
Dim jsonResponse As String = rest.FullRequestNoBody("GET", "/drive/v3/files")
If Not rest.LastMethodSuccess Then
Return rest.LastErrorText
Exit Function
End If
json.Load(jsonResponse)
rest.ClearAllQueryParams()
' Now that we know the ID for the Testes directory, get the id for the folder Nova having Testes as the parent.
Dim sbQuery As New Chilkat.StringBuilder
sbQuery.Append("name = 'nova' and '")
sbQuery.Append(json.StringOf("files[0].id"))
sbQuery.Append("' in parents")
rest.AddQueryParamSb("q", sbQuery)
jsonResponse = rest.FullRequestNoBody("GET", "/drive/v3/files")
If Not rest.LastMethodSuccess Then
Return (rest.LastErrorText)
Exit Function
End If
json.Load(jsonResponse)
Return json.StringOf("files[0].id")
End Function

I managed a way by performing iterative requests.
Don't know if this is the correct way, but it works...
Here's the code, now using the FolderPath with format /folder1/folder2/folderN
Private Function GetFolderID(ByVal FolderPath As String) As String
Dim Rest As New Chilkat.Rest
' Connect to Google APIs server
Dim Connected As Boolean = Rest.Connect("www.googleapis.com", 443, True, True)
If Not Connected Then
Return "Error attempting to connect: " & Rest.ConnectFailReason
Exit Function
End If
' Provide the Access token
Dim GAuth As New Chilkat.AuthGoogle
GAuth.AccessToken = M_AccessToken
Rest.SetAuthGoogle(GAuth)
' Instance to JSON object
Dim JSON As New Chilkat.JsonObject
JSON.EmitCompact = False
' Parse the provided path and split to array
Dim ParseFolder As String = Strings.Right(FolderPath, Len(FolderPath) - 1)
Dim Folders As String() = Split(ParseFolder, "/")
' Get the root folder that is in the Google Drive folders structure
Rest.AddQueryParam("q", "'root' in parents and name='" & Folders(0) & "'")
Dim Response As String = Rest.FullRequestNoBody("GET", "/drive/v3/files")
If Not Rest.LastMethodSuccess Then
Return Rest.LastErrorText
Exit Function
End If
JSON.Load(Response)
'Iterate on the folders to get the last folder's id
Rest.ClearAllQueryParams()
For i = 1 To Folders.Length - 1
Dim sbQuery As New Chilkat.StringBuilder
sbQuery.Append("name = '" & Folders(i) & "' and '")
sbQuery.Append(JSON.StringOf("files[0].id"))
sbQuery.Append("' in parents")
Rest.AddQueryParamSb("q", sbQuery)
Response = Rest.FullRequestNoBody("GET", "/drive/v3/files")
If Not Rest.LastMethodSuccess Then
Return Rest.LastErrorText
Exit Function
End If
JSON.Load(Response)
Next
' Get the folder id
Return JSON.StringOf("files[0].id")
End Function

Related

Phasing website directory/ folder name vb.net

I have a website with folders i want vb.net to phase (check) for existance of these. Obviously if Directory exists dosnt work in this scenario so I came up with the following code.
Dim PhaseUri As New System.Uri(http://www.example.com/My_Folder)
Dim PhaseURL As String = PhaseUri.Host.ToString
If My.Computer.Network.IsAvailable AndAlso My.Computer.Network.Ping(PhaseURL, 1000) Then
Else
End If
The code checks if www.example.com exists by extracting it from the entire (http://www.example.com/My_Folder), its as close as I can get, however if www.example.com exists but My_Folder dosnt then I have a problem. Basicaly my above code gets me as close as possible and then makes a short leap of faith in assuming the rest will also exist.
How can I phase/ validate/ check for the existance of the entier http://www.example.com/My_Folder using less than 100,000 lines and as minimal complex code as possible?
It only works if your 'folder' is a webpage or contains a default document.
Works for a page, not folder
public function IsFolderOnline(url as string) as boolean
try
dim wc as new system.net.webclient()
wc.downloadstring(url)
return true
catch ex as exception
return false
end try
end function
use it like this:
dim IsItOnline as boolean = IsFolderOnline("http://example.org/folder")
it is not possible to get all pages within a folder
you must check every page for href elements to find new urls. It will only find urls that have a weblink.
Webclient.Downloadstring() downloads the html of a page.
use this code to retrieve all urls from the page
' Finding urls in the page
Dim FoundUrls As New List(Of String)
Dim strRegex As String = "<a[^<>]*>"
Dim myRegex As New Text.RegularExpressions.Regex(strRegex, System.Text.RegularExpressions.RegexOptions.None)
For Each myMatch As Text.RegularExpressions.Match In myRegex.Matches(html)
If myMatch.Success Then
Dim strRegex2 As String = "href=""[^""]*"""
Dim myRegex2 As New Text.RegularExpressions.Regex(strRegex, System.Text.RegularExpressions.RegexOptions.None)
For Each myMatch2 As Text.RegularExpressions.Match In myRegex.Matches(myMatch.Value)
If myMatch2.Success Then
Dim value As String = Split(Split(myMatch2.Value, """", 2).Last, """", 2).First
If value.ToLower.StartsWith("http://" & DomainName.ToLower) Then
FoundUrls.Add(value)
End If
If value.ToLower.StartsWith("https://" & DomainName.ToLower) Then
FoundUrls.Add(value)
End If
If value.ToLower.StartsWith("/") Then
FoundUrls.Add(Protocol & DomainName & value)
Else
If Not value.Contains(":") Then
FoundUrls.Add(Protocol & DomainName & "/" & value)
End If
End If
End If
Next
End If
Next
you might want to remove links that contain files
'Remove unsupported urls
Dim UnsupportedExtensions() As String = {".css", ".ico", ".xml", ".axd", ".js", ".zip", ".rar", ".7z", ".tar", ".jar", ".pdf", ".jpg", ".jpeg", ".png", ".bmp", ".mp4", ".mov", ".mpeg", ".gif"}
For Each url In FoundUrls.ToList
For Each UnsupportedExtension In UnsupportedExtensions
If url.ToLower.EndsWith(UnsupportedExtension) Then
FoundUrls.Remove(url)
Exit For
End If
Next
Next

.NET Google API access token failing with no refresh token specified

I am trying to set up a class that can wrap around the .NET Google API so that I can use an Access Token that I have previously obtained to access a user's Google Drive. As of right now, I am just trying to get it to work so that I do not require a Refresh Token (more on that in a second). The ultimate goal is for somebody to go through a web page I have set up to authenticate where I obtain both an Access Token and a Refresh Token by directly calling to the Google Rest API (which I store in a database). They can then request to upload/download files onto their Drive on a different page which will first obtain the appropriate information from the database and then use the .NET Google API Library when accessing Drive.
However, when I attempt to access their Drive I get the the following error:
The access token has expired and could not be refreshed. Errors: refresh error, refresh error, refresh error
I know that the Access Token is valid because I obtain it only seconds earlier during my testing. Here is my code for setting up the Drive Service:
' NOTE: Code altered for brevity
Public Sub Initialize(accessToken As String)
' Set up the client secret information based on the default constants
Dim clientSecrets As New ClientSecrets()
clientSecrets.ClientId = DEFAULT_CLIENT_ID
clientSecrets.ClientSecret = DEFAULT_CLIENT_SECRET
' Set up a token based on the token data we got
' NOTE: Is it OK to leave some strings as NULL?
Dim token As New Responses.TokenResponse()
token.AccessToken = accessToken
token.RefreshToken = ""
token.TokenType = "Bearer"
token.IssuedUtc = DateTime.Now
token.ExpiresInSeconds = 3600
token.Scope = "drive"
token.IdToken = ""
' Set up a flow for the user credential
Dim init As New GoogleAuthorizationCodeFlow.Initializer()
init.ClientSecrets = clientSecrets
init.Scopes = New String() {DriveService.Scope.Drive}
init.Clock = Google.Apis.Util.SystemClock.Default
' Set up everything else and initialize the service
Dim baseInit As New BaseClientService.Initializer()
baseInit.HttpClientInitializer = New UserCredential(New GoogleAuthorizationCodeFlow(init), "user", token)
baseInit.ApplicationName = APP_NAME
_service = New DriveService(baseInit)
End Sub
Shortly after that, I then use the following code to request a folder so I can check to see if it exists or not.
Private Function GetDriveFolder(folderPath As String, ByRef folderIds As String(), Optional createMissingFolders As Boolean = False, Optional parentFolderId As String = "root") As Data.File
Dim creatingFolderPath As Boolean = False
Dim currentFolder As Data.File = Nothing
Dim folderPathSplit As String() = folderPath.Replace("/", "\").Trim("\").Split("\")
Dim folderIdList As New List(Of String)
folderIds = {}
' Loop through each folder in the path and seek each out until we reach the end
For x As Integer = 0 To folderPathSplit.Length - 1
Dim result As FileList = Nothing
If Not creatingFolderPath Then
' Build a list request which we will use to seek out the next folder
Dim request As FilesResource.ListRequest = _service.Files.List()
request.Q = "mimeType='application/vnd.google-apps.folder' and name='" & folderPathSplit(x) & "'"
If currentFolder Is Nothing Then
request.Q &= " and '" & EscapeDriveValue(parentFolderId) & "' in parents"
Else
request.Q &= " and '" & EscapeDriveValue(currentFolder.Id) & "' in parents"
End If
request.Spaces = "drive"
request.Fields = "files(id, name)"
' Execute the search, we should only get a single item back
' NOTE: Error thrown on this request
result = request.Execute()
End If
' So on.....
So, I'm just trying to get it to work with only the Access Token for the time being because if it ends up getting refreshed I'll need to know so that I can update my database. However, if I do include the Refresh Token I get the following error:
Error:"unauthorized_client", Description:"Unauthorized", Uri:""
I'm guessing this has something to do with the way I have configured my application through the Dev Console but if I authenticate through the Google API Library by having it launch a browser to get my credentials everything works fine. So, I'm really not sure where to go from here as I haven't found anybody having similar problems and the guides don't cover specifying your own Access Token.
Also, as a quick note this is the URL I am using when having the user authenticate:
String.Format("https://accounts.google.com/o/oauth2/v2/auth?client_id={0}&state={1}&redirect_uri={2}&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&access_type=offline&include_granted_scopes=true&prompt=select_account%20consent&response_type=code", GOOGLEAPI_CLIENTID, validateState, redirectUri)
Thanks for the help!
If you have an access-token then the simplest way to create a google credential is to use the GoogleCredential.FromAccessToken() method passing in your access token.
This returns you a GoogleCredential instance which you can use to set the HttpClientInitializer property when building the DriveService.
If you then still get an error when accessing the drive service, then it's likely there's something incorrect in how you are asking for the access-token.

Cannot retrieve path of Special Folders when redirection enabled

I have a tool that reads a .txt file for a list of paths and uses them in a copy. It looks like this:
***DESTINATION***
E:\Backup
***Sources***
%USERPROFILE%\Pictures
%USERPROFILE%\Favourites
%USERPROFILE%\Contacts
%USERPROFILE%\My Videos
My system has folder redirection enabled so 'Pictures' for example is actually D:\Adam\Pictures. However when using the following code it will only resolve as C:\Adam\Pictures and throw a "Cannot find path error".
'Declarations earlier in script
Dim Destpath As String = System.IO.File.ReadAllLines(Application.StartupPath + "\CONFIG.txt")(1)
Dim userprofilevar = (Environment.GetFolderPath(Environment.SpecialFolder.UserProfile))
'Snippet of line reading logic
ElseIf line.Contains("%USERPROFILE%") Then
Dim lineArray() As String = line.Split("\")
Dim lineuser As String = userprofilevar + "\"
Dim linepath As String = lineArray(1)
line = lineuser + linepath
Destpath = String.Concat(Destpath, "\", linepath)
MessageBox.Show(Destpath)
Else
Does anyone know how to resolve the correct path of the redirected folder through the %USERPROFILE% variable?
Solution I found:
After converting #AlexB's example into VB.NET and getting it working in my app, I simply declared each of the %Userprofile% folders as a string then have the line reading logic update the line string as the correct folder path:
'Declarations as start of Form
Dim downloadsPath As String = KnownFolders.GetPath(KnownFolder.Downloads)
Dim contactspath As String = KnownFolders.GetPath(KnownFolder.Contacts)
'Snippit of line reading logic
ElseIf line.Contains("%USERPROFILE%\Downloads") Then
line = downloadspath
ElseIf line.Contains("%USERPROFILE%\Contacts") Then
line = contactspath
It's not pretty to do for all 11 %Userprofile% folders, but it works!

How to read files in folders?

I am trying to get my application to check for folders in the folderbrowserdialogs selectedpath and then get those files, but it doesn't work I have tried both listed ways below. The second way gives me an error: (Expression is of type char which is not a collection type)
For Each folder In FileBrowserDialog.SelectedPath
Dim counter As _
System.Collections.ObjectModel.ReadOnlyCollection(Of String)
counter = My.Computer.FileSystem.GetFiles(folder)
Label1.Text = counter.Count.ToString
Next
For Each folder In FileBrowserDialog.SelectedPath
Dim counter As _
System.Collections.ObjectModel.ReadOnlyCollection(Of String)
For Each foundfile In folder
counter = My.Computer.FileSystem.GetFiles(foundfile)
Label1.Text = counter.Count.ToString
Next
Any help is appreciated.
FolderBrowserDialog1.SelectedPath will return the path the user selected in the dialog. You still need to write code to go get the files. There may not be a need to get the folders and then files in them. Net has ways to do that for you:
FolderBrowserDialog1.ShowDialog()
Dim myPath As String = FolderBrowserDialog1.SelectedPath
' get all files for a folder
Dim files = Directory.GetFiles(myPath)
' get all files for all sub folders
Dim files = Directory.GetFiles(myPath, "*.*",
System.IO.SearchOption.AllDirectories)
' get certain file types for folder and subs
Dim files = Directory.GetFiles(myPath, "*.jpg",
System.IO.SearchOption.AllDirectories)
You also are not going to be able to simply assign the results to a ReadOnlyCollection like that, because they are ReadOnly. The collection needs to be created/instanced with the complete list:
Dim counter As new ReadOnlyCollection(Of String)(files)

Set "client_updated_time" when uploading file to OneDrive

I have nearly completed a basic OneDrive interface, and am able to handle creating and writing folders, files, and so forth. The last element to get working is to update a file's date/time stamp to match that of the local (originating) file.
When I drop a file via the browser interface, the file's date/time stamp shows correctly in the view. This is reflected in the "client_updated_time" when I read the file's properties later in my application. Clear enough.
However, I cannot find any way to update this field programmatically from within my application. I am using the following code, to no avail. I have a valid _accessToken value, a valid fileId for the new file, and the call results always indicates success.
The "name" and "updated_time" elements are just in there to see if anything happens, and the file will indeed rename if I mangle the fileName variable a bit. I didn't expect the "updated_time" to updated, but it seems to me that the "client_updated_time" element should work.
Using fiddler, it appears that the browser-based interface (java?) opens a session, sends the file over, and then in the close-session call uses a header entry labelled "X-Last-Modified-ISO8601" to set the file's date-time stamp. However, using the REST interface, I cannot find any examples of this. The documentation for setting file properties mentions renaming only (which works in this code).
Any feedback on how to accomplish setting "client_updated_time" with REST calls would be much appreciated!
Here's the relevant code:
Private _liveURL As String = "https://apis.live.net/v5.0/"
Private Sub AddAuthorizationHeader(hc As HttpClient, authorization As String)
If Len(authorization) > 0 Then
hc.DefaultRequestHeaders.Authorization = New Headers.AuthenticationHeaderValue("Bearer", authorization)
End If
End Sub
Public Function WebPUT(uri As String, contentType As String, authorization As String, data As String) As String
Dim response As String = String.Empty
Try
Dim hc As New HttpClient()
Dim content As New Http.StringContent(data, System.Text.Encoding.UTF8, contentType)
AddAuthorizationHeader(hc, authorization)
Using r = hc.PutAsync(uri, content).Result
response = r.Content.ReadAsStringAsync.Result
End Using
Catch ex As Exception
' fake it
response = "{""error"": {""code"": ""invalid_request"", ""message"": """ + ex.Message + """}}"
End Try
Return response
End Function
Private Function UpdateFileDateTime(fileId As String, fileName As String, fileDt As String) As Boolean
Dim response As Boolean = False
Dim wr As String = WebHelper.WebPUT(_liveURL + fileId, "application/json", _accessToken, "{ ""name"": """ + fileName + """, ""updated_time"": """ + fileDt + """, ""client_updated_time"": """ + fileDt + """ }")
'... parse wr for response
Return response
End Function
Based on the file object reference, that field is read-only via the REST API: http://msdn.microsoft.com/en-us/library/dn631834.aspx