diff --git a/src/MyWebLog.Domain/DataTypes.fs b/src/MyWebLog.Domain/DataTypes.fs
index ddd805b..88f6134 100644
--- a/src/MyWebLog.Domain/DataTypes.fs
+++ b/src/MyWebLog.Domain/DataTypes.fs
@@ -388,6 +388,12 @@ type WebLog = {
member this.AbsoluteUrl(permalink: Permalink) =
$"{this.UrlBase}/{permalink}"
+ /// Convert a string URL to an absolute URL for this web log if required
+ /// The URL which may be translated to an absolute one
+ /// The given URL if it was already absolute, or a corresponding absolute URL if not
+ member this.UrlToAbsolute(url: string) =
+ if url.StartsWith "http" then url else this.AbsoluteUrl(Permalink url)
+
/// Generate a relative URL for the given link
/// The permalink for which a relative URL should be generated
/// A relative URL for the given link
diff --git a/src/MyWebLog.Domain/SupportTypes.fs b/src/MyWebLog.Domain/SupportTypes.fs
index f271343..73864a3 100644
--- a/src/MyWebLog.Domain/SupportTypes.fs
+++ b/src/MyWebLog.Domain/SupportTypes.fs
@@ -418,9 +418,12 @@ type OpenGraphAudio = {
|> dict
/// The meta properties for this image
- member this.Properties = seq {
- yield "og:audio", this.Url
- if this.Url.StartsWith "https:" then yield "og:audio:secure_url", this.Url
+ /// A function to convert relative URLs to absolute URLs
+ /// A sequence of key/value pairs for this OpenGraph audio file
+ member this.ToProperties(urlTransform: string -> string) = seq {
+ let url = urlTransform this.Url
+ yield "og:audio", url
+ if url.StartsWith "https:" then yield "og:audio:secure_url", url
match this.Type with
| Some typ -> yield "og:audio:type", typ
| None ->
@@ -472,9 +475,12 @@ type OpenGraphImage = {
|> dict
/// The meta properties for this image
- member this.Properties = seq {
- yield "og:image", this.Url
- if this.Url.StartsWith "https:" then yield "og:image:secure_url", this.Url
+ /// A function to convert relative URLs to absolute URLs
+ /// A sequence of key/value pairs for this OpenGraph image file
+ member this.ToProperties(urlTransform: string -> string) = seq {
+ let url = urlTransform this.Url
+ yield "og:image", url
+ if url.StartsWith "https:" then yield "og:image:secure_url", url
match this.Type with
| Some typ -> yield "og:image:type", typ
| None ->
@@ -520,9 +526,12 @@ type OpenGraphVideo = {
|> dict
/// The meta properties for this video
- member this.Properties = seq {
- yield "og:video", this.Url
- if this.Url.StartsWith "https:" then yield "og:video:secure_url", this.Url
+ /// A function to convert relative URLs to absolute URLs
+ /// A sequence of key/value pairs for this OpenGraph video file
+ member this.ToProperties(urlTransform: string -> string) = seq {
+ let url = urlTransform this.Url
+ yield "og:video", url
+ if url.StartsWith "https:" then yield "og:video:secure_url", url
match this.Type with
| Some typ -> yield "og:video:type", typ
| None ->
@@ -633,17 +642,19 @@ type OpenGraphProperties = {
Other = None }
/// The meta properties for this page or post
- member this.Properties = seq {
+ /// A function to convert relative URLs to absolute URLs
+ /// A sequence of key/value pairs for this set of OpenGraph properties
+ member this.ToProperties urlTransform = seq {
yield "og:type", string this.Type
- yield! this.Image.Properties
+ yield! this.Image.ToProperties urlTransform
match this.Description with Some desc -> yield "og:description", desc | None -> ()
match this.Determiner with Some det -> yield "og:determiner", det | None -> ()
match this.Locale with Some loc -> yield "og:locale", loc | None -> ()
match this.LocaleAlternate with
| Some alt -> yield! alt |> List.map (fun it -> "og:locale:alternate", it)
| None -> ()
- match this.Audio with Some audio -> yield! audio.Properties | None -> ()
- match this.Video with Some video -> yield! video.Properties | None -> ()
+ match this.Audio with Some audio -> yield! audio.ToProperties urlTransform | None -> ()
+ match this.Video with Some video -> yield! video.ToProperties urlTransform | None -> ()
match this.Other with Some oth -> yield! oth |> List.map (fun it -> it.Name, it.Value) | None -> ()
}
diff --git a/src/MyWebLog.Domain/ViewModels.fs b/src/MyWebLog.Domain/ViewModels.fs
index 423f190..2ec79f6 100644
--- a/src/MyWebLog.Domain/ViewModels.fs
+++ b/src/MyWebLog.Domain/ViewModels.fs
@@ -504,21 +504,18 @@ type EditCommonModel() =
post.OpenGraph |> Option.iter this.PopulateOpenGraph
/// Convert the properties of the model into a set of OpenGraph properties
- /// The current web log
- member this.ToOpenGraph(webLog: WebLog) =
+ member this.ToOpenGraph() =
if this.AssignOpenGraph then
- let toAbsolute (url: string) =
- if url.StartsWith "http" then url else webLog.AbsoluteUrl (Permalink url)
let audio =
match this.OpenGraphAudioUrl.Trim() with
| "" -> None
- | url -> Some { OpenGraphAudio.Url = toAbsolute url; Type = noneIfBlank this.OpenGraphAudioType }
+ | url -> Some { OpenGraphAudio.Url = url; Type = noneIfBlank this.OpenGraphAudioType }
let video =
match this.OpenGraphVideoUrl.Trim() with
| "" -> None
| url ->
Some {
- OpenGraphVideo.Url = toAbsolute url
+ OpenGraphVideo.Url = url
Type = noneIfBlank this.OpenGraphVideoType
Width = noneIfBlank this.OpenGraphVideoWidth |> Option.map int
Height = noneIfBlank this.OpenGraphVideoHeight |> Option.map int
@@ -526,7 +523,7 @@ type EditCommonModel() =
Some {
Type = if this.OpenGraphType = "" then Article else OpenGraphType.Parse this.OpenGraphType
Image = {
- Url = toAbsolute this.OpenGraphImageUrl
+ Url = this.OpenGraphImageUrl
Type = noneIfBlank this.OpenGraphImageType
Width = noneIfBlank this.OpenGraphImageWidth |> Option.map int
Height = noneIfBlank this.OpenGraphImageHeight |> Option.map int
@@ -749,10 +746,9 @@ type EditPageModel() =
/// Update a page with values from this model
/// The page to be updated
- /// The web log to which this page belongs
/// The Instant to use for this particular update
/// The page, updated with the values from this model
- member this.UpdatePage (page: Page) webLog now =
+ member this.UpdatePage (page: Page) now =
let revision = { AsOf = now; Text = MarkupText.Parse $"{this.Source}: {this.Text}" }
// Detect a permalink change, and add the prior one to the prior list
match string page.Permalink with
@@ -768,7 +764,7 @@ type EditPageModel() =
IsInPageList = this.IsShownInPageList
Template = match this.Template with "" -> None | tmpl -> Some tmpl
Text = revision.Text.AsHtml()
- OpenGraph = this.ToOpenGraph webLog
+ OpenGraph = this.ToOpenGraph()
Metadata = Seq.zip this.MetaNames this.MetaValues
|> Seq.filter (fun it -> fst it > "")
|> Seq.map (fun it -> { Name = fst it; Value = snd it })
@@ -908,10 +904,9 @@ type EditPostModel() =
/// Update a post with values from the submitted form
/// The post which should be updated
- /// The web log to which this post belongs
/// The Instant to use for this particular update
/// The post, updated with the values from this model
- member this.UpdatePost (post: Post) (webLog: WebLog) now =
+ member this.UpdatePost (post: Post) now =
let revision = { AsOf = now; Text = MarkupText.Parse $"{this.Source}: {this.Text}" }
// Detect a permalink change, and add the prior one to the prior list
match string post.Permalink with
@@ -935,7 +930,7 @@ type EditPostModel() =
Template = match this.Template.Trim() with "" -> None | tmpl -> Some tmpl
CategoryIds = this.CategoryIds |> Array.map CategoryId |> List.ofArray
Status = if this.DoPublish then Published else post.Status
- OpenGraph = this.ToOpenGraph webLog
+ OpenGraph = this.ToOpenGraph()
Metadata = Seq.zip this.MetaNames this.MetaValues
|> Seq.filter (fun it -> fst it > "")
|> Seq.map (fun it -> { Name = fst it; Value = snd it })
diff --git a/src/MyWebLog.Tests/Domain/DataTypesTests.fs b/src/MyWebLog.Tests/Domain/DataTypesTests.fs
index 8d04321..5e88437 100644
--- a/src/MyWebLog.Tests/Domain/DataTypesTests.fs
+++ b/src/MyWebLog.Tests/Domain/DataTypesTests.fs
@@ -34,6 +34,18 @@ let webLogTests = testList "WebLog" [
"https://my.site/blog/page.html"
"Absolute URL is incorrect"
}
+ testList "UrlToAbsolute" [
+ test "succeeds for relative URL" {
+ Expect.equal
+ ({ WebLog.Empty with UrlBase = "https://my.site" }.UrlToAbsolute "blog/page.html")
+ "https://my.site/blog/page.html"
+ "Absolute URL is incorrect"
+ }
+ test "succeeds for absolute URL" {
+ Expect.equal
+ (WebLog.Empty.UrlToAbsolute "https://test.units") "https://test.units" "Absolute URL is incorrect"
+ }
+ ]
testList "RelativeUrl" [
test "succeeds for domain root URL" {
Expect.equal
diff --git a/src/MyWebLog.Tests/Domain/SupportTypesTests.fs b/src/MyWebLog.Tests/Domain/SupportTypesTests.fs
index 884a471..84a3170 100644
--- a/src/MyWebLog.Tests/Domain/SupportTypesTests.fs
+++ b/src/MyWebLog.Tests/Domain/SupportTypesTests.fs
@@ -259,67 +259,79 @@ let markupTextTests = testList "MarkupText" [
/// Unit tests for the OpenGraphAudio type
let openGraphAudioTests = testList "OpenGraphAudio" [
- testList "Properties" [
+ let webLog = { WebLog.Empty with UrlBase = "https://unit.test/taco" }
+ let transform = webLog.UrlToAbsolute
+ testList "ToProperties" [
test "succeeds with minimum required" {
- let props = Array.ofSeq { OpenGraphAudio.Empty with Url = "http://test.this" }.Properties
+ let props = Array.ofSeq ({ OpenGraphAudio.Empty with Url = "http://test.this" }.ToProperties transform)
Expect.hasLength props 1 "There should be one property"
Expect.equal props[0] ("og:audio", "http://test.this") "The URL was not written correctly"
}
test "succeeds with secure URL" {
- let props = Array.ofSeq { OpenGraphAudio.Empty with Url = "https://test.this" }.Properties
+ let props = Array.ofSeq ({ OpenGraphAudio.Empty with Url = "https://test.this" }.ToProperties transform)
Expect.hasLength props 2 "There should be two properties"
Expect.equal props[0] ("og:audio", "https://test.this") "The URL was not written correctly"
Expect.equal
props[1] ("og:audio:secure_url", "https://test.this") "The Secure URL was not written correctly"
}
test "succeeds with all properties filled" {
- let props = Array.ofSeq { Url = "http://test.this"; Type = Some "audio/mpeg" }.Properties
+ let props = Array.ofSeq ({ Url = "http://test.this"; Type = Some "audio/mpeg" }.ToProperties transform)
Expect.hasLength props 2 "There should be two properties"
Expect.equal props[0] ("og:audio", "http://test.this") "The URL was not written correctly"
Expect.equal props[1] ("og:audio:type", "audio/mpeg") "The MIME type was not written correctly"
}
- test "succeeds when deriving AAC" {
- let props = Array.ofSeq { OpenGraphAudio.Empty with Url = "/this/cool.file.aac" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:audio:type", "audio/aac") "The MIME type for AAC was not derived correctly"
+ test "succeeds when deriving AAC and transforming URL" {
+ let props = Array.ofSeq ({ OpenGraphAudio.Empty with Url = "this/cool.file.aac" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal
+ props[0]
+ ("og:audio", "https://unit.test/taco/this/cool.file.aac")
+ "The URL was not transformed correctly"
+ Expect.equal
+ props[1]
+ ("og:audio:secure_url", "https://unit.test/taco/this/cool.file.aac")
+ "The URL was not transformed correctly"
+ Expect.equal props[2] ("og:audio:type", "audio/aac") "The MIME type for AAC was not derived correctly"
}
test "succeeds when deriving MP3" {
- let props = Array.ofSeq { OpenGraphAudio.Empty with Url = "/an.other/song.mp3" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:audio:type", "audio/mpeg") "The MIME type for MP3 was not derived correctly"
+ let props = Array.ofSeq ({ OpenGraphAudio.Empty with Url = "an.other/song.mp3" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal props[2] ("og:audio:type", "audio/mpeg") "The MIME type for MP3 was not derived correctly"
}
test "succeeds when deriving OGA" {
- let props = Array.ofSeq { OpenGraphAudio.Empty with Url = "/talks/speex.oga" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:audio:type", "audio/ogg") "The MIME type for OGA was not derived correctly"
+ let props = Array.ofSeq ({ OpenGraphAudio.Empty with Url = "talks/speex.oga" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal props[2] ("og:audio:type", "audio/ogg") "The MIME type for OGA was not derived correctly"
}
test "succeeds when deriving WAV" {
- let props = Array.ofSeq { OpenGraphAudio.Empty with Url = "/some/old.school.wav" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:audio:type", "audio/wav") "The MIME type for WAV was not derived correctly"
+ let props = Array.ofSeq ({ OpenGraphAudio.Empty with Url = "some/old.school.wav" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal props[2] ("og:audio:type", "audio/wav") "The MIME type for WAV was not derived correctly"
}
test "succeeds when deriving WEBA" {
- let props = Array.ofSeq { OpenGraphAudio.Empty with Url = "/new/format/file.weba" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:audio:type", "audio/webm") "The MIME type for WEBA was not derived correctly"
+ let props = Array.ofSeq ({ OpenGraphAudio.Empty with Url = "new/format/file.weba" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal props[2] ("og:audio:type", "audio/webm") "The MIME type for WEBA was not derived correctly"
}
test "succeeds when type cannot be derived" {
- let props = Array.ofSeq { OpenGraphAudio.Empty with Url = "/profile.jpg" }.Properties
- Expect.hasLength props 1 "There should be one property (only URL; no type derived)"
+ let props = Array.ofSeq ({ OpenGraphAudio.Empty with Url = "profile.jpg" }.ToProperties transform)
+ Expect.hasLength props 2 "There should be two properties (only URLs; no type derived)"
}
]
]
/// Tests for the OpenGraphImage type
let openGraphImageTests = testList "OpenGraphImage" [
- testList "Properties" [
+ let webLog = { WebLog.Empty with UrlBase = "https://unit.test/taco" }
+ let transform = webLog.UrlToAbsolute
+ testList "ToProperties" [
test "succeeds with minimum required" {
- let props = Array.ofSeq { OpenGraphImage.Empty with Url = "http://test.url" }.Properties
+ let props = Array.ofSeq ({ OpenGraphImage.Empty with Url = "http://test.url" }.ToProperties transform)
Expect.hasLength props 1 "There should be one property"
Expect.equal props[0] ("og:image", "http://test.url") "The URL was not written correctly"
}
test "succeeds with secure URL" {
- let props = Array.ofSeq { OpenGraphImage.Empty with Url = "https://secure.url" }.Properties
+ let props = Array.ofSeq ({ OpenGraphImage.Empty with Url = "https://secure.url" }.ToProperties transform)
Expect.hasLength props 2 "There should be two properties"
Expect.equal props[0] ("og:image", "https://secure.url") "The URL was not written correctly"
Expect.equal
@@ -331,7 +343,7 @@ let openGraphImageTests = testList "OpenGraphImage" [
Type = Some "image/jpeg"
Width = Some 400
Height = Some 600
- Alt = Some "This ought to be good" }.Properties
+ Alt = Some "This ought to be good" }.ToProperties transform
|> Array.ofSeq
Expect.hasLength props 5 "There should be five properties"
Expect.equal props[0] ("og:image", "http://test.this") "The URL was not written correctly"
@@ -340,69 +352,77 @@ let openGraphImageTests = testList "OpenGraphImage" [
Expect.equal props[3] ("og:image:height", "600") "The height was not written correctly"
Expect.equal props[4] ("og:image:alt", "This ought to be good") "The alt text was not written correctly"
}
- test "succeeds when deriving BMP" {
- let props = Array.ofSeq { OpenGraphImage.Empty with Url = "/old/windows.bmp" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:image:type", "image/bmp") "The MIME type for BMP was not derived correctly"
+ test "succeeds when deriving BMP and transforming URL" {
+ let props = Array.ofSeq ({ OpenGraphImage.Empty with Url = "old/windows.bmp" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal
+ props[0] ("og:image", "https://unit.test/taco/old/windows.bmp") "The URL was not transformed correctly"
+ Expect.equal
+ props[1]
+ ("og:image:secure_url", "https://unit.test/taco/old/windows.bmp")
+ "The URL was not transformed correctly"
+ Expect.equal props[2] ("og:image:type", "image/bmp") "The MIME type for BMP was not derived correctly"
}
test "succeeds when deriving GIF" {
- let props = Array.ofSeq { OpenGraphImage.Empty with Url = "/its.a.soft.g.gif" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:image:type", "image/gif") "The MIME type for GIF was not derived correctly"
+ let props = Array.ofSeq ({ OpenGraphImage.Empty with Url = "its.a.soft.g.gif" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal props[2] ("og:image:type", "image/gif") "The MIME type for GIF was not derived correctly"
}
test "succeeds when deriving ICO" {
- let props = Array.ofSeq { OpenGraphImage.Empty with Url = "/favicon.ico" }.Properties
- Expect.hasLength props 2 "There should be two properties"
+ let props = Array.ofSeq ({ OpenGraphImage.Empty with Url = "favicon.ico" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
Expect.equal
- props[1] ("og:image:type", "image/vnd.microsoft.icon") "The MIME type for ICO was not derived correctly"
+ props[2] ("og:image:type", "image/vnd.microsoft.icon") "The MIME type for ICO was not derived correctly"
}
test "succeeds when deriving JPEG" {
- let props = Array.ofSeq { OpenGraphImage.Empty with Url = "/big/name/photo.jpeg" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:image:type", "image/jpeg") "The MIME type for JPEG was not derived correctly"
+ let props = Array.ofSeq ({ OpenGraphImage.Empty with Url = "big/name/photo.jpeg" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal props[2] ("og:image:type", "image/jpeg") "The MIME type for JPEG was not derived correctly"
}
test "succeeds when deriving PNG" {
- let props = Array.ofSeq { OpenGraphImage.Empty with Url = "/some/nice/graphic.png" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:image:type", "image/png") "The MIME type for PNG was not derived correctly"
+ let props = Array.ofSeq ({ OpenGraphImage.Empty with Url = "some/nice/graphic.png" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal props[2] ("og:image:type", "image/png") "The MIME type for PNG was not derived correctly"
}
test "succeeds when deriving SVG" {
- let props = Array.ofSeq { OpenGraphImage.Empty with Url = "/fancy-new-vector.svg" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:image:type", "image/svg+xml") "The MIME type for SVG was not derived correctly"
+ let props = Array.ofSeq ({ OpenGraphImage.Empty with Url = "fancy-new-vector.svg" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal props[2] ("og:image:type", "image/svg+xml") "The MIME type for SVG was not derived correctly"
}
test "succeeds when deriving TIF" {
- let props = Array.ofSeq { OpenGraphImage.Empty with Url = "/tagged/file.tif" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:image:type", "image/tiff") "The MIME type for TIF was not derived correctly"
+ let props = Array.ofSeq ({ OpenGraphImage.Empty with Url = "tagged/file.tif" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal props[2] ("og:image:type", "image/tiff") "The MIME type for TIF was not derived correctly"
}
test "succeeds when deriving TIFF" {
- let props = Array.ofSeq { OpenGraphImage.Empty with Url = "/tagged/file.two.tiff" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:image:type", "image/tiff") "The MIME type for TIFF was not derived correctly"
+ let props = Array.ofSeq ({ OpenGraphImage.Empty with Url = "tagged/file.two.tiff" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal props[2] ("og:image:type", "image/tiff") "The MIME type for TIFF was not derived correctly"
}
test "succeeds when deriving WEBP" {
- let props = Array.ofSeq { OpenGraphImage.Empty with Url = "/modern/photo.webp" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:image:type", "image/webp") "The MIME type for WEBP was not derived correctly"
+ let props = Array.ofSeq ({ OpenGraphImage.Empty with Url = "modern/photo.webp" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal props[2] ("og:image:type", "image/webp") "The MIME type for WEBP was not derived correctly"
}
test "succeeds when type cannot be derived" {
- let props = Array.ofSeq { OpenGraphImage.Empty with Url = "/intro.mp3" }.Properties
- Expect.hasLength props 1 "There should be one property (only URL; no type derived)"
+ let props = Array.ofSeq ({ OpenGraphImage.Empty with Url = "intro.mp3" }.ToProperties transform)
+ Expect.hasLength props 2 "There should be two properties (only URLs; no type derived)"
}
]
]
/// Unit tests for the OpenGraphVideo type
let openGraphVideoTests = testList "OpenGraphVideo" [
- testList "Properties" [
+ let webLog = { WebLog.Empty with UrlBase = "https://unit.test/taco" }
+ let transform = webLog.UrlToAbsolute
+ testList "ToProperties" [
test "succeeds with minimum required" {
- let props = Array.ofSeq { OpenGraphVideo.Empty with Url = "http://url.test" }.Properties
+ let props = Array.ofSeq ({ OpenGraphVideo.Empty with Url = "http://url.test" }.ToProperties transform)
Expect.hasLength props 1 "There should be one property"
Expect.equal props[0] ("og:video", "http://url.test") "The URL was not written correctly"
}
test "succeeds with secure URL" {
- let props = Array.ofSeq { OpenGraphVideo.Empty with Url = "https://url.secure" }.Properties
+ let props = Array.ofSeq ({ OpenGraphVideo.Empty with Url = "https://url.secure" }.ToProperties transform)
Expect.hasLength props 2 "There should be two properties"
Expect.equal props[0] ("og:video", "https://url.secure") "The URL was not written correctly"
Expect.equal
@@ -413,7 +433,7 @@ let openGraphVideoTests = testList "OpenGraphVideo" [
{ Url = "http://test.this"
Type = Some "video/mpeg"
Width = Some 1200
- Height = Some 900 }.Properties
+ Height = Some 900 }.ToProperties transform
|> Array.ofSeq
Expect.hasLength props 4 "There should be five properties"
Expect.equal props[0] ("og:video", "http://test.this") "The URL was not written correctly"
@@ -421,34 +441,41 @@ let openGraphVideoTests = testList "OpenGraphVideo" [
Expect.equal props[2] ("og:video:width", "1200") "The width was not written correctly"
Expect.equal props[3] ("og:video:height", "900") "The height was not written correctly"
}
- test "succeeds when deriving AVI" {
- let props = Array.ofSeq { OpenGraphVideo.Empty with Url = "/my.video.avi" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:video:type", "video/x-msvideo") "The MIME type for AVI was not derived correctly"
+ test "succeeds when deriving AVI and transforming URL" {
+ let props = Array.ofSeq ({ OpenGraphVideo.Empty with Url = "my.video.avi" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal
+ props[0] ("og:video", "https://unit.test/taco/my.video.avi") "The URL not transformed correctly"
+ Expect.equal
+ props[1]
+ ("og:video:secure_url", "https://unit.test/taco/my.video.avi")
+ "The URL not transformed correctly"
+ Expect.equal props[2] ("og:video:type", "video/x-msvideo") "The MIME type for AVI was not derived correctly"
}
test "succeeds when deriving MP4" {
- let props = Array.ofSeq { OpenGraphVideo.Empty with Url = "/chapters/1/01.mp4" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:video:type", "video/mp4") "The MIME type for MP4 was not derived correctly"
+ let props = Array.ofSeq ({ OpenGraphVideo.Empty with Url = "chapters/1/01.mp4" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal props[2] ("og:video:type", "video/mp4") "The MIME type for MP4 was not derived correctly"
}
test "succeeds when deriving MPEG" {
- let props = Array.ofSeq { OpenGraphVideo.Empty with Url = "/viral/video.mpeg" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:video:type", "video/mpeg") "The MIME type for MPEG was not derived correctly"
+ let props = Array.ofSeq ({ OpenGraphVideo.Empty with Url = "viral/video.mpeg" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal props[2] ("og:video:type", "video/mpeg") "The MIME type for MPEG was not derived correctly"
}
test "succeeds when deriving OGV" {
- let props = Array.ofSeq { OpenGraphVideo.Empty with Url = "/open/video/example.ogv" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:video:type", "video/ogg") "The MIME type for OGV was not derived correctly"
+ let props =
+ Array.ofSeq ({ OpenGraphVideo.Empty with Url = "open/video/example.ogv" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal props[2] ("og:video:type", "video/ogg") "The MIME type for OGV was not derived correctly"
}
test "succeeds when deriving WEBM" {
- let props = Array.ofSeq { OpenGraphVideo.Empty with Url = "/images/hero.webm" }.Properties
- Expect.hasLength props 2 "There should be two properties"
- Expect.equal props[1] ("og:video:type", "video/webm") "The MIME type for WEBM was not derived correctly"
+ let props = Array.ofSeq ({ OpenGraphVideo.Empty with Url = "images/hero.webm" }.ToProperties transform)
+ Expect.hasLength props 3 "There should be three properties"
+ Expect.equal props[2] ("og:video:type", "video/webm") "The MIME type for WEBM was not derived correctly"
}
test "succeeds when type cannot be derived" {
- let props = Array.ofSeq { OpenGraphVideo.Empty with Url = "/favicon.ico" }.Properties
- Expect.hasLength props 1 "There should be one property (only URL; no type derived)"
+ let props = Array.ofSeq ({ OpenGraphVideo.Empty with Url = "favicon.ico" }.ToProperties transform)
+ Expect.hasLength props 2 "There should be two properties (only URLs; no type derived)"
}
]
]
@@ -552,7 +579,8 @@ let openGraphPropertiesTests = testList "OpenGraphProperties" [
test "succeeds with minimal values" {
let props =
{ OpenGraphProperties.Empty with
- Image = { OpenGraphImage.Empty with Url = "http://this.aint.nothing" } }.Properties
+ Image = { OpenGraphImage.Empty with Url = "http://this.aint.nothing" } }
+ .ToProperties WebLog.Empty.UrlToAbsolute
|> Array.ofSeq
Expect.hasLength props 2 "There should have been two properties"
Expect.equal props[0] ("og:type", "article") "Type not written correctly"
@@ -568,7 +596,8 @@ let openGraphPropertiesTests = testList "OpenGraphProperties" [
Locale = Some "en_US"
LocaleAlternate = Some [ "en_UK"; "es_MX" ]
Video = Some { OpenGraphVideo.Empty with Url = "http://this.video.file" }
- Other = Some [ { Name = "book.publisher"; Value = "Yep" } ] }.Properties
+ Other = Some [ { Name = "book.publisher"; Value = "Yep" } ] }
+ .ToProperties WebLog.Empty.UrlToAbsolute
|> Array.ofSeq
Expect.hasLength props 10 "There should have been ten properties"
Expect.equal props[0] ("og:type", "book") "Type not written correctly"
diff --git a/src/MyWebLog.Tests/Domain/ViewModelsTests.fs b/src/MyWebLog.Tests/Domain/ViewModelsTests.fs
index b2e4a33..0b51333 100644
--- a/src/MyWebLog.Tests/Domain/ViewModelsTests.fs
+++ b/src/MyWebLog.Tests/Domain/ViewModelsTests.fs
@@ -438,15 +438,14 @@ let editCommonModelTests = testList "EditCommonModel" [
]
testList "ToOpenGraph" [
test "succeeds when OpenGraph properties are not assigned" {
- Expect.isNone
- (EditCommonModel().ToOpenGraph WebLog.Empty) "No OpenGraph properties should have returned None"
+ Expect.isNone (EditCommonModel().ToOpenGraph()) "No OpenGraph properties should have returned None"
}
test "succeeds when minimal OpenGraph properties are assigned" {
let model = EditCommonModel()
model.AssignOpenGraph <- true
model.OpenGraphType <- string Article
model.OpenGraphImageUrl <- "https://unit.test/img.tiff"
- let tryOg = model.ToOpenGraph WebLog.Empty
+ let tryOg = model.ToOpenGraph()
Expect.isSome tryOg "There should have been a set of OpenGraph properties returned"
let og = tryOg.Value
Expect.equal og.Type Article "OpenGraph type not filled correctly"
@@ -484,7 +483,7 @@ let editCommonModelTests = testList "EditCommonModel" [
model.OpenGraphVideoHeight <- "768"
model.OpenGraphExtraNames <- [| "og:duration"; "og:rating" |]
model.OpenGraphExtraValues <- [| "1:30:27"; "G" |]
- let tryOg = model.ToOpenGraph WebLog.Empty
+ let tryOg = model.ToOpenGraph()
Expect.isSome tryOg "There should have been a set of OpenGraph properties returned"
let og = tryOg.Value
Expect.equal og.Type VideoMovie "OpenGraph type not filled correctly"
@@ -514,24 +513,6 @@ let editCommonModelTests = testList "EditCommonModel" [
[ { Name = "og:duration"; Value = "1:30:27" }; { Name = "og:rating"; Value = "G" } ]
"OpenGraph extra properties not filled properly"
}
- test "succeeds when relative URLs are assigned" {
- let model = EditCommonModel()
- model.AssignOpenGraph <- true
- model.OpenGraphType <- string Article
- model.OpenGraphImageUrl <- "image.jpg"
- model.OpenGraphAudioUrl <- "tunes/sound.ogg"
- model.OpenGraphVideoUrl <- "teaser.mp4"
- let tryOg = model.ToOpenGraph { WebLog.Empty with UrlBase = "https://test.units/verify" }
- Expect.isSome tryOg "There should have been a set of OpenGraph properties returned"
- let og = tryOg.Value
- Expect.equal og.Image.Url "https://test.units/verify/image.jpg" "OpenGraph image URL not filled properly"
- Expect.isSome og.Audio "OpenGraph audio should have been filled"
- Expect.equal
- og.Audio.Value.Url "https://test.units/verify/tunes/sound.ogg" "OpenGraph audio URL not filled properly"
- Expect.isSome og.Video "OpenGraph video should have been filled"
- Expect.equal
- og.Video.Value.Url "https://test.units/verify/teaser.mp4" "OpenGraph video URL not filled properly"
- }
]
]
@@ -743,7 +724,7 @@ let editPageModelTests = testList "EditPageModel" [
let model = EditPageModel.FromPage testFullPage
model.Title <- "Updated Page"
model.IsShownInPageList <- false
- let page = model.UpdatePage testFullPage WebLog.Empty (Noda.epoch + Duration.FromHours 4)
+ let page = model.UpdatePage testFullPage (Noda.epoch + Duration.FromHours 4)
Expect.equal page.Title "Updated Page" "Title not filled properly"
Expect.equal page.Permalink (Permalink "blog/page.html") "Permalink not filled properly"
Expect.isEmpty page.PriorPermalinks "PriorPermalinks should be empty"
@@ -778,7 +759,7 @@ let editPageModelTests = testList "EditPageModel" [
model.MetaNames <- [| "banana"; "apple"; "grape" |]
model.MetaValues <- [| "monkey"; "zebra"; "ape" |]
let now = Noda.epoch + Duration.FromDays 7
- let page = model.UpdatePage testFullPage WebLog.Empty now
+ let page = model.UpdatePage testFullPage now
Expect.equal page.Title "My Updated Page" "Title not filled properly"
Expect.equal page.Permalink (Permalink "blog/updated.html") "Permalink not filled properly"
Expect.equal page.PriorPermalinks [ Permalink "blog/page.html" ] "PriorPermalinks not filled properly"
@@ -919,7 +900,7 @@ let editPostModelTests = testList "EditPostModel" [
model
testList "UpdatePost" [
test "succeeds for a full podcast episode" {
- let post = (updatedModel ()).UpdatePost testFullPost WebLog.Empty (Noda.epoch + Duration.FromDays 400)
+ let post = (updatedModel ()).UpdatePost testFullPost (Noda.epoch + Duration.FromDays 400)
Expect.equal post.Title "An Updated Post" "Title not filled properly"
Expect.equal post.Permalink (Permalink "1970/01/updated-post.html") "Permalink not filled properly"
Expect.equal post.PriorPermalinks [ Permalink "1970/01/a-post.html" ] "PriorPermalinks not filled properly"
@@ -980,7 +961,7 @@ let editPostModelTests = testList "EditPostModel" [
minModel.SeasonDescription <- ""
minModel.EpisodeNumber <- ""
minModel.EpisodeDescription <- ""
- let post = minModel.UpdatePost testFullPost WebLog.Empty (Noda.epoch + Duration.FromDays 500)
+ let post = minModel.UpdatePost testFullPost (Noda.epoch + Duration.FromDays 500)
Expect.isSome post.Episode "There should have been a podcast episode"
let ep = post.Episode.Value
Expect.equal ep.Media "an-updated-ep.mp3" "Media not filled properly"
@@ -1007,7 +988,7 @@ let editPostModelTests = testList "EditPostModel" [
minModel.ChapterSource <- "internal"
minModel.ChapterFile <- ""
minModel.ChapterType <- ""
- let post = minModel.UpdatePost testFullPost WebLog.Empty (Noda.epoch + Duration.FromDays 500)
+ let post = minModel.UpdatePost testFullPost (Noda.epoch + Duration.FromDays 500)
Expect.isSome post.Episode "There should have been a podcast episode"
let ep = post.Episode.Value
Expect.equal ep.Chapters (Some []) "Chapters not filled properly"
@@ -1020,7 +1001,6 @@ let editPostModelTests = testList "EditPostModel" [
let post =
minModel.UpdatePost
{ testFullPost with Episode = Some { testFullPost.Episode.Value with Chapters = Some [] } }
- WebLog.Empty
(Noda.epoch + Duration.FromDays 500)
Expect.isSome post.Episode "There should have been a podcast episode"
let ep = post.Episode.Value
@@ -1033,15 +1013,14 @@ let editPostModelTests = testList "EditPostModel" [
let model = updatedModel ()
model.IsEpisode <- false
model.Template <- ""
- let post = model.UpdatePost testFullPost WebLog.Empty Noda.epoch
+ let post = model.UpdatePost testFullPost Noda.epoch
Expect.isNone post.Template "Template not filled properly"
Expect.isNone post.Episode "Episode not filled properly"
}
test "succeeds when publishing a draft" {
let model = updatedModel ()
model.DoPublish <- true
- let post =
- model.UpdatePost { testFullPost with Status = Draft } WebLog.Empty (Noda.epoch + Duration.FromDays 375)
+ let post = model.UpdatePost { testFullPost with Status = Draft } (Noda.epoch + Duration.FromDays 375)
Expect.equal post.Status Published "Status not set properly"
Expect.equal post.PublishedOn (Some (Noda.epoch + Duration.FromDays 375)) "PublishedOn not set properly"
}
diff --git a/src/MyWebLog/Handlers/Page.fs b/src/MyWebLog/Handlers/Page.fs
index 4f47040..0e47a95 100644
--- a/src/MyWebLog/Handlers/Page.fs
+++ b/src/MyWebLog/Handlers/Page.fs
@@ -164,7 +164,7 @@ let save : HttpHandler = requireAccess Author >=> fun next ctx -> task {
match! tryPage with
| Some page when canEdit page.AuthorId ctx ->
let updateList = page.IsInPageList <> model.IsShownInPageList
- let updatedPage = model.UpdatePage page ctx.WebLog now
+ let updatedPage = model.UpdatePage page now
do! (if model.IsNew then data.Page.Add else data.Page.Update) updatedPage
if updateList then do! PageListCache.update ctx
do! addMessage ctx { UserMessage.Success with Message = "Page saved successfully" }
diff --git a/src/MyWebLog/Handlers/Post.fs b/src/MyWebLog/Handlers/Post.fs
index fd20dc8..d6c9039 100644
--- a/src/MyWebLog/Handlers/Post.fs
+++ b/src/MyWebLog/Handlers/Post.fs
@@ -495,7 +495,7 @@ let save : HttpHandler = requireAccess Author >=> fun next ctx -> task {
| Some post when canEdit post.AuthorId ctx ->
let priorCats = post.CategoryIds
let updatedPost =
- model.UpdatePost post ctx.WebLog (Noda.now ())
+ model.UpdatePost post (Noda.now ())
|> function
| post ->
if model.SetPublished then
diff --git a/src/MyWebLog/Template.fs b/src/MyWebLog/Template.fs
index 39c567d..8f5aae9 100644
--- a/src/MyWebLog/Template.fs
+++ b/src/MyWebLog/Template.fs
@@ -207,7 +207,7 @@ let parser =
|> app.WebLog.AbsoluteUrl
|> function url -> writeOgProp ("og:url", url)
match if app.IsPage then app.Page.OpenGraph else app.Posts.Posts[0].OpenGraph with
- | Some props -> props.Properties |> Seq.iter writeOgProp
+ | Some props -> props.ToProperties app.WebLog.UrlToAbsolute |> Seq.iter writeOgProp
| None -> ()
writer.WriteLine $"""{s}"""