Page / Post edit pages work

Category in work
This commit is contained in:
Daniel J. Summers 2016-11-11 16:28:15 -06:00
parent 0d54fc2ec3
commit 458b8308ae
10 changed files with 115 additions and 74 deletions

View File

@ -53,22 +53,26 @@ type PageModule (data : IMyWebLogData, clock : IClock) as this =
let pageId = parameters.["id"].ToString ()
let form = this.Bind<EditPageForm> ()
let now = clock.GetCurrentInstant().ToUnixTimeTicks ()
match pageId with "new" -> Some Page.Empty | _ -> tryFindPage data this.WebLog.Id pageId
match pageId with "new" -> Some Page.Empty | _ -> tryFindPage data this.WebLog.Id pageId
|> function
| Some p ->
let page = match pageId with "new" -> { p with WebLogId = this.WebLog.Id } | _ -> p
let pId = { p with
Title = form.Title
Permalink = form.Permalink
PublishedOn = match pageId with "new" -> now | _ -> page.PublishedOn
UpdatedOn = now
Text = match form.Source with
| RevisionSource.Markdown -> (* Markdown.TransformHtml *) form.Text
| _ -> form.Text
Revisions = { AsOf = now
SourceType = form.Source
Text = form.Text } :: page.Revisions }
|> savePage data
let pId =
{ p with
Title = form.Title
Permalink = form.Permalink
PublishedOn = match pageId with "new" -> now | _ -> page.PublishedOn
UpdatedOn = now
ShowInPageList = form.ShowInPageList
Text = match form.Source with
| RevisionSource.Markdown -> (* Markdown.TransformHtml *) form.Text
| _ -> form.Text
Revisions = { AsOf = now
SourceType = form.Source
Text = form.Text
} :: page.Revisions
}
|> savePage data
let model = MyWebLogModel (this.Context, this.WebLog)
{ UserMessage.Empty with
Level = Level.Info

View File

@ -269,7 +269,7 @@ type PostModule(data : IMyWebLogData, clock : IClock) as this =
match postId with "new" -> Some Post.Empty | _ -> tryFindPost data this.WebLog.Id postId
|> function
| Some p ->
let justPublished = p.PublishedOn = int64 0 && form.PublishNow
let justPublished = p.PublishedOn = 0L && form.PublishNow
let post = match postId with
| "new" -> { p with
WebLogId = this.WebLog.Id
@ -281,7 +281,7 @@ type PostModule(data : IMyWebLogData, clock : IClock) as this =
Status = match form.PublishNow with true -> PostStatus.Published | _ -> PostStatus.Draft
Title = form.Title
Permalink = form.Permalink
PublishedOn = match justPublished with true -> now | _ -> int64 0
PublishedOn = match justPublished with true -> now | _ -> post.PublishedOn
UpdatedOn = now
Text = match form.Source with
| RevisionSource.Markdown -> (* Markdown.TransformHtml *) form.Text
@ -289,6 +289,7 @@ type PostModule(data : IMyWebLogData, clock : IClock) as this =
CategoryIds = Array.toList form.Categories
Tags = form.Tags.Split ','
|> Seq.map (fun t -> t.Trim().ToLowerInvariant ())
|> Seq.sort
|> Seq.toList
Revisions = { AsOf = now
SourceType = form.Source

View File

@ -220,6 +220,8 @@ type CategoryEditModel (ctx, webLog, category) =
inherit MyWebLogModel (ctx, webLog)
/// The form with the category information
member val Form = CategoryForm (category) with get, set
/// The category being edited
member val Category = category
/// The categories
member val Categories : IndentedCategory list = [] with get, set
@ -336,9 +338,15 @@ type PostForDisplay (webLog : WebLog, post : Post) =
/// The time zone for the web log to which this post belongs
member this.TimeZone = webLog.TimeZone
/// The date the post was published
member this.PublishedDate = FormatDateTime.longDate this.TimeZone this.Post.PublishedOn
member this.PublishedDate =
match this.Post.Status with
| PostStatus.Published -> FormatDateTime.longDate this.TimeZone this.Post.PublishedOn
| _ -> FormatDateTime.longDate this.TimeZone this.Post.UpdatedOn
/// The time the post was published
member this.PublishedTime = FormatDateTime.time this.TimeZone this.Post.PublishedOn
member this.PublishedTime =
match this.Post.Status with
| PostStatus.Published -> FormatDateTime.time this.TimeZone this.Post.PublishedOn
| _ -> FormatDateTime.time this.TimeZone this.Post.UpdatedOn
/// Tags
member this.Tags =
match List.length this.Post.Tags with
@ -389,14 +397,17 @@ type EditPostForm () =
/// The selected category Ids for the post
member val Categories : string[] = [||] with get, set
/// Whether the post should be published
member val PublishNow = true with get, set
member val PublishNow = false with get, set
/// Fill the form with applicable values from a post
member this.ForPost (post : Post) =
this.Title <- post.Title
this.Permalink <- post.Permalink
this.Tags <- List.reduce (fun acc x -> sprintf "%s, %s" acc x) post.Tags
this.Tags <- match List.isEmpty post.Tags with
| true -> ""
| _ -> List.reduce (fun acc x -> sprintf "%s, %s" acc x) post.Tags
this.Categories <- List.toArray post.CategoryIds
this.PublishNow <- post.Status = PostStatus.Published || "new" = post.Id
this
/// Fill the form with applicable values from a revision
@ -412,7 +423,7 @@ type DisplayCategory = {
Name : string
Description : string
IsChecked : bool
}
}
with
/// Create a display category
static member Create (cat : Category, indent) isChecked =
@ -442,6 +453,8 @@ type EditPostModel (ctx, webLog, post, revision) =
member this.PublishedDate = this.DisplayLongDate this.Post.PublishedOn
/// The published time
member this.PublishedTime = this.DisplayTime this.Post.PublishedOn
/// The "checked" attribute for the Publish Now box
member this.PublishNowCheckedAttr = match this.Form.PublishNow with true -> "checked=\"checked\"" | _ -> ""
// ---- User models ----

View File

@ -5,12 +5,6 @@ open RethinkDb.Driver.Ast
let private r = RethinkDb.Driver.RethinkDB.R
/// Shorthand to get a category by Id and filter by web log Id
let private category (webLogId : string) (catId : string) =
r.Table(Table.Category)
.Get(catId)
.Filter(ReqlFunction1 (fun c -> upcast c.["WebLogId"].Eq webLogId))
/// Get all categories for a web log
let getAllCategories conn (webLogId : string) =
async {
@ -24,10 +18,16 @@ let getAllCategories conn (webLogId : string) =
/// Get a specific category by its Id
let tryFindCategory conn webLogId catId : Category option =
async {
let! catt = (category webLogId catId).RunResultAsync<Category> conn
return catt
|> box
|> function null -> None | cat -> Some <| unbox cat
let! c =
r.Table(Table.Category)
.Get(catId)
.RunResultAsync<Category> conn
return
match box c with
| null -> None
| catt ->
let cat : Category = unbox catt
match cat.WebLogId = webLogId with true -> Some cat | _ -> None
}
|> Async.RunSynchronously
@ -48,53 +48,63 @@ type CategoryUpdateRecord =
}
/// Update a category
let updateCategory conn (cat : Category) =
async {
do! (category cat.WebLogId cat.Id)
.Update({ CategoryUpdateRecord.Name = cat.Name
match tryFindCategory conn cat.WebLogId cat.Id with
| Some _ ->
async {
do! r.Table(Table.Category)
.Get(cat.Id)
.Update(
{ CategoryUpdateRecord.Name = cat.Name
Slug = cat.Slug
Description = cat.Description
ParentId = cat.ParentId
})
.RunResultAsync conn
}
|> Async.RunSynchronously
.RunResultAsync conn
}
|> Async.RunSynchronously
| _ -> ()
type CategoryChildrenUpdateRecord =
{ Children : string list }
/// Update a category's children
let updateChildren conn webLogId parentId (children : string list) =
async {
do! (category webLogId parentId)
.Update({ CategoryChildrenUpdateRecord.Children = children })
.RunResultAsync conn
}
|> Async.RunSynchronously
match tryFindCategory conn webLogId parentId with
| Some _ ->
async {
do! r.Table(Table.Category)
.Get(parentId)
.Update(dict [ "Children", children ])
.RunResultAsync conn
}
|> Async.RunSynchronously
| _ -> ()
type CategoryParentUpdateRecord =
{ ParentId : string option }
type PostCategoriesUpdateRecord =
{ CategoryIds : string list }
/// Delete a category
let deleteCategory conn (cat : Category) =
async {
// Remove the category from its parent
match cat.ParentId with
| Some parentId -> match tryFindCategory conn cat.WebLogId parentId with
| Some parent -> parent.Children
|> List.filter (fun childId -> childId <> cat.Id)
|> updateChildren conn cat.WebLogId parentId
| _ -> ()
| Some parentId ->
match tryFindCategory conn cat.WebLogId parentId with
| Some parent -> parent.Children
|> List.filter (fun childId -> childId <> cat.Id)
|> updateChildren conn cat.WebLogId parentId
| _ -> ()
| _ -> ()
// Move this category's children to its parent
let newParent = { CategoryParentUpdateRecord.ParentId = cat.ParentId }
cat.Children
|> List.map (fun childId ->
async {
do! (category cat.WebLogId childId)
.Update(newParent)
.RunResultAsync conn
})
|> List.iter Async.RunSynchronously
match tryFindCategory conn cat.WebLogId childId with
| Some _ ->
async {
do! r.Table(Table.Category)
.Get(childId)
.Update(dict [ "ParentId", cat.ParentId ])
.RunResultAsync conn
}
|> Some
| _ -> None)
|> List.filter Option.isSome
|> List.map Option.get
|> List.iter Async.RunSynchronously
// Remove the category from posts where it is assigned
let! posts =
r.Table(Table.Post)
@ -105,13 +115,9 @@ let deleteCategory conn (cat : Category) =
posts
|> List.map (fun post ->
async {
let newCats =
{ PostCategoriesUpdateRecord.CategoryIds = post.CategoryIds
|> List.filter (fun c -> c <> cat.Id)
}
do! r.Table(Table.Post)
.Get(post.Id)
.Update(newCats)
.Update(dict [ "CategoryIds", post.CategoryIds |> List.filter (fun c -> c <> cat.Id) ])
.RunResultAsync conn
})
|> List.iter Async.RunSynchronously

View File

@ -62,6 +62,7 @@ type PageUpdateRecord =
Permalink : string
PublishedOn : int64
UpdatedOn : int64
ShowInPageList : bool
Text : string
Revisions : Revision list }
/// Update a page
@ -75,6 +76,7 @@ let updatePage conn (page : Page) =
Permalink = page.Permalink
PublishedOn = page.PublishedOn
UpdatedOn = page.UpdatedOn
ShowInPageList = page.ShowInPageList
Text = page.Text
Revisions = page.Revisions })
.RunResultAsync conn

View File

@ -85,10 +85,12 @@ let tryFindOlderTaggedPost conn (tag : string) post =
let findPageOfAllPosts conn (webLogId : string) pageNbr nbrPerPage =
// FIXME: sort unpublished posts by their last updated date
async {
// .orderBy(r.desc(r.branch(r.row("Status").eq("Published"), r.row("PublishedOn"), r.row("UpdatedOn"))))
return!
r.Table(Table.Post)
.GetAll(webLogId).OptArg("index", "WebLogId")
.OrderBy(r.Desc "PublishedOn")
.OrderBy(r.Desc (ReqlFunction1 (fun p ->
upcast r.Branch (p.["Status"].Eq("Published"), p.["PublishedOn"], p.["UpdatedOn"]))))
.Slice((pageNbr - 1) * nbrPerPage, pageNbr * nbrPerPage)
.RunResultAsync<Post list> conn
}

View File

@ -8,6 +8,9 @@
"AndPublished": " and Published",
"andXMore": "and {0} more...",
"at": "at",
"BackToCategoryList": "Back to Category List",
"BackToPageList": "Back to Page List",
"BackToPostList": "Back to Post List",
"Categories": "Categories",
"Category": "Category",
"CategoryDeleteWarning": "Are you sure you wish to delete the category",
@ -36,7 +39,7 @@
"MsgLogOffSuccess": "Log off successful | Have a nice day!",
"MsgLogOnSuccess": "Log on successful | Welcome to myWebLog!",
"MsgPageDeleted": "Deleted page successfully",
"MsgPageEditSuccess": "{0} edited successfully",
"MsgPageEditSuccess": "{0} page successfully",
"MsgPostEditSuccess": "{0}{1} post successfully",
"Name": "Name",
"NewerPosts": "Newer Posts",

View File

@ -5,6 +5,9 @@
@AntiForgeryToken
<div class="row">
<div class="col-xs-12">
<a href="/categories" class="btn btn-default">
<i class="fa fa-list-ul"></i> @Translate.BackToCategoryList
</a>
<div class="form-group">
<label class="control-label" for="Name">@Translate.Name</label>
<input type="text" class="form-control" id="Name" name="Name" value="@Model.Form.Name" />

View File

@ -5,6 +5,9 @@
@AntiForgeryToken
<div class="row">
<div class="col-sm-9">
<a href="/pages" class="btn btn-default">
<i class="fa fa-list-ul"></i> @Translate.BackToPageList
</a>
<div class="form-group">
<label class="control-label" for="Title">@Translate.Title</label>
<input type="text" name="Title" id="Title" class="form-control" value="@Model.Form.Title" />
@ -12,10 +15,11 @@
<div class="form-group">
<label class="control-label" for="Permalink">@Translate.Permalink</label>
<input type="text" name="Permalink" id="Permalink" class="form-control" value="@Model.Form.Permalink" />
<p class="form-hint"><em>@Translate.startingWith</em> http://@Model.WebLog.UrlBase/ </p>
<p class="form-hint"><em>@Translate.startingWith</em> //@Model.WebLog.UrlBase/</p>
</div>
<!-- // TODO: Markdown / HTML choice -->
<div class="form-group">
<input type="hidden" name="Source" value="html" />
<div class="form-group">
<textarea name="Text" id="Text" rows="15" class="form-control">@Model.Form.Text</textarea>
</div>
</div>
@ -34,7 +38,7 @@
</div>
@EndIf
<div class="form-group">
<input type="checkbox" name="ShowInPageList" id="ShowInPageList" @Model.PageListChecked />
<input type="checkbox" name="ShowInPageList" id="ShowInPageList" value="true" @Model.PageListChecked />
&nbsp; <label for="ShowInPageList">@Translate.ShowInPageList</label>
</div>
</div>

View File

@ -5,6 +5,9 @@
@AntiForgeryToken
<div class="row">
<div class="col-sm-9">
<a href="/posts/list" class="btn btn-default">
<i class="fa fa-list-ul"></i> @Translate.BackToPostList
</a>
<div class="form-group">
<label class="control-label" for="Title">@Translate.Title</label>
<input type="text" name="Title" id="Title" class="form-control" value="@Model.Form.Title" />
@ -12,10 +15,10 @@
<div class="form-group">
<label class="control-label" for="Permalink">@Translate.Permalink</label>
<input type="text" name="Permalink" id="Permalink" class="form-control" value="@Model.Form.Permalink" />
<!-- // FIXME: hard-coded "http" -->
<p class="form-hint"><em>@Translate.startingWith</em> http://@Model.WebLog.UrlBase/ </p>
<p class="form-hint"><em>@Translate.startingWith</em> //@Model.WebLog.UrlBase/ </p>
</div>
<!-- // TODO: Markdown / HTML choice -->
<input type="hidden" name="Source" value="html" />
<div class="form-group">
<textarea name="Text" id="Text" rows="15">@Model.Form.Text</textarea>
</div>
@ -49,7 +52,7 @@
<div class="panel-body" style="max-height:350px;overflow:scroll;">
@Each.Categories
@Current.Indent
<input type="checkbox" id="Category-@Current.Id" name="Category" value="@Current.Id" @Current.CheckedAttr />
<input type="checkbox" id="Category-@Current.Id" name="Categories" value="@Current.Id" @Current.CheckedAttr />
&nbsp;
<label for="Category-@Current.Id" title="@Current.Description">@Current.Name</label>
<br/>
@ -62,7 +65,7 @@
@EndIf
@IfNot.IsPublished
<div>
<input type="checkbox" name="PublishNow" id="PublishNow" value="true" checked="checked" />
<input type="checkbox" name="PublishNow" id="PublishNow" value="true" @Model.PublishNowCheckedAttr />
&nbsp; <label for="PublishNow">@Translate.PublishThisPost</label>
</div>
@EndIf