Schematics/Crudbin/Use-CrudBinSchematic.ps1

function Use-CrudBinSchematic
{
    <#
    .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
    )
    
    begin {
        $pages = @{}
    }
    
    process {                                                    
        if (-not ($parameter.Read -and $parameter.Create)) {
            Write-Error "crudbin must include gets and adds"
            return
        }
        
        if ($parameter.RequiresSignup)
        {
            if (-not $manifest.UserTable.Name) {
                Write-Error "If the crudbin requires signup, the manifest must contain a user table"
                return
            }
            
            if (-not $Manifest.UserTable.StorageAccountSetting) {
                Write-Error "No storage account name setting found in manifest"
                return
            }
            
            if (-not $manifest.UserTable.StorageKeySetting) {
                Write-Error "No storage account key setting found in manifest"
                return
            }
        } else {
            if (-not $manifest.Table.Name) {
                Write-Error "Bins must have a table or a user table"
                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
            }
        }
        
        
        
        
        # Data bins let people create, read, update, or remove structed items via several commands.
        
        
                
        
        $crudbinPage = {            
    




if ($pipeworksManifest.UserTable) {
    $userTableParameters = @{
        StorageAccount = (Get-WebConfigurationSetting -Setting $pipeworksManifest.UserTable.StorageAccountSetting)
        StorageKey = (Get-WebConfigurationSetting -Setting $pipeworksManifest.UserTable.StorageKeySetting)
        TableName = $pipeworksManifest.UserTable.Name
    }
    if (-not $connectedToTable) {    
        $connectedToTable = Get-AzureTable @userTableParameters
    }
}

if ($pipeworksManifest.Table) {
    $tableParameters = @{
        StorageAccount = (Get-WebConfigurationSetting -Setting $pipeworksManifest.Table.StorageAccountSetting)
        StorageKey = (Get-WebConfigurationSetting -Setting $pipeworksManifest.Table.StorageKeySetting)
        TableName = $pipeworksManifest.Table.Name
    }
    if (-not $connectedToTable) {    
        $connectedToTable = Get-AzureTable @tableParameters
    }
}

        
$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 { 
        $loginUrl = if ($pipeworksManifest.Facebook.AppId) {
            "Module.ashx?FacebookLogin=true"
        } else {
            "Module.ashx?join=true"
        }
@"
<div id='loginHolder_For_$cmdName'>
     
</div>
<script>
    query = '$loginUrl'
    `$(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 { 
        $loginUrl = if ($pipeworksManifest.Facebook.AppId) {
            "Module.ashx?FacebookLogin=true"
        } else {
            "Module.ashx?join=true"
        }
@"
<div id='loginHolder_For_$cmdName'>
     
</div>
<script>
    query = '$loginUrl'
    `$(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>
"@

    }
}



$crudbinParameter = $pipeworksManifest.crudbin



$regionParameters = @{
    Id = 'MainRegion'
    Layer = @{}
    Order = @()    
    AsPopin = $true
    
}


$info = $crudBinParameter.Info


if ($info) {

    foreach ($kv in $info.GetEnumerator()) {
        $part, $row = $kv.Value.Id -split ":"
        $displayName = $kv.Value.DisplayName
        $storageAccount, $storageKey, $tableName = 
            if ($pipeworksManifest.UserTable) {
                Get-WebConfigurationSetting -Setting $pipeworksManifest.UserTable.StorageAccountSetting
                Get-WebConfigurationSetting -Setting $pipeworksManifest.UserTable.StorageKeySetting
                $pipeworksManifest.UserTable.Name
            } elseif ($pipeworksManifest.UserTable) {
                Get-WebConfigurationSetting -Setting $pipeworksManifest.Table.StorageAccountSetting
                Get-WebConfigurationSetting -Setting $pipeworksManifest.Table.StorageKeySetting
                $pipeworksManifest.Table.Name
            }
         
        $regionParameters.Layer[$displayName] =    
            Show-WebObject -StorageAccount $storageAccount -StorageKey $storageKey -Table $tableName -Part $part -Row $row 
        $regionParameters.Order += $displayName.Trim()
    }
}


if ($crudBinParameter.EditProfile -and $session['User']) {
    $displayName = $crudBinParameter.EditProfile
    $regionParameters.Layer[$displayName] = & $editProfileIfLoggedIn
    $regionParameters.Order += $displayName.Trim()
}

$creates = $crudBinParameter.Create

foreach ($kv in $creates.GetEnumerator()) {
    $newCmd = Get-Command $kv.Value.Command
    $displayName = $kv.Value.DisplayName
    $regionContent = 
    if ($pipeworksManifest.WebCommand.($newCmd.Name).RequireLogin -or 
        $kv.Value.RequireLogin) {
        
        & $showCommandInputIfLoggedIn ($newCmd.Name) 
    } else {
        Request-CommandInput -CommandMetaData $newCmd.Name -DenyParameter $pipeworksManifest.WebCommand.($newCmd.Name).HideParameter
    }
         
    if ($regionContent) {
        $regionParameters.Layer[$displayName.Trim()] = "$regionContent"
        $regionParameters.Order += $displayName.Trim() 
    }   
    
            
    # If the getter is the default, and there's not already a default layer, make it the default layer
    if ($kv.Value.IsDefault) {
        $regionParameters.Default = $kv.Value.DisplayName
    }
}

# Process getters first
$getters = $crudBinParameter.Read

foreach ($kv in $getters.GetEnumerator()) {
    # If a default handler is present, use this information to populate a content area
        
    $getCmd = Get-Command $kv.Value.Command
    
    if (-not $getCmd) { continue }
    
    
    $getParameters = @{}
    if ($kv.Value.QueryParameter) {   
        
        foreach ($qp in $kv.Value.QueryParameter.GetEnumerator()) {
            
            if ($request[$qp.Key]) {
                $getParameters += @{$qp.Value.Trim()=$request[$qp.Key].Trim()}
            }
            
        }        
        
    }
    
    if ($kv.Value.DefaultParameter) {
        
        foreach ($qp in $kv.Value.DefaultParameter.GetEnumerator()) {
            $getParameters += @{$qp.Key=$qp.Value}                        
        }
    }
    
    $regionContent = if ($getParameters.Count) {
        if ($pipeworksManifest.WebCommand.($getCmd.Name).RequiresLogin -or 
            $kv.Value.RequireLogin) {
            . $showCommandOutputIfLoggedIn ($getCmd.Name) $getParameters | Out-HTML
        } else {            
            & $getCmd @getParameters | Out-HTML
        }
    } else {
        ''
    }
    
    
    
    if ($regionContent) {
        $regionParameters.Layer[$kv.Value.DisplayName] = $regionContent
        $regionParameters.Order += $kv.Value.DisplayName
        # If the getter is the default, and there's not already a default layer, make it the default layer
        if ($kv.Value.IsDefault) {
            $regionParameters.Default = $kv.Value.DisplayName
        }
    }                            
}

$default = 
    if ($Request['Show']) {
        $Request['Show']
    } else {
        ''
    }
    
if ($pipeworksManifest.CrudBin.Order) {
    $regionParameters.Order = $pipeworksManifest.CrudBin.Order
} else {
    $regionParameters.Order =  $regionParameters.Order  | Sort-Object
}

if ($default.Length) {
    $regionParameters.Default = $default
}

$mainContent = 
    New-Region @regionParameters |
        New-Region -Style @{
            'Margin-left'='10%'
            'Margin-Right' = '10%'
            'Text-Align' = 'center'
        }  
        
$lowerLoginButton = if ($pipeworksManifest.UserTable.Name) {
    $loginLink = if ($pipeworks.Facebook.Appid) {
        "Module.ashx?FacebookLogin=true"
    } else {
        "Module.ashx?Login=true"
    }
    Write-Link -Url "$loginLink" -Caption "<span class='ui-icon ui-icon-locked'> Login </span>" |
        New-Region -LayerID LoginButtonLayer -Style @{
            Position = 'Absolute'
            Right = '5px'
            Bottom = '5px'
        }
} else {
    ""
}
    
$lowerLoginButton, $mainContent | 
    New-WebPage -NoCache -Title $module.Name -UseJQueryUI -JQueryUITheme $pipeworksManifest.JQueryUITheme |
    Out-HTML -WriteResponse


        }



        
        $pages["bin.pspage"] = "<|
 
$crudbinPage
|>"

        $pages["default.pspage"] ="<|
$crudbinPage
|>"
     
                
    }
    end {
        $pages
    }
}