Option Explicit
Private Declare PtrSafe Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
#Else
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)
Public Type GoogleRegistrationType
client_id As String
client_secret As String
redirect_uri As String
End Type
Public Type GoogleOAuthType
code_verifier As String
authorisation_code As String
token_type As String
access_token As String
refresh_token As String
expires_in As String
expires_at As Date
End Type
Public Sub Get_WebLink_From_Google_Drive()
Dim GoogleDataSheet As Worksheet
Dim GoogleReg As GoogleRegistrationType
Dim GoogleOAuth As GoogleOAuthType
Dim fileId As String
Dim webViewLink As String
GoogleReg.client_id = "YOUR CLIENT_ID STRING"
GoogleReg.client_secret = "YOUR CLIENT_SECRET STRING"
GoogleReg.redirect_uri = "urn:ietf:wg:oauth:2.0:oob"
Set GoogleDataSheet = ThisWorkbook.Worksheets("Sheet1")
Load_OAuth_Data GoogleOAuth, GoogleDataSheet
If GoogleOAuth.authorisation_code = "" Then
GoogleOAuth.code_verifier = RandomString(43)
GoogleOAuth.authorisation_code = IE_Request_Auth_Code(GoogleReg, GoogleOAuth.code_verifier)
End If
If GoogleOAuth.authorisation_code <> "" Then
If GoogleOAuth.access_token = "" Then
Request_Access_Token GoogleOAuth, GoogleReg
ElseIf Has_Token_Expired(GoogleOAuth) Then
Refresh_Access_Token GoogleOAuth, GoogleReg
End If
Save_OAuth_Data GoogleOAuth, GoogleDataSheet
fileId = Find_File_In_Folder("Your folder name", "Your file name.ext", GoogleOAuth)
If fileId <> "" Then
webViewLink = Get_WebViewLink(fileId, GoogleOAuth)
MsgBox "webViewLink = " & webViewLink
End If
End If
End Sub
Private Function Find_File_In_Folder(folderName As String, findFileName As String, OAuth As GoogleOAuthType) As String
Dim URL As String
Dim folderId As String
Find_File_In_Folder = ""
URL = "https://www.googleapis.com/drive/v3/files?q=" & Encode("mimeType='application/vnd.google-apps.folder' and name='" & folderName & "'")
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", URL, False
.setRequestHeader "Authorization", OAuth.token_type & " " & Encode(OAuth.access_token)
.setRequestHeader "Accept", "application/json"
.Send
Debug.Print .responseText
If .Status = 200 Then
folderId = GetJSONvalue(.responseText, "id")
URL = "https://www.googleapis.com/drive/v3/files?q=" & Encode("name='" & findFileName & "' and '" & folderId & "' in parents")
.Open "GET", URL, False
.setRequestHeader "Authorization", OAuth.token_type & " " & Encode(OAuth.access_token)
.setRequestHeader "Accept", "application/json"
.Send
Debug.Print .responseText
If .Status = 200 Then
Find_File_In_Folder = GetJSONvalue(.responseText, "id")
Else
MsgBox "Find_File_In_Folder error " & .Status & vbCr & .statusText & vbCrLf & .responseText
End If
Else
MsgBox "Find_File_In_Folder error " & .Status & vbCr & .statusText & vbCrLf & .responseText
End If
End With
End Function
Private Function Get_WebViewLink(fileId As String, OAuth As GoogleOAuthType) As String
Dim URL As String
URL = "https://www.googleapis.com/drive/v3/files/" & fileId & "?fields=webViewLink"
With CreateObject("MSXML2.XMLHTTP")
.Open "GET", URL, False
.setRequestHeader "Authorization", OAuth.token_type & " " & Encode(OAuth.access_token)
.setRequestHeader "Accept", "application/json"
.Send
Debug.Print .responseText
If .Status = 200 Then
Get_WebViewLink = GetJSONvalue(.responseText, "webViewLink")
Else
MsgBox "Get_WebViewLink error " & .Status & vbCr & .statusText & vbCrLf & .responseText
End If
End With
End Function
Private Function IE_Request_Auth_Code(GoogleReg As GoogleRegistrationType, code_verifier As String) As String
Dim params As String
Dim p As Long
IE_Request_Auth_Code = ""
params = "?client_id=" & Encode(GoogleReg.client_id) & _
"&redirect_uri=" & Encode(GoogleReg.redirect_uri) & _
"&response_type=code" & _
"&scope=" & Encode("https://www.googleapis.com/auth/drive.readonly") & _
"&code_challenge=" & code_verifier & _
"&code_challenge_method=plain" & _
"&state=VBA_" & Format(Now, "YYYY-MM-DD_HHMMSS")
With CreateObject("InternetExplorer.Application")
.Visible = True
.navigate "https://accounts.google.com/o/oauth2/v2/auth" & params
While .Busy Or .readyState <> 4: DoEvents: Sleep 250: Wend
Do
DoEvents
Sleep 500
Loop Until InStr(1, .LocationURL, "&approvalCode", vbTextCompare) > 0 Or _
InStr(1, .LocationURL, "access_denied", vbTextCompare) > 0
If InStr(1, .LocationURL, "&approvalCode", vbTextCompare) > 0 Then
IE_Request_Auth_Code = Split(.LocationURL, "&approvalCode=")(1)
p = InStr(IE_Request_Auth_Code, "&")
If p > 0 Then IE_Request_Auth_Code = Left(IE_Request_Auth_Code, p - 1)
Debug.Print "approvalCode = " & IE_Request_Auth_Code
End If
.Quit
End With
End Function
Private Sub Request_Access_Token(ByRef OAuth As GoogleOAuthType, GoogleData As GoogleRegistrationType)
Dim URL As String
Dim postData As String
OAuth.access_token = ""
URL = "https://oauth2.googleapis.com/token"
postData = "client_id=" & GoogleData.client_id & _
"&client_secret=" & GoogleData.client_secret & _
"&code=" & OAuth.authorisation_code & _
"&code_verifier=" & OAuth.code_verifier & _
"&grant_type=authorization_code" & _
"&redirect_uri=" & GoogleData.redirect_uri
With CreateObject("MSXML2.XMLHTTP")
.Open "POST", URL, False
.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
.Send (postData)
Debug.Print .responseText
If .Status = 200 Then
OAuth.token_type = GetJSONvalue(.responseText, "token_type")
OAuth.access_token = GetJSONvalue(.responseText, "access_token")
OAuth.refresh_token = GetJSONvalue(.responseText, "refresh_token")
OAuth.expires_in = GetJSONvalue(.responseText, "expires_in")
OAuth.expires_at = DateAdd("s", OAuth.expires_in, Now)
Else
MsgBox "Request_Access_Token error " & .Status & vbCr & .statusText & vbCrLf & .responseText
End If
End With
End Sub
Private Sub Refresh_Access_Token(ByRef OAuth As GoogleOAuthType, GoogleData As GoogleRegistrationType)
Dim URL As String
Dim postData As String
URL = "https://accounts.google.com/o/oauth2/token"
postData = "refresh_token=" & OAuth.refresh_token & _
"&client_id=" & GoogleData.client_id & _
"&client_secret=" & GoogleData.client_secret & _
"&grant_type=refresh_token"
With CreateObject("MSXML2.XMLHTTP")
.Open "POST", URL, False
.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
.Send (postData)
If .Status = 200 Then
OAuth.token_type = GetJSONvalue(.responseText, "token_type")
OAuth.access_token = GetJSONvalue(.responseText, "access_token")
OAuth.expires_in = GetJSONvalue(.responseText, "expires_in")
OAuth.expires_at = DateAdd("s", OAuth.expires_in, Now)
Else
MsgBox "Refresh_Access_Token error " & .Status & vbCr & .statusText
End If
End With
End Sub
Private Function Has_Token_Expired(OAuth As GoogleOAuthType) As Boolean
If OAuth.expires_at = 0 Then
Has_Token_Expired = True
ElseIf OAuth.expires_at < Now Then
Has_Token_Expired = True
ElseIf DateAdd("s", -60, Now) >= OAuth.expires_at Then
Has_Token_Expired = True
Else
Has_Token_Expired = False
End If
End Function
Private Sub Save_OAuth_Data(OAuth As GoogleOAuthType, ws As Worksheet)
With ws
.Range("A1:B1").Value = Array("code_verifier", OAuth.code_verifier)
.Range("A2:B2").Value = Array("authorisation_code", OAuth.authorisation_code)
.Range("A3:B3").Value = Array("token_type", OAuth.token_type)
.Range("A4:B4").Value = Array("access_token", OAuth.access_token)
.Range("A5:B5").Value = Array("refresh_token", OAuth.refresh_token)
.Range("A6:B6").Value = Array("expires_in", OAuth.expires_in)
If OAuth.expires_in <> "" Then
.Range("A7:B7").Value = Array("expires_at", DateAdd("s", CDbl(OAuth.expires_in), Now))
End If
.Columns("A").AutoFit
End With
End Sub
Private Sub Load_OAuth_Data(ByRef OAuth As GoogleOAuthType, ws As Worksheet)
With ws
OAuth.code_verifier = .Range("B1").Value
OAuth.authorisation_code = .Range("B2").Value
OAuth.token_type = .Range("B3").Value
OAuth.access_token = .Range("B4").Value
OAuth.refresh_token = .Range("B5").Value
OAuth.expires_in = .Range("B6").Value
If .Range("B7").Value = "" Then
OAuth.expires_at = 0
Else
OAuth.expires_at = .Range("B7").Value
End If
End With
End Sub
Private Function Encode(ByVal param As String) As String
Encode = Application.WorksheetFunction.EncodeURL(param)
End Function
Private Function RandomString(num As Long) As String
Dim chars As String
Dim i As Long
Randomize
chars = "abcdefghijklmnopqrstuvwxyz"
chars = UCase(chars) & "0123456789"
For i = 1 To num
RandomString = RandomString & Mid$(chars, Int(Rnd() * Len(chars) + 1), 1)
Next
End Function
Private Function GetJSONvalue(JSONstring As String, paramName As String) As String
Dim p1 As Long, p2 As Long
p1 = InStr(JSONstring, Chr(34) & paramName & Chr(34) & ": ")
If p1 > 0 Then
p1 = p1 + Len(Chr(34) & paramName & Chr(34) & ": ")
p2 = InStr(p1, JSONstring, ",")
If p2 = 0 Then p2 = InStr(p1, JSONstring, vbLf)
GetJSONvalue = Mid(JSONstring, p1, p2 - p1)
GetJSONvalue = Replace(GetJSONvalue, Chr(34), "")
Debug.Print paramName & " = " & GetJSONvalue
End If
End Function