PoshCode Archive  Artifact [4d01ad1cd8]

Artifact 4d01ad1cd843b9b09c650da1e4a1a32b117e5b58b1573951bab62d9e6574e803:

  • File DekiWiki-Module.ps1 — part of check-in [62d0abaaf3] at 2018-06-10 14:22:36 on branch trunk — The first of many script cmdlets for working with DekiWiki (user: unknown size: 11945)

# encoding: ascii
# api: powershell
# title: DekiWiki Module
# description: The first of many script cmdlets for working with DekiWiki
# version: 1.5
# type: module
# license: CC0
# function: Set-DekiUrl
# x-poshcode-id: 692
# x-archived: 2010-05-08T05:18:14
#
# Depends on the HttpRest script-module: http://poshcode.org/691
#
## DekiWiki Module 1.5
#require -version 2.0
## Depends on the HttpRest script-module:
##              http :// huddledmasses.org/using-rest-apis-from-powershell-with-the-dream-sdk/ 
####################################################################################################
## The first of many script cmdlets for working with DekiWiki, based on the HttpREST module
##
## For documentation of the DekiWiki REST API:
## http :// wiki.developer.mindtouch.com/MindTouch_Deki/API_Reference
####################################################################################################
## USAGE:
##   Add-Module DekiWiki
##   Set-DekiUrl http`://powershell.wik.is
##   ...
## ## For usage of each cmdlet, see the comments above each individual function ## ## ## ## ## ## ##
####################################################################################################
## History:
## v 1.5 Rewrite with the "Dream" specific code extracted to the HttpRest module
## v 1.2 Remove-DekiFile
## v 1.0 Set-DekiCredential, Get-DekiContent, Set-DekiContent, New-DekiContent, Set-DekiFile
## 
$hr = Add-Module HttpRest -Passthru
Add-Module "$PSScriptRoot\Utilities.ps1"

$url = "http://powershell.wik.is"
$api = "$url/@api/deki"

#New-Alias Set-DekiCredential Set-HttpCredential -EA "SilentlyContinue"
#New-Alias Set-DekiUrl Set-HttpDefaultUrl -EA "SilentlyContinue"

FUNCTION Set-DekiUrl {
   PARAM ([uri]$baseUri=$(Read-Host "Please enter the base Uri for your RESTful web-service"))
   Set-HttpDefaultUrl $baseUri
}

FUNCTION Set-DekiCredential {
   PARAM($Credential=$(Get-Credential -Title "Http Authentication Request - $($global:url.Host)" `
                                      -Message "Your login for $($global:url.Host)" `
                                      -Domain $global:url.Host ))
   Set-HttpCredential $Credential
}

New-Alias e2 Encode-Twice -EA "SilentlyContinue"


Add-Type '
public class ModuleInfo {
   public string Name;
   public string[] Author;
   public string CompanyName;
   public string[] Copyright;
   public string[] Description;
   public System.Version ModuleVersion;
   public string[] RequiredAssemblies;
   public string[] Dependencies;
   public System.Guid GUID = System.Guid.NewGuid();
   public string[] PowerShellVersion;
   public string[] ModulesToProcess;
   public System.Version CLRVersion;
   public string[] FormatsToProcess;
   public string[] TypesToProcess;
   public string[] OtherItems;
   public string ModuleFile;
}
' -EA "SilentlyContinue"

# Retrieve a sitemap of all the pages in a wiki, 
# OR Retrieve all the subpages of a page as a sitemap
# Added by Mark E. Schill
CMDLET Get-DekiSiteMap {
PARAM( 
	[Parameter(Position=0, Mandatory=$false)]
	[string]
	$StartPage
,
	[Parameter(Position=1, Mandatory=$false)]
	[ValidateSet("xml","html","google")]
	[string]
	$Format = "xml"
)
   if($StartPage) {
      Invoke-Http GET "pages/=$(e2 $StartPage)/tree" @{"format"=$format} | Receive-Http -Out Xml
   } else {
      Invoke-Http GET "pages" @{"format"=$format} | Receive-Http -Out Xml
   }
}


