diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 81f263f..eb74919 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -3,8 +3,7 @@ name: "Create GitHub release and publish to the PowerShell Gallery" on: push: paths: - - 'PSShlink/**' - - '!PSShlink/tests/**' + - 'src/**' branches: - main - master @@ -36,15 +35,28 @@ jobs: Set-PSRepository -Name "PSGallery" -InstallationPolicy Trusted Install-Module "InvokeBuild" -Force $Username, $ProjectName = $env:GITHUB_REPOSITORY -split "/" - Invoke-Build -ModuleName $ProjectName -Author $Username -Task "InstallDependencies","ImportBuildModule","SetGitHubActionEnvironmentVariables" + Invoke-Build -File "invoke.build.ps1" -ModuleName $ProjectName -Author $Username -Task "InstallDependencies","ImportBuildModule","SetGitHubActionEnvironmentVariables" shell: pwsh - name: Build - run: Invoke-Build -ModuleName $env:GH_PROJECTNAME -Author $env:GH_USERNAME -Version $env:GitVersion_SemVer -NewRelease $true + run: | + $Params = @{ + ModuleName = $env:GH_PROJECTNAME + Author = $env:GH_USERNAME + Version = $env:GitVersion_SemVer + NewRelease = $true + } + Invoke-Build -File "custom.build.ps1" @Params -Task PreBuild + Invoke-Build -File "invoke.build.ps1" @Params + Invoke-Build -File "custom.build.ps1" @Params -Task PostBuild + shell: pwsh + + - name: Custom pre-release tasks + run: Invoke-Build -File "custom.build.ps1" -ModuleName $env:GH_PROJECTNAME -Author $env:GH_USERNAME -Version $env:GitVersion_SemVer -NewRelease $true -Task PreRelease shell: pwsh - name: Publish to PowerShell Gallery - run: Invoke-Build -ModuleName $env:GH_PROJECTNAME -Task "PublishModule" + run: Invoke-Build -File "invoke.build.ps1" -ModuleName $env:GH_PROJECTNAME -Task "PublishModule" shell: pwsh env: PSGALLERY_API_KEY: ${{ secrets.PSGALLERY_API_KEY }} @@ -76,10 +88,14 @@ jobs: run: | git config --global user.email "action@github.com" git config --global user.name "GitHub Action" - git add CHANGELOG.md ${GH_PROJECTNAME}/${GH_PROJECTNAME}.psd1 docs + git add CHANGELOG.md src/${GH_PROJECTNAME}.psd1 docs git commit -m "Released ${{ env.GitVersion_SemVer }}" - name: Push commit uses: ad-m/github-push-action@master with: - github_token: ${{ secrets.GITHUB_TOKEN }} \ No newline at end of file + github_token: ${{ secrets.GITHUB_TOKEN }} + + - name: Custom post-release tasks + run: Invoke-Build -File "custom.build.ps1" -ModuleName $env:GH_PROJECTNAME -Author $env:GH_USERNAME -Version $env:GitVersion_SemVer -NewRelease $true -Task PostRelease + shell: pwsh \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7b7f8f5..dd9c2d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +# This file does not start with a period in the codaamok.build FileList because there seems to be an issue with using files in a module manifest's FileList starting with a period build/* -release/* !*.gitkeep +release/* +.DS_Store \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 966c44c..722ae54 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -38,5 +38,49 @@ }, "problemMatcher": [] }, + { + "label": "Tests", + "type": "process", + "command": "pwsh", + "args": ["-noprofile","-command","Import-Module ${input:CodeType}; $env:ShlinkServer = '${input:ShlinkServer}'; $env:ShlinkAPIKey = '${input:ShlinkAPIKey}' | ConvertTo-SecureString -AsPlainText -Force | ConvertFrom-SecureString; Invoke-Pester -Path './tests/*' -Output Detailed"], + "group": { + "kind": "test", + "isDefault": true + }, + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared", + "showReuseMessage": true, + "clear": false + }, + "problemMatcher": [] + }, + ], + "inputs": [ + { + "description": "Please enter Shlink server name", + "id": "ShlinkServer", + "type": "promptString", + "default": "https://acook.io" + }, + { + "description": "Please enter Shlink API key", + "id": "ShlinkAPIKey", + "type": "promptString", + "default": "", + "password": true, + }, + { + "type": "pickString", + "id": "CodeType", + "description": "Would you like use built, or development code?", + "options": [ + "./src/PSShlink.psd1", + "./build/PSShlink/PSShlink.psd1" + ], + "default": "./src/PSShlink.psd1" + }, ] } \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index c322526..b612038 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,22 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added +- Function `Get-ShlinkUrl` has new parameter `-TagsMode`, new in Shlink 3.0.0 +- Function `Get-ShlinkTags` has new parameter `-SearchTerm`, new in Shlink 3.0.0 +- New function `Get-ShlinkVisitsNonOrphan`, new endpoint in Shlink 3.0.0 +- New parameter `-RoundBlockSize` for `Save-ShlinkUrlQrCode` + +### Changed +- `Get-ShlinkTags` uses the new `/tags/stats` endpoint to include stats in the data returned. This change is purely internal of the function, does not impact how the function is used or how the data is returned. +- `Get-ShlinkDomains` now includes two parent properties when data is returned: `data` and `defaultRedirects`. In Shlink 2.10.0, this endpoint was updated to include the `defaultRedirects` property. Previously, all that was returned was everything within the `data` property. +- New parameter set of possible values for `-OrderBy` parameter of `Get-ShlinkUrl` function: `longUrl-ASC`, `longUrl-DESC`, `shortCode-ASC`, `shortCode-DESC`, `dateCreated-ASC`, `dateCreated-DESC`, `visits-ASC`, `visits-DESC`, `title-ASC`, and `title-DESC` + +### Removed +- Function `New-ShlinKTag` as the endpoint was removed from Shlink REST API in 3.0.0 + +### Fixed +- `Remove-ShlinkTag` ShouldProcess prompts listed the entire array of tags passed to it, rather than the current iterable it was working on ## [0.8.2] - 2021-11-21 ### Fixed diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3cd4be9..589b065 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -28,4 +28,4 @@ git fetch upstream # If there are changes, pull and work on merge conflicts git pull --rebase upstream develop ``` -4. Make sure you have pushed your commits to your new branch and then create a pull request +6. Make sure you have pushed your commits to your new branch and then create a pull request diff --git a/PSShlink/.DS_Store b/PSShlink/.DS_Store deleted file mode 100644 index 5008ddf..0000000 Binary files a/PSShlink/.DS_Store and /dev/null differ diff --git a/PSShlink/PSShlink.Format.ps1xml b/PSShlink/PSShlink.Format.ps1xml deleted file mode 100644 index 511eb52..0000000 --- a/PSShlink/PSShlink.Format.ps1xml +++ /dev/null @@ -1,31 +0,0 @@ - - - - - PSShlink - - PSShlinkVisits - - - - - - - date - - - referer - - - userAgent - - - visitLocation - - - - - - - - \ No newline at end of file diff --git a/PSShlink/Public/New-ShlinkTag.ps1 b/PSShlink/Public/New-ShlinkTag.ps1 deleted file mode 100644 index 7daa8bf..0000000 --- a/PSShlink/Public/New-ShlinkTag.ps1 +++ /dev/null @@ -1,62 +0,0 @@ -function New-ShlinkTag { - <# - .SYNOPSIS - Creates one or more new tags on your Shlink server - .DESCRIPTION - Creates one or more new tags on your Shlink server - .PARAMETER Tags - Name(s) for your new tag(s) - .PARAMETER ShlinkServer - The URL of your Shlink server (including schema). For example "https://example.com". - It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. - .PARAMETER ShlinkApiKey - A SecureString object of your Shlink server's API key. - It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. - .EXAMPLE - PS C:\> New-ShlinkTag -Tags "oldwebsite","newwebsite","misc" - - Creates the following new tags on your Shlink server: "oldwebsite","newwebsite","misc" - .INPUTS - This function does not accept pipeline input. - .OUTPUTS - System.Management.Automation.PSObject - #> - [CmdletBinding()] - param ( - [Parameter(Mandatory)] - [String[]]$Tags, - - [Parameter()] - [String]$ShlinkServer, - - [Parameter()] - [SecureString]$ShlinkApiKey - ) - - try { - GetShlinkConnection -Server $ShlinkServer -ApiKey $ShlinkApiKey - } - catch { - Write-Error -ErrorRecord $_ -ErrorAction "Stop" - } - - $Params = @{ - Endpoint = "tags" - Method = "POST" - Body = @{ - tags = @($Tags) - } - PropertyTree = "tags", "data" - ErrorAction = "Stop" - } - - try { - InvokeShlinkRestMethod @Params - } - catch { - Write-Error -ErrorRecord $_ - } - finally { - Write-Warning -Message "As of Shlink 2.4.0, this endpoint is deprecated. New tags are automatically created when you specify them in the -Tags parameter with New-ShlinkUrl. At some point, this function may be removed from PSShlink." - } -} \ No newline at end of file diff --git a/README.md b/README.md index 9bfcf06..59b222d 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,8 @@ An unofficial PowerShell module for Shlink (https://shlink.io), an open-source s - [Get-ShlinkTags](docs/Get-ShlinkTags.md) - [Get-ShlinkUrl](docs/Get-ShlinkUrl.md) - [Get-ShlinkVisits](docs/Get-ShlinkVisits.md) +- [Get-ShlinkVisitsNonOrphan](docs/Get-ShlinkVisitsNonOrphan.md) - [Get-ShlinkVisitsOrphan](docs/Get-ShlinkVisitsOrphan.md) -- [New-ShlinkTag](docs/New-ShlinkTag.md) - [New-ShlinkUrl](docs/New-ShlinkUrl.md) - [Remove-ShlinkTag](docs/Remove-ShlinkTag.md) - [Remove-ShlinkUrl](docs/Remove-ShlinkUrl.md) @@ -26,7 +26,7 @@ An unofficial PowerShell module for Shlink (https://shlink.io), an open-source s ## Requirements - PowerShell 5.1 or newer (including PowerShell Core, 7.0 or newer) -- Shlink 2.9.0 or newer +- Shlink 3.0.0 or newer - If you need support for older versions of Shlink, you can still source older versions of PSShlink [here](https://github.com/codaamok/PSShlink/releases) or use the `-RequiredVersion` parameter of `Install-Module` when installed from the PowerShell Gallery ## Getting started diff --git a/custom.build.ps1 b/custom.build.ps1 new file mode 100644 index 0000000..d18d5df --- /dev/null +++ b/custom.build.ps1 @@ -0,0 +1,40 @@ +<# +.SYNOPSIS + Build script which leverages the InvokeBuild module. +.DESCRIPTION + Build script which leverages the InvokeBuild module. + This build script is used in the build pipeline and local development for building this project. + Invoked by invoke.build.ps1 in this project where its intent is to implement project-specific custom pre/post build actions during the build pipeline andds local development. +#> +[CmdletBinding()] +param ( + [Parameter()] + [ValidateNotNullOrEmpty()] + [String]$ModuleName, + + [Parameter()] + [ValidateNotNullOrEmpty()] + [String]$Author, + + [Parameter()] + [String]$Version, + + [Parameter()] + [Bool]$NewRelease +) + +task PreBuild { + +} + +task PostBuild { + +} + +task PreRelease { + +} + +task PostRelease { + +} diff --git a/docs/New-ShlinkTag.md b/docs/New-ShlinkTag.md deleted file mode 100644 index 86934c2..0000000 --- a/docs/New-ShlinkTag.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -external help file: PSShlink-help.xml -Module Name: PSShlink -online version: -schema: 2.0.0 ---- - -# New-ShlinkTag - -## SYNOPSIS -Creates one or more new tags on your Shlink server - -## SYNTAX - -``` -New-ShlinkTag [-Tags] [[-ShlinkServer] ] [[-ShlinkApiKey] ] - [] -``` - -## DESCRIPTION -Creates one or more new tags on your Shlink server - -## EXAMPLES - -### EXAMPLE 1 -``` -New-ShlinkTag -Tags "oldwebsite","newwebsite","misc" -``` - -Creates the following new tags on your Shlink server: "oldwebsite","newwebsite","misc" - -## PARAMETERS - -### -Tags -Name(s) for your new tag(s) - -```yaml -Type: String[] -Parameter Sets: (All) -Aliases: - -Required: True -Position: 1 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -ShlinkServer -The URL of your Shlink server (including schema). -For example "https://example.com". -It is not required to use this parameter for every use of this function. -When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. - -```yaml -Type: String -Parameter Sets: (All) -Aliases: - -Required: False -Position: 2 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### -ShlinkApiKey -A SecureString object of your Shlink server's API key. -It is not required to use this parameter for every use of this function. -When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. - -```yaml -Type: SecureString -Parameter Sets: (All) -Aliases: - -Required: False -Position: 3 -Default value: None -Accept pipeline input: False -Accept wildcard characters: False -``` - -### CommonParameters -This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216). - -## INPUTS - -### This function does not accept pipeline input. -## OUTPUTS - -### System.Management.Automation.PSObject -## NOTES - -## RELATED LINKS diff --git a/invoke.build.ps1 b/invoke.build.ps1 index 3057ef2..1e60e15 100644 --- a/invoke.build.ps1 +++ b/invoke.build.ps1 @@ -1,3 +1,10 @@ +<# +.SYNOPSIS + Build script which leverages the InvokeBuild module. +.DESCRIPTION + Build script which leverages the InvokeBuild module. + This build script is used in the build pipeline and local development for building this project. +#> [CmdletBinding()] param ( [Parameter(Mandatory)] @@ -12,10 +19,10 @@ param ( [String]$Version, [Parameter()] - [Bool]$UpdateDocs = $false, + [Bool]$NewRelease = $false, [Parameter()] - [Bool]$NewRelease = $false + [Bool]$UpdateDocs = $false ) # Synopsis: Initiate the build process @@ -56,7 +63,7 @@ task PublishModule { task ImportBuildModule { if ($Script:ModuleName -eq "codaamok.build") { # This is to use module for building codaamok.build itself - Import-Module .\codaamok.build\codaamok.build.psd1 + Import-Module .\src\codaamok.build.psd1 } else { Import-Module "codaamok.build" @@ -70,47 +77,19 @@ task InitaliseBuildDirectory { "{0}\release" -f $BuildRoot ) - if (Test-Path -Path $BuildRoot\$Script:ModuleName\* -Include "*format.ps1xml") { - $Script:FormatFiles = Copy-Item -Path $BuildRoot\$Script:ModuleName\* -Destination $BuildRoot\build\$Script:ModuleName -Filter "*format.ps1xml" -PassThru + if (Test-Path -Path $BuildRoot\src\* -Include "*format.ps1xml") { + $Script:FormatFiles = Copy-Item -Path $BuildRoot\src\* -Destination $BuildRoot\build\$Script:ModuleName -Filter "*format.ps1xml" -PassThru } - if (Test-Path -Path $BuildRoot\$Script:ModuleName\Files\*) { - $Script:FileList = Copy-Item -Path $BuildRoot\$Script:ModuleName\Files\* -Destination $BuildRoot\build\$Script:ModuleName -Recurse -PassThru + if (Test-Path -Path $BuildRoot\src\Files\*) { + $Script:FileList = Copy-Item -Path $BuildRoot\src\Files\* -Destination $BuildRoot\build\$Script:ModuleName -Recurse -Force -PassThru } Copy-Item -Path $BuildRoot\LICENSE -Destination $BuildRoot\build\$Script:ModuleName\LICENSE - Copy-Item -Path $BuildRoot\$Script:ModuleName\en-US -Destination $BuildRoot\build\$Script:ModuleName -Recurse - $Script:ManifestFile = Copy-Item -Path $BuildRoot\$Script:ModuleName\$Script:ModuleName.psd1 -Destination $BuildRoot\build\$Script:ModuleName\$Script:ModuleName.psd1 -PassThru + Copy-Item -Path $BuildRoot\src\en-US -Destination $BuildRoot\build\$Script:ModuleName -Recurse + $Script:ManifestFile = Copy-Item -Path $BuildRoot\src\$Script:ModuleName.psd1 -Destination $BuildRoot\build\$Script:ModuleName\$Script:ModuleName.psd1 -PassThru } -<# Synopsis: Determine version number to build with -task GetVersionToBuild { - $Params = @{ - NewRelease = $Script:NewRelease - } - - if ($Script:CommitMessage -match 'Version to build:') { - if ($Script:CommitMessage -match '^Version to build: (\d+\.\d+\.\d+)$') { - $Params["VersionToBuild"] = $Matches[1] - } - else { - throw "Unable to parse version number from commit message '$Script:CommitMessage'" - } - } - else { - $Params["ModuleName"] = $Script:ModuleName - $Params["ManifestData"] = Import-PowerShellDataFile -Path ("{0}\{1}\{1}.psd1" -f $BuildRoot, $Script:ModuleName) - $Params["ChangeLogData"] = $Script:ChangeLogData - } - - $Script:VersionToBuild = Get-BuildVersionNumber @Params - - New-BuildEnvironmentVariable -Platform "GitHubActions" -Variable @{ - "VersionToBuild" = $Script:VersionToBuild.ToString() - } -} -#> - # Synopsis: Get change log data, copy it to the build directory, and create releasenotes.txt task CopyChangeLog { Copy-Item -Path $BuildRoot\CHANGELOG.md -Destination $BuildRoot\build\$Script:ModuleName\CHANGELOG.md @@ -132,13 +111,13 @@ task UpdateChangeLog -If ($Script:NewRelease) { # Synopsis: Creates a single .psm1 file of all private and public functions of the to-be-built module task CreateRootModule { $Script:RootModule = "{0}\build\{1}\{1}.psm1" -f $BuildRoot, $Script:ModuleName - $DevModulePath = "{0}\{1}" -f $BuildRoot, $Script:ModuleName + $DevModulePath = "{0}\src" -f $BuildRoot Export-RootModule -DevModulePath $DevModulePath -RootModule $Script:RootModule } # Synopsis: Create a single Process.ps1 script file for all script files under ScriptsToProcess\* (if any) -task CreateProcessScript -If (Test-Path -Path ("{0}\{1}\ScriptsToProcess" -f $BuildRoot, $Script:ModuleName) -Include "*.ps1") { - Export-ScriptsToProcess -Path ("{0}\{1}\ScriptsToProcess" -f $BuildRoot, $Script:ModuleName) +task CreateProcessScript -If (Test-Path -Path ("{0}\src\ScriptsToProcess" -f $BuildRoot) -Include "*.ps1") { + Export-ScriptsToProcess -Path ("{0}\src\ScriptsToProcess" -f $BuildRoot) $Script:ProcessScript = $true } @@ -147,7 +126,7 @@ task UpdateModuleManifest { $UpdateModuleManifestSplat = @{ Path = $Script:ManifestFile RootModule = (Split-Path $Script:RootModule -Leaf) - FunctionsToExport = Get-PublicFunctions -Path $BuildRoot\$Script:ModuleName\Public + FunctionsToExport = Get-PublicFunctions -Path $BuildRoot\src\Public ReleaseNotes = (Get-Content $BuildRoot\release\releasenotes.txt) -replace '`' } @@ -207,11 +186,11 @@ task UpdateProjectRepo -If ($NewRelease) { # Instead of copying the manifest from the .\build directory, update it in place # This enables me to keep FunctionsToExport = '*' for development. Therefore instead only update the important bits e.g. version and release notes $UpdateModuleManifestSplat = @{ - Path = "{0}\{1}\{1}.psd1" -f $BuildRoot, $Script:ModuleName + Path = "{0}\src\{1}.psd1" -f $BuildRoot, $Script:ModuleName ModuleVersion = $ManifestData.ModuleVersion ReleaseNotes = $ManifestData.PrivateData.PSData.ReleaseNotes } Update-ModuleManifest @UpdateModuleManifestSplat - $null = Test-ModuleManifest -Path ("{0}\{1}\{1}.psd1" -f $BuildRoot, $Script:ModuleName) + $null = Test-ModuleManifest -Path ("{0}\src\{1}.psd1" -f $BuildRoot, $Script:ModuleName) } diff --git a/src/PSShlink.Format.ps1xml b/src/PSShlink.Format.ps1xml new file mode 100644 index 0000000..6c30906 --- /dev/null +++ b/src/PSShlink.Format.ps1xml @@ -0,0 +1,51 @@ + + + + + PSShlinkVisits + + PSShlinkVisits + + + + + + + date + + + referer + + + userAgent + + + visitLocation + + + + + + + + PSShlinkDomains + + PSShlinkDomains + + + + + + + data + + + defaultRedirects + + + + + + + + \ No newline at end of file diff --git a/PSShlink/PSShlink.psd1 b/src/PSShlink.psd1 similarity index 100% rename from PSShlink/PSShlink.psd1 rename to src/PSShlink.psd1 diff --git a/PSShlink/PSShlink.psm1 b/src/PSShlink.psm1 similarity index 100% rename from PSShlink/PSShlink.psm1 rename to src/PSShlink.psm1 diff --git a/PSShlink/Private/GetShlinkConnection.ps1 b/src/Private/GetShlinkConnection.ps1 similarity index 100% rename from PSShlink/Private/GetShlinkConnection.ps1 rename to src/Private/GetShlinkConnection.ps1 diff --git a/PSShlink/Private/InvokeShlinkRestMethod.ps1 b/src/Private/InvokeShlinkRestMethod.ps1 similarity index 100% rename from PSShlink/Private/InvokeShlinkRestMethod.ps1 rename to src/Private/InvokeShlinkRestMethod.ps1 diff --git a/PSShlink/Public/Get-ShlinkDomains.ps1 b/src/Public/Get-ShlinkDomains.ps1 similarity index 96% rename from PSShlink/Public/Get-ShlinkDomains.ps1 rename to src/Public/Get-ShlinkDomains.ps1 index bae41c0..df86a8d 100644 --- a/PSShlink/Public/Get-ShlinkDomains.ps1 +++ b/src/Public/Get-ShlinkDomains.ps1 @@ -37,7 +37,8 @@ function Get-ShlinkDomains { $Params = @{ Endpoint = "domains" - PropertyTree = "domains", "data" + PropertyTree = "domains" + PSTypeName = "PSShlinkDomains" ErrorAction = "Stop" } diff --git a/PSShlink/Public/Get-ShlinkServer.ps1 b/src/Public/Get-ShlinkServer.ps1 similarity index 100% rename from PSShlink/Public/Get-ShlinkServer.ps1 rename to src/Public/Get-ShlinkServer.ps1 diff --git a/PSShlink/Public/Get-ShlinkTags.ps1 b/src/Public/Get-ShlinkTags.ps1 similarity index 77% rename from PSShlink/Public/Get-ShlinkTags.ps1 rename to src/Public/Get-ShlinkTags.ps1 index 7e37239..94ad23f 100644 --- a/PSShlink/Public/Get-ShlinkTags.ps1 +++ b/src/Public/Get-ShlinkTags.ps1 @@ -4,6 +4,8 @@ function Get-ShlinkTags { Returns the list of all tags used in any short URL, including stats and ordered by name. .DESCRIPTION Returns the list of all tags used in any short URL, including stats and ordered by name. + .PARAMETER SearchTerm + A query used to filter results by searching for it on the tag name. .PARAMETER ShlinkServer The URL of your Shlink server (including schema). For example "https://example.com". It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. @@ -14,6 +16,10 @@ function Get-ShlinkTags { PS C:\> Get-ShlinkTags Returns the list of all tags used in any short URL, including stats and ordered by name. + .EXAMPLE + PS C:\> Get-ShlinkTags -SearchTerm "pwsh" + + Returns the list of all tags used in any short URL, including stats and ordered by name, where those match the term "pwsh" by name of tag. .INPUTS This function does not accept pipeline input. .OUTPUTS @@ -21,6 +27,9 @@ function Get-ShlinkTags { #> [CmdletBinding()] param ( + [Parameter()] + [String]$SearchTerm, + [Parameter()] [String]$ShlinkServer, @@ -37,11 +46,14 @@ function Get-ShlinkTags { $QueryString = [System.Web.HttpUtility]::ParseQueryString('') - $QueryString.Add("withStats", "true") - $Params = @{ Endpoint = "tags" - PropertyTree = "tags", "stats" + Path = "stats" + PropertyTree = "tags", "data" + } + + if ($PSBoundParameters.ContainsKey("SearchTerm")) { + $QueryString.Add("searchTerm", $SearchTerm) } $Params["Query"] = $QueryString diff --git a/PSShlink/Public/Get-ShlinkUrl.ps1 b/src/Public/Get-ShlinkUrl.ps1 similarity index 86% rename from PSShlink/Public/Get-ShlinkUrl.ps1 rename to src/Public/Get-ShlinkUrl.ps1 index 92b88b5..dde6438 100644 --- a/PSShlink/Public/Get-ShlinkUrl.ps1 +++ b/src/Public/Get-ShlinkUrl.ps1 @@ -13,8 +13,10 @@ function Get-ShlinkUrl { The search term to search for a short code with. .PARAMETER Tags One or more tags can be passed to find short codes using said tag(s). + .PARAMETER TagsMode + Tells how the filtering by tags should work, returning short URLs containing "any" of the tags, or "all" the tags. It's ignored if no tags are provided, and defaults to "any" if not provided. .PARAMETER OrderBy - Order the results returned by "longUrl", "shortCode", "dateCreated", or "visits". The default sort order is in ascending order. + Order the results returned by "longUrl-ASC", "longUrl-DESC", "shortCode-ASC", "shortCode-DESC", "dateCreated-ASC", "dateCreated-DESC", "visits-ASC", "visits-DESC", "title-ASC", "title-DESC". .PARAMETER StartDate A datetime object to search for short codes where its start date is equal or greater than this value. If a start date is not configured for the short code(s), this filters on the dateCreated property. @@ -39,9 +41,9 @@ function Get-ShlinkUrl { Returns the short code "profile" using the domain "example.com". This is useful if your Shlink instance is responding/creating short URLs for multiple domains. .EXAMPLE - PS C:\> Get-ShlinkUrl -Tags "oldwebsite", "evenolderwebsite" -OrderBy "dateCreated" + PS C:\> Get-ShlinkUrl -Tags "oldwebsite", "evenolderwebsite" -TagsMode "any" -OrderBy "dateCreated-ASC" - Returns short codes which are associated with the tags "oldwebsite" and "evenolderwebsite". Ordered by the dateCreated property in ascending order. + Returns short codes which are associated with the tags "oldwebsite" or "evenolderwebsite". Ordered by the dateCreated property in ascending order. .EXAMPLE PS C:\> Get-ShlinkUrl -StartDate (Get-Date "2020-10-25 11:00:00") @@ -72,7 +74,11 @@ function Get-ShlinkUrl { [String[]]$Tags, [Parameter(ParameterSetName="ListShortUrls")] - [ValidateSet("longUrl", "shortCode", "dateCreated", "visits")] + [ValidateSet("any","all")] + [String]$TagsMode, + + [Parameter(ParameterSetName="ListShortUrls")] + [ValidateSet("longUrl-ASC", "longUrl-DESC", "shortCode-ASC", "shortCode-DESC", "dateCreated-ASC", "dateCreated-DESC", "visits-ASC", "visits-DESC", "title-ASC", "title-DESC")] [String]$OrderBy, [Parameter(ParameterSetName="ListShortUrls")] @@ -130,6 +136,9 @@ function Get-ShlinkUrl { $QueryString.Add("tags[]", $Tag) } } + "TagsMode" { + $QueryString.Add("tagsMode", $TagsMode) + } "SearchTerm" { $QueryString.Add("searchTerm", $SearchTerm) } diff --git a/PSShlink/Public/Get-ShlinkVisits.ps1 b/src/Public/Get-ShlinkVisits.ps1 similarity index 100% rename from PSShlink/Public/Get-ShlinkVisits.ps1 rename to src/Public/Get-ShlinkVisits.ps1 diff --git a/src/Public/Get-ShlinkVisitsNonOrphan.ps1 b/src/Public/Get-ShlinkVisitsNonOrphan.ps1 new file mode 100644 index 0000000..d7a1c8a --- /dev/null +++ b/src/Public/Get-ShlinkVisitsNonOrphan.ps1 @@ -0,0 +1,85 @@ +function Get-ShlinkVisitsNonOrphan { + <# + .SYNOPSIS + Get the list of visits to invalid short URLs, the base URL or any other 404. + .DESCRIPTION + Get the list of visits to invalid short URLs, the base URL or any other 404. + .PARAMETER StartDate + A datetime object to filter the visit data where the start date is equal or greater than this value. + .PARAMETER EndDate + A datetime object to filter the visit data where its end date is equal or less than this value. + .PARAMETER ExcludeBots + Exclude visits from bots or crawlers. + .PARAMETER ShlinkServer + The URL of your Shlink server (including schema). For example "https://example.com". + It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. + .PARAMETER ShlinkApiKey + A SecureString object of your Shlink server's API key. + It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. + .EXAMPLE + PS C:\> Get-ShlinkVisitsOrphan + + Get the list of visits to invalid short URLs, the base URL or any other 404. + .EXAMPLE + PS C:\> Get-ShlinkVisitsOrphan -StartDate (Get-Date "2020-11-01") -EndDate (Get-Date "2020-12-01") -ExcludeBots + + Get the list of visits to invalid short URLs, the base URL or any other 404, for the whole of November and excluding bots/crawlers. + .INPUTS + This function does not accept pipeline input. + .OUTPUTS + System.Management.Automation.PSObject + #> + [CmdletBinding()] + param ( + [Parameter()] + [datetime]$StartDate, + + [Parameter()] + [datetime]$EndDate, + + [Parameter()] + [Switch]$ExcludeBots, + + [Parameter()] + [String]$ShlinkServer, + + [Parameter()] + [SecureString]$ShlinkApiKey + ) + + try { + GetShlinkConnection -Server $ShlinkServer -ApiKey $ShlinkApiKey + } + catch { + Write-Error -ErrorRecord $_ -ErrorAction "Stop" + } + + $QueryString = [System.Web.HttpUtility]::ParseQueryString('') + + $Params = @{ + Endpoint = "visits" + Path = "non-orphan" + PropertyTree = "visits", "data" + } + + switch ($PSBoundParameters.Keys) { + "StartDate" { + $QueryString.Add("startDate", (Get-Date $StartDate -Format "yyyy-MM-ddTHH:mm:sszzzz")) + } + "EndDate" { + $QueryString.Add("endDate", (Get-Date $EndDate -Format "yyyy-MM-ddTHH:mm:sszzzz")) + } + "ExcludeBots" { + $QueryString.Add("excludeBots", "true") + } + } + + $Params["Query"] = $QueryString + + try { + InvokeShlinkRestMethod @Params + } + catch { + Write-Error -ErrorRecord $_ + } +} \ No newline at end of file diff --git a/PSShlink/Public/Get-ShlinkVisitsOrphan.ps1 b/src/Public/Get-ShlinkVisitsOrphan.ps1 similarity index 100% rename from PSShlink/Public/Get-ShlinkVisitsOrphan.ps1 rename to src/Public/Get-ShlinkVisitsOrphan.ps1 diff --git a/PSShlink/Public/New-ShlinkUrl.ps1 b/src/Public/New-ShlinkUrl.ps1 similarity index 100% rename from PSShlink/Public/New-ShlinkUrl.ps1 rename to src/Public/New-ShlinkUrl.ps1 diff --git a/PSShlink/Public/Remove-ShlinkTag.ps1 b/src/Public/Remove-ShlinkTag.ps1 similarity index 96% rename from PSShlink/Public/Remove-ShlinkTag.ps1 rename to src/Public/Remove-ShlinkTag.ps1 index 341cd38..930ff7e 100644 --- a/PSShlink/Public/Remove-ShlinkTag.ps1 +++ b/src/Public/Remove-ShlinkTag.ps1 @@ -85,9 +85,9 @@ function Remove-ShlinkTag { } if ($PSCmdlet.ShouldProcess( - ("Would delete tag '{0}' from Shlink server '{1}'" -f ([String]::Join("', '", $Tags)), $Script:ShlinkServer), + ("Would delete tag '{0}' from Shlink server '{1}'" -f $Tag, $Script:ShlinkServer), "Are you sure you want to continue?", - ("Removing tag '{0}' from Shlink server '{1}'" -f ([String]::Join("', '", $Tags)), $Script:ShlinkServer))) { + ("Removing tag '{0}' from Shlink server '{1}'" -f $Tag, $Script:ShlinkServer))) { try { InvokeShlinkRestMethod @Params } diff --git a/PSShlink/Public/Remove-ShlinkUrl.ps1 b/src/Public/Remove-ShlinkUrl.ps1 similarity index 100% rename from PSShlink/Public/Remove-ShlinkUrl.ps1 rename to src/Public/Remove-ShlinkUrl.ps1 diff --git a/PSShlink/Public/Save-ShlinkUrlQrCode.ps1 b/src/Public/Save-ShlinkUrlQrCode.ps1 similarity index 94% rename from PSShlink/Public/Save-ShlinkUrlQrCode.ps1 rename to src/Public/Save-ShlinkUrlQrCode.ps1 index dd6db0a..0863219 100644 --- a/PSShlink/Public/Save-ShlinkUrlQrCode.ps1 +++ b/src/Public/Save-ShlinkUrlQrCode.ps1 @@ -28,6 +28,10 @@ function Save-ShlinkUrlQrCode { Specify the level of error correction you would like in the QR code. Choose from L for low, M for medium, Q for quartile, or H for high. If omitted, the default configuration of your Shlink server is used. + .PARAMETER RoundBlockSize + Allows to disable block size rounding, which might reduce the readability of the QR code, but ensures no extra margin is added. + Possible values are true or false boolean types. + If omitted, the default configuration of your Shlink server is used. .PARAMETER ShlinkServer The URL of your Shlink server (including schema). For example "https://example.com". It is not required to use this parameter for every use of this function. When it is used once for any of the functions in the PSShlink module, its value is retained throughout the life of the PowerShell session and its value is only accessible within the module's scope. @@ -78,6 +82,9 @@ function Save-ShlinkUrlQrCode { [ValidateSet("L", "M", "Q", "H")] [String]$ErrorCorrection, + [Parameter()] + [Bool]$RoundBlockSize, + [Parameter(ParameterSetName="SpecifyProperties")] [String]$ShlinkServer, @@ -100,6 +107,9 @@ function Save-ShlinkUrlQrCode { "ErrorCorrection" { $QueryString.Add("errorCorrection", $ErrorCorrection) } + "RoundBlockSize" { + $QueryString.Add("roundBlockSize", $RoundBlockSize.ToString().ToLower()) + } } if ($PSCmdlet.ParameterSetName -ne "InputObject") { diff --git a/PSShlink/Public/Set-ShlinkDomainRedirects.ps1 b/src/Public/Set-ShlinkDomainRedirects.ps1 similarity index 100% rename from PSShlink/Public/Set-ShlinkDomainRedirects.ps1 rename to src/Public/Set-ShlinkDomainRedirects.ps1 diff --git a/PSShlink/Public/Set-ShlinkTag.ps1 b/src/Public/Set-ShlinkTag.ps1 similarity index 100% rename from PSShlink/Public/Set-ShlinkTag.ps1 rename to src/Public/Set-ShlinkTag.ps1 diff --git a/PSShlink/Public/Set-ShlinkUrl.ps1 b/src/Public/Set-ShlinkUrl.ps1 similarity index 100% rename from PSShlink/Public/Set-ShlinkUrl.ps1 rename to src/Public/Set-ShlinkUrl.ps1 diff --git a/PSShlink/en-US/about_PSShlink.help.txt b/src/en-US/about_PSShlink.help.txt similarity index 100% rename from PSShlink/en-US/about_PSShlink.help.txt rename to src/en-US/about_PSShlink.help.txt diff --git a/tests/Public/New-ShlinkUrl.Tests.ps1 b/tests/Public/New-ShlinkUrl.Tests.ps1 index 03dff40..b09ef17 100644 --- a/tests/Public/New-ShlinkUrl.Tests.ps1 +++ b/tests/Public/New-ShlinkUrl.Tests.ps1 @@ -1,7 +1,9 @@ BeforeAll { - Import-Module $PSScriptRoot/../../../build/PSShlink/PSShlink.psd1 -Force - $env:ShlinkServer = "https://acook.io" - $env:ShlinkAPIKey = (Get-Secure "Shlink").Password | ConvertFrom-SecureString + # Check if module is already imported, as it can be via VSCode task where you can choose what code base to test + # and you might not want to cloober it with the non-built code + if (-not (Get-Module PSShlink)) { + Import-Module $PSScriptRoot/../../src/PSShlink.psd1 -Force + } } Describe "Create new short URLs" { @@ -34,7 +36,7 @@ Describe "Create new short URLs" { It "New invalid short URL with validation off" { $Guid = (New-Guid).Guid - # Multiply guid string by 3 because ideally we really do not want a valid URL + # Multiply guid string by 3 because ideally we *really* do not want a valid URL $Url = 'https://{0}.com' -f ($Guid * 3) { Invoke-WebRequest -Uri $Url -ErrorAction 'Stop' } | Should -Throw -ExceptionType ([System.Net.Http.HttpRequestException])