UblionConnect.psm1

Function Log {
    param(
        [Parameter(Mandatory=$true)][String]$msg
    )
    
    $folder = $env:LOCALAPPDATA + "\ublion"
    $logFile = Join-Path $folder "logfile.txt"
    $data = (Get-date).ToString() + " "  + $msg
    Add-Content $logFile $data
}
function Get-UblionLog {
    param(
        [switch]$watching
    )

    $folder = $env:LOCALAPPDATA + "\ublion"
    $logFile = Join-Path $folder "logfile.txt"
    if ($watching) {
        Get-Content $logFile -Wait
    } else {
        get-content $logFile
    }
}
function Get-DownloadFile {
    [CmdletBinding()]
    param($id, $filename, $path)
      #get the pdf as a file base 64 stream
       $apiGetPDF = "api/services/app/Document/GetDocumentPDF?id="+$id
       $result   = Start-GetResult -request $apiGetPDF
       $b64      = $result.result.fileBase64

       # construct the filename for the pdf
       $filename = $path+"\"+$filename
       $fileOutputPdf = $filename+".pdf"

       # convert the file from base 64 to byte and write it to disk
       $bytes    = [Convert]::FromBase64String($b64)
       [IO.File]::WriteAllBytes($fileOutputPdf, $bytes)    
   
       
       $apiGetUbl = "api/services/app/Ubl/DownloadUbl"
       $body = "{""id"": ""$id""}"
       $result   = Start-GetResult -request $apiGetUbl -body $body
       $fileOutputUbl = $filename+".xml"
       $downloadFile = "/File/DownloadTempFile?FileType="+$result.result.fileType+"&FileToken="+$result.result.fileToken+"&FileName="+$result.result.filename
     
       log -msg ("Download file to $fileOutputPdf")
       Invoke-RestMethod ((Get-UrlHost)+$downloadFile) -OutFile $fileOutputUbl  
   
   }

   <#
   .SYNOPSIS
   Get modified documents
    
   .DESCRIPTION
   A document is deleiered when it is changing the state and it's not send before with GetModifiedDocuments, It's a infinitely loop
    
   .EXAMPLE
   An example
    
   .NOTES
   General notes
   #>

function Start-GetResultFiles {
    [CmdletBinding()]
    param()

    $DocumentType = @{Outgoing = 25}

    $ublionConfiguration = Get-UblionConfiguration
    While ($true) {
        if( -not (Test-path $resultFolder))
        {
            mkdir $resultFolder
        }
        try {
            # Check for incoming documents
            $apiGetModifiedFiles = "api/services/app/Document/GetModifiedDocuments"
            $result = Start-GetResult -request $apiGetModifiedFiles
            if ($result.result.GetType().Name -eq "Object[]") {
                #foreach available document
                foreach ($document in $result.result){
                    
                    if ($document.type.id -eq $DocumentType.Outgoing) {
                        $outbresultFolderound = Join-Path $ublionConfiguration.baseFolder  $ublionConfiguration.incomingFolderOrders
                    } 
                    else {
                        $outbresultFolderound = Join-Path $ublionConfiguration.baseFolder  $ublionConfiguration.incomingFolderInvoices
                    }
                    Get-DownloadFile -id ($document.id) -filename ($document.name) -path ($outbresultFolderound)
                }
            } 
        } 
        catch {
            write-host error $_
        }
        Start-Sleep -Seconds 10
    }
}


<#
.SYNOPSIS
Get the tenant url
 
.DESCRIPTION
Returns the url host
 
.EXAMPLE
An example
 
.NOTES
General notes
#>
#
function Get-UrlHost {
    "https://"+(Get-UblionConfiguration).tenant+"_connectapi.fan2customer.com/"
}

<#
.SYNOPSIS
Create bearer token
 
.DESCRIPTION
Create a bearer token based on the login credentials
 
.EXAMPLE
An example
 
