Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue #1096 - Add Save-PodeRequestFile functionality - disable overwrite and return filepaths #1097

Open
wants to merge 5 commits into
base: develop
Choose a base branch
from

Conversation

acommonusername
Copy link

Description of the Change

Added functionality to make it possible to disable overwriting files, and instead add a numerical suffix to the filename if it already exists in the directory. Enabled via Switch parameter.

Added functionality to make it possible to return a list of filepaths of the uploaded files. Enabled via Switch parameter.

Help comment updated to include parameters and an example.

Related Issue

Resolves #1096

Examples

Parameter NoOverwrite
If supplied, disables overwriting already existing files, and adds a numerical suffix to the filename if necessary.
F.x. if C:\pode\test.txt already exists and test.txt is uploaded again, it will be saved as C:\pode\test (1).txt

Parameter Return
If supplied, filepaths of all saved files will be returned as a list.

Usage
$filePaths = Save-PodeRequestFile -Key 'avatar' -Path 'F:/Images' -NoOverwrite -Return

Result
In the above example, if F:/Images already contains test.jpg and you're uploading the files test.jpg and asdf.jpg. test.jpg will be saved as test (1).jpg and asdf.jpg as asdf.jpg, the function will then return a list containing the following filepaths:

F:/Images\test (1).jpg
F:/Images\asdf.jpg

@Badgerati
Copy link
Owner

Hey @acommonusername,

Thanks for the PR! Looking at this there's quite a few use cases this would have to cover when -NoOverwrite is supplied:

  • File names with no extension: .gitignore
  • File names with multiple .: example.2023.05.11.txt
  • Files being saves to a PS Drive or SMB, in this instance Test-Path has to be used as [Path]::Exists(...) doesn't work
  • Existing file names with the (id) suffix that could range from 1 > 1000 - ie: this would result in 1000 exists checks

I have built something similar once before, and it would be worth moving the "file ID suffix builder" into it's own function in Private/Helpers.ps1; checking if -NoOverwrite was supplied back in Save-PodeRequestFile, and then calling the new function.

Using the logic I've built before, and combing your logic produces the following (which should cover all use-cases above):

param(
    $FilePath = 'C:\temp\tests.txt'
)

# check the initial file path, and use that if it doesn't exist
if (!(Test-Path $filepath)) {
    return $filepath
}

# vars for some regex
$fileRegex = '(.+)(\.(?=[^\\\/\.]+$))'
$idRegex = '^.+? \((?<id>\d+)\).*$'

# split the file path into base path and name
$filepath, $filename = $filepath -split '[\\/](?=[^\\\/]+$)'

# build a wildcard file name pattern for filtering existing files
# the regex check is for ".name" use cases where there is no extension
if ($filename -imatch $fileRegex) {
    $wildFilename = $filename -replace $fileRegex, '$1 (*)$2'
} else {
    $wildFilename = "$($filename) (*)"
}

# calculate the next "id" based on existing files
$nextId = 1
$files = @(Get-ChildItem -Name -File -Force -Path $filepath -Filter $wildFilename |
    Sort-Object -Property { $_.Length },{ $_ })

$lastId = $files[-1] -replace $idRegex, '$1'
if (($file.Length -eq $lastId)) {
    $nextId = $lastId + 1
} else {
    foreach ($file in $files) {
        if (($file -replace $idRegex, '$1') -ne $nextId) {
            break
        }

        $nextId++
    }
}

# generate the new file name
if ($filename -imatch $fileRegex) {
    $filename = $filename -replace $fileRegex, "`$1 ($($nextId))`$2"
} else {
    $filename = "$($filename) ($($nextId))"
}

# combine the new file name with the original base path, and return
$filepath = [System.IO.Path]::Combine($filepath, $filename)
return $filepath

For the -Return flag, you can actually return values directly from the foreach into an array and then return that 😄

# save the files
$filePathsList = @(foreach ($file in $files) {
    # logic

    if ($Return) {
        $filePath
    }
})

if ($Return) {
    return $filePathsList
}

Saves building list objects and appending to them 😉

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add Save-PodeRequestFile functionality - disable overwrite and return filepaths
2 participants