Schematics/Blog/Use-BlogSchematic.ps1

function Use-BlogSchematic
{
    <#
    .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.Name) {
            Write-Error "No Blog name found in parameters"
            return
        }
        
        
        $blogName = $parameter.Name 
        if (-not $Parameter.Description) {
            Write-Error "No description found in parameters"
            return
        }
        
        
        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
        }
        
        
        #$manifest.AcceptAnyUrl = $true


        $psm1 = Get-childItem $DeploymentDirectory -Filter bin | 
            Get-ChildItem -Filter "$($module)" | 
            Get-ChildItem -Filter "*.psm1"


        # If we find a PSM1, we can do something pretty nifty:
        # Slightly rewrite it with a couple of new commands and aliases:
        # - Get-$ModuleFeed (alias rss)
        # - Show-$ModuleTag (alias tag/tags)
        if ($psm1) {
            
        }
        



                                        
        
        $blogPage = {

#region Resolve the absolute URL
$protocol = ($request['Server_Protocol'] -split '/')[0]  # Split out the protocol
$serverName= $request['Server_Name']                     # And what it thinks it called the server
$shortPath = Split-Path $request['PATH_INFO']            # And the relative path beneath that URL
$remoteCommandUrl =                                      # Put them all together
    $Protocol + '://' + $ServerName.Replace('\', '/').TrimEnd('/') + '/' + $shortPath.Replace('\','/').TrimStart('/')

$absoluteUrl =        
    $remoteCommandUrl.TrimEnd("/") + $request['Url'].ToString().Substring(
        $request['Url'].ToString().LastIndexOf("/"))

#endregion Resolve the absolute URL

#region Unpack blog items
$unpackItem = 
    {
        $item = $_
        $item.psobject.properties |                         
            Where-Object { 
                ('Timestamp', 'RowKey', 'TableName', 'PartitionKey' -notcontains $_.Name) -and
                (-not "$($_.Value)".Contains(' ')) 
            }|                        
            ForEach-Object {
                try {
                    $expanded = Expand-Data -CompressedData $_.Value
                    $item | Add-Member NoteProperty $_.Name $expanded -Force
                } catch{
                    Write-Verbose $_
                
                }
            }
            
        $item.psobject.properties |                         
            Where-Object { 
                ('Timestamp', 'RowKey', 'TableName', 'PartitionKey' -notcontains $_.Name) -and
                (-not "$($_.Value)".Contains('<')) 
            }|                                   
            ForEach-Object {
                try {
                    $fromMarkdown = ConvertFrom-Markdown -Markdown $_.Value
                    $item | Add-Member NoteProperty $_.Name $fromMarkdown -Force
                } catch{
                    Write-Verbose $_
                
                }
            }

        $item                         
    }
#endregion Unpack blog items


#region Blog Metadata
$blogName = 
    if ($pipeworksManifest.Blog.Name) {
        $pipeworksManifest.Blog.Name
    } else {
        $module.Name
    }
    
$blogDescription = 
    if ($pipeworksManifest.Blog.Description) {
        $pipeworksManifest.Blog.Description
    } else {
        $module.Description
    }
$partitionKey = $blogName
#endregion

  
#region Blog Title Bar

$rssButton = Write-Link -Button -Style @{'font-size'='xx-small'} -Caption "<span class='ui-icon ui-icon-signal-diag'></span>" -Url "Module.ashx?rss=$BlogName"
$shareButton = 
    New-Region -AsPopdown -LayerID SharePopdown -Style @{
        'font-size' = 'xx-small'
    } -Layer @{
        "<span class='ui-icon ui-icon-mail-closed'></span>" = "
        $(Write-Link twitter:tweet)
        <br/>
        $(Write-Link google:plusone)
        "

    }
    
    
$searchButton = 
    New-Region -AsPopdown -LayerID SearchPopdown -Style @{
        'font-size' = 'xx-small'
    } -Layer @{
        "<span class='ui-icon ui-icon-search'></span>" = "
        <form>
            <input name='term' value='$([Web.HttpUtility]::HtmlAttributeEncode($request['Term']))'type='text' style='width:80%' placeholder='Search $blogName' />
        </form>
        "

    }

$titleBar = @"
<table style='margin-left:2%;margin-right:2%;width=70%'>
    <tr>
        <td style='width:20%'>
            $(Write-Link -Url '' -Button -Caption "<span style='font-size:large'>$blogName</span>")
        </td>
        <td style='width:50%;text-align:right'>
            $("<span style='font-size:medium;text-align:right'>$blogDescription</span>")
        </td>
        <td style='width:10%;text-align:right'>
        </td>
    </tr>
</table>
 
<br/>
 
<div style='text-align:right'>
    $rssButton
    $shareButton
    $searchButton
</div>
 
<br/>
<br/>
"@
 | 
    New-Region -layerId Titlebar -AsWidget -CssClass clearfix, theme-group, corner-all -Style @{    
        "margin-top" = "1%"  
        "margin-left" = "12%"
        "margin-right" = "12%"    
    }
   
   
#region Generate output
$results = 
    if ($Request['Post']) { 
        #region Fetch a Specific Post
        $storageAccount = Get-WebConfigurationSetting -Setting $pipeworksManifest.Table.StorageAccountSetting
        $storageKey = Get-WebConfigurationSetting -Setting $pipeworksManifest.Table.StorageKeySetting
        $nameMatch  =([ScriptBLock]::Create("`$_.Name -eq '$($request['post'])'"))
        Search-AzureTable -Where $nameMatch -TableName $pipeworksManifest.Table.Name -StorageAccount $storageAccount -StorageKey $storageKey |
            ForEach-Object $unpackItem |
            ForEach-Object { 
                $_ | Out-HTML -ItemType http://schema.org/BlogPosting
            }           
        #endregion Fetch a Specific Post
    } elseif ($Request['Term']) {
        #region Look for a search term
        @"
<div id='OutputContainer' style='height:100%'>
    Searching $($Module.Name) <progress max='100'> </progress>
</div>
 
<script>
    query = 'Module.ashx?Search=' + '$($Request['Term'])'
    `$(function() {
        `$.ajax({
            url: query,
            success: function(data){
                `$('#OutputContainer').html(data);
            },
            error: function(data) {
                `$('#outputContainer').html("Post not found")
            }
        })
    })
</script>
"@

        #endregion Look for a search term
    } else {
        #region Display the latest item

        $storageAccount = (Get-WebConfigurationSetting -Setting $pipeworksManifest.Table.StorageAccountSetting)
        $storageKey = (Get-WebConfigurationSetting -Setting $pipeworksManifest.Table.StorageKeySetting)                                                           

        Search-AzureTable -TableName $pipeworksManifest.Table.Name -Filter "PartitionKey eq '$partitionKey'" -Select Timestamp, DatePublished, PartitionKey, RowKey -StorageAccount $storageAccount -StorageKey $storageKey |
            Sort-Object -Descending {
                if ($_.DatePublished) {
                    [DateTime]$_.DatePublished
                } else {
                    [DateTime]$_.Timestamp
                }
            } |
            Select-Object -First 1 |
            Get-AzureTable -TableName $pipeworksManifest.Table.Name |
            ForEach-Object $UnpackItem |
            ForEach-Object { 
                $_ | Out-HTML -ItemType http://schema.org/BlogPosting
            }
        #endregion Display the latest item
    }             


