Skip to content

Commit 7c6dcb3

Browse files
committed
reworked Add-GoogleDriveFile to use Resolve-GoogleDriveFolder
1 parent c9521f3 commit 7c6dcb3

5 files changed

Lines changed: 227 additions & 20 deletions

File tree

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
<#
2+
.SYNOPSIS
3+
Maps a local folder path to a corresponding Google Drive folder, creating any missing folders or subfolders as needed.
4+
5+
.DESCRIPTION
6+
This function takes a folder path (e.g., "PSBlogger/Subfolder") and returns the corresponding Google Drive folder object.
7+
If any part of the folder path does not exist in Google Drive, it will be created automatically.
8+
9+
.PARAMETER FolderPath
10+
The folder path within Google Drive, using '/' as the separator for subfolders (e.g., "PSBlogger/Subfolder").
11+
12+
13+
#>
14+
function Resolve-GoogleDriveFolder
15+
{
16+
param(
17+
[Parameter(Mandatory = $true)]
18+
[string]$FolderPath
19+
)
20+
21+
Write-Verbose "Resolve-GoogleDriveFolder: Resolving folder path '$FolderPath' in Google Drive"
22+
23+
# Get all Folders in Google Drive
24+
$folderCache = @{}
25+
26+
$items = Get-GoogleDriveItems -ResultType "Folders"
27+
foreach($item in $items) {
28+
$folderCache[$item.Id] = $item
29+
}
30+
31+
$folders = $FolderPath -split '/'
32+
$folderId = $null
33+
34+
foreach($folder in $folders) {
35+
36+
$item = $null
37+
38+
# attempt to locate folder in cache
39+
if ($null -eq $folderId) {
40+
# root folder won't have an id yet, so find it by name only
41+
$item = $folderCache.Values | Where-Object { $_.name -eq $folder }
42+
} else {
43+
# find by name and parent id
44+
$item = $folderCache.Values | Where-Object { $_.name -eq $folder -and $_.parents -contains $folderId }
45+
}
46+
47+
# if the folder wasn't found, create it
48+
if ($null -eq $item) {
49+
Write-Verbose "Add-GoogleDriveFile: Folder '$folder' not found. Creating new folder."
50+
51+
$newFolderParams = @{
52+
Name = $folder
53+
}
54+
if ($folderId) {
55+
$newFolderParams.ParentId = $folderId
56+
}
57+
$item = Add-GoogleDriveFolder @newFolderParams
58+
59+
# save new folder into cache
60+
$folderCache[$item.id] = $item
61+
$folderId = $item.id
62+
} else {
63+
# folder was found, so just update the folderId for the next iteration
64+
$folderId = $item.id
65+
}
66+
}
67+
68+
return $folderCache[$folderId]
69+
}

src/public/Add-GoogleDriveFile.ps1

Lines changed: 8 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
The local path to the file to upload.
1111
1212
.PARAMETER FileName
13-
Optional custom name for the file. If not specified, uses the original filename.
13+
Optional custom name for the file. If not specified, uses the original filename. Can include the target folder structure.
1414
1515
.PARAMETER Force
1616
If specified, will overwrite an existing file with the same name in the target folder.
@@ -43,24 +43,15 @@ function Add-GoogleDriveFile {
4343
$FileName = $sourceItem.Name
4444
}
4545

