Version 2.1 #41
@ -254,10 +254,7 @@ let all pageNbr : HttpHandler = requireAccess Author >=> fun next ctx -> task {
|
|||||||
let data = ctx.Data
|
let data = ctx.Data
|
||||||
let! posts = data.Post.FindPageOfPosts ctx.WebLog.Id pageNbr 25
|
let! posts = data.Post.FindPageOfPosts ctx.WebLog.Id pageNbr 25
|
||||||
let! hash = preparePostList ctx.WebLog posts AdminList "" pageNbr 25 data
|
let! hash = preparePostList ctx.WebLog posts AdminList "" pageNbr 25 data
|
||||||
return!
|
return! adminPage "Posts" true (Views.Post.list (hash[ViewContext.Model] :?> PostDisplay)) next ctx
|
||||||
addToHash ViewContext.PageTitle "Posts" hash
|
|
||||||
|> withAntiCsrf ctx
|
|
||||||
|> adminView "post-list" next ctx
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET /admin/post/{id}/edit
|
// GET /admin/post/{id}/edit
|
||||||
@ -294,12 +291,13 @@ let edit postId : HttpHandler = requireAccess Author >=> fun next ctx -> task {
|
|||||||
| None -> return! Error.notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
// POST /admin/post/{id}/delete
|
// DELETE /admin/post/{id}
|
||||||
let delete postId : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task {
|
let delete postId : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task {
|
||||||
match! ctx.Data.Post.Delete (PostId postId) ctx.WebLog.Id with
|
match! ctx.Data.Post.Delete (PostId postId) ctx.WebLog.Id with
|
||||||
| true -> do! addMessage ctx { UserMessage.Success with Message = "Post deleted successfully" }
|
| true -> do! addMessage ctx { UserMessage.Success with Message = "Post deleted successfully" }
|
||||||
| false -> do! addMessage ctx { UserMessage.Error with Message = "Post not found; nothing deleted" }
|
| false -> do! addMessage ctx { UserMessage.Error with Message = "Post not found; nothing deleted" }
|
||||||
return! redirectToGet "admin/posts" next ctx
|
//return! redirectToGet "admin/posts" next ctx
|
||||||
|
return! all 1 next ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
// GET /admin/post/{id}/permalinks
|
// GET /admin/post/{id}/permalinks
|
||||||
|
@ -184,7 +184,6 @@ let router : HttpHandler = choose [
|
|||||||
route "/save" >=> Post.save
|
route "/save" >=> Post.save
|
||||||
route "/permalinks" >=> Post.savePermalinks
|
route "/permalinks" >=> Post.savePermalinks
|
||||||
routef "/%s/chapter/%i" Post.saveChapter
|
routef "/%s/chapter/%i" Post.saveChapter
|
||||||
routef "/%s/delete" Post.delete
|
|
||||||
routef "/%s/revision/%s/delete" Post.deleteRevision
|
routef "/%s/revision/%s/delete" Post.deleteRevision
|
||||||
routef "/%s/revision/%s/restore" Post.restoreRevision
|
routef "/%s/revision/%s/restore" Post.restoreRevision
|
||||||
routef "/%s/revisions/purge" Post.purgeRevisions
|
routef "/%s/revisions/purge" Post.purgeRevisions
|
||||||
@ -220,6 +219,7 @@ let router : HttpHandler = choose [
|
|||||||
]
|
]
|
||||||
DELETE >=> validateCsrf >=> choose [
|
DELETE >=> validateCsrf >=> choose [
|
||||||
subRoute "/post" (choose [
|
subRoute "/post" (choose [
|
||||||
|
routef "/%s" Post.delete
|
||||||
routef "/%s/chapter/%i" Post.deleteChapter
|
routef "/%s/chapter/%i" Post.deleteChapter
|
||||||
])
|
])
|
||||||
subRoute "/settings" (requireAccess WebLogAdmin >=> choose [
|
subRoute "/settings" (requireAccess WebLogAdmin >=> choose [
|
||||||
|
@ -218,3 +218,110 @@ let chapters withNew (model: ManageChaptersModel) app = [
|
|||||||
yield! chapterList withNew model app
|
yield! chapterList withNew model app
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
|
/// Display a list of posts
|
||||||
|
let list (model: PostDisplay) app = [
|
||||||
|
let dateCol = "col-xs-12 col-md-3 col-lg-2"
|
||||||
|
let titleCol = "col-xs-12 col-md-7 col-lg-6 col-xl-5 col-xxl-4"
|
||||||
|
let authorCol = "col-xs-12 col-md-2 col-lg-1"
|
||||||
|
let tagCol = "col-lg-3 col-xl-4 col-xxl-5 d-none d-lg-inline-block"
|
||||||
|
h2 [ _class "my-3" ] [ txt app.PageTitle ]
|
||||||
|
article [] [
|
||||||
|
a [ _href (relUrl app "admin/post/new/edit"); _class "btn btn-primary btn-sm mb-3" ] [ raw "Write a New Post" ]
|
||||||
|
if model.Posts.Length > 0 then
|
||||||
|
form [ _method "post"; _class "container mb-3"; _hxTarget "body" ] [
|
||||||
|
antiCsrf app
|
||||||
|
div [ _class "row mwl-table-heading" ] [
|
||||||
|
div [ _class dateCol ] [
|
||||||
|
span [ _class "d-md-none" ] [ raw "Post" ]; span [ _class "d-none d-md-inline" ] [ raw "Date" ]
|
||||||
|
]
|
||||||
|
div [ _class $"{titleCol} d-none d-md-inline-block" ] [ raw "Title" ]
|
||||||
|
div [ _class $"{authorCol} d-none d-md-inline-block" ] [ raw "Author" ]
|
||||||
|
div [ _class tagCol ] [ raw "Tags" ]
|
||||||
|
]
|
||||||
|
for post in model.Posts do
|
||||||
|
div [ _class "row mwl-table-detail" ] [
|
||||||
|
div [ _class $"{dateCol} no-wrap" ] [
|
||||||
|
small [ _class "d-md-none" ] [
|
||||||
|
if post.PublishedOn.HasValue then
|
||||||
|
raw "Published "; txt (post.PublishedOn.Value.ToString "MMMM d, yyyy")
|
||||||
|
else raw "Not Published"
|
||||||
|
if post.PublishedOn.HasValue && post.PublishedOn.Value <> post.UpdatedOn then
|
||||||
|
em [ _class "text-muted" ] [
|
||||||
|
raw " (Updated "; txt (post.UpdatedOn.ToString "MMMM d, yyyy"); raw ")"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
span [ _class "d-none d-md-inline" ] [
|
||||||
|
if post.PublishedOn.HasValue then txt (post.PublishedOn.Value.ToString "MMMM d, yyyy")
|
||||||
|
else raw "Not Published"
|
||||||
|
if not post.PublishedOn.HasValue || post.PublishedOn.Value <> post.UpdatedOn then
|
||||||
|
br []
|
||||||
|
small [ _class "text-muted" ] [
|
||||||
|
em [] [ txt (post.UpdatedOn.ToString "MMMM d, yyyy") ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
div [ _class titleCol ] [
|
||||||
|
if Option.isSome post.Episode then
|
||||||
|
span [ _class "badge bg-success float-end text-uppercase mt-1" ] [ raw "Episode" ]
|
||||||
|
raw post.Title; br []
|
||||||
|
small [] [
|
||||||
|
let postUrl = relUrl app $"admin/post/{post.Id}"
|
||||||
|
a [ _href (relUrl app post.Permalink); _target "_blank" ] [ raw "View Post" ]
|
||||||
|
if app.IsEditor || (app.IsAuthor && app.UserId.Value = WebLogUserId post.AuthorId) then
|
||||||
|
span [ _class "text-muted" ] [ raw " • " ]
|
||||||
|
a [ _href $"{postUrl}/edit" ] [ raw "Edit" ]
|
||||||
|
if app.IsWebLogAdmin then
|
||||||
|
span [ _class "text-muted" ] [ raw " • " ]
|
||||||
|
a [ _href postUrl; _hxDelete postUrl; _class "text-danger"
|
||||||
|
_hxConfirm $"Are you sure you want to delete the post “{post.Title}”? This action cannot be undone." ] [
|
||||||
|
raw "Delete"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
div [ _class authorCol ] [
|
||||||
|
let author =
|
||||||
|
model.Authors
|
||||||
|
|> List.tryFind (fun a -> a.Name = post.AuthorId)
|
||||||
|
|> Option.map _.Value
|
||||||
|
|> Option.defaultValue "--"
|
||||||
|
|> txt
|
||||||
|
small [ _class "d-md-none" ] [
|
||||||
|
raw "Authored by "; author; raw " | "
|
||||||
|
raw (if post.Tags.Length = 0 then "No" else string post.Tags.Length)
|
||||||
|
raw " Tag"; if post.Tags.Length <> 0 then raw "s"
|
||||||
|
]
|
||||||
|
span [ _class "d-none d-md-inline" ] [ author ]
|
||||||
|
]
|
||||||
|
div [ _class tagCol ] [
|
||||||
|
let tags =
|
||||||
|
post.Tags |> List.mapi (fun idx tag -> idx, span [ _class "no-wrap" ] [ txt tag ])
|
||||||
|
for tag in tags do
|
||||||
|
snd tag
|
||||||
|
if fst tag < tags.Length - 1 then raw ", "
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
if Option.isSome model.NewerLink || Option.isSome model.OlderLink then
|
||||||
|
div [ _class "d-flex justify-content-evenly mb-3" ] [
|
||||||
|
div [] [
|
||||||
|
if Option.isSome model.NewerLink then
|
||||||
|
p [] [
|
||||||
|
a [ _href model.NewerLink.Value; _class "btn btn-secondary"; ] [
|
||||||
|
raw "« Newer Posts"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
div [ _class "text-right" ] [
|
||||||
|
if Option.isSome model.OlderLink then
|
||||||
|
p [] [
|
||||||
|
a [ _href model.OlderLink.Value; _class "btn btn-secondary" ] [
|
||||||
|
raw "Older Posts »"
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
else
|
||||||
|
p [ _class "text-muted fst-italic text-center" ] [ raw "This web log has no posts" ]
|
||||||
|
]
|
||||||
|
]
|
||||||
|
@ -1,98 +0,0 @@
|
|||||||
<h2 class=my-3>{{ page_title }}</h2>
|
|
||||||
<article>
|
|
||||||
<a href="{{ "admin/post/new/edit" | relative_link }}" class="btn btn-primary btn-sm mb-3">Write a New Post</a>
|
|
||||||
{%- assign post_count = model.posts | size -%}
|
|
||||||
{%- if post_count > 0 %}
|
|
||||||
<form method=post class="container mb-3" hx-target=body>
|
|
||||||
<input type=hidden name="{{ csrf.form_field_name }}" value="{{ csrf.request_token }}">
|
|
||||||
{%- assign date_col = "col-xs-12 col-md-3 col-lg-2" -%}
|
|
||||||
{%- assign title_col = "col-xs-12 col-md-7 col-lg-6 col-xl-5 col-xxl-4" -%}
|
|
||||||
{%- assign author_col = "col-xs-12 col-md-2 col-lg-1" -%}
|
|
||||||
{%- assign tag_col = "col-lg-3 col-xl-4 col-xxl-5 d-none d-lg-inline-block" -%}
|
|
||||||
<div class="row mwl-table-heading">
|
|
||||||
<div class="{{ date_col }}">
|
|
||||||
<span class=d-md-none>Post</span><span class="d-none d-md-inline">Date</span>
|
|
||||||
</div>
|
|
||||||
<div class="{{ title_col }} d-none d-md-inline-block">Title</div>
|
|
||||||
<div class="{{ author_col }} d-none d-md-inline-block">Author</div>
|
|
||||||
<div class="{{ tag_col }}">Tags</div>
|
|
||||||
</div>
|
|
||||||
{% for post in model.posts -%}
|
|
||||||
<div class="row mwl-table-detail">
|
|
||||||
<div class="{{ date_col }} no-wrap">
|
|
||||||
<small class=d-md-none>
|
|
||||||
{%- if post.published_on -%}
|
|
||||||
Published {{ post.published_on | date: "MMMM d, yyyy" }}
|
|
||||||
{%- else -%}
|
|
||||||
Not Published
|
|
||||||
{%- endif -%}
|
|
||||||
{%- if post.published_on != post.updated_on -%}
|
|
||||||
<em class=text-muted> (Updated {{ post.updated_on | date: "MMMM d, yyyy" }})</em>
|
|
||||||
{%- endif %}
|
|
||||||
</small>
|
|
||||||
<span class="d-none d-md-inline">
|
|
||||||
{%- if post.published_on -%}
|
|
||||||
{{ post.published_on | date: "MMMM d, yyyy" }}
|
|
||||||
{%- else -%}
|
|
||||||
Not Published
|
|
||||||
{%- endif -%}
|
|
||||||
{%- if post.published_on != post.updated_on %}<br>
|
|
||||||
<small class=text-muted><em>{{ post.updated_on | date: "MMMM d, yyyy" }}</em></small>
|
|
||||||
{%- endif %}
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<div class="{{ title_col }}">
|
|
||||||
{%- if post.episode %}<span class="badge bg-success float-end text-uppercase mt-1">Episode</span>{% endif -%}
|
|
||||||
{{ post.title }}<br>
|
|
||||||
<small>
|
|
||||||
<a href="{{ post | relative_link }}" target=_blank>View Post</a>
|
|
||||||
{% if is_editor or is_author and user_id == post.author_id %}
|
|
||||||
<span class=text-muted> • </span>
|
|
||||||
<a href="{{ post | edit_post_link }}">Edit</a>
|
|
||||||
{% endif %}
|
|
||||||
{% if is_web_log_admin %}
|
|
||||||
<span class=text-muted> • </span>
|
|
||||||
{%- assign post_del_link = "admin/post/" | append: post.id | append: "/delete" | relative_link -%}
|
|
||||||
<a href="{{ post_del_link }}" hx-post="{{ post_del_link }}" class=text-danger
|
|
||||||
hx-confirm="Are you sure you want to delete the post “{{ post.title | strip_html | escape }}”? This action cannot be undone.">
|
|
||||||
Delete
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</small>
|
|
||||||
</div>
|
|
||||||
<div class="{{ author_col }}">
|
|
||||||
{%- assign tag_count = post.tags | size -%}
|
|
||||||
<small class=d-md-none>
|
|
||||||
Authored by {{ model.authors | value: post.author_id }} |
|
|
||||||
{% if tag_count == 0 -%}
|
|
||||||
No
|
|
||||||
{%- else -%}
|
|
||||||
{{ tag_count }}
|
|
||||||
{%- endif %} Tag{% unless tag_count == 1 %}s{% endunless %}
|
|
||||||
</small>
|
|
||||||
<span class="d-none d-md-inline">{{ model.authors | value: post.author_id }}</span>
|
|
||||||
</div>
|
|
||||||
<div class="{{ tag_col }}">
|
|
||||||
<span class=no-wrap>{{ post.tags | join: "</span>, <span class='no-wrap'>" }}</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{%- endfor %}
|
|
||||||
</form>
|
|
||||||
{% if model.newer_link or model.older_link %}
|
|
||||||
<div class="d-flex justify-content-evenly mb-3">
|
|
||||||
<div>
|
|
||||||
{% if model.newer_link %}
|
|
||||||
<p><a class="btn btn-secondary" href="{{ model.newer_link.value }}">« Newer Posts</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
<div class="text-right">
|
|
||||||
{% if model.older_link %}
|
|
||||||
<p><a class="btn btn-secondary" href="{{ model.older_link.value }}">Older Posts »</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% else %}
|
|
||||||
<p class="text-muted fst-italic text-center">This web log has no posts
|
|
||||||
{% endif %}
|
|
||||||
</article>
|
|
Loading…
Reference in New Issue
Block a user