Add person data access, integ tests, backup/restore (#17)
This commit is contained in:
@@ -9,6 +9,14 @@ module Json =
|
||||
|
||||
open Newtonsoft.Json
|
||||
|
||||
/// <summary>Converter for the <see cref="AccessLevel" /> type</summary>
|
||||
type AccessLevelConverter() =
|
||||
inherit JsonConverter<AccessLevel>()
|
||||
override _.WriteJson(writer: JsonWriter, value: AccessLevel, _: JsonSerializer) =
|
||||
writer.WriteValue(string value)
|
||||
override _.ReadJson(reader: JsonReader, _: Type, _: AccessLevel, _: bool, _: JsonSerializer) =
|
||||
(string >> AccessLevel.Parse) reader.Value
|
||||
|
||||
/// <summary>Converter for the <see cref="AutoHtmxType" /> type</summary>
|
||||
type AutoHtmxTypeConverter() =
|
||||
inherit JsonConverter<AutoHtmxType>()
|
||||
@@ -195,7 +203,8 @@ module Json =
|
||||
/// <summary>Configure a serializer to use these converters (and other settings)</summary>
|
||||
let configure (ser: JsonSerializer) =
|
||||
// Our converters
|
||||
[ AutoHtmxTypeConverter() :> JsonConverter
|
||||
[ AccessLevelConverter() :> JsonConverter
|
||||
AutoHtmxTypeConverter()
|
||||
CategoryIdConverter()
|
||||
CommentIdConverter()
|
||||
CommentStatusConverter()
|
||||
|
||||
@@ -22,7 +22,7 @@ type PostgresPersonData(log: ILogger) =
|
||||
Find.byFieldsOrdered<Person>
|
||||
Table.Person
|
||||
All
|
||||
[ Field.In (nameof Person.Empty.Id) (assignments |> List.map _.PersonId) ]
|
||||
[ Field.In (nameof Person.Empty.Id) (assignments |> List.map (fun it -> string it.PersonId)) ]
|
||||
[ Field.Named (nameof Person.Empty.Name) ]
|
||||
|
||||
/// Find a person by their ID for the given web log
|
||||
@@ -46,7 +46,7 @@ type PostgresPersonData(log: ILogger) =
|
||||
/// Find all persons for the given web log
|
||||
let findByWebLog webLogId =
|
||||
log.LogTrace "Person.findByWebLog"
|
||||
Find.byContainsOrdered<Person> Table.Person (webLogContains webLogId) [ Field.Named (nameof Person.Empty.Name) ]
|
||||
Find.byContainsOrdered<Person> Table.Person (webLogDoc webLogId) [ Field.Named (nameof Person.Empty.Name) ]
|
||||
|
||||
|
||||
/// Restore persons from a backup
|
||||
|
||||
@@ -20,7 +20,7 @@ type SQLitePersonData(conn: SqliteConnection, log: ILogger) =
|
||||
log.LogTrace "Person.findByAssignment"
|
||||
conn.findByFieldsOrdered<Person>
|
||||
Table.Person All
|
||||
[ Field.In "PersonId" (assignments |> List.map _.PersonId) ]
|
||||
[ Field.In (nameof Person.Empty.Id) (assignments |> List.map (fun it -> string it.PersonId)) ]
|
||||
[ Field.Named (nameof Person.Empty.Name) ]
|
||||
|
||||
/// Find a person by their ID
|
||||
|
||||
@@ -414,7 +414,7 @@ type PersonId =
|
||||
|
||||
/// <summary>Create a new person ID</summary>
|
||||
/// <returns>A new person ID</returns>
|
||||
static member Create =
|
||||
static member Create() =
|
||||
Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Replace('/', '_').Replace('+', '-')[..21] |> PersonId
|
||||
|
||||
/// <inheritdoc />
|
||||
|
||||
@@ -88,7 +88,9 @@ type AccessLevel =
|
||||
/// <exception cref="InvalidArgumentException">If the string is not valid</exception>
|
||||
static member Parse level =
|
||||
match level with
|
||||
// Legacy name; superseded by Author on PersonRole
|
||||
| "Author" -> ContentAuthor
|
||||
| "ContentAuthor" -> ContentAuthor
|
||||
| "Editor" -> Editor
|
||||
| "WebLogAdmin" -> WebLogAdmin
|
||||
| "Administrator" -> Administrator
|
||||
@@ -97,7 +99,7 @@ type AccessLevel =
|
||||
/// <inheritdoc />
|
||||
override this.ToString() =
|
||||
match this with
|
||||
| ContentAuthor -> "Author"
|
||||
| ContentAuthor -> "ContentAuthor"
|
||||
| Editor -> "Editor"
|
||||
| WebLogAdmin -> "WebLogAdmin"
|
||||
| Administrator -> "Administrator"
|
||||
|
||||
@@ -6,6 +6,20 @@ open MyWebLog
|
||||
open MyWebLog.Converters.Json
|
||||
open Newtonsoft.Json
|
||||
|
||||
/// Unit tests for the AutoHtmxTypeConverter type
|
||||
let accessLevelConverterTests = testList "AccessLevelConverter" [
|
||||
let opts = JsonSerializerSettings()
|
||||
opts.Converters.Add(AccessLevelConverter())
|
||||
test "succeeds when serializing" {
|
||||
let after = JsonConvert.SerializeObject(Editor, opts)
|
||||
Expect.equal after "\"Editor\"" "Access Level serialized incorrectly"
|
||||
}
|
||||
test "succeeds when deserializing" {
|
||||
let after = JsonConvert.DeserializeObject<AccessLevel>("\"Author\"", opts)
|
||||
Expect.equal after ContentAuthor "Access Level deserialized incorrectly"
|
||||
}
|
||||
]
|
||||
|
||||
/// Unit tests for the AutoHtmxTypeConverter type
|
||||
let autoHtmxTypeConverterTests = testList "AutoHtmxTypeConverter" [
|
||||
let opts = JsonSerializerSettings()
|
||||
@@ -324,6 +338,7 @@ open NodaTime.Serialization.JsonNet
|
||||
let configureTests = test "Json.configure succeeds" {
|
||||
let has typ (converter: JsonConverter) = converter.GetType() = typ
|
||||
let ser = configure (JsonSerializer.Create())
|
||||
Expect.hasCountOf ser.Converters 1u (has typeof<AccessLevelConverter>) "Access Level converter not found"
|
||||
Expect.hasCountOf ser.Converters 1u (has typeof<AutoHtmxTypeConverter>) "Auto htmx type converter not found"
|
||||
Expect.hasCountOf ser.Converters 1u (has typeof<CategoryIdConverter>) "Category ID converter not found"
|
||||
Expect.hasCountOf ser.Converters 1u (has typeof<CommentIdConverter>) "Comment ID converter not found"
|
||||
@@ -354,6 +369,7 @@ let configureTests = test "Json.configure succeeds" {
|
||||
|
||||
/// All tests for the Data.Converters file
|
||||
let all = testList "Converters" [
|
||||
accessLevelConverterTests
|
||||
autoHtmxTypeConverterTests
|
||||
categoryIdConverterTests
|
||||
commentIdConverterTests
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/// <summary>Integration tests for <see cref="IPersonData" /> implementations</summary>
|
||||
module PersonDataTests
|
||||
|
||||
open System
|
||||
open Expecto
|
||||
open MyWebLog
|
||||
open MyWebLog.Data
|
||||
|
||||
/// The ID of the root web log
|
||||
let private rootId = CategoryDataTests.rootId
|
||||
|
||||
/// The person ID for "Crackpot"
|
||||
let private crackpotPersonId = PersonId "Q-6ElUj4cEyg5_wQeMpH_A"
|
||||
|
||||
/// The person ID for "Buzzkill" (RIP, JCD)
|
||||
let private buzzkillPersonId = PersonId "a8M4gN58R0evXnJEt9j95w"
|
||||
|
||||
let ``Add succeeds`` (data: IData) = task {
|
||||
let person =
|
||||
{ Id = PersonId "person-x"
|
||||
WebLogId = WebLogId "web-log-x"
|
||||
Name = "Anonny Moose"
|
||||
Url = None
|
||||
ImageUrl = Some "sunglasses.jpg" }
|
||||
do! data.Person.Add person
|
||||
let! stored = data.Person.FindById person.Id person.WebLogId
|
||||
Expect.isSome stored "The added person should have been retrieved"
|
||||
let it = stored.Value
|
||||
Expect.equal it.Id person.Id "ID not saved properly"
|
||||
Expect.equal it.WebLogId person.WebLogId "Web Log ID not saved properly"
|
||||
Expect.equal it.Name person.Name "Name not saved properly"
|
||||
Expect.equal it.Url person.Url "URL not saved properly"
|
||||
Expect.equal it.ImageUrl person.ImageUrl "Image URL not saved properly"
|
||||
}
|
||||
|
||||
let ``FindByAssignment succeeds when assignments are found`` (data: IData) = task {
|
||||
let assignments =
|
||||
[ { PersonId = crackpotPersonId; Role = Producer }; { PersonId = buzzkillPersonId; Role = Producer } ]
|
||||
let! people = data.Person.FindByAssignment assignments
|
||||
Expect.hasLength people 2 "There should have been two people returned"
|
||||
Expect.equal (people |> List.head).Name "Buzzkill" "The list was not sorted correctly"
|
||||
}
|
||||
|
||||
let ``FindByAssignment succeeds when no assignments are found`` (data: IData) = task {
|
||||
let assignments =
|
||||
[ { PersonId = PersonId "missing"; Role = Guest }
|
||||
{ PersonId = PersonId "still-missing"; Role = GuestHost } ]
|
||||
let! people = data.Person.FindByAssignment assignments
|
||||
Expect.hasLength people 0 "There should not have been any people returned"
|
||||
}
|
||||
|
||||
let ``FindById succeeds when a person is found`` (data: IData) = task {
|
||||
let! person = data.Person.FindById buzzkillPersonId rootId
|
||||
Expect.isSome person "There should have been a person returned"
|
||||
let it = person.Value
|
||||
Expect.equal it.Id buzzkillPersonId "ID retrieved incorrectly"
|
||||
Expect.equal it.WebLogId rootId "Web Log ID retrieved incorrectly"
|
||||
Expect.equal it.Name "Buzzkill" "Name retrieved incorrectly"
|
||||
Expect.isNone it.Url "URL should have been blank"
|
||||
Expect.isNone it.ImageUrl "Image URL should have been blank"
|
||||
}
|
||||
|
||||
let ``FindById succeeds when a person is not found (incorrect weblog)`` (data: IData) = task {
|
||||
let! person = data.Person.FindById crackpotPersonId (WebLogId "incorrect")
|
||||
Expect.isNone person "There should not have been a person returned"
|
||||
}
|
||||
|
||||
let ``FindById succeeds when a person is not found (bad person ID)`` (data: IData) = task {
|
||||
let! person = data.Person.FindById (PersonId "bad") rootId
|
||||
Expect.isNone person "There should not have been a person returned"
|
||||
}
|
||||
|
||||
let ``FindByWebLog succeeds when people are found`` (data: IData) = task {
|
||||
let! people = data.Person.FindByWebLog rootId
|
||||
Expect.hasLength people 2 "There should have been 2 people returned"
|
||||
Expect.equal (people |> List.head).Name "Buzzkill" "The people were not sorted correctly"
|
||||
}
|
||||
|
||||
let ``FindByWebLog succeeds when no people are found`` (data: IData) = task {
|
||||
let! people = data.Person.FindByWebLog (WebLogId "no-folks")
|
||||
Expect.hasLength people 0 "There should have been no people returned"
|
||||
}
|
||||
|
||||
let ``Update succeeds when person is updated`` (data: IData) = task {
|
||||
let! person = data.Person.FindById crackpotPersonId rootId
|
||||
Expect.isSome person "The original person should have been returned"
|
||||
do! data.Person.Update { person.Value with Name = "Crackpot!" }
|
||||
let! updated = data.Person.FindById crackpotPersonId rootId
|
||||
Expect.isSome updated "The updated person should have been returned"
|
||||
Expect.equal updated.Value.Name "Crackpot!" "Name was not updated"
|
||||
// Put the name back
|
||||
do! data.Person.Update person.Value
|
||||
}
|
||||
|
||||
let ``Update succeeds when person is not updated`` (data: IData) = task {
|
||||
let! person = data.Person.FindById crackpotPersonId rootId
|
||||
Expect.isSome person "The original person should have been returned"
|
||||
do! data.Person.Update { person.Value with Name = "New Name"; WebLogId = WebLogId "invalid" }
|
||||
let! updated = data.Person.FindById crackpotPersonId rootId
|
||||
Expect.isSome updated "The updated person should have been returned"
|
||||
Expect.equal updated.Value.Name "Crackpot" "The update should not have occurred"
|
||||
}
|
||||
|
||||
// TODO: write delete tests when they cover podcasts and episodes as well
|
||||
@@ -1,6 +1,4 @@
|
||||
/// <summary>
|
||||
/// Integration tests for <see cref="IPostData" /> implementations
|
||||
/// </summary>
|
||||
/// <summary>Integration tests for <see cref="IPostData" /> implementations</summary>
|
||||
module PostDataTests
|
||||
|
||||
open System
|
||||
@@ -39,6 +37,12 @@ let private testPost1Published = Instant.FromDateTimeOffset(DateTimeOffset.Parse
|
||||
/// The category IDs for "Spitball" (parent) and "Moonshot"
|
||||
let private testCatIds = [ CategoryId "jw6N69YtTEWVHAO33jHU-w"; CategoryId "ScVpyu1e7UiP7bDdge3ZEw" ]
|
||||
|
||||
/// The person ID for "Crackpot"
|
||||
let private crackpotPersonId = PersonId "Q-6ElUj4cEyg5_wQeMpH_A"
|
||||
|
||||
/// The person ID for "Buzzkill" (RIP, JCD)
|
||||
let private buzzkillPersonId = PersonId "a8M4gN58R0evXnJEt9j95w"
|
||||
|
||||
/// Ensure that a list of posts has text for each post
|
||||
let private ensureHasText (posts: Post list) =
|
||||
for post in posts do Expect.isNotEmpty post.Text $"Text should not be blank (post ID {post.Id})"
|
||||
@@ -129,6 +133,11 @@ let ``FindById succeeds when a post is found`` (data: IData) = task {
|
||||
Expect.equal ep.SeasonDescription (Some "The First Season") "Episode season description is incorrect"
|
||||
Expect.equal ep.EpisodeNumber (Some 1.) "Episode number is incorrect"
|
||||
Expect.equal ep.EpisodeDescription (Some "The first episode ever!") "Episode description is incorrect"
|
||||
Expect.isSome ep.People "There should have been people on the episode"
|
||||
let ppl = ep.People.Value
|
||||
Expect.hasLength ppl 2 "There should have been 2 people on the episode"
|
||||
Expect.contains ppl { PersonId = crackpotPersonId; Role = CoHost } "Crackpot not found on episode"
|
||||
Expect.contains ppl { PersonId = buzzkillPersonId; Role = VoiceActor } "Buzzkill not found on episode"
|
||||
Expect.equal
|
||||
it.Metadata
|
||||
[ { Name = "Density"; Value = "Non-existent" }; { Name = "Intensity"; Value = "Low" } ]
|
||||
|
||||
@@ -224,6 +224,40 @@ let private pageTests = testList "Page" [
|
||||
]
|
||||
]
|
||||
|
||||
/// Integration tests for the Person implementation in PostgreSQL
|
||||
let private personTests = testList "Person" [
|
||||
testTask "Add succeeds" {
|
||||
do! PersonDataTests.``Add succeeds`` (mkData ())
|
||||
}
|
||||
testTask "FindByAssignment succeeds when assignments are found" {
|
||||
do! PersonDataTests.``FindByAssignment succeeds when assignments are found`` (mkData ())
|
||||
}
|
||||
testTask "FindByAssignment succeeds when no assignments are found" {
|
||||
do! PersonDataTests.``FindByAssignment succeeds when no assignments are found`` (mkData ())
|
||||
}
|
||||
testTask "FindById succeeds when a person is found" {
|
||||
do! PersonDataTests.``FindById succeeds when a person is found`` (mkData ())
|
||||
}
|
||||
testTask "FindById succeeds when a person is not found (incorrect weblog)" {
|
||||
do! PersonDataTests.``FindById succeeds when a person is not found (incorrect weblog)`` (mkData ())
|
||||
}
|
||||
testTask "FindById succeeds when a person is not found (bad person ID)" {
|
||||
do! PersonDataTests.``FindById succeeds when a person is not found (bad person ID)`` (mkData ())
|
||||
}
|
||||
testTask "FindByWebLog succeeds when people are found" {
|
||||
do! PersonDataTests.``FindByWebLog succeeds when people are found`` (mkData ())
|
||||
}
|
||||
testTask "FindByWebLog succeeds when no people are found" {
|
||||
do! PersonDataTests.``FindByWebLog succeeds when no people are found`` (mkData ())
|
||||
}
|
||||
testTask "Update succeeds when person is updated" {
|
||||
do! PersonDataTests.``Update succeeds when person is updated`` (mkData ())
|
||||
}
|
||||
testTask "Update succeeds when person is not updated" {
|
||||
do! PersonDataTests.``Update succeeds when person is not updated`` (mkData ())
|
||||
}
|
||||
]
|
||||
|
||||
/// Integration tests for the Post implementation in PostgreSQL
|
||||
let private postTests = testList "Post" [
|
||||
testTask "Add succeeds" {
|
||||
@@ -711,6 +745,7 @@ let all =
|
||||
[ environmentSetUp
|
||||
categoryTests
|
||||
pageTests
|
||||
personTests
|
||||
postTests
|
||||
tagMapTests
|
||||
themeTests
|
||||
|
||||
@@ -218,6 +218,40 @@ let private pageTests = testList "Page" [
|
||||
]
|
||||
]
|
||||
|
||||
/// Integration tests for the Post implementation in RethinkDB
|
||||
let private personTests = testList "Person" [
|
||||
testTask "Add succeeds" {
|
||||
do! PersonDataTests.``Add succeeds`` data.Value
|
||||
}
|
||||
testTask "FindByAssignment succeeds when assignments are found" {
|
||||
do! PersonDataTests.``FindByAssignment succeeds when assignments are found`` data.Value
|
||||
}
|
||||
testTask "FindByAssignment succeeds when no assignments are found" {
|
||||
do! PersonDataTests.``FindByAssignment succeeds when no assignments are found`` data.Value
|
||||
}
|
||||
testTask "FindById succeeds when a person is found" {
|
||||
do! PersonDataTests.``FindById succeeds when a person is found`` data.Value
|
||||
}
|
||||
testTask "FindById succeeds when a person is not found (incorrect weblog)" {
|
||||
do! PersonDataTests.``FindById succeeds when a person is not found (incorrect weblog)`` data.Value
|
||||
}
|
||||
testTask "FindById succeeds when a person is not found (bad person ID)" {
|
||||
do! PersonDataTests.``FindById succeeds when a person is not found (bad person ID)`` data.Value
|
||||
}
|
||||
testTask "FindByWebLog succeeds when people are found" {
|
||||
do! PersonDataTests.``FindByWebLog succeeds when people are found`` data.Value
|
||||
}
|
||||
testTask "FindByWebLog succeeds when no people are found" {
|
||||
do! PersonDataTests.``FindByWebLog succeeds when no people are found`` data.Value
|
||||
}
|
||||
testTask "Update succeeds when person is updated" {
|
||||
do! PersonDataTests.``Update succeeds when person is updated`` data.Value
|
||||
}
|
||||
testTask "Update succeeds when person is not updated" {
|
||||
do! PersonDataTests.``Update succeeds when person is not updated`` data.Value
|
||||
}
|
||||
]
|
||||
|
||||
/// Integration tests for the Post implementation in RethinkDB
|
||||
let private postTests = testList "Post" [
|
||||
testTask "Add succeeds" {
|
||||
@@ -693,6 +727,7 @@ let all =
|
||||
[ environmentSetUp
|
||||
categoryTests
|
||||
pageTests
|
||||
personTests
|
||||
postTests
|
||||
tagMapTests
|
||||
themeTests
|
||||
|
||||
@@ -326,6 +326,60 @@ let private pageTests = testList "Page" [
|
||||
]
|
||||
]
|
||||
|
||||
/// Integration tests for the Person implementation in SQLite
|
||||
let private personTests = testList "Person" [
|
||||
testTask "Add succeeds" {
|
||||
let data = mkData ()
|
||||
try do! PersonDataTests.``Add succeeds`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "FindByAssignment succeeds when assignments are found" {
|
||||
let data = mkData ()
|
||||
try do! PersonDataTests.``FindByAssignment succeeds when assignments are found`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "FindByAssignment succeeds when no assignments are found" {
|
||||
let data = mkData ()
|
||||
try do! PersonDataTests.``FindByAssignment succeeds when no assignments are found`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "FindById succeeds when a person is found" {
|
||||
let data = mkData ()
|
||||
try do! PersonDataTests.``FindById succeeds when a person is found`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "FindById succeeds when a person is not found (incorrect weblog)" {
|
||||
let data = mkData ()
|
||||
try do! PersonDataTests.``FindById succeeds when a person is not found (incorrect weblog)`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "FindById succeeds when a person is not found (bad person ID)" {
|
||||
let data = mkData ()
|
||||
try do! PersonDataTests.``FindById succeeds when a person is not found (bad person ID)`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "FindByWebLog succeeds when people are found" {
|
||||
let data = mkData ()
|
||||
try do! PersonDataTests.``FindByWebLog succeeds when people are found`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "FindByWebLog succeeds when no people are found" {
|
||||
let data = mkData ()
|
||||
try do! PersonDataTests.``FindByWebLog succeeds when no people are found`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "Update succeeds when person is updated" {
|
||||
let data = mkData ()
|
||||
try do! PersonDataTests.``Update succeeds when person is updated`` data
|
||||
finally dispose data
|
||||
}
|
||||
testTask "Update succeeds when person is not updated" {
|
||||
let data = mkData ()
|
||||
try do! PersonDataTests.``Update succeeds when person is not updated`` data
|
||||
finally dispose data
|
||||
}
|
||||
]
|
||||
|
||||
/// Integration tests for the Post implementation in SQLite
|
||||
let private postTests = testList "Post" [
|
||||
testTask "Add succeeds" {
|
||||
@@ -1043,6 +1097,7 @@ let all =
|
||||
[ environmentSetUp
|
||||
categoryTests
|
||||
pageTests
|
||||
personTests
|
||||
postTests
|
||||
tagMapTests
|
||||
themeTests
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
/// <summary>
|
||||
/// Integration tests for <see cref="IWebLogData" /> implementations
|
||||
/// </summary>
|
||||
/// <summary>Integration tests for <see cref="IWebLogData" /> implementations</summary>
|
||||
module WebLogDataTests
|
||||
|
||||
open System
|
||||
@@ -122,6 +120,11 @@ let ``FindById succeeds when a web log is found`` (data: IData) = task {
|
||||
Expect.equal pod.FundingUrl (Some "https://example.com/support-us") "Podcast funding URL is incorrect"
|
||||
Expect.equal pod.FundingText (Some "Support Our Work") "Podcast funding text is incorrect"
|
||||
Expect.equal pod.Medium (Some Newsletter) "Podcast medium is incorrect"
|
||||
Expect.isSome pod.People "There should have been people associated with the podcast"
|
||||
let ppl = pod.People.Value
|
||||
Expect.hasLength ppl 2 "There should have been 2 people associatged with the podcast"
|
||||
Expect.contains ppl { PersonId = PersonId "Q-6ElUj4cEyg5_wQeMpH_A"; Role = Host } "Crackpot not found"
|
||||
Expect.contains ppl { PersonId = PersonId "a8M4gN58R0evXnJEt9j95w"; Role = Host } "Buzzkill not found :("
|
||||
}
|
||||
|
||||
let ``FindById succeeds when a web log is not found`` (data: IData) = task {
|
||||
|
||||
@@ -33,6 +33,10 @@ let accessLevelTests = testList "AccessLevel" [
|
||||
test "succeeds for \"Author\"" {
|
||||
Expect.equal (AccessLevel.Parse "Author") AccessLevel.ContentAuthor "Author not parsed correctly"
|
||||
}
|
||||
test "succeeds for \"ContentAuthor\"" {
|
||||
Expect.equal
|
||||
(AccessLevel.Parse "ContentAuthor") AccessLevel.ContentAuthor "ContentAuthor not parsed correctly"
|
||||
}
|
||||
test "succeeds for \"Editor\"" {
|
||||
Expect.equal (AccessLevel.Parse "Editor") Editor "Editor not parsed correctly"
|
||||
}
|
||||
@@ -49,7 +53,7 @@ let accessLevelTests = testList "AccessLevel" [
|
||||
]
|
||||
testList "ToString" [
|
||||
test "ContentAuthor succeeds" {
|
||||
Expect.equal (string AccessLevel.ContentAuthor) "Author" "ContentAuthor string incorrect"
|
||||
Expect.equal (string AccessLevel.ContentAuthor) "ContentAuthor" "ContentAuthor string incorrect"
|
||||
}
|
||||
test "Editor succeeds" {
|
||||
Expect.equal (string Editor) "Editor" "Editor string incorrect"
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
<Compile Include="Data\UtilsTests.fs" />
|
||||
<Compile Include="Data\CategoryDataTests.fs" />
|
||||
<Compile Include="Data\PageDataTests.fs" />
|
||||
<Compile Include="Data\PersonDataTests.fs" />
|
||||
<Compile Include="Data\PostDataTests.fs" />
|
||||
<Compile Include="Data\TagMapDataTests.fs" />
|
||||
<Compile Include="Data\ThemeDataTests.fs" />
|
||||
|
||||
@@ -36,7 +36,17 @@
|
||||
"PodcastGuid": "10fd7f79-c719-4e1d-9da7-10405dd4fd96",
|
||||
"FundingUrl": "https://example.com/support-us",
|
||||
"FundingText": "Support Our Work",
|
||||
"Medium": "newsletter"
|
||||
"Medium": "newsletter",
|
||||
"People": [
|
||||
{
|
||||
"PersonId": "Q-6ElUj4cEyg5_wQeMpH_A",
|
||||
"Role": "Host"
|
||||
},
|
||||
{
|
||||
"PersonId": "a8M4gN58R0evXnJEt9j95w",
|
||||
"Role": "Host"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
@@ -200,6 +210,19 @@
|
||||
]
|
||||
}
|
||||
],
|
||||
"People": [
|
||||
{
|
||||
"Id": "Q-6ElUj4cEyg5_wQeMpH_A",
|
||||
"WebLogId": "uSitJEuD3UyzWC9jgOHc8g",
|
||||
"Name": "Crackpot",
|
||||
"Url": "bio.html"
|
||||
},
|
||||
{
|
||||
"Id": "a8M4gN58R0evXnJEt9j95w",
|
||||
"WebLogId": "uSitJEuD3UyzWC9jgOHc8g",
|
||||
"Name": "Buzzkill"
|
||||
}
|
||||
],
|
||||
"Posts": [
|
||||
{
|
||||
"Id": "RCsCU2puYEmkpzotoi8p4g",
|
||||
@@ -260,7 +283,17 @@
|
||||
"SeasonNumber": 1,
|
||||
"SeasonDescription": "The First Season",
|
||||
"EpisodeNumber": 1.0,
|
||||
"EpisodeDescription": "The first episode ever!"
|
||||
"EpisodeDescription": "The first episode ever!",
|
||||
"People": [
|
||||
{
|
||||
"PersonId": "Q-6ElUj4cEyg5_wQeMpH_A",
|
||||
"Role": "Co-Host"
|
||||
},
|
||||
{
|
||||
"PersonId": "a8M4gN58R0evXnJEt9j95w",
|
||||
"Role": "Voice Actor"
|
||||
}
|
||||
]
|
||||
},
|
||||
"Metadata": [
|
||||
{
|
||||
|
||||
@@ -229,6 +229,9 @@ module Backup =
|
||||
/// The pages for this web log (containing only the most recent revision)
|
||||
Pages: Page list
|
||||
|
||||
/// The person entries for this web log
|
||||
People: Person list
|
||||
|
||||
/// The posts for this web log (containing only the most recent revision)
|
||||
Posts: Post list
|
||||
|
||||
@@ -249,6 +252,7 @@ module Backup =
|
||||
let categoryCount = List.length archive.Categories
|
||||
let tagMapCount = List.length archive.TagMappings
|
||||
let pageCount = List.length archive.Pages
|
||||
let personCount = List.length archive.People
|
||||
let postCount = List.length archive.Posts
|
||||
let uploadCount = List.length archive.Uploads
|
||||
|
||||
@@ -263,6 +267,7 @@ module Backup =
|
||||
printfn $""" - {categoryCount} categor{plural categoryCount "y" "ies"}"""
|
||||
printfn $""" - {tagMapCount} tag mapping{plural tagMapCount "" "s"}"""
|
||||
printfn $""" - {pageCount} page{plural pageCount "" "s"}"""
|
||||
printfn $""" - {personCount} people"""
|
||||
printfn $""" - {postCount} post{plural postCount "" "s"}"""
|
||||
printfn $""" - {uploadCount} uploaded file{plural uploadCount "" "s"}"""
|
||||
|
||||
@@ -283,6 +288,9 @@ module Backup =
|
||||
printfn "- Exporting pages..."
|
||||
let! pages = data.Page.FindFullByWebLog webLog.Id
|
||||
|
||||
printfn "- Exporting people..."
|
||||
let! people = data.Person.FindByWebLog webLog.Id
|
||||
|
||||
printfn "- Exporting posts..."
|
||||
let! posts = data.Post.FindFullByWebLog webLog.Id
|
||||
|
||||
@@ -298,6 +306,7 @@ module Backup =
|
||||
Categories = categories
|
||||
TagMappings = tagMaps
|
||||
Pages = pages |> List.map (fun p -> { p with Revisions = List.truncate 1 p.Revisions })
|
||||
People = people
|
||||
Posts = posts |> List.map (fun p -> { p with Revisions = List.truncate 1 p.Revisions })
|
||||
Uploads = uploads |> List.map EncodedUpload.fromUpload }
|
||||
|
||||
@@ -319,15 +328,17 @@ module Backup =
|
||||
return { archive with Archive.WebLog.UrlBase = defaultArg newUrlBase webLog.UrlBase }
|
||||
| Some _ ->
|
||||
// Err'body gets new IDs...
|
||||
let newWebLogId = WebLogId.Create()
|
||||
let newCatIds = archive.Categories |> List.map (fun cat -> cat.Id, CategoryId.Create() ) |> dict
|
||||
let newMapIds = archive.TagMappings |> List.map (fun tm -> tm.Id, TagMapId.Create() ) |> dict
|
||||
let newPageIds = archive.Pages |> List.map (fun page -> page.Id, PageId.Create() ) |> dict
|
||||
let newPostIds = archive.Posts |> List.map (fun post -> post.Id, PostId.Create() ) |> dict
|
||||
let newUserIds = archive.Users |> List.map (fun user -> user.Id, WebLogUserId.Create()) |> dict
|
||||
let newUpIds = archive.Uploads |> List.map (fun up -> up.Id, UploadId.Create() ) |> dict
|
||||
let newWebLogId = WebLogId.Create()
|
||||
let newCatIds = archive.Categories |> List.map (fun cat -> cat.Id, CategoryId.Create() ) |> dict
|
||||
let newMapIds = archive.TagMappings |> List.map (fun tm -> tm.Id, TagMapId.Create() ) |> dict
|
||||
let newPageIds = archive.Pages |> List.map (fun page -> page.Id, PageId.Create() ) |> dict
|
||||
let newPersonIds = archive.People |> List.map (fun psn -> psn.Id, PersonId.Create() ) |> dict
|
||||
let newPostIds = archive.Posts |> List.map (fun post -> post.Id, PostId.Create() ) |> dict
|
||||
let newUserIds = archive.Users |> List.map (fun user -> user.Id, WebLogUserId.Create()) |> dict
|
||||
let newUpIds = archive.Uploads |> List.map (fun up -> up.Id, UploadId.Create() ) |> dict
|
||||
return
|
||||
{ archive with
|
||||
// TODO: person IDs should be updated in podcasts and episodes
|
||||
WebLog = { archive.WebLog with Id = newWebLogId; UrlBase = Option.get newUrlBase }
|
||||
Users = archive.Users
|
||||
|> List.map (fun u -> { u with Id = newUserIds[u.Id]; WebLogId = newWebLogId })
|
||||
@@ -341,6 +352,9 @@ module Backup =
|
||||
Id = newPageIds[page.Id]
|
||||
WebLogId = newWebLogId
|
||||
AuthorId = newUserIds[page.AuthorId] })
|
||||
People = archive.People
|
||||
|> List.map (fun person ->
|
||||
{ person with Id = newPersonIds[person.Id]; WebLogId = newWebLogId })
|
||||
Posts = archive.Posts
|
||||
|> List.map (fun post ->
|
||||
{ post with
|
||||
@@ -381,6 +395,9 @@ module Backup =
|
||||
if isInteractive then printfn "- Restoring pages..."
|
||||
if not (List.isEmpty restore.Pages) then do! data.Page.Restore restore.Pages
|
||||
|
||||
if isInteractive then printfn "- Restoring people..."
|
||||
if not (List.isEmpty restore.People) then do! data.Person.Restore restore.People
|
||||
|
||||
if isInteractive then printfn "- Restoring posts..."
|
||||
if not (List.isEmpty restore.Posts) then do! data.Post.Restore restore.Posts
|
||||
|
||||
|
||||
Reference in New Issue
Block a user