[string] $ListenUrl = "http://+:8080/" Import-Module ./AppriseNotification.psm1 function Write-JsonResponse { param( [Parameter(Mandatory=$true)] [System.Net.HttpListenerResponse] $Response, [Parameter(Mandatory=$true)] [int] $StatusCode, [Parameter(Mandatory=$true)] [hashtable] $Body ) $json = $Body | ConvertTo-Json -Depth 10 $bytes = [System.Text.Encoding]::UTF8.GetBytes($json) $Response.StatusCode = $StatusCode $Response.ContentType = "application/json" $Response.ContentEncoding = [System.Text.Encoding]::UTF8 $Response.ContentLength64 = $bytes.Length $Response.OutputStream.Write($bytes, 0, $bytes.Length) $Response.OutputStream.Close() } function Read-RequestBody { param( [Parameter(Mandatory=$true)] [System.Net.HttpListenerRequest] $Request ) $reader = [System.IO.StreamReader]::new($Request.InputStream, $Request.ContentEncoding) try { return $reader.ReadToEnd() } finally { $reader.Close() } } function Receive-Webhook { param( [Parameter(Mandatory=$true)] [System.Net.HttpListenerContext] $Context ) $request = $Context.Request $response = $Context.Response if ($request.HttpMethod -ne "POST") { Write-JsonResponse -Response $response -StatusCode 405 -Body @{ ok = $false error = "Only POST requests are supported." } return } $rawBody = Read-RequestBody -Request $request $payload = $null try { if ($rawBody) { $payload = $rawBody | ConvertFrom-Json } } catch { Write-JsonResponse -Response $response -StatusCode 400 -Body @{ ok = $false error = "Request body was not valid JSON." } return } Write-Host "Webhook received at $(Get-Date -Format o)" Write-Host "From: $($request.RemoteEndPoint)" Write-Host "Path: $($request.Url.AbsolutePath)" if ($payload) { Write-Host "Payload:" Write-Host ($payload | ConvertTo-Json -Depth 20) } else { Write-Host "Payload: " } $notificationTitle = "" $notificationContent = "" switch($payload.type) { "task.completed" { $notificationTitle = "Donetick Task Completed" $notificationContent = "$($payload.data.chore.name) marked completed!" } "task.reminder" { $notificationTitle = "Donetick Task Reminder" $notificationContent = "$($payload.data.name) is due at $((Get-Date $payload.data.due_date).ToLocalTime())" } "task.created" { $notificationTitle = "Donetick Task Created" if ($null -eq $payload.data.chore.nextDueDate) { $notificationContent = "$($payload.data.chore.name) created" } else { $notificationContent = "$($payload.data.chore.name) created with due date of $((Get-Date $payload.data.chore.nextDueDate).ToLocalTime())" } } default { $notificationTitle = "Donetick Notification" $notificationContent = "Donetick event of type $($payload.type) received" } } Send-AppriseNotification -title $notificationTitle -content $notificationContent Write-JsonResponse -Response $response -StatusCode 200 -Body @{ ok = $true message = "Webhook accepted." receivedAt = (Get-Date -Format o) } } $listener = [System.Net.HttpListener]::new() $listener.Prefixes.Add($ListenUrl) try { $listener.Start() Write-Host "Webhook consumer listening on $ListenUrl" Write-Host "Press Ctrl+C to stop." while ($listener.IsListening) { $context = $listener.GetContext() Receive-Webhook -Context $context } } finally { if ($listener.IsListening) { $listener.Stop() } $listener.Close() }