# Get the contents of a page from a DekiWiki
# Note that by default you retrieve the "view" (rendered) markup
# If you want to see it before the extensions run, you should specify at least -mode viewnoexecute
# If you want to see the source so you can make changes, be sure to specify -mode edit
CMDLET Get-DekiContent {
PARAM(
   [Parameter(Position=0, Mandatory=$true)]
   [string]
   $pageName
, 
   [Parameter(Position=1, Mandatory=$false)]
   [int]
   $section
, 
   [Parameter(Position=5, Mandatory=$false)]
   [ValidateSet("edit", "raw", "view", "viewnoexecute")]
   [string]
   $mode="view"
)
   Invoke-Http "GET" "pages/=$(e2 $pageName)/contents" @{mode=$mode;section=$section} | Receive-Http -Out Xml
}

# Get-DekiFile will LIST all files if called with just a PageName
# Otherwise, fileName can be a single fileName, or wildcards
# To download all the attachments on a page, try:
# Get-DekiFile PageName | Get-DekiFile 
CMDLET Get-DekiFile {
PARAM(
   [Parameter(Position=0, Mandatory=$true, ValueFromPipelineByPropertyName=$true)]
   [string]
   $pageName
,
   [Parameter(Position=1, Mandatory=$false, ValueFromPipelineByPropertyName=$true)]
   [string]
   $fileName
,
   [Parameter(Position=2, Mandatory=$false)]
   [string]
   $destination
)
PROCESS {
   ## Remember, we can get both on the pipeline, so ...
   $files = Invoke-Http "GET" "pages/=$(e2 $pageName)/files" | Receive-Http Xml //file
   
   Write-Verbose "Fetching $($fileName) from the $($files.Count) in $pageName"
   if(!$fileName) {
      ## Add a PageName property, because then you can pipe the output back to Get-DekiFile after filtering...
      write-output $files | Add-Member NoteProperty PageName $pageName -passthru
   } else {
      ## Using -like means $fileName allows globbing
      foreach($file in $($files | where { $_.filename -like $fileName } )) {
         Invoke-Http "GET" "pages/=$(e2 $pageName)/files/=$(e2 $file.filename)" | Receive-Http File $(Get-FileName $file.filename $destination)
      }
   }
}
}