$mainRegion ="
<div style='text-align:center'>
$($results |
    New-Region -layerId outputContent -Style @{
        "margin-left" = "2%"
        "margin-right" = "2%"
    })
</div>
"
 | 
    New-Region -CssClass theme-group, ui-widget-content, clearfix -Style @{
        "margin-top" = "2%"  
        "margin-left" = "12%"
        "margin-right" = "12%"
        "min-height"='75%'    
    }



$adRegion = 
    if ($pipeworksManifest.AdSlot -and $pipeworksManifest.AdSenseId) {

        $adSenseId = $pipeworksManifest.AdSenseId
        $adslot = $pipeworksManifest.AdSlot
        @"
<br/>
<br/>
<script type='text/javascript'>
<!--
google_ad_client = 'ca-pub-$adSenseId';
/* AdSense Banner */
google_ad_slot = '$adslot';
google_ad_width = 728;
google_ad_height = 90;
//-->
</script>
<script type='text/javascript'
src='http://pagead2.googlesyndication.com/pagead/show_ads.js'>
</script>
"@
     
    } else {
        ""
    }


$adRegion += 
    if ($pipeworksManifest.HidePipeworksBranding) {
""    
    } else {
@"
<br/>
<br/>
<div style='float:bottom'>
    <span style='font-size:xx-small'>Built with <a href='http://PowerShellPipeworks.com'>PowerShell Pipeworks</a>
</div>
"@
    
    }

    

$advert = 
    $adRegion | 
        New-Region -Style @{
            "margin-top" = "1%"  
            "margin-left" = "12%"
            "margin-right" = "12%"
            "text-align" = "center" 
        }

$titleBar, $mainRegion, $advert |
        New-WebPage -Title $blogName -Rss @{
            $blogName = "Module.ashx?rss=$BlogName"
        } -UseJQueryUI

        }
        
        
        
