From 84f90265b0bbf40846d96db8d1bc0160c236ba7b Mon Sep 17 00:00:00 2001 From: rulasg Date: Sun, 9 Mar 2025 00:18:59 +0100 Subject: [PATCH 01/11] feat: enhance Salesforce data handling with new opportunity support and refactor attribute management --- Test/include/database.mock.ps1 | 8 ++ Test/private/mock_SfDataQueery.ps1 | 19 +++++ ...ata-query-account_0010V00002KIWkaQAH.json} | 0 ...-query-opportunity_0065c00001SFRbYAAX.json | 18 +++++ Test/public/Get-SfObjectIdFromUrl.test.ps1 | 2 +- Test/public/getsfopportunity.test.ps1 | 58 +++++++++++++++ Test/public/getstaccount.test.ps1 | 69 ++++++++++++++++++ Test/public/sfDataQuery.test.ps1 | 37 ---------- public/getsfaccount.ps1 | 40 +--------- public/getsfopportunity.ps1 | 73 +++++++++++++++++++ public/sfDataQuery.ps1 | 2 +- public/sfconfig.ps1 | 8 +- public/transformations.ps1 | 44 +++++++++++ 13 files changed, 298 insertions(+), 80 deletions(-) create mode 100644 Test/private/mock_SfDataQueery.ps1 rename Test/private/mocks/{sf-data-query-account.json => sf-data-query-account_0010V00002KIWkaQAH.json} (100%) create mode 100644 Test/private/mocks/sf-data-query-opportunity_0065c00001SFRbYAAX.json create mode 100644 Test/public/getsfopportunity.test.ps1 create mode 100644 Test/public/getstaccount.test.ps1 delete mode 100644 Test/public/sfDataQuery.test.ps1 create mode 100644 public/getsfopportunity.ps1 create mode 100644 public/transformations.ps1 diff --git a/Test/include/database.mock.ps1 b/Test/include/database.mock.ps1 index 5c5ed6f..b64721b 100644 --- a/Test/include/database.mock.ps1 +++ b/Test/include/database.mock.ps1 @@ -5,8 +5,16 @@ function Mock_Database([switch]$ResetDatabase){ MockCallToString $DB_INVOKE_GET_ROOT_PATH_CMD -OutString "test_database_path" + $dbstore = Invoke-MyCommand -Command $DB_INVOKE_GET_ROOT_PATH_CMD + Assert-AreEqual -Expected "test_database_path" -Presented $dbstore + if($ResetDatabase){ Reset-DatabaseStore } +} + +function Get-Mock_DatabaseStore{ + $dbstore = Invoke-MyCommand -Command $DB_INVOKE_GET_ROOT_PATH_CMD + return $dbstore } \ No newline at end of file diff --git a/Test/private/mock_SfDataQueery.ps1 b/Test/private/mock_SfDataQueery.ps1 new file mode 100644 index 0000000..c519389 --- /dev/null +++ b/Test/private/mock_SfDataQueery.ps1 @@ -0,0 +1,19 @@ +function Mock_SfDataQuery { + [CmdletBinding()] + param ( + [Parameter(Mandatory = $true)][string]$attrib, + [Parameter(Mandatory = $true)][string]$type, + [Parameter(Mandatory = $true)][string]$id, + [Parameter(Mandatory = $true)][string]$filename + + ) + + $command = 'sf data query --query "SELECT {attributes} FROM {type} WHERE Id=''{id}''" -r=json' + $command = $command -replace "{attributes}", $attrib + $command = $command -replace "{type}", $type + $command = $command -replace "{id}", $id + MockCall -Command $command -filename $filename +} + +#sf data query --query "SELECT Id,Name,OwnerId FROM opportunity WHERE Id='0065c00001SFRbYAAX'" -r=json +#sf data query --query "SELECT Id,Name FROM Opportunity WHERE Id='0065c00001SFRbYAAX'" -r=json \ No newline at end of file diff --git a/Test/private/mocks/sf-data-query-account.json b/Test/private/mocks/sf-data-query-account_0010V00002KIWkaQAH.json similarity index 100% rename from Test/private/mocks/sf-data-query-account.json rename to Test/private/mocks/sf-data-query-account_0010V00002KIWkaQAH.json diff --git a/Test/private/mocks/sf-data-query-opportunity_0065c00001SFRbYAAX.json b/Test/private/mocks/sf-data-query-opportunity_0065c00001SFRbYAAX.json new file mode 100644 index 0000000..a0cbc66 --- /dev/null +++ b/Test/private/mocks/sf-data-query-opportunity_0065c00001SFRbYAAX.json @@ -0,0 +1,18 @@ +{ + "status": 0, + "result": { + "records": [ + { + "attributes": { + "type": "Opportunity", + "url": "/services/data/v63.0/sobjects/Opportunity/0065c00001SFRbYAAX" + }, + "Id": "0065c00001SFRbYAAX", + "Name": "Secret Services IT 10 Seat 2025_Q3 Order", + "OwnerId": "0053o000008Skv3AAC" + } + ], + "totalSize": 1, + "done": true + } +} diff --git a/Test/public/Get-SfObjectIdFromUrl.test.ps1 b/Test/public/Get-SfObjectIdFromUrl.test.ps1 index dca5d81..6d539d5 100644 --- a/Test/public/Get-SfObjectIdFromUrl.test.ps1 +++ b/Test/public/Get-SfObjectIdFromUrl.test.ps1 @@ -1,4 +1,4 @@ -function Test_GetSfAccountFromUrl{ +function Test_fObjectIdFromUrl{ . $PSScriptRoot/../../private/auxiliarfunctions.ps1 diff --git a/Test/public/getsfopportunity.test.ps1 b/Test/public/getsfopportunity.test.ps1 new file mode 100644 index 0000000..816ce61 --- /dev/null +++ b/Test/public/getsfopportunity.test.ps1 @@ -0,0 +1,58 @@ + +function Test_GetSfOpportunity{ + + Reset-InvokeCommandMock + Mock_Database -ResetDatabase + Mock_Config + + # Mock Sf call + $id = "0065c00001SFRbYAAX" + $cacheFileName = "sfDataQuery-opportunity-$id--1356351343.json" + $url = "https://github.lightning.force.com/lightning/r/Account/$id/view" + Mock_SfDataQuery_Opportunity_0065c00001SFRbYAAX + + # Act with out cache + $result = Get-SfOpportunity -SfUrl $url + + # Assert + Assert-AreEqual -Expected $id -Presented $result.Id + $path = Get-Mock_DatabaseStore | Join-Path -ChildPath $cacheFileName + Assert-ItemExist -Path $path + + # Remove sf data + Reset-InvokeCommandMock + Mock_Database + Mock_Config + + # Act with cache + $result = Get-SfOpportunity -SfUrl $url + + # Assert + Assert-AreEqual -Expected $id -Presented $result.Id + +} + +function Test_GetSfOpportunity_Live{ + Assert-SkipTest "Test live connection to Salesforce" + + Reset-InvokeCommandMock + Enable-InvokeCommandAliasModule + + $result = Get-SfOpportunity https://github.lightning.force.com/lightning/r/Opportunity/0065c00001SFRbYAAX/view + Assert-notnull -Object $result + + Assert-NotImplemented +} + + +function Mock_SfDataQuery_Opportunity_0065c00001SFRbYAAX{ + [CmdletBinding()] + param() + + $attrib = "Id,Name,OwnerId" + $type = "Opportunity" + $id = "0065c00001SFRbYAAX" + $filename = "sf-data-query-opportunity_0065c00001SFRbYAAX.json" + + Mock_SfDataQuery -attrib $attrib -type $type -id $id -filename $filename +} \ No newline at end of file diff --git a/Test/public/getstaccount.test.ps1 b/Test/public/getstaccount.test.ps1 new file mode 100644 index 0000000..4492332 --- /dev/null +++ b/Test/public/getstaccount.test.ps1 @@ -0,0 +1,69 @@ +function Test_GetSfAccount{ + + Reset-InvokeCommandMock + + $mockAttrib = @{account_attributes = @("Potential_Seats_Manual__c","Website","PhotoUrl")} + + # Mocks + Mock_Database -ResetDatabase + Mock_Config -Config $mockAttrib + + # Mock Sf call + $id = "0010V00002KIWkaQAH" + $url = "https://github.lightning.force.com/lightning/r/Account/$id/view" + $filename = "sfDataQuery-Account-0010V00002KIWkaQAH-2035968354.json" + Mock_SfDataQuery_Account_0010V00002KIWkaQAH -AdditionalAttributes $mockAttrib.account_attributes + + # Act with out cache + $result = Get-SfAccount -SfUrl $url + + # Assert with cache + Assert-AreEqual -Expected $id -Presented $result.Id + $path = Get-Mock_DatabaseStore | Join-Path -ChildPath $filename + Assert-ItemExist -Path $path + + # Reset Mock and skip Mock_SfDataQuery_Account_0010V00002KIWkaQAH + Reset-InvokeCommandMock + Mock_Database + Mock_Config -Config $mockAttrib + + # Act with cache + $result = Get-SfAccount -SfUrl $url + + # Assert + Assert-AreEqual -Expected "0010V00002KIWkaQAH" -Presented $result.Id +} + +function Test_GetSfAccount_Transformations{ + Reset-InvokeCommandMock + + # Mocks + Mock_Database -ResetDatabase + Mock_Config + Mock_SfDataQuery_Account_0010V00002KIWkaQAH + + # Act with out cache + $result = Get-SfAccount https://github.lightning.force.com/lightning/r/Account/0010V00002KIWkaQAH/view + + # Assert + Assert-AreEqual -Expected "Oana Dinca" -Presented $result.OwnerName + +} + +function Mock_SfDataQuery_Account_0010V00002KIWkaQAH{ + [CmdletBinding()] + param( + [Parameter(Position=0)][string[]]$AdditionalAttributes + ) + + $attrib = "Id,Name,OwnerId,Industry,Account_Owner__c,Account_Segment__c,Account_Owner_Role__c,Account_Tier__c,Potential_Seats__c,Country_Name__c,Current_Seats__c,Current_ARR_10__c,Salesforce_Record_URL__c" + $type = "Account" + $id = "0010V00002KIWkaQAH" + $filename = "sf-data-query-account_0010V00002KIWkaQAH.json" + + if ($AdditionalAttributes) { + $attrib += "," + ($AdditionalAttributes -join ",") + } + + Mock_SfDataQuery -attrib $attrib -type $type -id $id -filename $filename +} diff --git a/Test/public/sfDataQuery.test.ps1 b/Test/public/sfDataQuery.test.ps1 deleted file mode 100644 index 8fd9530..0000000 --- a/Test/public/sfDataQuery.test.ps1 +++ /dev/null @@ -1,37 +0,0 @@ -function Test_GetSfAccount{ - - Reset-InvokeCommandMock - Mock_Database -ResetDatabase - $mockAttrib = @{attributes = @("Potential_Seats_Manual__c","Website","PhotoUrl")} - Mock_Config -Config $mockAttrib - - $dbstore = Invoke-MyCommand -Command $DB_INVOKE_GET_ROOT_PATH_CMD - Assert-AreEqual -Expected "test_database_path" -Presented $dbstore - - $attrib = "Id,Name,OwnerId,Industry,Account_Owner__c,Account_Segment__c,Account_Owner_Role__c,Account_Tier__c,Potential_Seats__c,Country_Name__c,Current_Seats__c,Current_ARR_10__c,Salesforce_Record_URL__c,Potential_Seats_Manual__c,Website,PhotoUrl" - $type = "Account" - $id = "0010V00002KIWkaQAH" - - $command = 'sf data query --query "SELECT {attributes} FROM {type} WHERE Id=''{id}''" -r=json' - $command = $command -replace "{attributes}", $attrib - $command = $command -replace "{type}", $type - $command = $command -replace "{id}", $id - MockCall -Command $command -filename "sf-data-query-account.json" - - # Act with out cache - $result = get-sfAccount https://github.lightning.force.com/lightning/r/Account/0010V00002KIWkaQAH/view - Assert-AreEqual -Expected $Id -Presented $result.Id - $dbfiles = Get-ChildItem $dbstore - Assert-Count -Expected 1 -Presented $dbfiles - Assert-IsTrue -Condition ($dbfiles[0].Name -like "sfDataQuery*-$type-$id-*.json") - - # Remove sf data - Reset-InvokeCommandMock - Mock_Database - Mock_Config -Config $mockAttrib - - # Act with cache - $result = Get-SfAccount https://github.lightning.force.com/lightning/r/Account/0010V00002KIWkaQAH/view - Assert-AreEqual -Expected $Id -Presented $result.Id - -} \ No newline at end of file diff --git a/public/getsfaccount.ps1 b/public/getsfaccount.ps1 index 7cce9b5..3a74830 100644 --- a/public/getsfaccount.ps1 +++ b/public/getsfaccount.ps1 @@ -1,7 +1,4 @@ -$PROFILE_ATTRIBUTES_FILE_PATH = "~/.helpers/sfhelper/sfattributes.txt" - - <# .SYNOPSIS Retrieves Salesforce Account data based on the specified Salesforce URL. @@ -52,16 +49,17 @@ function Get-SfAccount{ "Salesforce_Record_URL__c" ) + # Add attributes from parameter if ($AdditionalAttributes) { $additionalAttributesArray = $AdditionalAttributes -split "," "adding attributes from additional attributes $additionalAttributesArray" | Write-Verbose $attributes += $additionalAttributesArray | Select-Object -Unique } - ## Add attributes from file + ## Add attributes from config if (Test-Configuration ) { $config = Get-Configuration - $attributesFromConfig = $config.attributes + $attributesFromConfig = $config.account_attributes "adding attributes from config $($attributesFromConfig -join ',' )" | Write-Verbose $attributes += $attributesFromConfig | Select-Object -Unique } @@ -80,36 +78,4 @@ function Get-SfAccount{ return $ret } Export-ModuleMember -Function Get-SfAccount -# Function to extract Owner Name from HTML -function Get-OwnerNameFromHtml { - param ( - [string]$html - ) - - if ([string]::IsNullOrEmpty($html)) { - return "" - } - - if ($html -match ']*>([^<]+)') { - return $matches[1] - } - return $null -} - -<# -.SYNOPSIS -Edit profile attributes file -#> -function Edit-SfProfileAttributesFile { - param ( - [string]$FilePath = $PROFILE_ATTRIBUTES_FILE_PATH - ) - - if (-not (Test-Path $FilePath)) { - $null = New-Item -Path $FilePath -ItemType File -Force - } - - Write-Host $FilePath - code $FilePath -} Export-ModuleMember -Function Edit-SfProfileAttributesFile diff --git a/public/getsfopportunity.ps1 b/public/getsfopportunity.ps1 new file mode 100644 index 0000000..404a627 --- /dev/null +++ b/public/getsfopportunity.ps1 @@ -0,0 +1,73 @@ + + +<# +.SYNOPSIS +Retrieves Salesforce Opportunity data based on the specified Salesforce URL. + +.DESCRIPTION +The `Get-SfOpportunity` function extracts the Salesforce Opportunity ID from the provided URL and retrieves the specified attributes for the Opportunity object. It uses the `Get-SfDataQuery` function to perform the query and returns the result as a PowerShell object. The function also performs transformations to clean up certain fields. + +.PARAMETER SfUrl +The Salesforce URL of the Opportunity object to query. + +.OUTPUTS +The function returns a PowerShell object representing the queried Salesforce Opportunity data. If the query is unsuccessful or the object is not found, the function returns `$null`. + +.EXAMPLE +PS> $sfUrl = "https://example.salesforce.com/0013o00002OHreEAAT" +PS> $result = Get-SfOpportunity -SfUrl $sfUrl +PS> $result + +This example retrieves the specified attributes for the Salesforce Opportunity object with the ID extracted from the provided URL. + +#> +function Get-SfOpportunity{ + [CmdletBinding()] + param( + [Parameter(Mandatory,Position=0)][string]$SfUrl, + [string]$AdditionalAttributes + ) + + # Extract Id from URL + $Id = Get-SfObjectIdFromUrl -SfUrl $SfUrl + + $attributes = @( + "Id", + "Name" + "OwnerId" + # "Industry", + # "Account_Owner__c", + # "Account_Segment__c", + # "Account_Owner_Role__c", + # "Account_Tier__c", + # "Potential_Seats__c", + # "Country_Name__c", + # "Current_Seats__c", + # "Current_ARR_10__c", + # "Salesforce_Record_URL__c" + ) + + # Add attributes from parameter + if ($AdditionalAttributes) { + $additionalAttributesArray = $AdditionalAttributes -split "," + "adding attributes from additional attributes $additionalAttributesArray" | Write-Verbose + $attributes += $additionalAttributesArray | Select-Object -Unique + } + + ## Add attributes from file + if (Test-Configuration ) { + $config = Get-Configuration + $attributesFromConfig = $config.opportunity_attributes + "adding attributes from config $($attributesFromConfig -join ',' )" | Write-Verbose + $attributes += $attributesFromConfig | Select-Object -Unique + } + + # Get object + $ret = Get-SfDataQuery -Type opportunity -Id $Id -Attributes $attributes + + # Transformations + + # $ret.PsObject.Properties.Remove("attributes") + + return $ret +} Export-ModuleMember -Function Get-SfOpportunity diff --git a/public/sfDataQuery.ps1 b/public/sfDataQuery.ps1 index 7cf0b07..a6cbd62 100644 --- a/public/sfDataQuery.ps1 +++ b/public/sfDataQuery.ps1 @@ -3,7 +3,7 @@ Set-MyInvokeCommandAlias -Alias "sfDataQuery" -Command 'sf data query --query " function Get-SfDataQuery{ [CmdletBinding()] param( - [Parameter(Mandatory)][ValidateSet("Account", "User")][string]$Type, + [Parameter(Mandatory)][ValidateSet("Account", "User", "Opportunity")][string]$Type, [Parameter(Mandatory)][string]$Id, [Parameter(Mandatory)][string[]]$Attributes ) diff --git a/public/sfconfig.ps1 b/public/sfconfig.ps1 index 0a496fd..4b690df 100644 --- a/public/sfconfig.ps1 +++ b/public/sfconfig.ps1 @@ -51,13 +51,13 @@ function Add-SfConfigAttribute{ $config = @{} } - if(-Not $config.attributes){ - $config.attributes = @() + if(-Not $config.account_attributes){ + $config.account_attributes = @() } } process{ - $config.attributes += $Attribute + $config.account_attributes += $Attribute } End{ @@ -67,7 +67,7 @@ function Add-SfConfigAttribute{ } $config = Get-SfConfig - Write-Output $config.attributes + Write-Output $config.account_attributes } diff --git a/public/transformations.ps1 b/public/transformations.ps1 new file mode 100644 index 0000000..32146d8 --- /dev/null +++ b/public/transformations.ps1 @@ -0,0 +1,44 @@ +function Edit-AttributeValueFromHTML{ + [CmdletBinding()] + [OutputType([object])] + param( + [Parameter(Mandatory,Position=0)][string]$AttributeName, + [Parameter(Mandatory,Position=1)][string]$NewAttributeName, + [Parameter(Mandatory,ValueFromPipeline,Position=2)][object]$Object, + [Parameter()][switch] $RemoveOriginalAttribute + ) + + $value = Get-OwnerNameFromHtml -html $($Object.$AttributeName) + + # return if value is null + if ($value -eq $null) { + "Attribute $AttributeName is not found or empty in object $($object.id)" | Write-Warning + return $Object + } + + # Add the new attribute + Add-Member -InputObject $ret -MemberType NoteProperty -Name $NewAttributeName -Value $value + + if ($RemoveOriginalAttribute) { + $Object.Properties.Remove($AttributeName) + } + + return $Object + +} + +# Function to extract Owner Name from HTML +function Get-OwnerNameFromHtml { + param ( + [string]$html + ) + + if ([string]::IsNullOrEmpty($html)) { + return "" + } + + if ($html -match ']*>([^<]+)') { + return $matches[1] + } + return $null +} \ No newline at end of file From dd8f8fb690343db463dc956436646731d42a8d9d Mon Sep 17 00:00:00 2001 From: rulasg Date: Sun, 9 Mar 2025 04:06:00 +0100 Subject: [PATCH 02/11] feat: add Get-HashCode function for MD5 hashing and update tests with new cache file naming --- Test/public/getsfopportunity.test.ps1 | 2 +- Test/public/getstaccount.test.ps1 | 2 +- include/getHashCode.ps1 | 21 +++++++++++++++++++++ public/sfDataQuery.ps1 | 2 +- 4 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 include/getHashCode.ps1 diff --git a/Test/public/getsfopportunity.test.ps1 b/Test/public/getsfopportunity.test.ps1 index 816ce61..707162c 100644 --- a/Test/public/getsfopportunity.test.ps1 +++ b/Test/public/getsfopportunity.test.ps1 @@ -7,7 +7,7 @@ function Test_GetSfOpportunity{ # Mock Sf call $id = "0065c00001SFRbYAAX" - $cacheFileName = "sfDataQuery-opportunity-$id--1356351343.json" + $cacheFileName = "sfDataQuery-opportunity-$id-5106802FEB193611777BC7DA26122EF5.json" $url = "https://github.lightning.force.com/lightning/r/Account/$id/view" Mock_SfDataQuery_Opportunity_0065c00001SFRbYAAX diff --git a/Test/public/getstaccount.test.ps1 b/Test/public/getstaccount.test.ps1 index 4492332..2a39bf3 100644 --- a/Test/public/getstaccount.test.ps1 +++ b/Test/public/getstaccount.test.ps1 @@ -11,7 +11,7 @@ function Test_GetSfAccount{ # Mock Sf call $id = "0010V00002KIWkaQAH" $url = "https://github.lightning.force.com/lightning/r/Account/$id/view" - $filename = "sfDataQuery-Account-0010V00002KIWkaQAH-2035968354.json" + $filename = "sfDataQuery-Account-$id-01F5F2DFDE481D1146E8D504BB935E4D.json" Mock_SfDataQuery_Account_0010V00002KIWkaQAH -AdditionalAttributes $mockAttrib.account_attributes # Act with out cache diff --git a/include/getHashCode.ps1 b/include/getHashCode.ps1 new file mode 100644 index 0000000..3b9f166 --- /dev/null +++ b/include/getHashCode.ps1 @@ -0,0 +1,21 @@ + +# This script defines a function to compute the MD5 hash of a given string. +# The hash is returned as a hexadecimal string without dashes. +# The function is useful for generating unique keys based on input strings, +# such as for caching purposes in a database or other storage. +# The hash generated is equal on all environments making it usedfull across computers. + +function Get-HashCode { + param ( + [Parameter(Mandatory,ValueFromPipeline,Position=0)] + [string]$InputString + ) + + # Generate MD5 hash + $md5 = [System.Security.Cryptography.MD5]::Create() + $bytes = [System.Text.Encoding]::UTF8.GetBytes($InputString) + $hashBytes = $md5.ComputeHash($bytes) + $hashString = [BitConverter]::ToString($hashBytes) -replace '-', '' + + return $hashString +} \ No newline at end of file diff --git a/public/sfDataQuery.ps1 b/public/sfDataQuery.ps1 index a6cbd62..b4c9df2 100644 --- a/public/sfDataQuery.ps1 +++ b/public/sfDataQuery.ps1 @@ -57,7 +57,7 @@ function getcacheKey{ # Add hash of attributes to key $attribString = $Attributes -join "," "Attributes : $attribString" | Write-Verbose - $attributesHash = $attribString.GetHashCode() + $attributesHash = $attribString | Get-HashCode "AttributesHash : $attributesHash" | Write-Verbose $cacheKey = "sfDataQuery-$Type-$Id-$attributesHash" From 24f11a6038879cd3f34528f817d80df81c85eca5 Mon Sep 17 00:00:00 2001 From: rulasg Date: Sun, 9 Mar 2025 04:08:46 +0100 Subject: [PATCH 03/11] feat: introduce Set-MyInvokeCommandAlias function and related module variable for command alias management --- include/mySetInvokeCommandAlias.ps1 | 26 +++++++++++++++++++ .../mySetInvokeCommandAlias_Varaibles.ps1.ps1 | 3 +++ private/start/START.ps1 | 3 --- private/start/SetMyInvokeCommandAlias.ps1 | 21 --------------- 4 files changed, 29 insertions(+), 24 deletions(-) create mode 100644 include/mySetInvokeCommandAlias.ps1 create mode 100644 private/mySetInvokeCommandAlias_Varaibles.ps1.ps1 delete mode 100644 private/start/SetMyInvokeCommandAlias.ps1 diff --git a/include/mySetInvokeCommandAlias.ps1 b/include/mySetInvokeCommandAlias.ps1 new file mode 100644 index 0000000..be2826d --- /dev/null +++ b/include/mySetInvokeCommandAlias.ps1 @@ -0,0 +1,26 @@ + +# SET MY INVOKE COMMAND ALIAS +# +# Allows calling constitely InvokeHelper with the module tag +# Need to define a variable called $MODULE_INVOKATION_TAG +# +# Sample: +# $MODULE_INVOKATION_TAG = "SfHelperModule" + + +function Set-MyInvokeCommandAlias{ + [CmdletBinding(SupportsShouldProcess)] + param( + [Parameter(Mandatory,Position=0)][string]$Alias, + [Parameter(Mandatory,Position=1)][string]$Command + ) + + # throw if MODULE_INVOKATION_TAG is not set + if (-not $MODULE_INVOKATION_TAG) { + throw "MODULE_INVOKATION_TAG is not set. Please set it before calling Set-MyInvokeCommandAlias." + } + + if ($PSCmdlet.ShouldProcess("InvokeCommandAliasList", ("Add Command Alias [{0}] = [{1}]" -f $Alias, $Command))) { + InvokeHelper\Set-InvokeCommandAlias -Alias $Alias -Command $Command -Tag $MODULE_INVOKATION_TAG + } +} \ No newline at end of file diff --git a/private/mySetInvokeCommandAlias_Varaibles.ps1.ps1 b/private/mySetInvokeCommandAlias_Varaibles.ps1.ps1 new file mode 100644 index 0000000..f6d0833 --- /dev/null +++ b/private/mySetInvokeCommandAlias_Varaibles.ps1.ps1 @@ -0,0 +1,3 @@ +# Required by Include My SetInvokeCommandAlias + +$MODULE_INVOKATION_TAG = "SfHelperModule" diff --git a/private/start/START.ps1 b/private/start/START.ps1 index 8a7366f..0f66eee 100644 --- a/private/start/START.ps1 +++ b/private/start/START.ps1 @@ -6,9 +6,6 @@ if (! $LOADED_EARLYLOADED){ # This is useful when you have a dependency to run - # Load Invoke helper functions - . $(($PSScriptRoot | Join-Path -ChildPath SetMyInvokeCommandAlias.ps1 | Get-Item).FullName) - function Get-ModuleName{ $local = $PSScriptRoot | Split-Path -Parent | Split-Path -Parent $moduleName = (Get-ChildItem -Path $local -Filter *.psd1 | Select-Object -First 1).BaseName diff --git a/private/start/SetMyInvokeCommandAlias.ps1 b/private/start/SetMyInvokeCommandAlias.ps1 deleted file mode 100644 index 57cfcbc..0000000 --- a/private/start/SetMyInvokeCommandAlias.ps1 +++ /dev/null @@ -1,21 +0,0 @@ -# Managing dependencies - -# Gate to be loaded only onces -if (!$SET_MY_INVOKECOMMANDALIAS_LOADED){ - $SET_MY_INVOKECOMMANDALIAS_LOADED = $true - - $MODULE_INVOKATION_TAG = "SfHelperModule" - - function Set-MyInvokeCommandAlias{ - [CmdletBinding(SupportsShouldProcess)] - param( - [Parameter(Mandatory,Position=0)][string]$Alias, - [Parameter(Mandatory,Position=1)][string]$Command - ) - - if ($PSCmdlet.ShouldProcess("InvokeCommandAliasList", ("Add Command Alias [{0}] = [{1}]" -f $Alias, $Command))) { - InvokeHelper\Set-InvokeCommandAlias -Alias $Alias -Command $Command -Tag $MODULE_INVOKATION_TAG - } - } - -} \ No newline at end of file From fd9df0e34bc1e956a38ed86c98cb2c514f99ed08 Mon Sep 17 00:00:00 2001 From: rulasg Date: Sun, 9 Mar 2025 04:09:51 +0100 Subject: [PATCH 04/11] feat: add Invoke Command Mock functionality with support for command alias management and mock file handling --- Test/Test.psm1 | 6 +++--- .../invokeCommand.Mock.ps1} | 18 +++++++++++++----- Test/private/mock_variables.ps1 | 6 ++++++ 3 files changed, 22 insertions(+), 8 deletions(-) rename Test/{private/InvokeCommandMock.ps1 => include/invokeCommand.Mock.ps1} (87%) create mode 100644 Test/private/mock_variables.ps1 diff --git a/Test/Test.psm1 b/Test/Test.psm1 index 6fc3d0b..cb13f91 100644 --- a/Test/Test.psm1 +++ b/Test/Test.psm1 @@ -4,12 +4,12 @@ Write-Information -Message ("Loading {0} ..." -f ($PSCommandPath | Split-Path -L $MODULE_PATH = $PSScriptRoot #Get public and private function definition files. -$Include = @( Get-ChildItem -Path $MODULE_PATH\include\*.ps1 -Recurse -ErrorAction SilentlyContinue ) -$Public = @( Get-ChildItem -Path $MODULE_PATH\public\*.ps1 -Recurse -ErrorAction SilentlyContinue ) +$Include = @( Get-ChildItem -Path $MODULE_PATH\include\*.ps1 -ErrorAction SilentlyContinue ) $Private = @( Get-ChildItem -Path $MODULE_PATH\private\*.ps1 -Recurse -ErrorAction SilentlyContinue ) +$Public = @( Get-ChildItem -Path $MODULE_PATH\public\*.ps1 -Recurse -ErrorAction SilentlyContinue ) #Dot source the files -Foreach($import in @($Include + $Public + $Private)) +Foreach($import in @($Include + $Private + $Public)) { Try { diff --git a/Test/private/InvokeCommandMock.ps1 b/Test/include/invokeCommand.Mock.ps1 similarity index 87% rename from Test/private/InvokeCommandMock.ps1 rename to Test/include/invokeCommand.Mock.ps1 index 9762ab4..cd9cf19 100644 --- a/Test/private/InvokeCommandMock.ps1 +++ b/Test/include/invokeCommand.Mock.ps1 @@ -1,8 +1,16 @@ -# Managing dependencies -$MODULE_INVOKATION_TAG = "SfHelperModule" -$MODULE_INVOKATION_TAG_MOCK = "SfHelperModule-Mock" -$ROOT = $PSScriptRoot | Split-Path -Parent -$MOCK_PATH = $ROOT | Join-Path -ChildPath 'private' -AdditionalChildPath 'mocks' + +# INVOKE COMMAND MOCK +# +# This includes help commands to mock invokes in a test module +# You need to set the following variables +# $MODULE_INVOKATION_TAG : name of the module that you are testing. This needs to match with the Tag used in the module you are testing. +# $MODULE_INVOKATION_TAG_MOCK : Tag for the mock functions on the testing moodule you are loading this include in +# MOCK_PATH : path to the mocks folder. This is where the mock files will be saved and loaded from. +# +# Sample: +# $MODULE_INVOKATION_TAG = "SfHelperModule" +# $MODULE_INVOKATION_TAG_MOCK = "SfHelperModule-Mock" +# $MOCK_PATH = $PSScriptRoot | Split-Path -Parent | Join-Path -ChildPath 'private' -AdditionalChildPath 'mocks' function Set-InvokeCommandMock{ diff --git a/Test/private/mock_variables.ps1 b/Test/private/mock_variables.ps1 new file mode 100644 index 0000000..972f028 --- /dev/null +++ b/Test/private/mock_variables.ps1 @@ -0,0 +1,6 @@ + +# Required for INVOKE COMMAND MOCK + +$MODULE_INVOKATION_TAG = "SfHelperModule" +$MODULE_INVOKATION_TAG_MOCK = "SfHelperModule-Mock" +$MOCK_PATH = $PSScriptRoot | Split-Path -Parent | Join-Path -ChildPath 'private' -AdditionalChildPath 'mocks' \ No newline at end of file From a732cd0d88181b54754e8c1d83e1ab1e15f8cdf3 Mon Sep 17 00:00:00 2001 From: rulasg Date: Sun, 9 Mar 2025 04:10:03 +0100 Subject: [PATCH 05/11] fix: adjust file import order in SfHelper.psm1 for improved module loading --- SfHelper.psm1 | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/SfHelper.psm1 b/SfHelper.psm1 index 4d6908e..839784f 100644 --- a/SfHelper.psm1 +++ b/SfHelper.psm1 @@ -9,12 +9,12 @@ $START = Get-ChildItem -Path $MODULE_PATH -Filter start.ps1 -Recurse if($START | Test-Path){ . $($START | Get-Item).FullName } #Get public and private function definition files. -$Include = @( Get-ChildItem -Path $MODULE_PATH\include\*.ps1 -Recurse -ErrorAction SilentlyContinue ) -$Public = @( Get-ChildItem -Path $MODULE_PATH\public\*.ps1 -Recurse -ErrorAction SilentlyContinue ) +$Include = @( Get-ChildItem -Path $MODULE_PATH\include\*.ps1 -ErrorAction SilentlyContinue ) $Private = @( Get-ChildItem -Path $MODULE_PATH\private\*.ps1 -Recurse -ErrorAction SilentlyContinue ) +$Public = @( Get-ChildItem -Path $MODULE_PATH\public\*.ps1 -Recurse -ErrorAction SilentlyContinue ) #Dot source the files -Foreach($import in @($Include + $Public + $Private)) +Foreach($import in @($Include + $Private + $Public)) { Try { From 9fb48667cbc43423ffe956820b60ced449841068 Mon Sep 17 00:00:00 2001 From: rulasg Date: Sun, 9 Mar 2025 04:10:52 +0100 Subject: [PATCH 06/11] feat: enhance configuration and database modules with improved documentation and error handling --- include/config.ps1 | 9 ++++++--- include/databaseV2.ps1 | 14 ++++++++++---- include/getHashCode.ps1 | 2 ++ private/auxiliarfunctions.ps1 | 3 ++- public/sfDatabase.ps1 | 3 ++- public/sfconfig.ps1 | 3 +++ 6 files changed, 25 insertions(+), 9 deletions(-) diff --git a/include/config.ps1 b/include/config.ps1 index f446200..6c0a1ae 100644 --- a/include/config.ps1 +++ b/include/config.ps1 @@ -1,5 +1,7 @@ +# CONFIG +# # Configuration management module - +# # Include design description # This is the function ps1. This file is the same for all modules. # Create a public psq with variables, Set-MyInvokeCommandAlias call and Invoke public function. @@ -10,7 +12,7 @@ # All functions of this ps1 will depend on `GetConfigFile` for functionality. # # TODO : Create a related public ps1 - +# # Create a related public ps1 # 1. define $CONFIG_INVOKE_GET_ROOT_PATH_ALIAS. Make it unique. # 2. define $CONFIG_INVOKE_GET_ROOT_PATH_CMD. Point to the invoke function that calls GetConfigRootPath to get the store path @@ -27,7 +29,8 @@ # } Export-ModuleMember -Function Invoke-MyModuleGetConfigRootPath -$moduleName = Get-ModuleName +$moduleRootPath = $PSScriptRoot | Split-Path -Parent +$moduleName = (Get-ChildItem -Path $moduleRootPath -Filter *.psd1 | Select-Object -First 1).BaseName $CONFIG_ROOT = [System.Environment]::GetFolderPath('UserProfile') | Join-Path -ChildPath ".helpers" -AdditionalChildPath $moduleName, "config" # Create the config root if it does not exist diff --git a/include/databaseV2.ps1 b/include/databaseV2.ps1 index 02a009c..4829f94 100644 --- a/include/databaseV2.ps1 +++ b/include/databaseV2.ps1 @@ -1,5 +1,7 @@ +# DATABASE V2 +# # Database driver to store the cache - +# # Include design description # This is the function ps1. This file is the same for all modules. # Create a public psq with variables, Set-MyInvokeCommandAlias call and Invoke public function. @@ -28,9 +30,8 @@ # # } Export-ModuleMember -Function Invoke-SfGetDbRootPath -# Invoke to allow mockig the store path on testing - -$moduleName = Get-ModuleName +$moduleRootPath = $PSScriptRoot | Split-Path -Parent +$moduleName = (Get-ChildItem -Path $moduleRootPath -Filter *.psd1 | Select-Object -First 1).BaseName $DATABASE_ROOT = [System.Environment]::GetFolderPath('UserProfile') | Join-Path -ChildPath ".helpers" -AdditionalChildPath $moduleName, "databaseCache" # Create the database root if it does not exist @@ -52,6 +53,11 @@ function GetDatabaseFile{ [Parameter(Position = 0)][string]$Key ) + # throw if DB_INVOKE_GET_ROOT_PATH_ALIAS is not set + if (-not $DB_INVOKE_GET_ROOT_PATH_ALIAS) { + throw "DB_INVOKE_GET_ROOT_PATH_ALIAS is not set. Please set it before calling GetDatabaseFile." + } + $databaseRoot = Invoke-MyCommand -Command $DB_INVOKE_GET_ROOT_PATH_ALIAS $path = $databaseRoot | Join-Path -ChildPath "$Key.json" diff --git a/include/getHashCode.ps1 b/include/getHashCode.ps1 index 3b9f166..a235823 100644 --- a/include/getHashCode.ps1 +++ b/include/getHashCode.ps1 @@ -1,4 +1,6 @@ +# Get HASH CODE +# # This script defines a function to compute the MD5 hash of a given string. # The hash is returned as a hexadecimal string without dashes. # The function is useful for generating unique keys based on input strings, diff --git a/private/auxiliarfunctions.ps1 b/private/auxiliarfunctions.ps1 index c3aa86f..9928d14 100644 --- a/private/auxiliarfunctions.ps1 +++ b/private/auxiliarfunctions.ps1 @@ -19,4 +19,5 @@ function Get-SfObjectIdFromUrl { } else { throw "Invalid Salesforce Object URL $SfUrl" } -} \ No newline at end of file +} + diff --git a/public/sfDatabase.ps1 b/public/sfDatabase.ps1 index 6bb48ad..19452f1 100644 --- a/public/sfDatabase.ps1 +++ b/public/sfDatabase.ps1 @@ -1,4 +1,4 @@ - +# This file is required for INCLUDE DATABASE V2 $DB_INVOKE_GET_ROOT_PATH_ALIAS = "SfGetDbRootPath" $DB_INVOKE_GET_ROOT_PATH_CMD = "Invoke-SfGetDbRootPath" @@ -14,6 +14,7 @@ function Invoke-SfGetDbRootPath{ } Export-ModuleMember -Function Invoke-SfGetDbRootPath +# Extra functions not needed by INCLUDE DATABASE V2 function Reset-DatabaseStore{ [CmdletBinding()] diff --git a/public/sfconfig.ps1 b/public/sfconfig.ps1 index 4b690df..7fb8e02 100644 --- a/public/sfconfig.ps1 +++ b/public/sfconfig.ps1 @@ -1,3 +1,4 @@ +# Required by INCLUDE CONFIG $CONFIG_INVOKE_GET_ROOT_PATH_ALIAS = "SfGetConfigRootPath" $CONFIG_INVOKE_GET_ROOT_PATH_CMD = "Invoke-SfGetConfigRootPath" @@ -10,6 +11,8 @@ function Invoke-SfGetConfigRootPath{ } Export-ModuleMember -Function Invoke-SfGetConfigRootPath +# Extra functions not needed by INCLUDE CONFIG + function Get-SfConfig{ [CmdletBinding()] param() From d8d5c58a5b7c214db8be9f75eb72714705f025f3 Mon Sep 17 00:00:00 2001 From: rulasg Date: Sun, 9 Mar 2025 04:53:07 +0100 Subject: [PATCH 07/11] feat: implement Get-SfObjectTypeFromUrl function and enhance URL validation in related functions --- Test/public/Get-SfObjectIdFromUrl.test.ps1 | 17 --------- Test/public/auxiliarfunctions.test.ps1 | 42 +++++++++++++++++++++ Test/public/getsfopportunity.test.ps1 | 2 +- Test/public/sfConfig.test.ps1 | 43 ++++++++++++++++++++++ include/config.ps1 | 2 +- private/auxiliarfunctions.ps1 | 23 ++++++++++++ public/getsfaccount.ps1 | 5 +++ public/getsfopportunity.ps1 | 5 +++ public/sfApiRequest.ps1 | 2 +- public/sfconfig.ps1 | 14 ++++--- 10 files changed, 130 insertions(+), 25 deletions(-) delete mode 100644 Test/public/Get-SfObjectIdFromUrl.test.ps1 create mode 100644 Test/public/auxiliarfunctions.test.ps1 create mode 100644 Test/public/sfConfig.test.ps1 diff --git a/Test/public/Get-SfObjectIdFromUrl.test.ps1 b/Test/public/Get-SfObjectIdFromUrl.test.ps1 deleted file mode 100644 index 6d539d5..0000000 --- a/Test/public/Get-SfObjectIdFromUrl.test.ps1 +++ /dev/null @@ -1,17 +0,0 @@ -function Test_fObjectIdFromUrl{ - - . $PSScriptRoot/../../private/auxiliarfunctions.ps1 - - $urlList = @( - "https://github.lightning.force.com/lightning/r/Account/0010V00002Q8r78QAB/view", - "https://github.lightning.force.com/lightning/r/Account/0010V00002Q8r78QAB/", - "https://github.lightning.force.com/lightning/r/Account/0010V00002Q8r78QAB", - "https://github.my.salesforce.com/0010V00002Q8r78QAB" - ) - - $urlList | ForEach-Object { - $result = Get-SfObjectIdFromUrl $_ - Assert-AreEqual -Expected "0010V00002Q8r78QAB" -Presented $result - } - -} \ No newline at end of file diff --git a/Test/public/auxiliarfunctions.test.ps1 b/Test/public/auxiliarfunctions.test.ps1 new file mode 100644 index 0000000..a59c00e --- /dev/null +++ b/Test/public/auxiliarfunctions.test.ps1 @@ -0,0 +1,42 @@ +function Test_sfObjectIdFromUrl{ + + . $PSScriptRoot/../../private/auxiliarfunctions.ps1 + + $urlList = @( + "https://github.lightning.force.com/lightning/r/Account/0010V00002Q8r78QAB/view", + "https://github.lightning.force.com/lightning/r/Account/0010V00002Q8r78QAB/", + "https://github.lightning.force.com/lightning/r/Account/0010V00002Q8r78QAB", + "https://github.my.salesforce.com/0010V00002Q8r78QAB" + ) + + $urlList | ForEach-Object { + $result = Get-SfObjectIdFromUrl $_ + Assert-AreEqual -Expected "0010V00002Q8r78QAB" -Presented $result + } + +} + +function Test_sfObjectTypeFromUrl{ + + . $PSScriptRoot/../../private/auxiliarfunctions.ps1 + + $urlList = @( + "https://github.lightning.force.com/lightning/r/Account/0010V00002Q8r78QAB/view", + "https://github.lightning.force.com/lightning/r/Account/0010V00002Q8r78QAB/", + "https://github.lightning.force.com/lightning/r/Account/0010V00002Q8r78QAB" + ) + + $urlList | ForEach-Object { + $result = Get-SfObjectTypeFromUrl $_ + Assert-AreEqual -Expected "Account" -Presented $result + } + + $urlList = @( + "https://github.my.salesforce.com/0010V00002Q8r78QAB" + ) + $urlList | ForEach-Object { + $result = Get-SfObjectTypeFromUrl $_ + Assert-IsNull -Object $result + } + +} \ No newline at end of file diff --git a/Test/public/getsfopportunity.test.ps1 b/Test/public/getsfopportunity.test.ps1 index 707162c..5fbd7a4 100644 --- a/Test/public/getsfopportunity.test.ps1 +++ b/Test/public/getsfopportunity.test.ps1 @@ -8,7 +8,7 @@ function Test_GetSfOpportunity{ # Mock Sf call $id = "0065c00001SFRbYAAX" $cacheFileName = "sfDataQuery-opportunity-$id-5106802FEB193611777BC7DA26122EF5.json" - $url = "https://github.lightning.force.com/lightning/r/Account/$id/view" + $url = "https://github.lightning.force.com/lightning/r/Opportunity/$id/view" Mock_SfDataQuery_Opportunity_0065c00001SFRbYAAX # Act with out cache diff --git a/Test/public/sfConfig.test.ps1 b/Test/public/sfConfig.test.ps1 new file mode 100644 index 0000000..01099f6 --- /dev/null +++ b/Test/public/sfConfig.test.ps1 @@ -0,0 +1,43 @@ +function Test_AddSfConfigAttribute{ + Reset-InvokeCommandMock + Mock_Config + + # Emput config + $result = Get-SfConfig + Assert-IsNull -Object $result + + # Add acount + Add-SfConfigAttribute -objectType "Account" -Attribute "acountattribute" + $result = Get-SfConfig + Assert-Count -Expected 1 -Presented $result.account_attributes + Assert-Contains -Expected "acountattribute" -Presented $result.account_attributes + Add-SfConfigAttribute -objectType "Account" -Attribute "acountattribute2" + $result = Get-SfConfig + Assert-Count -Expected 2 -Presented $result.account_attributes + Assert-Contains -Expected "acountattribute" -Presented $result.account_attributes + Assert-Contains -Expected "acountattribute2" -Presented $result.account_attributes + + # Add user + Add-SfConfigAttribute -objectType "User" -Attribute "userattribute" + $result = Get-SfConfig + Assert-Count -Expected 1 -Presented $result.user_attributes + Assert-Contains -Expected "userattribute" -Presented $result.user_attributes + Add-SfConfigAttribute -objectType "User" -Attribute "userattribute2" + $result = Get-SfConfig + Assert-Count -Expected 2 -Presented $result.user_attributes + Assert-Contains -Expected "userattribute" -Presented $result.user_attributes + Assert-Contains -Expected "userattribute2" -Presented $result.user_attributes + + # Add Opportunity + Add-SfConfigAttribute -objectType "Opportunity" -Attribute "opportunityattribute" + $result = Get-SfConfig + Assert-Count -Expected 1 -Presented $result.opportunity_attributes + Assert-Contains -Expected "opportunityattribute" -Presented $result.opportunity_attributes + Add-SfConfigAttribute -objectType "Opportunity" -Attribute "opportunityattribute2" + $result = Get-SfConfig + Assert-Count -Expected 2 -Presented $result.opportunity_attributes + Assert-Contains -Expected "opportunityattribute" -Presented $result.opportunity_attributes + Assert-Contains -Expected "opportunityattribute2" -Presented $result.opportunity_attributes + +} + diff --git a/include/config.ps1 b/include/config.ps1 index 6c0a1ae..07b249e 100644 --- a/include/config.ps1 +++ b/include/config.ps1 @@ -81,7 +81,7 @@ function Get-Configuration { } try{ - $ret = Get-Content $path | ConvertFrom-Json -ErrorAction Stop + $ret = Get-Content $path | ConvertFrom-Json -AsHashtable -ErrorAction Stop return $ret } catch{ diff --git a/private/auxiliarfunctions.ps1 b/private/auxiliarfunctions.ps1 index 9928d14..b87b940 100644 --- a/private/auxiliarfunctions.ps1 +++ b/private/auxiliarfunctions.ps1 @@ -21,3 +21,26 @@ function Get-SfObjectIdFromUrl { } } +function Get-SfObjectTypeFromUrl { + param ( + [string]$SfUrl + ) + + $uri = [System.Uri]::new($SfUrl) + $segments = $uri.Segments + + # "https://github.lightning.force.com/lightning/r/Account/0010V00002Q8r78QAB/view" + # "https://github.lightning.force.com/lightning/r/Account/0010V00002Q8r78QAB/" + # "https://github.lightning.force.com/lightning/r/Account/0010V00002Q8r78QAB" + if ($segments.Length -ge 3 -and $segments[1] -eq "lightning/" -and $segments[2] -eq "r/") { + return $segments[3].TrimEnd('/') + + #"https://github.my.salesforce.com/0010V00002Q8r78QAB" + } elseif ($segments.Length -eq 2) { + return $null + + } else { + throw "Invalid Salesforce Object URL $SfUrl" + } +} + diff --git a/public/getsfaccount.ps1 b/public/getsfaccount.ps1 index 3a74830..4cb770c 100644 --- a/public/getsfaccount.ps1 +++ b/public/getsfaccount.ps1 @@ -32,6 +32,11 @@ function Get-SfAccount{ # Extract Id from URL $Id = Get-SfObjectIdFromUrl -SfUrl $SfUrl + $type = Get-SfObjectTypeFromUrl -SfUrl $SfUrl + + if ($type -ne "Account") { + throw "Invalid Salesforce Object URL $SfUrl" + } $attributes = @( "Id", diff --git a/public/getsfopportunity.ps1 b/public/getsfopportunity.ps1 index 404a627..9542913 100644 --- a/public/getsfopportunity.ps1 +++ b/public/getsfopportunity.ps1 @@ -30,6 +30,11 @@ function Get-SfOpportunity{ # Extract Id from URL $Id = Get-SfObjectIdFromUrl -SfUrl $SfUrl + $type = Get-SfObjectTypeFromUrl -SfUrl $SfUrl + + if ($type -ne "Opportunity") { + throw "Invalid Salesforce Object URL $SfUrl" + } $attributes = @( "Id", diff --git a/public/sfApiRequest.ps1 b/public/sfApiRequest.ps1 index cbe113f..c212a19 100644 --- a/public/sfApiRequest.ps1 +++ b/public/sfApiRequest.ps1 @@ -3,7 +3,7 @@ Set-MyInvokeCommandAlias -Alias "sfApiRequest" -Command 'sf api request rest /se function Get-SfApiRequest { [CmdletBinding()] param( - [Parameter(Mandatory)][ValidateSet("Account", "User")][string]$objectType, + [Parameter(Mandatory)][ValidateSet("Account", "User", "Opportunity")][string]$objectType, [Parameter(Mandatory,Position=1)][string]$Id ) diff --git a/public/sfconfig.ps1 b/public/sfconfig.ps1 index 7fb8e02..84425fa 100644 --- a/public/sfconfig.ps1 +++ b/public/sfconfig.ps1 @@ -44,23 +44,27 @@ function Open-SfConfig{ function Add-SfConfigAttribute{ [CmdletBinding()] param( - [Parameter(Mandatory, ValueFromPipeline, Position = 0)][string]$Attribute + [Parameter(Mandatory,Position=0)][ValidateSet("Account", "User", "Opportunity")][string]$objectType, + + [Parameter(Mandatory, ValueFromPipeline, Position = 1)][string]$Attribute + ) begin{ $config = Get-Configuration + $configAttribute = ($objectType + "_attributes").ToLower() if(-Not $config){ $config = @{} } - if(-Not $config.account_attributes){ - $config.account_attributes = @() + if(-Not $config.$configAttribute){ + $config.$configAttribute = @() } } process{ - $config.account_attributes += $Attribute + $config.$configAttribute += $Attribute } End{ @@ -70,7 +74,7 @@ function Add-SfConfigAttribute{ } $config = Get-SfConfig - Write-Output $config.account_attributes + Write-Output $config.$configAttribute } From c03365e6a755379400aa11d2917bce40b5ee7d7b Mon Sep 17 00:00:00 2001 From: rulasg Date: Sun, 9 Mar 2025 05:00:03 +0100 Subject: [PATCH 08/11] refactor: clean up whitespace and improve code formatting in test and utility scripts --- Test/private/mock_SfDataQueery.ps1 | 2 +- Test/public/getsfopportunity.test.ps1 | 4 ++-- Test/public/getstaccount.test.ps1 | 8 +++---- include/getHashCode.ps1 | 17 +++++++++------ include/mySetInvokeCommandAlias.ps1 | 2 +- public/transformations.ps1 | 31 +++++++++++++++------------ 6 files changed, 35 insertions(+), 29 deletions(-) diff --git a/Test/private/mock_SfDataQueery.ps1 b/Test/private/mock_SfDataQueery.ps1 index c519389..6372d58 100644 --- a/Test/private/mock_SfDataQueery.ps1 +++ b/Test/private/mock_SfDataQueery.ps1 @@ -5,7 +5,7 @@ function Mock_SfDataQuery { [Parameter(Mandatory = $true)][string]$type, [Parameter(Mandatory = $true)][string]$id, [Parameter(Mandatory = $true)][string]$filename - + ) $command = 'sf data query --query "SELECT {attributes} FROM {type} WHERE Id=''{id}''" -r=json' diff --git a/Test/public/getsfopportunity.test.ps1 b/Test/public/getsfopportunity.test.ps1 index 5fbd7a4..6c1ed91 100644 --- a/Test/public/getsfopportunity.test.ps1 +++ b/Test/public/getsfopportunity.test.ps1 @@ -4,7 +4,7 @@ function Test_GetSfOpportunity{ Reset-InvokeCommandMock Mock_Database -ResetDatabase Mock_Config - + # Mock Sf call $id = "0065c00001SFRbYAAX" $cacheFileName = "sfDataQuery-opportunity-$id-5106802FEB193611777BC7DA26122EF5.json" @@ -19,7 +19,7 @@ function Test_GetSfOpportunity{ $path = Get-Mock_DatabaseStore | Join-Path -ChildPath $cacheFileName Assert-ItemExist -Path $path - # Remove sf data + # Remove sf data Reset-InvokeCommandMock Mock_Database Mock_Config diff --git a/Test/public/getstaccount.test.ps1 b/Test/public/getstaccount.test.ps1 index 2a39bf3..98d4102 100644 --- a/Test/public/getstaccount.test.ps1 +++ b/Test/public/getstaccount.test.ps1 @@ -1,9 +1,9 @@ function Test_GetSfAccount{ Reset-InvokeCommandMock - + $mockAttrib = @{account_attributes = @("Potential_Seats_Manual__c","Website","PhotoUrl")} - + # Mocks Mock_Database -ResetDatabase Mock_Config -Config $mockAttrib @@ -29,7 +29,7 @@ function Test_GetSfAccount{ # Act with cache $result = Get-SfAccount -SfUrl $url - + # Assert Assert-AreEqual -Expected "0010V00002KIWkaQAH" -Presented $result.Id } @@ -45,7 +45,7 @@ function Test_GetSfAccount_Transformations{ # Act with out cache $result = Get-SfAccount https://github.lightning.force.com/lightning/r/Account/0010V00002KIWkaQAH/view - # Assert + # Assert Assert-AreEqual -Expected "Oana Dinca" -Presented $result.OwnerName } diff --git a/include/getHashCode.ps1 b/include/getHashCode.ps1 index a235823..830a869 100644 --- a/include/getHashCode.ps1 +++ b/include/getHashCode.ps1 @@ -13,11 +13,14 @@ function Get-HashCode { [string]$InputString ) - # Generate MD5 hash - $md5 = [System.Security.Cryptography.MD5]::Create() - $bytes = [System.Text.Encoding]::UTF8.GetBytes($InputString) - $hashBytes = $md5.ComputeHash($bytes) - $hashString = [BitConverter]::ToString($hashBytes) -replace '-', '' - - return $hashString + process{ + # Generate MD5 hash + $md5 = [System.Security.Cryptography.MD5]::Create() + $bytes = [System.Text.Encoding]::UTF8.GetBytes($InputString) + $hashBytes = $md5.ComputeHash($bytes) + $hashString = [BitConverter]::ToString($hashBytes) -replace '-', '' + + return $hashString + } + } \ No newline at end of file diff --git a/include/mySetInvokeCommandAlias.ps1 b/include/mySetInvokeCommandAlias.ps1 index be2826d..f573cea 100644 --- a/include/mySetInvokeCommandAlias.ps1 +++ b/include/mySetInvokeCommandAlias.ps1 @@ -2,7 +2,7 @@ # SET MY INVOKE COMMAND ALIAS # # Allows calling constitely InvokeHelper with the module tag -# Need to define a variable called $MODULE_INVOKATION_TAG +# Need to define a variable called $MODULE_INVOKATION_TAG # # Sample: # $MODULE_INVOKATION_TAG = "SfHelperModule" diff --git a/public/transformations.ps1 b/public/transformations.ps1 index 32146d8..f4f58cf 100644 --- a/public/transformations.ps1 +++ b/public/transformations.ps1 @@ -8,23 +8,26 @@ function Edit-AttributeValueFromHTML{ [Parameter()][switch] $RemoveOriginalAttribute ) - $value = Get-OwnerNameFromHtml -html $($Object.$AttributeName) - - # return if value is null - if ($value -eq $null) { - "Attribute $AttributeName is not found or empty in object $($object.id)" | Write-Warning + process{ + + $value = Get-OwnerNameFromHtml -html $($Object.$AttributeName) + + # return if value is null + if ($null -eq $value) { + "Attribute $AttributeName is not found or empty in object $($object.id)" | Write-Warning + return $Object + } + + # Add the new attribute + Add-Member -InputObject $ret -MemberType NoteProperty -Name $NewAttributeName -Value $value + + if ($RemoveOriginalAttribute) { + $Object.Properties.Remove($AttributeName) + } + return $Object } - # Add the new attribute - Add-Member -InputObject $ret -MemberType NoteProperty -Name $NewAttributeName -Value $value - - if ($RemoveOriginalAttribute) { - $Object.Properties.Remove($AttributeName) - } - - return $Object - } # Function to extract Owner Name from HTML From 0cf053d93da474a9dd07b6b9b6abb038094167f4 Mon Sep 17 00:00:00 2001 From: rulasg Date: Sun, 9 Mar 2025 05:03:49 +0100 Subject: [PATCH 09/11] refactor: remove unused START.ps1 file and clean up import logic in SfHelper.psm1 --- SfHelper.psm1 | 7 +------ private/start/START.ps1 | 16 ---------------- 2 files changed, 1 insertion(+), 22 deletions(-) delete mode 100644 private/start/START.ps1 diff --git a/SfHelper.psm1 b/SfHelper.psm1 index 839784f..6a09d0f 100644 --- a/SfHelper.psm1 +++ b/SfHelper.psm1 @@ -3,13 +3,8 @@ Write-Information -Message ("Loading {0} ..." -f ($PSCommandPath | Split-Path -L #Module path is where resides the RootModule file. This file. :) $MODULE_PATH = $PSScriptRoot -# Import START -# $START = $MODULE_PATH | Join-Path -ChildPath "private" -AdditionalChildPath 'START.ps1' -$START = Get-ChildItem -Path $MODULE_PATH -Filter start.ps1 -Recurse -if($START | Test-Path){ . $($START | Get-Item).FullName } - #Get public and private function definition files. -$Include = @( Get-ChildItem -Path $MODULE_PATH\include\*.ps1 -ErrorAction SilentlyContinue ) +$Include = @( Get-ChildItem -Path $MODULE_PATH\include\*.ps1 -ErrorAction SilentlyContinue ) $Private = @( Get-ChildItem -Path $MODULE_PATH\private\*.ps1 -Recurse -ErrorAction SilentlyContinue ) $Public = @( Get-ChildItem -Path $MODULE_PATH\public\*.ps1 -Recurse -ErrorAction SilentlyContinue ) diff --git a/private/start/START.ps1 b/private/start/START.ps1 deleted file mode 100644 index 0f66eee..0000000 --- a/private/start/START.ps1 +++ /dev/null @@ -1,16 +0,0 @@ -# Gate to be loaded only onces -if (! $LOADED_EARLYLOADED){ - $LOADED_EARLYLOADED = $true - - # Add all modules that requies to be loadd before the code modules. - # This is useful when you have a dependency to run - - - function Get-ModuleName{ - $local = $PSScriptRoot | Split-Path -Parent | Split-Path -Parent - $moduleName = (Get-ChildItem -Path $local -Filter *.psd1 | Select-Object -First 1).BaseName - - return $moduleName - } - -} From 20f579cf3817f3a14cd337de680e58893702dd72 Mon Sep 17 00:00:00 2001 From: rulasg Date: Sun, 9 Mar 2025 05:20:49 +0100 Subject: [PATCH 10/11] feat: enhance Get-SfAccount function with improved attribute transformation and null checks --- Test/public/getstaccount.test.ps1 | 3 ++- public/getsfaccount.ps1 | 10 ++++------ public/transformations.ps1 | 16 +++++++++++----- 3 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Test/public/getstaccount.test.ps1 b/Test/public/getstaccount.test.ps1 index 98d4102..f0f2fcd 100644 --- a/Test/public/getstaccount.test.ps1 +++ b/Test/public/getstaccount.test.ps1 @@ -45,8 +45,9 @@ function Test_GetSfAccount_Transformations{ # Act with out cache $result = Get-SfAccount https://github.lightning.force.com/lightning/r/Account/0010V00002KIWkaQAH/view - # Assert + # Transformation Account_Owner__c -> OwnerName Assert-AreEqual -Expected "Oana Dinca" -Presented $result.OwnerName + Assert-IsNull -Object $result.Account_Owner__c } diff --git a/public/getsfaccount.ps1 b/public/getsfaccount.ps1 index 4cb770c..308585d 100644 --- a/public/getsfaccount.ps1 +++ b/public/getsfaccount.ps1 @@ -73,12 +73,10 @@ function Get-SfAccount{ $ret = Get-SfDataQuery -Type Account -Id $Id -Attributes $attributes # Transformations - - ## Clean up the Account_Owner__c field to show the name of the owner - Add-Member -InputObject $ret -MemberType NoteProperty -Name "OwnerName" -Value $(Get-OwnerNameFromHtml -html $($ret.Account_Owner__c)) - $ret.PSObject.Properties.Remove("Account_Owner__c") - - # $ret.PsObject.Properties.Remove("attributes") + $ret = $ret | Edit-AttributeValueFromHTML ` + -AttributeName "Account_Owner__c" ` + -NewAttributeName "OwnerName" ` + -RemoveOriginalAttribute return $ret } Export-ModuleMember -Function Get-SfAccount diff --git a/public/transformations.ps1 b/public/transformations.ps1 index f4f58cf..13a856f 100644 --- a/public/transformations.ps1 +++ b/public/transformations.ps1 @@ -10,21 +10,27 @@ function Edit-AttributeValueFromHTML{ process{ + # Check if the attribute exists in the object + if($null -eq $Object.$AttributeName) { + "Attribute $AttributeName is not found in object $($object.id)" | Write-Warning + return $Object + } + $value = Get-OwnerNameFromHtml -html $($Object.$AttributeName) - + # return if value is null if ($null -eq $value) { "Attribute $AttributeName is not found or empty in object $($object.id)" | Write-Warning return $Object } - + # Add the new attribute Add-Member -InputObject $ret -MemberType NoteProperty -Name $NewAttributeName -Value $value - + if ($RemoveOriginalAttribute) { - $Object.Properties.Remove($AttributeName) + $Object.PsObject.Properties.Remove($AttributeName) } - + return $Object } From 14e03614f089c1c040611df4cd6ff17ea97c86b1 Mon Sep 17 00:00:00 2001 From: rulasg Date: Sun, 9 Mar 2025 05:21:02 +0100 Subject: [PATCH 11/11] refactor: remove unnecessary whitespace in getsfopportunity.test.ps1 --- Test/public/getsfopportunity.test.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Test/public/getsfopportunity.test.ps1 b/Test/public/getsfopportunity.test.ps1 index 6c1ed91..6699227 100644 --- a/Test/public/getsfopportunity.test.ps1 +++ b/Test/public/getsfopportunity.test.ps1 @@ -26,7 +26,7 @@ function Test_GetSfOpportunity{ # Act with cache $result = Get-SfOpportunity -SfUrl $url - + # Assert Assert-AreEqual -Expected $id -Presented $result.Id