# Set the contents of a DekiWiki page
# Note that you can pass the content as an XML document, plain text, or a filename...
CMDLET Set-DekiContent {
PARAM(
   [Parameter(Position=0, Mandatory=$true)]
   [string]
   $pageName
, 
   [Parameter(Position=1, Mandatory=$true, 
                          ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
   [Alias("FullName")]
   [string]
   $content
, 
   [Parameter(Position=2, Mandatory=$false)]
   $section
,
   [switch]$new
,
   [switch]$append
)
   $with = @{"edittime"=$(Get-UtcTime "yyyyMMddhhmmss")}
   
   if($new) {
      $with.abort = "exists"
   }
   if($append) {
      $with.section = "0"
   } elseif($section) {
      $with.section = $section
   }

   $result = Invoke-Http POST "pages/=$(e2 $pageName)/contents" -With $with -Content $content -Auth $true -Wait
   if($result.IsSuccessful) {
      return "$url/$($result | Receive-Http Text //edit/page/path)"
   } else {
      return $result
   }
}

# Same as Set-DekiContent, except this one crashes if the page already exists.
# This is technically the only safe way to create new pages without fear of conflicts...
CMDLET New-DekiContent {
PARAM(
   [Parameter(Position=0, Mandatory=$true)]
   [string]$pageName
, 
   [Parameter(Position=1, Mandatory=$true, 
              ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
   [Alias("FullName")]
   [string]
   $content
)
PROCESS {
   Set-DekiContent $pageName $content -new
}
}

# Add a new attachment (or a new version of an existing attachment)
# You can use wildcards, and specify arrays.  But you could also include descriptions
# USAGE:
## Set-DekiFile Path/PageName *.ps1,*.psm1
## Set-DekiFile Path/PageName @{"Neat.jpg"="A really cool screenshot";"Source.zip"="The source code"}
## Set-DekiFile Path/PageName Something.png
## ls *.png | Set-DekiFile Path/PageName
CMDLET Set-DekiFile {
param(
   [Parameter(Position=0, Mandatory=$true)]
   [string]$pageName
, 
   [Parameter(Position=1, Mandatory=$true,
              ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
   [Alias("FullName")]
   $Files
)
   # Two ways to specify files: 1) hashtable: file = "description" 1) array: file, file, file
   $hasDescriptions = $false;
   if($files -is [Hashtable]) {
      $hasDescriptions = $true;
      $fileNames = $files.Keys
   } else {
      $fileNames = $files
   }
   
   foreach($fileName in $fileNames) {
      foreach($file in (gci $fileName)) {
         $with = @{}
         if($hasDescriptions) {
            $With.description = $files[$fileName]
         }

         $result = Http-Invoke PUT "pages/=$(e2 $pageName)/files/=$($file.Name)" $With $file.FullName -Wait
         if($result.IsSuccessful) {
            return ($result | Receive-Http Text //file/href)
         } else {
            return $result.Response
         }
      }
   }
}

## Move a page from one place to another (leaving an "alias" placeholder)

CMDLET Move-DekiContent {
PARAM(
   [Parameter(Position=0, Mandatory=$true)]
   [string]
   $pageName
, 
   [Parameter(Position=1, Mandatory=$true)]
   [string]
   $newPageName
)
   $with = @{"to"="$newPageName"}
   
   $result = Invoke-Http POST "pages/=$(e2 $pageName)/move" -With $with -Auth $true -Wait
   if($result.IsSuccessful) {
      return "$url/$($result | Receive-Http Text '//page[1]/path' )"
   } else {
      return $result
   }
}

CMDLET New-DekiAlias {
PARAM(
   [Parameter(Position=0, Mandatory=$true)]
   [string]
   $pageName
, 
   [Parameter(Position=1, Mandatory=$true)]
   [string]
   $Alias
)
  
   $result = Invoke-Http POST "pages/=$(e2 $pageName)/move" @{"to"="$Alias"} -Auth $true -Wait
   if($result.IsSuccessful) {
      $aliasPage = "$url/$($result | Receive-Http Text '//page[1]/path' )"
      $result = Invoke-Http POST "pages/=$(e2 $Alias)/move" @{"to"="$pageName"} -Auth $true -Wait
      if($result.IsSuccessful) {
         return $aliasPage
      } else {
         return $result
      }
   } else {
      return $result
   }
}

# Delete a page from a dekiwiki, with an option to RECURSIVELY delete all child pages.
# NOTE: if you delete a page that has children, and don't recurse, the contents are removed
#       and then replaced with template text, because they can't go away completely
# NOTE: if you delete a page, it is actually put in the archive
# TODO: add a -Force parameter to allow them to be permanently deleted from the archive
CMDLET Remove-DekiContent {
PARAM(
   [Parameter(Position=0, Mandatory=$true,ValueFromPipelineByPropertyName=$true)][string]$pageName
,
   [Parameter(Position=2, Mandatory=$false)][switch]$recurse
)

   Http-Invoke DELETE "pages/=$(e2 $pageName)" @{recursive=$($recurse.ToBool())}
   if($result.IsSuccessful) {
      return "DELETED $url/$PageName"
   } else {
      return $result.Response
   }
}

# Delete a file attachment from a dekiwiki page
# You can use wildcards, and specify arrays:
## USAGE:
## Remove-DekiFile Path/PageName *.ps1,*.psm1
## Remove-DekiFile Path/PageName Something.png
## ls *.png | Remove-DekiFile Path/PageName
CMDLET Remove-DekiFile {
PARAM(
   [Parameter(Position=0, Mandatory=$true,ValueFromPipelineByPropertyName=$true)][string]$pageName
,
   [Parameter(Position=1, Mandatory=$true,
              ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true)]
   [Alias("Name")]
   $fileNames
)
   $files = Invoke-Http GET "pages/=$(e2 $pageName)/files" | Receive-Http Text //file/filename
   foreach($fileName in $fileNames) {
      foreach($file in $($files -like $fileName)) {
         $path = "pages/=$(e2 $pageName)/files/=$(e2 $file)"
         Write-Host $path -fore cyan
         $result = Invoke-Http DELETE $path -Auth $true -Wait
      
         if($result.IsSuccessful) {
            "DELETED: $api/$path"
         } else {
            $result.Response
         }
      }
   }
}

Export-ModuleMember Set-DekiCredential, Set-DekiUrl, 
                    Get-HtmlHelp, Get-DekiFile, Get-DekiSiteMap, Get-DekiContent, 
                    Set-DekiContent, New-DekiContent,
                    Move-DekiContent, New-DekiAlias,
                    Remove-DekiContent, Remove-DekiFile,
                    Set-DekiFile