.NOTES
General notes
#>
#
function Get-Token{
    $token = $global:token
    
    if (-not [string]::IsNullOrEmpty($token)){
        $token
    } else {
    write-host -backgroundcolor green new token required
    $data = Get-UblionConfiguration
    $loginBody = "{""userNameOrEmailAddress"": """+$data.user+""",""password"": """+$data.pass+"""}"
    $connectionApiString = "api/TokenAuth/Authenticate"

    $authorizationUrl = (Get-UrlHost) + $connectionApiString
    $login = Invoke-RestMethod  $authorizationUrl -Method Post -Body $loginBody -ContentType "application/json" 

    $global:token = $login.result.accessToken
    $global:token
    }
}
function Start-GetResult{
    [CmdletBinding()]
    param($request, $body)
    $token = Get-Token
    $headers = @{"Authorization"="Bearer "+$token;}
    $requestUrl = (Get-UrlHost) + $request
    try {
        if ($body) {
            $answer = Invoke-RestMethod $requestUrl -Method Post -Body $body -ContentType "application/json" -Headers $headers
        } else {
            $answer = Invoke-RestMethod $requestUrl -Headers $headers
        } } catch {
            write-host "Token not accepected. Try renewing"
            if ($global:token) {
                Remove-Variable token -Scope Global
            }
            $token = Get-Token
            $headers = @{"Authorization"="Bearer "+$token;}
        if ($body) {
            $answer = Invoke-RestMethod $requestUrl -Method Post -Body $body -ContentType "application/json" -Headers $headers
        } else {
            $answer = Invoke-RestMethod $requestUrl -Headers $headers
        }
    }

    return $answer
}

function Start-Ublion {
    [CmdletBinding()]
    Param (
        [Parameter()] 
        [String]$WatchFolder,
        [Parameter()]
        [String]$DestinationFolder
        )
        
    # start watcher for outgoing invoices
    $ublionConfiguration = Get-UblionConfiguration

    $filter = '*.JSO'
    $outbound = Join-Path $ublionConfiguration.baseFolder $ublionConfiguration.outgoingFolderInvoices
    $resultFolder = Join-Path $ublionConfiguration.baseFolder $ublionConfiguration.outgoingFolderInvoices
    $fsw = New-Object IO.FileSystemWatcher $outbound, $filter -Property @{IncludeSubdirectories = $false;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'} 
    $action = {
        try{ 
            import-module UblionConnect
            Start-Sleep -Seconds 1
            $documentCreateApi = "api/services/app/Document/Create"
            $path              = $Event.SourceEventArgs.FullPath
            $FileName          = $Event.SourceEventArgs.Name
            $hashfunction      = '[IO.File]::ReadAllLines($path)'
            $base64            = (Invoke-Expression $hashfunction).Replace("""","\""")
            $sendFile          = "{""name"": """+$FileName.Replace(".JSO","")+""",""type"": ""invoiceJson"", ""file"": """+$base64+"""}"

            Start-GetResult -request $documentCreateApi -body $sendFile
            Remove-Item $Event.SourceEventArgs.FullPath
        }
        catch {
            write-host -ForegroundColor Red $_.Exception.Message
            write-host -ForegroundColor Red $_.Exception.ItemName
            write-host "ERROR in file "$Event.SourceEventArgs.FullPath -ForegroundColor Red
        }
    }
    
    $backupscript = Register-ObjectEvent -EventName "Created" -InputObject $fsw -Action $action -MessageData $resultFolder 
    Write-Host "WatchFolder: `"$($baseFolder)`" DestinationFolder: `"$($resultFolder)`" started. Job is in: $backupscript" -ForegroundColor Green


    #start watcher for incoming invoices
    if (-not [string]::IsNullOrEmpty($ublionConfiguration.outgoingFolderOrders)){
            $filter = '*.JSO'
            $outbound = Join-Path $ublionConfiguration.baseFolder $ublionConfiguration.outgoingFolderOrders
            $resultFolder = Join-Path $ublionConfiguration.baseFolder $ublionConfiguration.outgoingFolderOrders
            $fsw = New-Object IO.FileSystemWatcher $outbound, $filter -Property @{IncludeSubdirectories = $false;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'} 
            $action = {
                try{ 
                    import-module UblionConnect
                    Start-Sleep -Seconds 1
                    $documentCreateApi = "api/services/app/Document/Create"
                    $path              = $Event.SourceEventArgs.FullPath
                    $FileName          = $Event.SourceEventArgs.Name
                    $hashfunction      = '[IO.File]::ReadAllLines($path)'
                    $base64            = (Invoke-Expression $hashfunction).Replace("""","\""")
                    $sendFile          = "{""name"": """+$FileName.Replace(".JSO","")+""",""type"": ""orderJson"", ""file"": """+$base64+"""}"
    
                    Start-GetResult -request $documentCreateApi -body $sendFile
                    Remove-Item $Event.SourceEventArgs.FullPath
                }
                catch {
                    write-host -ForegroundColor Red $_.Exception.Message
                    write-host -ForegroundColor Red $_.Exception.ItemName
                    write-host "ERROR in file "$Event.SourceEventArgs.FullPath -ForegroundColor Red
                }
            }
            
            $backupscript = Register-ObjectEvent -EventName "Created" -InputObject $fsw -Action $action -MessageData $resultFolder 
            Write-Host "WatchFolder: `"$($baseFolder)`" DestinationFolder: `"$($resultFolder)`" started. Job is in: $backupscript" -ForegroundColor Green
        }
        Log("Start ublion watchers")


        Start-GetResultFiles
        Log("Start downloading items")
}

function Install-Ublion{
    
    [CmdletBinding()]
    param(
        [Parameter(Mandatory)]
        [String]$Tenant,
        
        # The base folder
        [Parameter(Mandatory)]
        [String]$BaseFolder,

        [System.Management.Automation.PSCredential]
        $Credential = $(Get-Credential),

        # The incoming folder for invoices from ublion
        [String]$IncomingFolder = "FromUblion",

        # The folder which contains the document to upload
        [String]$OutgoingFolder = "ToUblion",

        #the order folder
        [String]$OrderPrefix = "Order",

        #the order folder
        [String]$InvoicePrefix = "Invoice"
    )

    $secureStringText = $Credential.Password | ConvertFrom-SecureString 
    $folder = $env:LOCALAPPDATA + "\ublion"
    Install-AppData -DirectoryToCreate $folder


    
    Install-AppData -DirectoryToCreate ($BaseFolder + "\" + $InvoicePrefix + $OutgoingFolder)
    Install-AppData -DirectoryToCreate ($BaseFolder + "\"+ $InvoicePrefix + $IncomingFolder)


    if (-not [string]::IsNullOrEmpty($OrderPrefix)) {        
        
        $OutgoingFolderOrder = $OrderPrefix + $OutgoingFolder     
        $IncomingFolderOrder = $OrderPrefix + $IncomingFolder

        Install-AppData -DirectoryToCreate ($BaseFolder + "\" + $OutgoingFolderOrder)
        Install-AppData -DirectoryToCreate ($BaseFolder + "\"+  $IncomingFolderOrder)

    }
    Set-Content "$folder\data.log" (
        #password
        $secureStringText + "`n" + 
        #username
        $Credential.UserName + "`n" + 
        #Tenant
        $Tenant + "`n" + 
        #Root folder for data
        $BaseFolder + "`n" + 
        # Outgoing folder invoices
        $InvoicePrefix + $OutgoingFolder + "`n" + 
        # Incoming folder invoices
        $InvoicePrefix + $IncomingFolder + "`n" +
        # Outgoing folder orders
        $OutgoingFolderOrder + "`n" + 
        # Incoming folder orders
        $IncomingFolderOrder + "`n"
        )

    Log("Install ublion configuration to $folder")
}


function Remove-Ublion {
    $folder = $env:LOCALAPPDATA + "\ublion"
    if (Test-Path -LiteralPath $folder) {
        Remove-Item $folder
        "Ublion configuration removed"
    }
}

function Get-UblionConfiguration {
    $folder = $env:LOCALAPPDATA + "\ublion"
    $data = (Get-Content "$folder\data.log").split("`n")
    

    $secureString = $data[0] | ConvertTo-SecureString
    $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($secureString)
    $UnsecurePassword = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR)


    @{user = $data[1]
    pass = $UnsecurePassword
    tenant = $data[2]
    baseFolder = $data[3]
    outgoingFolderInvoices = $data[4]
    incomingFolderInvoices = $data[5]
    outgoingFolderOrders = $data[6]
    incomingFolderOrders = $data[7] 
    }
}
function Install-AppData{
    [CmdletBinding()]
    Param(
    [Parameter(Mandatory = $True)]
    [String] $DirectoryToCreate)

    if (-not (Test-Path -LiteralPath $DirectoryToCreate)) {
        
        try {
            New-Item -Path $DirectoryToCreate -ItemType Directory -ErrorAction Stop | Out-Null #-Force
        }
        catch {
            Write-Error -Message "Unable to create directory '$DirectoryToCreate'. Error was: $_" -ErrorAction Stop
        }
        "Successfully saved credentials"

    }
    else {
        "Directory already existed"
    }
}

<#
.SYNOPSIS
Upload invoice templates
 
.DESCRIPTION
Upload invoice template for footer, main and header. The template is a html file with complete styling.
 
.EXAMPLE
An example
 
.NOTES
General notes
#>
#
function Start-UploadTemplate{
    [CmdletBinding()]
    param()
    Process {
        $filter = '*.html'
        $fsw = New-Object IO.FileSystemWatcher $templateFolder, $filter -Property @{IncludeSubdirectories = $false;NotifyFilter = [IO.NotifyFilters]'FileName, LastWrite'} 
        $action = {
                write-host Start uploading $Event.SourceEventArgs.FullPath 
                try{
                import-module UblionConnect
                Start-Sleep -Seconds 2
                $documentCreateApi = "api/services/app/EmailTemplates/CreateOrEdit"
                $path              = $Event.SourceEventArgs.FullPath
                $FileName          = $Event.SourceEventArgs.Name
                $hashfunction      = '[System.Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes([IO.File]::ReadAllLines($path)))'
                $base64            = (Invoke-Expression $hashfunction).Replace("""","\""")
                $sendFile          = "{""name"": """+$FileName.replace(".html","")+""",""description"": ""invoiceJson"", ""template"": """+$base64+"""}"
                write-host request file
                Start-GetResult -request $documentCreateApi -body $sendFile
            }
            catch {
                write-host -ForegroundColor Red $_.Exception.Message
                write-host -ForegroundColor Red $_.Exception.ItemName
                write-host "ERROR in file "$Event.SourceEventArgs.FullPath -ForegroundColor Red
            }
        }
        $backupscript = Register-ObjectEvent -EventName "Changed" -InputObject $fsw -Action $action -MessageData $resultFolder 
        Write-Host "Template watcher is started. WatchFolder: `"$($templateFolder)`" Job is in: $ backupscript" -ForegroundColor Green
    }
}

function Get-ReleaseNotes {
    Write-host "20/08/2020: Fix logic to route order to outgoing folder"
    write-host "22/07/2020: Add order "
    write-host "15/07/2020: Added order functionality, remove connection code, make order folder "
}

Export-ModuleMember -function  Get-DownloadFile
Export-ModuleMember -function  Start-GetResultFiles
Export-ModuleMember -function  Get-UrlHost
Export-ModuleMember -function  Get-Token
Export-ModuleMember -function  Start-GetResult
Export-ModuleMember -function  Start-Ublion 
Export-ModuleMember -function  Start-UploadTemplate
Export-ModuleMember -function  Install-Ublion
Export-ModuleMember -function  Get-UblionConfiguration
Export-ModuleMember -function  Get-ReleaseNotes
Export-ModuleMember -function  Remove-Ublion
Export-ModuleMember -function  Get-UblionLog