diff --git a/SfHelper.psm1 b/SfHelper.psm1 index 4d6908e..6a09d0f 100644 --- a/SfHelper.psm1 +++ b/SfHelper.psm1 @@ -3,18 +3,13 @@ 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 -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/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/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/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_SfDataQueery.ps1 b/Test/private/mock_SfDataQueery.ps1 new file mode 100644 index 0000000..6372d58 --- /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/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 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 deleted file mode 100644 index dca5d81..0000000 --- a/Test/public/Get-SfObjectIdFromUrl.test.ps1 +++ /dev/null @@ -1,17 +0,0 @@ -function Test_GetSfAccountFromUrl{ - - . $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 new file mode 100644 index 0000000..6699227 --- /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-5106802FEB193611777BC7DA26122EF5.json" + $url = "https://github.lightning.force.com/lightning/r/Opportunity/$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..f0f2fcd --- /dev/null +++ b/Test/public/getstaccount.test.ps1 @@ -0,0 +1,70 @@ +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-$id-01F5F2DFDE481D1146E8D504BB935E4D.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 + + # Transformation Account_Owner__c -> OwnerName + Assert-AreEqual -Expected "Oana Dinca" -Presented $result.OwnerName + Assert-IsNull -Object $result.Account_Owner__c + +} + +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/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/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/include/config.ps1 b/include/config.ps1 index f446200..07b249e 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 @@ -78,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/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 new file mode 100644 index 0000000..830a869 --- /dev/null +++ b/include/getHashCode.ps1 @@ -0,0 +1,26 @@ + +# 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, +# 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 + ) + + 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 new file mode 100644 index 0000000..f573cea --- /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/auxiliarfunctions.ps1 b/private/auxiliarfunctions.ps1 index c3aa86f..b87b940 100644 --- a/private/auxiliarfunctions.ps1 +++ b/private/auxiliarfunctions.ps1 @@ -19,4 +19,28 @@ function Get-SfObjectIdFromUrl { } else { throw "Invalid Salesforce Object URL $SfUrl" } -} \ No newline at end of file +} + +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/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 deleted file mode 100644 index 8a7366f..0000000 --- a/private/start/START.ps1 +++ /dev/null @@ -1,19 +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 - - - # 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 - - return $moduleName - } - -} 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 diff --git a/public/getsfaccount.ps1 b/public/getsfaccount.ps1 index 7cce9b5..308585d 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. @@ -35,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", @@ -52,16 +54,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 } @@ -70,46 +73,12 @@ 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 -# 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..9542913 --- /dev/null +++ b/public/getsfopportunity.ps1 @@ -0,0 +1,78 @@ + + +<# +.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 + $type = Get-SfObjectTypeFromUrl -SfUrl $SfUrl + + if ($type -ne "Opportunity") { + throw "Invalid Salesforce Object URL $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/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/sfDataQuery.ps1 b/public/sfDataQuery.ps1 index 7cf0b07..b4c9df2 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 ) @@ -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" 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 0a496fd..84425fa 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() @@ -41,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.attributes){ - $config.attributes = @() + if(-Not $config.$configAttribute){ + $config.$configAttribute = @() } } process{ - $config.attributes += $Attribute + $config.$configAttribute += $Attribute } End{ @@ -67,7 +74,7 @@ function Add-SfConfigAttribute{ } $config = Get-SfConfig - Write-Output $config.attributes + Write-Output $config.$configAttribute } diff --git a/public/transformations.ps1 b/public/transformations.ps1 new file mode 100644 index 0000000..13a856f --- /dev/null +++ b/public/transformations.ps1 @@ -0,0 +1,53 @@ +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 + ) + + 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.PsObject.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