$anyPage = {

    $storageAccount = (Get-WebConfigurationSetting -Setting $pipeworksManifest.Table.StorageAccountSetting)
    $storageKey = (Get-WebConfigurationSetting -Setting $pipeworksManifest.Table.StorageKeySetting)                                                           

    $originalUrl = $context.Request.ServerVariables["HTTP_X_ORIGINAL_URL"]

    $pathInfoUrl = $request.Url.ToString().Substring(0, $request.Url.ToString().LastIndexOf("/"))
            
        
        
    $pathInfoUrl = $pathInfoUrl.ToLower()
    $protocol = ($request['Server_Protocol'] -split '/')[0]  # Split out the protocol
    $serverName= $request['Server_Name']                     # And what it thinks it called the server

    $fullOriginalUrl = $protocol.ToLower() + "://" + $serverName + $request.Params["HTTP_X_ORIGINAL_URL"]
    
    $relativeUrl = $fullOriginalUrl.Replace("$pathInfoUrl", "")            
    
    
    
    if (-not $fullOriginalUrl) {
        "No Original URL"
        return    
    }
    $itemIdentifier = $relativeUrl -split "/" -ne ""
    $itemIdentifier = foreach ($i in $itemIdentifier) {
        [Web.httpUtility]::UrlDecode($i)
    }
    
    
    
    
    # If there's only one identifier, it's a post name
    # If there's two identifiers,
    # ... and the first ID is keyword, keywords, tag, tags, k, or t
    # ... and the first ID is posts, posts, names, name, p, or n
    # ... and the first ID is year or y
    # ... and the first ID is month or m
    # ... and the first ID is ID or i
    # ... or the posts are both numbers
    # ...... If one number has 4 digits, it's the year
    # If there's three identifiers
    # ... then treat them as year/month/day
    
    
    
        
    

    if ($itemIdentifier.Count) {
        $itemIdentifier
    } else {
        
        $selectItems = (@($itemSet.By) + "RowKey" + "Name") | Select-Object -Unique
        $tableItems = Search-AzureTable -TableName $pipeworksManifest.Table.Name -Filter "PartitionKey eq '$($itemSet.Partition)'" -StorageAccount $storageAccount -StorageKey $storageKey -Select $selectItems
        
        $depth = 0
        if ($request -and $request.Params["HTTP_X_ORIGINAL_URL"]) {
        
            $pathInfoUrl = $request.Url.ToString().Substring(0, $request.Url.ToString().LastIndexOf("/"))
            
            
            
            $pathInfoUrl = $pathInfoUrl.ToLower()
            $protocol = ($request['Server_Protocol'] -split '/')[0]  # Split out the protocol
            $serverName= $request['Server_Name']                     # And what it thinks it called the server

            $fullOriginalUrl = $protocol.ToLower() + "://" + $serverName + $request.Params["HTTP_X_ORIGINAL_URL"]
            
            $relativeUrl = $fullOriginalUrl.Replace("$pathInfoUrl", "")            
            
            if ($relativeUrl -like "*/*") {
                $depth = @($relativeUrl -split "/" -ne "").Count - 1
            } else {
                $depth  = 0
            }
            
        }
        
        
        
        foreach ($byTerm in $itemSet.By) {
            $tableItems |
                Sort-Object {
                    if ($_.DatePublished) {
                        [DateTime]$_.DatePublished 
                    } elseif ($_.Timestamp) {
                        [DateTime]$_.Timestamp
                    } 
                } -Descending | 
                Where-Object {
                    $_.$byTerm -like "*${itemIdentifier}*"
                } |
                ForEach-Object -Begin {
                    $popouts = @{}
                    $popoutUrls = @{}
                    
                    $order = @()
                } -Process {
                    $name = if ($_.Name) {
                        $_.Name
                    } else {
                        " " + ($order.Count + 1)
                    }
                    $popoutUrls[$name] = ("../" * $depth) + "Module.ashx?id=$($itemSet.Partition):$($_.RowKey)"
                    $popouts[$name] = " "
                    $order += $name
                } -End {
                    New-Region -LayerID InventoryItems -Order $order -Layer $popouts -LayerUrl $popoutUrls -AsPopout |
                        New-WebPage -Title "$($itemsetName) | $($itemIdentifier)" -UseJQueryUI 
                }
                
        }
           
    }



}
               
        
        
               
        @{
            "default.pspage" = "<| $blogPage |>"                         
            "${BlogName}.pspage" = "<| $blogPage |>"
            
        }                                   
    }        
}