param( [Parameter(Mandatory = $true)][string]$Path, [string]$ConfigPath = (Join-Path (Split-Path -Parent $PSScriptRoot) 'config.ini') ) $ErrorActionPreference = 'Stop' . (Join-Path $PSScriptRoot 'template-common.ps1') $context = Get-MailContext -ConfigPath $ConfigPath $limits = Get-TemplateLimits $context $sourcePath = [System.IO.Path]::GetFullPath($Path) if (-not (Test-Path -LiteralPath $sourcePath -PathType Leaf)) { throw "Template not found: $sourcePath" } if (-not $sourcePath.StartsWith($limits.Root + [System.IO.Path]::DirectorySeparatorChar, [StringComparison]::OrdinalIgnoreCase)) { throw 'Template must be inside TEMPLATE_ROOT' } $templateName = [System.IO.Path]::GetFileNameWithoutExtension($sourcePath) if ($templateName.Length -gt 200) { throw 'Template file name is too long' } $document = Read-SafeTemplate $sourcePath $images = Get-TemplateImages $document $sourcePath $limits $html = $document.OuterXml $htmlBytes = [System.Text.Encoding]::UTF8.GetBytes($html) $total = $htmlBytes.Length foreach ($image in $images) { $total += $image.Bytes.Length } if ($total -gt $limits.MessageLimit) { throw 'Template and images exceed TEMPLATE_MESSAGE_MAX_BYTES' } $connection = Open-MailDatabase $context $transaction = $null try { $transaction = $connection.BeginTransaction() $next = $connection.CreateCommand() $next.Transaction = $transaction $next.CommandText = 'SELECT MAX([VersionNumber]) FROM [TemplateVersion] WHERE [TemplateName]=?' Add-TextParameter $next 'name' 200 $templateName $maximum = $next.ExecuteScalar() $version = if ($maximum -is [DBNull]) { 1 } else { [int]$maximum + 1 } $insert = $connection.CreateCommand() $insert.Transaction = $transaction $insert.CommandText = 'INSERT INTO [TemplateVersion] ([TemplateName],[VersionNumber],[HtmlContent],[ContentHash],[ImportedAtUtc],[ValidationStatus]) VALUES (?,?,?,?,?,?)' Add-TextParameter $insert 'name' 200 $templateName $null = $insert.Parameters.Add('version', [System.Data.OleDb.OleDbType]::Integer) $insert.Parameters[1].Value = $version $null = $insert.Parameters.Add('html', [System.Data.OleDb.OleDbType]::LongVarWChar) $insert.Parameters[2].Value = $html Add-TextParameter $insert 'hash' 64 (Get-HashHex $htmlBytes) $null = $insert.Parameters.Add('imported', [System.Data.OleDb.OleDbType]::Date) $insert.Parameters[4].Value = [DateTime]::UtcNow Add-TextParameter $insert 'status' 30 'validated' $null = $insert.ExecuteNonQuery() $identity = $connection.CreateCommand() $identity.Transaction = $transaction $identity.CommandText = 'SELECT @@IDENTITY' $templateId = [int]$identity.ExecuteScalar() foreach ($image in $images) { $command = $connection.CreateCommand() $command.Transaction = $transaction $command.CommandText = 'INSERT INTO [TemplateImage] ([TemplateVersionId],[OriginalRelativePath],[ContentType],[ContentHash],[SnapshotBytes],[ContentId]) VALUES (?,?,?,?,?,?)' $null = $command.Parameters.Add('template', [System.Data.OleDb.OleDbType]::Integer) $command.Parameters[0].Value = $templateId Add-TextParameter $command 'path' 255 $image.Path Add-TextParameter $command 'type' 40 $image.Type Add-TextParameter $command 'hash' 64 $image.Hash $null = $command.Parameters.Add('bytes', [System.Data.OleDb.OleDbType]::LongVarBinary, $image.Bytes.Length) $command.Parameters[4].Value = $image.Bytes Add-TextParameter $command 'cid' 200 $image.Cid $null = $command.ExecuteNonQuery() } $transaction.Commit() $transaction = $null Write-Output "Imported template ID $templateId, version $version, $($images.Count) inline image(s)." } catch { if ($transaction) { $transaction.Rollback() } throw } finally { $connection.Dispose() }