46-
# First, find or create the upload folder in Google Drive
47-
Write-Verbose "Add-GoogleDriveFile: Verifying target folder: $TargetFolderName"
48-
$folder = Get-GoogleDriveItems -ResultType "Folders" -Title $TargetFolderName
46+
$relativeFolderPath = "$TargetFolderName/$(Split-Path -Path $FileName.ToLower() -Parent)".Replace('\', '/').Trim('/')
47+
$relativeFilePath = Split-Path -Path $FileName -Leaf
4948

50-
if (-not $folder) {
51-
# Create the folder if it doesn't exist
52-
Write-Verbose "Add-GoogleDriveFile: Folder '$TargetFolderName' not found. Creating new folder."
53-
$folder = Add-GoogleDriveFolder -Name $TargetFolderName
54-
}
55-
else {
56-
# Get the first folder if multiple exist
57-
Write-Verbose "Add-GoogleDriveFile: Folder '$TargetFolderName' found."
58-
$folder = $folder | Select-Object -First 1
59-
}
49+
# First, find or create the upload folder in Google Drive
50+
$folder = Resolve-GoogleDriveFolder -FolderPath $relativeFolderPath
6051

6152
# Determine if the file already exists in the target folder
62-
Write-Verbose "Add-GoogleDriveFile: Checking if file '$FileName' already exists in folder '$TargetFolderName'"
63-
$existingFile = Get-GoogleDriveItems -ResultType "Files" -Title $FileName -ParentId $folder.id
53+
Write-Verbose "Add-GoogleDriveFile: Checking if file '$relativeFilePath' already exists in folder '$relativeFolderPath'"
54+
$existingFile = Get-GoogleDriveItems -ResultType "Files" -Title $relativeFilePath -ParentId $folder.id
6455
if ($existingFile) {
6556
if (-not $Force) {
6657
# use existing file
@@ -75,7 +66,7 @@ function Add-GoogleDriveFile {
7566

7667
# Prepare metadata for the file
7768
$metadata = @{
78-
name = $FileName
69+
name = $relativeFilePath
7970
parents = @($folder.id)
8071
} | ConvertTo-Json -Compress
8172

src/public/Get-GoogleDriveItems.ps1

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ function Get-GoogleDriveItems {
5858
$queryArgs = @{
5959
q = [System.Web.HttpUtility]::UrlEncode($q -join ' and ')
6060
pageSize = 40
61+
fields = "nextPageToken,files(id,name,mimeType,parents)"
6162
}
6263

6364
do {

src/tests/Add-GoogleDriveFile.Tests.ps1

Lines changed: 88 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ Describe 'Add-GoogleDriveFile' {
2727

2828
# folder does not exist
2929
Mock Get-GoogleDriveItems -ParameterFilter {
30-
$ResultType -eq "Folders" -and $Title -eq "TestFolder"
30+
$ResultType -eq "Folders"
3131
} { return $null }
3232

3333
# folder was added
@@ -55,7 +55,7 @@ Describe 'Add-GoogleDriveFile' {
5555
InModuleScope PSBlogger {
5656
# folder exists
5757
Mock Get-GoogleDriveItems -ParameterFilter {
58-
$ResultType -eq "Folders" -and $Title -eq "TestFolder"
58+
$ResultType -eq "Folders"
5959
} { return @([pscustomobject]@{ id = "12345"; name = "TestFolder" }) }
6060
}
6161
}
@@ -144,6 +144,91 @@ Describe 'Add-GoogleDriveFile' {
144144
Should -InvokeVerifiable
145145
}
146146
}
147+
148+
Context "Preserve subfolder path" {
149+
150+
It "Should create full paths in GoogleDrive matching the supplied FileName" {
151+
# arrange
152+
InModuleScope PSBlogger {
153+
# folders do not exist
154+
Mock Get-GoogleDriveItems -ParameterFilter {
155+
$ResultType -eq "Folders"
156+
} { return $null }
157+
158+
# create root folder
159+
Mock Add-GoogleDriveFolder -ParameterFilter { $Name -eq "TestFolder" } {
160+
return [pscustomobject]@{ id = "12345"; name = "TestFolder" }
161+
} -Verifiable
162+
163+
# create subfolder
164+
Mock Add-GoogleDriveFolder -ParameterFilter { $Name -eq "subfolder" -and $ParentId -eq "12345" } {
165+
return [pscustomobject]@{ id = "67890"; name = "subfolder" }
166+
} -Verifiable
167+
168+
# file in subfolder does not exist
169+
Mock Get-GoogleDriveItems -ParameterFilter {
170+
$ResultType -eq "Files" -and $Title -eq "my.png" -and $ParentId -eq "67890"
171+
} { return $null }
172+
173+
# file was added
174+
Mock Invoke-GApi -ParameterFilter {
175+
$uri -eq "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart" -and `
176+
$body -match '"parents":\s*\["67890"\]' -and `
177+
$body -match '"name":\s*"my\.png"'
178+
} {
179+
return [pscustomobject]@{ id = "abcde"; name = "my.png" }
180+
} -Verifiable
181+
}
182+
183+
# act
184+
$result = Add-GoogleDriveFile -FilePath "$PSScriptRoot\data\my.png" -FileName "subfolder/my.png" -TargetFolderName "TestFolder"
185+
186+
# assert
187+
$result | Should -Not -BeNullOrEmpty
188+
Should -InvokeVerifiable
189+
}
190+
191+
It "Should create missing subfolders in Google Drive matching the supplied FileName" {
192+
# arrange
193+
InModuleScope PSBlogger {
194+
# folders do not exist
195+
Mock Get-GoogleDriveItems -ParameterFilter {
196+
$ResultType -eq "Folders"
197+
} {
198+
@(
199+
[pscustomobject]@{ id= "12345"; name = "TestFolder" }
200+
)
201+
}
202+
203+
# create subfolder
204+
Mock Add-GoogleDriveFolder -ParameterFilter { $Name -eq "subfolder" -and $ParentId -eq "12345" } {
205+
return [pscustomobject]@{ id = "67890"; name = "subfolder" }
206+
} -Verifiable
207+
208+
# file in subfolder does not exist
209+
Mock Get-GoogleDriveItems -ParameterFilter {
210+
$ResultType -eq "Files" -and $Title -eq "my.png" -and $ParentId -eq "67890"
211+
} { return $null }
212+
213+
# file was added
214+
Mock Invoke-GApi -ParameterFilter {
215+
$uri -eq "https://www.googleapis.com/upload/drive/v3/files?uploadType=multipart" -and `
216+
$body -match '"parents":\s*\["67890"\]' -and `
217+
$body -match '"name":\s*"my\.png"'
218+
} {
219+
return [pscustomobject]@{ id = "abcde"; name = "my.png" }
220+
} -Verifiable
221+
}
222+
223+
# act
224+
$result = Add-GoogleDriveFile -FilePath "$PSScriptRoot\data\my.png" -FileName "subfolder/my.png" -TargetFolderName "TestFolder"
225+
226+
# assert
227+
$result | Should -Not -BeNullOrEmpty
228+
Should -InvokeVerifiable
229+
230+
}
231+
}
147232
}
148233

149234
Context "Existing File" {
@@ -152,7 +237,7 @@ Describe 'Add-GoogleDriveFile' {
152237
InModuleScope PSBlogger {
153238
# folder exists
154239
Mock Get-GoogleDriveItems -ParameterFilter {
155-
$ResultType -eq "Folders" -and $Title -eq "TestFolder"
240+
$ResultType -eq "Folders"
156241
} { return @([pscustomobject]@{ id = "12345"; name = "TestFolder" }) }
157242

158243
# file exists
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
Describe "Resolve-GoogleDriveFolder" {
2+
3+
BeforeEach {
4+
Import-Module $PSScriptRoot\..\PSBlogger.psm1 -Force
5+
Import-Module $PSScriptRoot\_TestHelpers.ps1 -Force
6+
}
7+
8+
Context "No folders exist" {
9+
10+
It "Should create the root folder" {
11+
12+
InModuleScope PSBlogger {
13+
# arrange
14+
# return no folders
15+
Mock Get-GoogleDriveItems -ParameterFilter {
16+
$ResultType -eq "Folders"
17+
} { return @() }
18+
19+
# ensure folder is created
20+
Mock Add-GoogleDriveFolder -ParameterFilter { $Name -eq "PSBlogger" } {
21+
return [pscustomobject]@{ id = "root"; name = "PSBlogger" }
22+
} -Verifiable
23+
24+
# act
25+
$result = Resolve-GoogleDriveFolder -FolderPath "PSBlogger"
26+
27+
# assert
28+
$result | Should -Not -BeNullOrEmpty
29+
Should -InvokeVerifiable
30+
}
31+
}
32+
33+
It "Should create root folder and subfolder" {
34+
InModuleScope PSBlogger {
35+
# arrange
36+
# return no folders
37+
Mock Get-GoogleDriveItems -ParameterFilter {
38+
$ResultType -eq "Folders"
39+
} { return @() }
40+
41+
# ensure root folder is created
42+
Mock Add-GoogleDriveFolder -ParameterFilter { $Name -eq "PSBlogger" } {
43+
return [pscustomobject]@{ id = "root"; name = "PSBlogger"; }
44+
} -Verifiable
45+
46+
# ensure subfolder is created
47+
Mock Add-GoogleDriveFolder -ParameterFilter { $Name -eq "Subfolder" -and $ParentId -eq "root" } {
48+
return [pscustomobject]@{ id = "subfolder"; name = "Subfolder"; parents = @("root") }
49+
} -Verifiable
50+
51+
# act
52+
$result = Resolve-GoogleDriveFolder -FolderPath "PSBlogger/Subfolder"
53+
54+
# assert
55+
$result | Should -Not -BeNullOrEmpty
56+
Should -InvokeVerifiable
57+
}
58+
}
59+
60+
}
61+
}

0 commit comments

Comments
 (0)