WIP on backups
This commit is contained in:
parent
476a3acd73
commit
2cb2a7f453
|
@ -26,6 +26,9 @@ type ICategoryData =
|
||||||
/// Find a category by its ID
|
/// Find a category by its ID
|
||||||
abstract member findById : CategoryId -> WebLogId -> Task<Category option>
|
abstract member findById : CategoryId -> WebLogId -> Task<Category option>
|
||||||
|
|
||||||
|
/// Find all categories for the given web log
|
||||||
|
abstract member findByWebLog : WebLogId -> Task<Category list>
|
||||||
|
|
||||||
/// Update a category (slug, name, description, and parent ID)
|
/// Update a category (slug, name, description, and parent ID)
|
||||||
abstract member update : Category -> Task<unit>
|
abstract member update : Category -> Task<unit>
|
||||||
|
|
||||||
|
@ -60,6 +63,9 @@ type IPageData =
|
||||||
/// Find a page by its ID (including revisions and prior permalinks)
|
/// Find a page by its ID (including revisions and prior permalinks)
|
||||||
abstract member findFullById : PageId -> WebLogId -> Task<Page option>
|
abstract member findFullById : PageId -> WebLogId -> Task<Page option>
|
||||||
|
|
||||||
|
/// Find all pages for the given web log (including revisions and prior permalinks)
|
||||||
|
abstract member findFullByWebLog : WebLogId -> Task<Page list>
|
||||||
|
|
||||||
/// Find pages marked as "show in page list" for the given web log (excluding text, revisions, and prior permalinks)
|
/// Find pages marked as "show in page list" for the given web log (excluding text, revisions, and prior permalinks)
|
||||||
abstract member findListed : WebLogId -> Task<Page list>
|
abstract member findListed : WebLogId -> Task<Page list>
|
||||||
|
|
||||||
|
@ -94,6 +100,9 @@ type IPostData =
|
||||||
/// Find a post by its ID (including revisions and prior permalinks)
|
/// Find a post by its ID (including revisions and prior permalinks)
|
||||||
abstract member findFullById : PostId -> WebLogId -> Task<Post option>
|
abstract member findFullById : PostId -> WebLogId -> Task<Post option>
|
||||||
|
|
||||||
|
/// Find all posts for the given web log (including revisions and prior permalinks)
|
||||||
|
abstract member findFullByWebLog : WebLogId -> Task<Post list>
|
||||||
|
|
||||||
/// Find posts to be displayed on a category list page (excluding revisions and prior permalinks)
|
/// Find posts to be displayed on a category list page (excluding revisions and prior permalinks)
|
||||||
abstract member findPageOfCategorizedPosts :
|
abstract member findPageOfCategorizedPosts :
|
||||||
WebLogId -> CategoryId list -> pageNbr : int -> postsPerPage : int -> Task<Post list>
|
WebLogId -> CategoryId list -> pageNbr : int -> postsPerPage : int -> Task<Post list>
|
||||||
|
@ -121,9 +130,6 @@ type IPostData =
|
||||||
/// Functions to manipulate tag mappings
|
/// Functions to manipulate tag mappings
|
||||||
type ITagMapData =
|
type ITagMapData =
|
||||||
|
|
||||||
/// Retrieve all tag mappings for the given web log
|
|
||||||
abstract member all : WebLogId -> Task<TagMap list>
|
|
||||||
|
|
||||||
/// Delete a tag mapping
|
/// Delete a tag mapping
|
||||||
abstract member delete : TagMapId -> WebLogId -> Task<bool>
|
abstract member delete : TagMapId -> WebLogId -> Task<bool>
|
||||||
|
|
||||||
|
@ -133,6 +139,9 @@ type ITagMapData =
|
||||||
/// Find a tag mapping by its URL value
|
/// Find a tag mapping by its URL value
|
||||||
abstract member findByUrlValue : string -> WebLogId -> Task<TagMap option>
|
abstract member findByUrlValue : string -> WebLogId -> Task<TagMap option>
|
||||||
|
|
||||||
|
/// Retrieve all tag mappings for the given web log
|
||||||
|
abstract member findByWebLog : WebLogId -> Task<TagMap list>
|
||||||
|
|
||||||
/// Find tag mappings for the given tags
|
/// Find tag mappings for the given tags
|
||||||
abstract member findMappingForTags : tags : string list -> WebLogId -> Task<TagMap list>
|
abstract member findMappingForTags : tags : string list -> WebLogId -> Task<TagMap list>
|
||||||
|
|
||||||
|
@ -171,6 +180,9 @@ type IThemeAssetData =
|
||||||
/// Find all assets for the given theme (excludes data)
|
/// Find all assets for the given theme (excludes data)
|
||||||
abstract member findByTheme : ThemeId -> Task<ThemeAsset list>
|
abstract member findByTheme : ThemeId -> Task<ThemeAsset list>
|
||||||
|
|
||||||
|
/// Find all assets for the given theme (includes data)
|
||||||
|
abstract member findByThemeWithData : ThemeId -> Task<ThemeAsset list>
|
||||||
|
|
||||||
/// Save a theme asset (insert or update)
|
/// Save a theme asset (insert or update)
|
||||||
abstract member save : ThemeAsset -> Task<unit>
|
abstract member save : ThemeAsset -> Task<unit>
|
||||||
|
|
||||||
|
@ -209,6 +221,9 @@ type IWebLogUserData =
|
||||||
/// Find a web log user by their ID
|
/// Find a web log user by their ID
|
||||||
abstract member findById : WebLogUserId -> WebLogId -> Task<WebLogUser option>
|
abstract member findById : WebLogUserId -> WebLogId -> Task<WebLogUser option>
|
||||||
|
|
||||||
|
/// Find all web log users for the given web log
|
||||||
|
abstract member findByWebLog : WebLogId -> Task<WebLogUser list>
|
||||||
|
|
||||||
/// Get a user ID -> name dictionary for the given user IDs
|
/// Get a user ID -> name dictionary for the given user IDs
|
||||||
abstract member findNames : WebLogId -> WebLogUserId list -> Task<MetaItem list>
|
abstract member findNames : WebLogId -> WebLogUserId list -> Task<MetaItem list>
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,6 @@ namespace MyWebLog.Data
|
||||||
open LiteDB
|
open LiteDB
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open System.Threading.Tasks
|
open System.Threading.Tasks
|
||||||
open MyWebLog.Converters
|
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
|
|
||||||
/// Functions to assist with retrieving data
|
/// Functions to assist with retrieving data
|
||||||
|
@ -156,6 +155,10 @@ type LiteDbData (db : LiteDatabase) =
|
||||||
Collection.Category.FindById (CategoryIdMapping.toBson catId)
|
Collection.Category.FindById (CategoryIdMapping.toBson catId)
|
||||||
|> verifyWebLog webLogId (fun c -> c.webLogId)
|
|> verifyWebLog webLogId (fun c -> c.webLogId)
|
||||||
|
|
||||||
|
member _.findByWebLog webLogId =
|
||||||
|
Collection.Category.Find (fun c -> c.webLogId = webLogId)
|
||||||
|
|> toList
|
||||||
|
|
||||||
member this.delete catId webLogId = backgroundTask {
|
member this.delete catId webLogId = backgroundTask {
|
||||||
match! this.findById catId webLogId with
|
match! this.findById catId webLogId with
|
||||||
| Some _ ->
|
| Some _ ->
|
||||||
|
@ -234,6 +237,10 @@ type LiteDbData (db : LiteDatabase) =
|
||||||
return result |> Option.map (fun pg -> pg.permalink)
|
return result |> Option.map (fun pg -> pg.permalink)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
member _.findFullByWebLog webLogId =
|
||||||
|
Collection.Page.Find (fun p -> p.webLogId = webLogId)
|
||||||
|
|> toList
|
||||||
|
|
||||||
member _.findListed webLogId =
|
member _.findListed webLogId =
|
||||||
Collection.Page.Find (fun p -> p.webLogId = webLogId && p.showInPageList)
|
Collection.Page.Find (fun p -> p.webLogId = webLogId && p.showInPageList)
|
||||||
|> Seq.map pageWithoutText
|
|> Seq.map pageWithoutText
|
||||||
|
@ -300,6 +307,10 @@ type LiteDbData (db : LiteDatabase) =
|
||||||
return result |> Option.map (fun post -> post.permalink)
|
return result |> Option.map (fun post -> post.permalink)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
member _.findFullByWebLog webLogId =
|
||||||
|
Collection.Post.Find (fun p -> p.webLogId = webLogId)
|
||||||
|
|> toList
|
||||||
|
|
||||||
member _.findPageOfCategorizedPosts webLogId categoryIds pageNbr postsPerPage =
|
member _.findPageOfCategorizedPosts webLogId categoryIds pageNbr postsPerPage =
|
||||||
Collection.Post.Find (fun p ->
|
Collection.Post.Find (fun p ->
|
||||||
p.webLogId = webLogId
|
p.webLogId = webLogId
|
||||||
|
@ -361,11 +372,6 @@ type LiteDbData (db : LiteDatabase) =
|
||||||
member _.TagMap = {
|
member _.TagMap = {
|
||||||
new ITagMapData with
|
new ITagMapData with
|
||||||
|
|
||||||
member _.all webLogId =
|
|
||||||
Collection.TagMap.Find (fun tm -> tm.webLogId = webLogId)
|
|
||||||
|> Seq.sortBy (fun tm -> tm.tag)
|
|
||||||
|> toList
|
|
||||||
|
|
||||||
member _.findById tagMapId webLogId =
|
member _.findById tagMapId webLogId =
|
||||||
Collection.TagMap.FindById (TagMapIdMapping.toBson tagMapId)
|
Collection.TagMap.FindById (TagMapIdMapping.toBson tagMapId)
|
||||||
|> verifyWebLog webLogId (fun tm -> tm.webLogId)
|
|> verifyWebLog webLogId (fun tm -> tm.webLogId)
|
||||||
|
@ -383,6 +389,11 @@ type LiteDbData (db : LiteDatabase) =
|
||||||
Collection.TagMap.Find (fun tm -> tm.webLogId = webLogId && tm.urlValue = urlValue)
|
Collection.TagMap.Find (fun tm -> tm.webLogId = webLogId && tm.urlValue = urlValue)
|
||||||
|> tryFirst
|
|> tryFirst
|
||||||
|
|
||||||
|
member _.findByWebLog webLogId =
|
||||||
|
Collection.TagMap.Find (fun tm -> tm.webLogId = webLogId)
|
||||||
|
|> Seq.sortBy (fun tm -> tm.tag)
|
||||||
|
|> toList
|
||||||
|
|
||||||
member _.findMappingForTags tags webLogId =
|
member _.findMappingForTags tags webLogId =
|
||||||
Collection.TagMap.Find (fun tm -> tm.webLogId = webLogId && tags |> List.contains tm.tag)
|
Collection.TagMap.Find (fun tm -> tm.webLogId = webLogId && tags |> List.contains tm.tag)
|
||||||
|> toList
|
|> toList
|
||||||
|
@ -445,6 +456,11 @@ type LiteDbData (db : LiteDatabase) =
|
||||||
|> Seq.map (fun ta -> { ta with data = [||] })
|
|> Seq.map (fun ta -> { ta with data = [||] })
|
||||||
|> toList
|
|> toList
|
||||||
|
|
||||||
|
member _.findByThemeWithData themeId =
|
||||||
|
Collection.ThemeAsset.Find (fun ta ->
|
||||||
|
(ThemeAssetId.toString ta.id).StartsWith (ThemeId.toString themeId))
|
||||||
|
|> toList
|
||||||
|
|
||||||
member _.save asset = backgroundTask {
|
member _.save asset = backgroundTask {
|
||||||
let _ = Collection.ThemeAsset.Upsert asset
|
let _ = Collection.ThemeAsset.Upsert asset
|
||||||
do! checkpoint ()
|
do! checkpoint ()
|
||||||
|
@ -499,6 +515,10 @@ type LiteDbData (db : LiteDatabase) =
|
||||||
Collection.WebLogUser.FindById (WebLogUserIdMapping.toBson userId)
|
Collection.WebLogUser.FindById (WebLogUserIdMapping.toBson userId)
|
||||||
|> verifyWebLog webLogId (fun u -> u.webLogId)
|
|> verifyWebLog webLogId (fun u -> u.webLogId)
|
||||||
|
|
||||||
|
member _.findByWebLog webLogId =
|
||||||
|
Collection.WebLogUser.Find (fun wlu -> wlu.webLogId = webLogId)
|
||||||
|
|> toList
|
||||||
|
|
||||||
member _.findNames webLogId userIds =
|
member _.findNames webLogId userIds =
|
||||||
Collection.WebLogUser.Find (fun wlu -> userIds |> List.contains wlu.id)
|
Collection.WebLogUser.Find (fun wlu -> userIds |> List.contains wlu.id)
|
||||||
|> Seq.map (fun u -> { name = WebLogUserId.toString u.id; value = WebLogUser.displayName u })
|
|> Seq.map (fun u -> { name = WebLogUserId.toString u.id; value = WebLogUser.displayName u })
|
||||||
|
|
|
@ -213,6 +213,12 @@ type RethinkDbData (conn : Net.IConnection, config : DataConfig, log : ILogger<R
|
||||||
}
|
}
|
||||||
|> verifyWebLog webLogId (fun c -> c.webLogId) <| conn
|
|> verifyWebLog webLogId (fun c -> c.webLogId) <| conn
|
||||||
|
|
||||||
|
member _.findByWebLog webLogId = rethink<Category list> {
|
||||||
|
withTable Table.Category
|
||||||
|
getAll [ webLogId ] (nameof webLogId)
|
||||||
|
result; withRetryDefault conn
|
||||||
|
}
|
||||||
|
|
||||||
member this.delete catId webLogId = backgroundTask {
|
member this.delete catId webLogId = backgroundTask {
|
||||||
match! this.findById catId webLogId with
|
match! this.findById catId webLogId with
|
||||||
| Some _ ->
|
| Some _ ->
|
||||||
|
@ -290,14 +296,6 @@ type RethinkDbData (conn : Net.IConnection, config : DataConfig, log : ILogger<R
|
||||||
return result.Deleted > 0UL
|
return result.Deleted > 0UL
|
||||||
}
|
}
|
||||||
|
|
||||||
member _.findFullById pageId webLogId =
|
|
||||||
rethink<Page> {
|
|
||||||
withTable Table.Page
|
|
||||||
get pageId
|
|
||||||
resultOption; withRetryOptionDefault
|
|
||||||
}
|
|
||||||
|> verifyWebLog webLogId (fun it -> it.webLogId) <| conn
|
|
||||||
|
|
||||||
member _.findById pageId webLogId =
|
member _.findById pageId webLogId =
|
||||||
rethink<Page> {
|
rethink<Page> {
|
||||||
withTable Table.Page
|
withTable Table.Page
|
||||||
|
@ -331,6 +329,20 @@ type RethinkDbData (conn : Net.IConnection, config : DataConfig, log : ILogger<R
|
||||||
return result |> Option.map (fun pg -> pg.permalink)
|
return result |> Option.map (fun pg -> pg.permalink)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
member _.findFullById pageId webLogId =
|
||||||
|
rethink<Page> {
|
||||||
|
withTable Table.Page
|
||||||
|
get pageId
|
||||||
|
resultOption; withRetryOptionDefault
|
||||||
|
}
|
||||||
|
|> verifyWebLog webLogId (fun it -> it.webLogId) <| conn
|
||||||
|
|
||||||
|
member _.findFullByWebLog webLogId = rethink<Page list> {
|
||||||
|
withTable Table.Page
|
||||||
|
getAll [ webLogId ] (nameof webLogId)
|
||||||
|
result; withRetryDefault conn
|
||||||
|
}
|
||||||
|
|
||||||
member _.findListed webLogId = rethink<Page list> {
|
member _.findListed webLogId = rethink<Page list> {
|
||||||
withTable Table.Page
|
withTable Table.Page
|
||||||
getAll [ webLogId ] (nameof webLogId)
|
getAll [ webLogId ] (nameof webLogId)
|
||||||
|
@ -443,6 +455,12 @@ type RethinkDbData (conn : Net.IConnection, config : DataConfig, log : ILogger<R
|
||||||
return result |> Option.map (fun post -> post.permalink)
|
return result |> Option.map (fun post -> post.permalink)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
member _.findFullByWebLog webLogId = rethink<Post list> {
|
||||||
|
withTable Table.Post
|
||||||
|
getAll [ webLogId ] (nameof webLogId)
|
||||||
|
result; withRetryDefault conn
|
||||||
|
}
|
||||||
|
|
||||||
member _.findPageOfCategorizedPosts webLogId categoryIds pageNbr postsPerPage = rethink<Post list> {
|
member _.findPageOfCategorizedPosts webLogId categoryIds pageNbr postsPerPage = rethink<Post list> {
|
||||||
withTable Table.Post
|
withTable Table.Post
|
||||||
getAll (objList categoryIds) "categoryIds"
|
getAll (objList categoryIds) "categoryIds"
|
||||||
|
@ -546,13 +564,6 @@ type RethinkDbData (conn : Net.IConnection, config : DataConfig, log : ILogger<R
|
||||||
member _.TagMap = {
|
member _.TagMap = {
|
||||||
new ITagMapData with
|
new ITagMapData with
|
||||||
|
|
||||||
member _.all webLogId = rethink<TagMap list> {
|
|
||||||
withTable Table.TagMap
|
|
||||||
between (r.Array (webLogId, r.Minval ())) (r.Array (webLogId, r.Maxval ())) [ Index "webLogAndTag" ]
|
|
||||||
orderBy "tag"
|
|
||||||
result; withRetryDefault conn
|
|
||||||
}
|
|
||||||
|
|
||||||
member _.delete tagMapId webLogId = backgroundTask {
|
member _.delete tagMapId webLogId = backgroundTask {
|
||||||
let! result = rethink<Model.Result> {
|
let! result = rethink<Model.Result> {
|
||||||
withTable Table.TagMap
|
withTable Table.TagMap
|
||||||
|
@ -581,6 +592,13 @@ type RethinkDbData (conn : Net.IConnection, config : DataConfig, log : ILogger<R
|
||||||
}
|
}
|
||||||
|> tryFirst <| conn
|
|> tryFirst <| conn
|
||||||
|
|
||||||
|
member _.findByWebLog webLogId = rethink<TagMap list> {
|
||||||
|
withTable Table.TagMap
|
||||||
|
between (r.Array (webLogId, r.Minval ())) (r.Array (webLogId, r.Maxval ())) [ Index "webLogAndTag" ]
|
||||||
|
orderBy "tag"
|
||||||
|
result; withRetryDefault conn
|
||||||
|
}
|
||||||
|
|
||||||
member _.findMappingForTags tags webLogId = rethink<TagMap list> {
|
member _.findMappingForTags tags webLogId = rethink<TagMap list> {
|
||||||
withTable Table.TagMap
|
withTable Table.TagMap
|
||||||
getAll (tags |> List.map (fun tag -> r.Array (webLogId, tag) :> obj)) "webLogAndTag"
|
getAll (tags |> List.map (fun tag -> r.Array (webLogId, tag) :> obj)) "webLogAndTag"
|
||||||
|
@ -656,6 +674,12 @@ type RethinkDbData (conn : Net.IConnection, config : DataConfig, log : ILogger<R
|
||||||
result; withRetryDefault conn
|
result; withRetryDefault conn
|
||||||
}
|
}
|
||||||
|
|
||||||
|
member _.findByThemeWithData themeId = rethink<ThemeAsset list> {
|
||||||
|
withTable Table.ThemeAsset
|
||||||
|
filter (matchAssetByThemeId themeId)
|
||||||
|
result; withRetryDefault conn
|
||||||
|
}
|
||||||
|
|
||||||
member _.save asset = rethink {
|
member _.save asset = rethink {
|
||||||
withTable Table.ThemeAsset
|
withTable Table.ThemeAsset
|
||||||
get asset.id
|
get asset.id
|
||||||
|
@ -742,6 +766,12 @@ type RethinkDbData (conn : Net.IConnection, config : DataConfig, log : ILogger<R
|
||||||
}
|
}
|
||||||
|> verifyWebLog webLogId (fun u -> u.webLogId) <| conn
|
|> verifyWebLog webLogId (fun u -> u.webLogId) <| conn
|
||||||
|
|
||||||
|
member _.findByWebLog webLogId = rethink<WebLogUser list> {
|
||||||
|
withTable Table.WebLogUser
|
||||||
|
getAll [ webLogId ] (nameof webLogId)
|
||||||
|
result; withRetryDefault conn
|
||||||
|
}
|
||||||
|
|
||||||
member _.findNames webLogId userIds = backgroundTask {
|
member _.findNames webLogId userIds = backgroundTask {
|
||||||
let! users = rethink<WebLogUser list> {
|
let! users = rethink<WebLogUser list> {
|
||||||
withTable Table.WebLogUser
|
withTable Table.WebLogUser
|
||||||
|
|
|
@ -264,7 +264,7 @@ open Microsoft.AspNetCore.Http
|
||||||
|
|
||||||
/// Get the hash necessary to render the tag mapping list
|
/// Get the hash necessary to render the tag mapping list
|
||||||
let private tagMappingHash (ctx : HttpContext) = task {
|
let private tagMappingHash (ctx : HttpContext) = task {
|
||||||
let! mappings = ctx.Data.TagMap.all ctx.WebLog.id
|
let! mappings = ctx.Data.TagMap.findByWebLog ctx.WebLog.id
|
||||||
return Hash.FromAnonymousObject {|
|
return Hash.FromAnonymousObject {|
|
||||||
web_log = ctx.WebLog
|
web_log = ctx.WebLog
|
||||||
csrf = csrfToken ctx
|
csrf = csrfToken ctx
|
||||||
|
|
|
@ -135,6 +135,9 @@ let loadTheme (args : string[]) (sp : IServiceProvider) = task {
|
||||||
/// Back up a web log's data
|
/// Back up a web log's data
|
||||||
module Backup =
|
module Backup =
|
||||||
|
|
||||||
|
open MyWebLog.Converters
|
||||||
|
open Newtonsoft.Json
|
||||||
|
|
||||||
/// A theme asset, with the data base-64 encoded
|
/// A theme asset, with the data base-64 encoded
|
||||||
type EncodedAsset =
|
type EncodedAsset =
|
||||||
{ /// The ID of the theme asset
|
{ /// The ID of the theme asset
|
||||||
|
@ -154,6 +157,14 @@ module Backup =
|
||||||
data = Convert.ToBase64String asset.data
|
data = Convert.ToBase64String asset.data
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a theme asset from an encoded theme asset
|
||||||
|
static member fromAsset (asset : EncodedAsset) : ThemeAsset =
|
||||||
|
{ id = asset.id
|
||||||
|
updatedOn = asset.updatedOn
|
||||||
|
data = Convert.FromBase64String asset.data
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// A unified archive for a web log
|
/// A unified archive for a web log
|
||||||
type Archive =
|
type Archive =
|
||||||
{ /// The web log to which this archive belongs
|
{ /// The web log to which this archive belongs
|
||||||
|
@ -181,7 +192,63 @@ module Backup =
|
||||||
posts : Post list
|
posts : Post list
|
||||||
}
|
}
|
||||||
|
|
||||||
let inline await f = (Async.AwaitTask >> Async.RunSynchronously) f
|
|
||||||
|
|
||||||
// TODO: finish implementation; paused for LiteDB data capability development, will work with both
|
// TODO: finish implementation; paused for LiteDB data capability development, will work with both
|
||||||
|
|
||||||
|
/// Create a JSON serializer (uses RethinkDB data implementation's JSON converters)
|
||||||
|
let private getSerializer () =
|
||||||
|
let serializer = JsonSerializer.CreateDefault ()
|
||||||
|
Json.all () |> Seq.iter serializer.Converters.Add
|
||||||
|
serializer
|
||||||
|
|
||||||
|
/// Create a backup archive
|
||||||
|
let createBackup webLog (fileName : string) (data : IData) = task {
|
||||||
|
// Create the data structure
|
||||||
|
let themeId = ThemeId webLog.themePath
|
||||||
|
let! theme = data.Theme.findById themeId
|
||||||
|
let! assets = data.ThemeAsset.findByThemeWithData themeId
|
||||||
|
let! users = data.WebLogUser.findByWebLog webLog.id
|
||||||
|
let! categories = data.Category.findByWebLog webLog.id
|
||||||
|
let! tagMaps = data.TagMap.findByWebLog webLog.id
|
||||||
|
let! pages = data.Page.findFullByWebLog webLog.id
|
||||||
|
let! posts = data.Post.findFullByWebLog webLog.id
|
||||||
|
let archive = {
|
||||||
|
webLog = webLog
|
||||||
|
users = users
|
||||||
|
theme = Option.get theme
|
||||||
|
assets = assets |> List.map EncodedAsset.fromAsset
|
||||||
|
categories = categories
|
||||||
|
tagMappings = tagMaps
|
||||||
|
pages = pages |> List.map (fun p -> { p with revisions = List.truncate 1 p.revisions })
|
||||||
|
posts = posts |> List.map (fun p -> { p with revisions = List.truncate 1 p.revisions })
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the structure to the backup file
|
||||||
|
if File.Exists fileName then File.Delete fileName
|
||||||
|
let serializer = getSerializer ()
|
||||||
|
use writer = new StreamWriter (fileName)
|
||||||
|
serializer.Serialize (writer, archive)
|
||||||
|
writer.Close ()
|
||||||
|
|
||||||
|
printfn "Backup Stats:"
|
||||||
|
printfn $" - Users: {archive.users |> List.length}"
|
||||||
|
printfn $" - Categories: {archive.categories |> List.length}"
|
||||||
|
printfn $" - Tag Maps: {archive.tagMappings |> List.length}"
|
||||||
|
printfn $" - Pages: {archive.pages |> List.length}"
|
||||||
|
printfn $" - Posts: {archive.posts |> List.length}"
|
||||||
|
printfn ""
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Generate a backup archive
|
||||||
|
let generateBackup (args : string[]) (sp : IServiceProvider) = task {
|
||||||
|
if args.Length = 3 then
|
||||||
|
let data = sp.GetRequiredService<IData> ()
|
||||||
|
match! data.WebLog.findByHost args[1] with
|
||||||
|
| Some webLog ->
|
||||||
|
let fileName = if args[2].EndsWith ".json" then args[2] else $"{args[1]}.json"
|
||||||
|
do! createBackup webLog fileName data
|
||||||
|
printfn $"Backup created for {args[1]}"
|
||||||
|
| None -> printfn $"Error: no web log found for {args[1]}"
|
||||||
|
else
|
||||||
|
printfn "Usage: MyWebLog backup [url-base] [backup-file-name]"
|
||||||
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ open Microsoft.AspNetCore.HttpOverrides
|
||||||
open RethinkDB.DistributedCache
|
open RethinkDB.DistributedCache
|
||||||
|
|
||||||
[<EntryPoint>]
|
[<EntryPoint>]
|
||||||
let main args =
|
let rec main args =
|
||||||
|
|
||||||
let builder = WebApplication.CreateBuilder(args)
|
let builder = WebApplication.CreateBuilder(args)
|
||||||
let _ = builder.Services.Configure<ForwardedHeadersOptions>(fun (opts : ForwardedHeadersOptions) ->
|
let _ = builder.Services.Configure<ForwardedHeadersOptions>(fun (opts : ForwardedHeadersOptions) ->
|
||||||
|
@ -118,9 +118,10 @@ let main args =
|
||||||
let app = builder.Build ()
|
let app = builder.Build ()
|
||||||
|
|
||||||
match args |> Array.tryHead with
|
match args |> Array.tryHead with
|
||||||
| Some it when it = "init" -> Maintenance.createWebLog args app.Services
|
| Some it when it = "init" -> Maintenance.createWebLog args app.Services
|
||||||
| Some it when it = "import-links" -> Maintenance.importLinks args app.Services
|
| Some it when it = "import-links" -> Maintenance.importLinks args app.Services
|
||||||
| Some it when it = "load-theme" -> Maintenance.loadTheme args app.Services
|
| Some it when it = "load-theme" -> Maintenance.loadTheme args app.Services
|
||||||
|
| Some it when it = "backup" -> Maintenance.Backup.generateBackup args app.Services
|
||||||
| _ ->
|
| _ ->
|
||||||
let _ = app.UseForwardedHeaders ()
|
let _ = app.UseForwardedHeaders ()
|
||||||
let _ = app.UseCookiePolicy (CookiePolicyOptions (MinimumSameSitePolicy = SameSiteMode.Strict))
|
let _ = app.UseCookiePolicy (CookiePolicyOptions (MinimumSameSitePolicy = SameSiteMode.Strict))
|
||||||
|
|
Loading…
Reference in New Issue
Block a user