Schematics/Dashboard/Use-DashboardSchematic.ps1

function Use-DashboardSchematic
{
    <#
    .Synopsis
        Builds a web application according to a schematic
    .Description
        Use-Schematic builds a web application according to a schematic.
         
        Web applications should not be incredibly unique: they should be built according to simple schematics.
    .Notes
     
        When ConvertTo-ModuleService is run with -UseSchematic, if a directory is found beneath either Pipeworks
        or the published module's Schematics directory with the name Use-Schematic.ps1 and containing a function
        Use-Schematic, then that function will be called in order to generate any pages found in the schematic.
         
        The schematic function should accept a hashtable of parameters, which will come from the appropriately named
        section of the pipeworks manifest
        (for instance, if -UseSchematic Blog was passed, the Blog section of the Pipeworks manifest would be used for the parameters).
         
        It should return a hashtable containing the content of the pages. Content can either be static HTML or .PSPAGE
    #>

    [OutputType([Hashtable])]
    param(
    # Any parameters for the schematic
    [Parameter(Mandatory=$true)][Hashtable]$Parameter,
    
    # The pipeworks manifest, which is used to validate common parameters
    [Parameter(Mandatory=$true)][Hashtable]$Manifest,
    
    # The directory the schemtic is being deployed to
    [Parameter(Mandatory=$true)][string]$DeploymentDirectory,
    
    # The directory the schematic is being deployed from
    [Parameter(Mandatory=$true)][string]$InputDirectory     
    )
    
    process {
    
        if (-not $Parameter.Dashboards) {
            Write-Error "No items found"
            return
        }
        
        if (-not $Parameter.EdgeColor) {
            Write-Error "Managers must have an edge color"
            return
        }
        
        if (-not $Parameter.BackgroundColor) {
            Write-Error "Managers must have a background color"
            return
        }
        
        
        
                               
                                                              
        
        $stagesInTables = 
            $parameter.Dashboards.GetEnumerator() | 
                Where-Object { 
                    $_.Value.Id 
                } 
        
        if ($stagesInTables) {
            if (-not $Manifest.Table.Name) {
                Write-Error "No table found in manifest"
                return
            }
            
            if (-not $Manifest.Table.StorageAccountSetting) {
                Write-Error "No storage account name setting found in manifest"
                return
            }
            
            if (-not $manifest.Table.StorageKeySetting) {
                Write-Error "No storage account key setting found in manifest"
                return
            }
        }
        
        
        $outputPages = @{}
        
        $orgName = $parameter.Organization.Name
        
        
        $orginfo = if ($parameter.Organization) {
            $parameter.Organization
        } else {
            @{}
        }
        
        $pageName = $parameter.Name
        $pageHeaderImage = $parameter.pageHeaderImage
        
        
        
        foreach ($dashboardObject in @($parameter.Dashboards)) {
            $pageName = $dashboardObject.Name
            $pageHeaderImage = $dashboardObject.pageHeaderImage
            
            $pageScript = "
`$pageName = '$pageName'
`$pageHeaderImage = '$pageHeaderImage';
`$edgeColor = '$($parameter.EdgeColor)';`
`$dashboardColor ='$($parameter.DashboardColor)';
`$bgColor = '$($parameter.BackgroundColor)';
`$fontName = '$(if ($parameter.FontName) { $parameter.FontName }else { 'Gisha' } )'
`$orginfo= $(Write-PowerShellHashtable -InputObject $orginfo )
`$dashboard = @(`$pipeworksManifest.Dashboard.Dashboards) | Where-Object { `$_.Name -eq '$pageName' }
"
 + {
$headerContent = 
    if ($pageHeaderImage) {
        "<img src='Assets/$pageHeaderImage' style='width:100%' />
        "
    
    } else {
        "<h1 style='text-align:center;font-size:xx-large;' class='ui-widget-content ui-corner-all'>
            $($module.Name)
        </h1>
        "

    }
        
        
$showCommandOutputIfLoggedIn = {
    param($cmdName, [Hashtable]$CmdParameter = @{}) 
    
    if (-not $session['User'] -and $request.Cookies["$($module.Name)_ConfirmationCookie"]) {
        
        $storageAccount = (Get-WebConfigurationSetting -Setting $pipeworksManifest.UserTable.StorageAccountSetting)
        $storageKey = (Get-WebConfigurationSetting -Setting $pipeworksManifest.UserTable.StorageKeySetting)
        $confirmCookie= $Request.Cookies["$($module.Name)_ConfirmationCookie"]

        $matchApiInfo = [ScriptBLock]::Create("`$_.SecondaryApiKey -eq '$($confirmCookie.Values['Key'])'")           
        $userFound = 
            Search-AzureTable -TableName $pipeworksManifest.UserTable.Name -StorageAccount $storageAccount -StorageKey $storageKey -Where $matchApiInfo 

        if (-not $userFound) {
            $secondaryApiKey = $session["$($module.Name)_ApiKey"]
            $confirmCookie = New-Object Web.HttpCookie "$($module.Name)_ConfirmationCookie"
            $confirmCookie["Key"] = "$secondaryApiKey"
            $confirmCookie["CookiedIssuedOn"] = (Get-Date).ToString("r")
            $confirmCookie.Expires = (Get-Date).AddDays(-365)                    
            $response.Cookies.Add($confirmCookie)
            $response.Flush()
            
            $response.Write("User $($confirmCookie | Out-String) Not Found, ConfirmationCookie Set to Expire")                                        
            return
        }                                        

        $userIsConfirmed = $userFound |
            Where-Object {
                $_.Confirmed -ilike "*$true*" 
            }
            
        $userIsConfirmedOnThisMachine = $userIsConfirmed |
            Where-Object {
                $_.ConfirmedOn -ilike "*$($Request['REMOTE_ADDR'] + $request['REMOTE_HOST'])*"
            }
                
        if (-not $userIsConfirmedOnThisMachine) {                                                            
                return
        }
         
        $session['User'] = $userIsConfirmedOnThisMachine
        $session['UserId'] = $userIsConfirmedOnThisMachine.UserId


        $secondaryApiKey = "$($confirmCookie.Values['Key'])"                                                                                   

        $partitionKey = $userIsConfirmedOnThisMachine.PartitionKey
        $rowKey = $userIsConfirmedOnThisMachine.RowKey
        $tableName = $userIsConfirmedOnThisMachine.TableName
        $userIsConfirmedOnThisMachine.psobject.properties.Remove('PartitionKey')
        $userIsConfirmedOnThisMachine.psobject.properties.Remove('RowKey')
        $userIsConfirmedOnThisMachine.psobject.properties.Remove('TableName')                    
        $userIsConfirmedOnThisMachine | Add-Member -MemberType NoteProperty -Name LastLogon -Force -Value (Get-Date)
        $userIsConfirmedOnThisMachine | Add-Member -MemberType NoteProperty -Name LastLogonFrom -Force -Value "$($Request['REMOTE_ADDR'] + $request['REMOTE_HOST'])"
        $userIsConfirmedOnThisMachine |
            Update-AzureTable -TableName $tableName -RowKey $rowKey -PartitionKey $partitionKey -Value { $_} 
            
        $session['User'] = $userIsConfirmedOnThisMachine                
    }
                             
        
    if ($session['User']) {   
        $loginName = if ($session['User'].Name) {
            $session['User'].Name
        } else {
            $session['User'].UserEmail
        }
        $commandInfo = Get-Command $cmdName        
        & $commandInfo @CmdParameter | Out-HTML
    } else { @"
<div id='loginHolder_For_$cmdName'>
     
</div>
<script>
    query = 'Module.ashx?join=true'
    `$(function() {
        `$.ajax({
            url: query,
            cache: false,
            success: function(data){
                `$('#loginHolder_For_$cmdName').html(data);
            }
        })
    })
</script>
"@

    }
    
}

$showCommandInputIfLoggedIn = { param($cmdName) 
    if (-not $session['User'] -and $request.Cookies["$($module.Name)_ConfirmationCookie"]) {
        
        $storageAccount = (Get-WebConfigurationSetting -Setting $pipeworksManifest.UserTable.StorageAccountSetting)
        $storageKey = (Get-WebConfigurationSetting -Setting $pipeworksManifest.UserTable.StorageKeySetting)
        $confirmCookie= $Request.Cookies["$($module.Name)_ConfirmationCookie"]

        $matchApiInfo = [ScriptBLock]::Create("`$_.SecondaryApiKey -eq '$($confirmCookie.Values['Key'])'")           
        $userFound = 
            Search-AzureTable -TableName $pipeworksManifest.UserTable.Name -StorageAccount $storageAccount -StorageKey $storageKey -Where $matchApiInfo 

        if (-not $userFound) {
            $secondaryApiKey = $session["$($module.Name)_ApiKey"]
            $confirmCookie = New-Object Web.HttpCookie "$($module.Name)_ConfirmationCookie"
            $confirmCookie["Key"] = "$secondaryApiKey"
            $confirmCookie["CookiedIssuedOn"] = (Get-Date).ToString("r")
            $confirmCookie.Expires = (Get-Date).AddDays(-365)                    
            $response.Cookies.Add($confirmCookie)
            $response.Flush()
            
            $response.Write("User $($confirmCookie | Out-String) Not Found, ConfirmationCookie Set to Expire")                                        
            return
        }                                        

        $userIsConfirmed = $userFound |
            Where-Object {
                $_.Confirmed -ilike "*$true*" 
            }
            
        $userIsConfirmedOnThisMachine = $userIsConfirmed |
            Where-Object {
                $_.ConfirmedOn -ilike "*$($Request['REMOTE_ADDR'] + $request['REMOTE_HOST'])*"
            }
                
        if (-not $userIsConfirmedOnThisMachine) {                                                            
                return
        }
         
        $session['User'] = $userIsConfirmedOnThisMachine
        $session['UserId'] = $userIsConfirmedOnThisMachine.UserId


        $secondaryApiKey = "$($confirmCookie.Values['Key'])"                                                                                   

        $partitionKey = $userIsConfirmedOnThisMachine.PartitionKey
        $rowKey = $userIsConfirmedOnThisMachine.RowKey
        $tableName = $userIsConfirmedOnThisMachine.TableName
        $userIsConfirmedOnThisMachine.psobject.properties.Remove('PartitionKey')
        $userIsConfirmedOnThisMachine.psobject.properties.Remove('RowKey')
        $userIsConfirmedOnThisMachine.psobject.properties.Remove('TableName')                    
        $userIsConfirmedOnThisMachine | Add-Member -MemberType NoteProperty -Name LastLogon -Force -Value (Get-Date)
        $userIsConfirmedOnThisMachine | Add-Member -MemberType NoteProperty -Name LastLogonFrom -Force -Value "$($Request['REMOTE_ADDR'] + $request['REMOTE_HOST'])"
        $userIsConfirmedOnThisMachine |
            Update-AzureTable -TableName $tableName -RowKey $rowKey -PartitionKey $partitionKey -Value { $_} 
            
        $session['User'] = $userIsConfirmedOnThisMachine                
    }
    
    if ($session['User']) {
        $loginName = if ($session['User'].Name) {
            $session['User'].Name
        } else {
            $session['User'].UserEmail
        }
        $hide = @{}
        if ($pipeworksManifest.WebCommand.$cmdName.HideParameter) {
            $hide["HideParameter"] = $pipeworksManifest.WebCommand.$cmdName.HideParameter
        }
        Request-CommandInput -CommandMetaData (Get-Command $cmdName) -Action "$cmdName/?" @hide
    } else { @"
<div id='loginHolder_For_$cmdName'>
     
</div>
<script>
    query = 'Module.ashx?join=true'
    `$(function() {
        `$.ajax({
            url: query,
            cache: false,
            success: function(data){
                `$('#loginHolder_For_$cmdName').html(data);
            }
        })
    })
</script>
"@

    }
}


$editProfileIfLoggedIn = { 
    if ($session['User']) {
        @"
<div id='editProfileHolder'>
     
</div>
<script>
    query = 'Module.ashx?editProfile=true'
    `$(function() {
        `$.ajax({
            url: query,
            cache: false,
            success: function(data){
                `$('#editProfileHolder').html(data);
            }
        })
    })
</script>
"@

    } elseif ($request.Cookies["$($module.Name)_ConfirmationCookie"]) {
        $out = ""
        $out += Write-Link -Caption "Login as $($request.Cookies["$($module.Name)_ConfirmationCookie"]["Email"])?" -Url "Module.ashx?Login=true" |
            New-Region -LayerId "ShouldILogin_For_$cmdName" -Style @{
                'margin-left' = $MarginPercentLeftString
                'margin-right' = $MarginPercentRightString
            }
        $out
    } else { @"
<div id='loginToEditProfile'>
     
</div>
<script>
    query = 'Module.ashx?join=true'
    `$(function() {
        `$.ajax({
            url: query,
            success: function(data){
                `$('#loginToEditProfile').html(data);
            }
        })
    })
</script>
"@

    }
}
    
$header = 
    $headerContent |
        New-Region -LayerID InnerHeader -Style @{
            "margin-left" = "auto"
            "margin-right" = "auto"            
            "color" = $bgColor            
            "width" = '100%'
        } | 
        New-Region -LayerID OuterHeader -Style @{                
            "margin-left" = "5%"
            "margin-right" = "5%"
        } 


$dashboardLayers = @{}
$dashboardItemOrder = @()
$dashboardUrls = @{}
$defaultDashboardItem = ""
foreach ($dashboardTable in @($pipeworksManifest.Dashboard.Dashboards)) {
    
    

    $itemOrder = @()
    $layers = @{}
    
    # add the link to other dashboards
    
    if ($dashboardTable.Name -ne $pageName) { 
        $dashboardItemOrder += $dashboardTable.Name
        $dashboardUrls[$dashboardTable.Name] += "$($dashboardTable.Name).aspx"        
        continue 
    } else {
        $defaultDashboardItem = $dashboardTable.Name
    }
    $defaultLayerParameter = @{}
    foreach ($dashboardItemHashtable in $dashboard.Items) {
        
        $dashboardItem = New-Object PSObject -Property $dashboardItemHashtable
        
        $layerContent = 
            if ($dashboardItem.Id) {
                $storageAccount = Get-WebConfigurationSetting -Setting $pipeworksManifest.Table.StorageAccountSetting
                $storageKey = Get-WebConfigurationSetting -Setting $pipeworksManifest.Table.StorageKeySetting
                $part, $row = $dashboardItem.Value.Id -split ":"
                Show-WebObject -Table $pipeworksManifest.Table.Name -Part $part -Row $row
            } elseif ($dashboardItem.Content) {        
                $dashboardItem.Content
            } elseif ($dashboardItem.Command) {
                $cmdObj = Get-Command $dashboardItem.Command
              
                $getParameters = @{}
                if ($dashboardItem.QueryParameter) {   
                    
                    foreach ($qp in $dashboardItem.QueryParameter.GetEnumerator()) {
                        
                        if ($request[$qp.Key]) {
                            $getParameters += @{$qp.Value.Trim()=$request[$qp.Key].Trim()}
                        }
                        
                    }        
                    
                    if (-not $getParameters.Count) { continue} else {
                        $defaultLayerParameter["Default"] = $dashboardItem.DisplayName
                    }
                }
                
                if ($dashboardItem.DefaultParameter) {
                    
                    foreach ($qp in $dashboardItem.DefaultParameter.GetEnumerator()) {
                        $getParameters += @{$qp.Key=$qp.Value}                        
                    }
                }
                                
                
                if ($getParameters.Count) {
                    if ($pipeworksManifest.WebCommand.($cmdObj.Name).RequireLogin -or 
                        $dashboardItem.RequireLogin) {
                        & $showCommandOutputIfLoggedIn ($cmdObj.Name) $getParameters | Out-HTML
                    } else {            
                        & $cmdObj @getParameters | Out-HTML
                    }
                } else {
                    if ($pipeworksManifest.WebCommand.($cmdObj.Name)) {
                        if ($pipeworksManifest.WebCommand.($cmdObj.Name).RequireLogin -or 
                            $dashboardItem.RequireLogin) {
                            & $showCommandInputIfLoggedIn ($cmdObj.Name)
                        } else {            
                            Request-CommandInput -Action "$($cmdObj.Name)/" -CommandMetaData $cmdObj -DenyParameter $pipeworksManifest.WebCommand.($cmdObj.Name).HideParameter
                        }  
                    }
                    # Display an input form if the command is a web command
                }                                
               
                
                   
            } elseif ($dashboardItem.EditProfile -and $session['User']) {
                $displayName = $dashboardItem.EditProfile
                & $editProfileIfLoggedIn        
            }
            
            if ($layerContent) {
                $itemOrder += $dashboardItem.DisplayName
                $layers[$dashboardItem.DisplayName] =$layerContent
            }
    }

    $LayerOrder = 
        $ItemOrder

    
    if ($request['Show']) {
        $defaultLayerParameter['Default'] = $Request['Show']
    }

    $content = 
        New-Region -LayerID "Dashboard_$($dashboard.Name)" -Style @{
            "border"="blank"
            "width" = "100%"
            "padding" = "3px"
        } -AsLeftSidebarMenu -Order $itemOrder -Layer $layers @defaultLayerParameter

    $dashboardItemOrder += $dashboardTable.Name
    $dashboardLayers[$dashboardTable.Name] = $content
    
     
}

$style = @{    
    "margin-left" = "5%"
    "margin-right" = "5%"    
}

$browserSpecificStyle =
    if ($Request.UserAgent -clike "*IE*") {
        @{'height'='78%';"margin-top"="-5px"}
    } else {
        @{'min-height'='78%'}
    }  

$style += $browserSpecificStyle
$content = 
    New-Region -LayerID "MainDashboard" -AsPopIn -Order $dashboardItemOrder -Layer $dashboardLayers -Style $style -LayerUrl $dashboardUrls -Default $defaultDashboardItem 



$footer = 
    if ($orgInfo.Count) {
        "<p text-align='center' style='background-color:$edgeColor'>
    <span itemprop='Address'>$($orgInfo.Address)</span> | <span itemprop='telephone'>$($orgInfo.telephone)</span><br><span style='font-size:xx-small'><span itemprop='name'>$($orgInfo.Name)</span> | Copyright $((Get-Date).Year)
    </span></p>"

    } else {
        " "
    }

$footer = $footer| 
    New-Region -LayerID Footer -ItemType http://schema.org/Organization -CssClass ui-widget-content, ui-corner-all -Style @{
        "margin-left" = "5%"
        "margin-right" = "5%"                  
        "Color" = $dashboardColor
        "padding" = "10px"          
        "text-align" = "center"
    }
    
    
$lowerLoginButton = if ($pipeworksManifest.UserTable.Name) {
    Write-Link -Url "Module.ashx?Login=true" -Caption "<span class='ui-icon ui-icon-locked'> Login </span>" |
        New-Region -LayerID LoginButtonLayer -Style @{
            Position = 'Absolute'
            Right = '5px'
            Bottom = '5px'
        }
} else {
    ""
}    

$lowerLoginButton, $header, $content | 
    New-WebPage -NoCache -Css @{
        Body = @{
            "background-color" = $bgColor
            "font" = $fontName
        }
    } -Title "$pageName"
            
        } 
        if (-not $outputPages.Count) {
            $outputPages["default.pspage"] = "<| $pageScript |>"
        }
        $outputPages["$pageName.pspage"] = "<| $pageScript |>"
    }        
        
        
        
                    
          
        
        $outputPages                         
        
        
                                           
    }        
}