V2 #1
|
@ -3,7 +3,7 @@ module MyWebLog.Data
|
|||
|
||||
/// Table names
|
||||
[<RequireQualifiedAccess>]
|
||||
module private Table =
|
||||
module Table =
|
||||
|
||||
/// The category table
|
||||
let Category = "Category"
|
||||
|
|
|
@ -265,6 +265,11 @@ module WebLog =
|
|||
/// Convert a permalink to an absolute URL
|
||||
let absoluteUrl webLog = function Permalink link -> $"{webLog.urlBase}{link}"
|
||||
|
||||
/// Convert a date/time to the web log's local date/time
|
||||
let localTime webLog (date : DateTime) =
|
||||
let tz = TimeZoneInfo.FindSystemTimeZoneById webLog.timeZone
|
||||
TimeZoneInfo.ConvertTimeFromUtc (DateTime (date.Ticks, DateTimeKind.Utc), tz)
|
||||
|
||||
|
||||
/// A user of the web log
|
||||
[<CLIMutable; NoComparison; NoEquality>]
|
||||
|
|
|
@ -232,7 +232,7 @@ type EditPostModel =
|
|||
setUpdated : bool
|
||||
}
|
||||
/// Create an edit model from an existing past
|
||||
static member fromPost (post : Post) =
|
||||
static member fromPost webLog (post : Post) =
|
||||
let latest =
|
||||
match post.revisions |> List.sortByDescending (fun r -> r.asOf) |> List.tryHead with
|
||||
| Some rev -> rev
|
||||
|
@ -250,7 +250,7 @@ type EditPostModel =
|
|||
metaNames = post.metadata |> List.map (fun m -> m.name) |> Array.ofList
|
||||
metaValues = post.metadata |> List.map (fun m -> m.value) |> Array.ofList
|
||||
setPublished = false
|
||||
pubOverride = Nullable<DateTime> ()
|
||||
pubOverride = post.publishedOn |> Option.map (WebLog.localTime webLog) |> Option.toNullable
|
||||
setUpdated = false
|
||||
}
|
||||
|
||||
|
@ -338,8 +338,7 @@ type PostListItem =
|
|||
|
||||
/// Create a post list item from a post
|
||||
static member fromPost (webLog : WebLog) (post : Post) =
|
||||
let tz = TimeZoneInfo.FindSystemTimeZoneById webLog.timeZone
|
||||
let inTZ (it : DateTime) = TimeZoneInfo.ConvertTimeFromUtc (DateTime (it.Ticks, DateTimeKind.Utc), tz)
|
||||
let inTZ = WebLog.localTime webLog
|
||||
{ id = PostId.toString post.id
|
||||
authorId = WebLogUserId.toString post.authorId
|
||||
status = PostStatus.toString post.status
|
||||
|
|
|
@ -716,23 +716,23 @@ module Post =
|
|||
|
||||
// GET /post/{id}/edit
|
||||
let edit postId : HttpHandler = requireUser >=> fun next ctx -> task {
|
||||
let webLogId = webLogId ctx
|
||||
let conn = conn ctx
|
||||
let! result = task {
|
||||
let webLog = WebLogCache.get ctx
|
||||
let conn = conn ctx
|
||||
let! result = task {
|
||||
match postId with
|
||||
| "new" -> return Some ("Write a New Post", { Post.empty with id = PostId "new" })
|
||||
| _ ->
|
||||
match! Data.Post.findByFullId (PostId postId) webLogId conn with
|
||||
match! Data.Post.findByFullId (PostId postId) webLog.id conn with
|
||||
| Some post -> return Some ("Edit Post", post)
|
||||
| None -> return None
|
||||
}
|
||||
match result with
|
||||
| Some (title, post) ->
|
||||
let! cats = Data.Category.findAllForView webLogId conn
|
||||
let! cats = Data.Category.findAllForView webLog.id conn
|
||||
return!
|
||||
Hash.FromAnonymousObject {|
|
||||
csrf = csrfToken ctx
|
||||
model = EditPostModel.fromPost post
|
||||
model = EditPostModel.fromPost webLog post
|
||||
page_title = title
|
||||
categories = cats
|
||||
|}
|
||||
|
|
|
@ -72,6 +72,9 @@ module DotLiquidBespoke =
|
|||
/// Create the default information for a new web log
|
||||
module NewWebLog =
|
||||
|
||||
open System.IO
|
||||
open RethinkDb.Driver.FSharp
|
||||
|
||||
/// Create the web log information
|
||||
let private createWebLog (args : string[]) (sp : IServiceProvider) = task {
|
||||
|
||||
|
@ -134,7 +137,7 @@ module NewWebLog =
|
|||
]
|
||||
} conn
|
||||
|
||||
Console.WriteLine($"Successfully initialized database for {args[2]} with URL base {args[1]}");
|
||||
printfn $"Successfully initialized database for {args[2]} with URL base {args[1]}"
|
||||
}
|
||||
|
||||
/// Create a new web log
|
||||
|
@ -142,7 +145,50 @@ module NewWebLog =
|
|||
match args |> Array.length with
|
||||
| 5 -> return! createWebLog args sp
|
||||
| _ ->
|
||||
Console.WriteLine "Usage: MyWebLog init [url] [name] [admin-email] [admin-pw]"
|
||||
printfn "Usage: MyWebLog init [url] [name] [admin-email] [admin-pw]"
|
||||
return! System.Threading.Tasks.Task.CompletedTask
|
||||
}
|
||||
|
||||
/// Import prior permalinks from a text files with lines in the format "[old] [new]"
|
||||
let importPriorPermalinks urlBase file (sp : IServiceProvider) = task {
|
||||
let conn = sp.GetRequiredService<IConnection> ()
|
||||
|
||||
match! Data.WebLog.findByHost urlBase conn with
|
||||
| Some webLog ->
|
||||
|
||||
let mapping =
|
||||
File.ReadAllLines file
|
||||
|> Seq.ofArray
|
||||
|> Seq.map (fun it ->
|
||||
let parts = it.Split " "
|
||||
Permalink parts[0], Permalink parts[1])
|
||||
|
||||
for old, current in mapping do
|
||||
match! Data.Post.findByPermalink current webLog.id conn with
|
||||
| Some post ->
|
||||
let! withLinks = rethink<Post> {
|
||||
withTable Data.Table.Post
|
||||
get post.id
|
||||
result conn
|
||||
}
|
||||
do! rethink {
|
||||
withTable Data.Table.Post
|
||||
get post.id
|
||||
update [ "priorPermalinks", old :: withLinks.priorPermalinks :> obj]
|
||||
write; ignoreResult conn
|
||||
}
|
||||
printfn $"{Permalink.toString old} -> {Permalink.toString current}"
|
||||
| None -> printfn $"Cannot find current post for {Permalink.toString current}"
|
||||
printfn "Done!"
|
||||
| None -> printfn $"No web log found at {urlBase}"
|
||||
}
|
||||
|
||||
/// Import permalinks if all is well
|
||||
let importPermalinks args sp = task {
|
||||
match args |> Array.length with
|
||||
| 3 -> return! importPriorPermalinks args[1] args[2] sp
|
||||
| _ ->
|
||||
printfn "Usage: MyWebLog import-permalinks [url] [file-name]"
|
||||
return! System.Threading.Tasks.Task.CompletedTask
|
||||
}
|
||||
|
||||
|
@ -219,7 +265,10 @@ let main args =
|
|||
let app = builder.Build ()
|
||||
|
||||
match args |> Array.tryHead with
|
||||
| Some it when it = "init" -> NewWebLog.create args app.Services |> Async.AwaitTask |> Async.RunSynchronously
|
||||
| Some it when it = "init" ->
|
||||
NewWebLog.create args app.Services |> Async.AwaitTask |> Async.RunSynchronously
|
||||
| Some it when it = "import-permalinks" ->
|
||||
NewWebLog.importPermalinks args app.Services |> Async.AwaitTask |> Async.RunSynchronously
|
||||
| _ ->
|
||||
let _ = app.UseCookiePolicy (CookiePolicyOptions (MinimumSameSitePolicy = SameSiteMode.Strict))
|
||||
let _ = app.UseMiddleware<WebLogMiddleware> ()
|
||||
|
|
|
@ -97,7 +97,10 @@
|
|||
<div class="col-4">
|
||||
<div class="form-floating">
|
||||
<input type="datetime-local" name="pubOverride" id="pubOverride" class="form-control"
|
||||
placeholder="Override Date">
|
||||
placeholder="Override Date"
|
||||
{%- if model.pub_override -%}
|
||||
value="{{ model.pub_override | date: "yyyy-MM-dd\THH:mm" }}"
|
||||
{%- endif %}>
|
||||
<label for="pubOverride" class="form-label">Published On</label>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -5,7 +5,13 @@
|
|||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<meta name="generator" content="{{ generator }}">
|
||||
<title>{{ page_title | strip_html }}{% if page_title and page_title != "" %} » {% endif %}{{ web_log.name }}</title>
|
||||
<title>
|
||||
{%- if is_home %}
|
||||
{{ web_log.name }}{% if web_log.subtitle %} | {{ web_log.subtitle.value }}{% endif %}
|
||||
{%- else %}
|
||||
{{ page_title | strip_html }}{% if page_title and page_title != "" %} » {% endif %}{{ web_log.name }}
|
||||
{%- endif %}
|
||||
</title>
|
||||
<link rel="preload" href="https://fonts.googleapis.com/css?family=Quicksand|Oswald" as="style">
|
||||
<link rel="preload" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css" as="style">
|
||||
<link rel="preload" href="/themes/{{ web_log.theme_path }}/style.css" as="style">
|
||||
|
@ -79,9 +85,9 @@
|
|||
<td class="text-center" style="line-height:1.3em;">
|
||||
2021 Season — <strong>NR</strong><br>
|
||||
<small>
|
||||
(5-5 • 3-4 SEC/3<sup>rd</sup> East)<br><br>
|
||||
Last — L (17-41) vs. <sub>1</sub> Georgia<br>
|
||||
Next — 11/20 vs. South Alabama
|
||||
(7-6 • 4-4 SEC/3<sup>rd</sup> East)<br><br>
|
||||
Last — L* (45-48) vs. Purdue<br>
|
||||
<em>Music City Bowl</em>
|
||||
</small>
|
||||
</td>
|
||||
</tr></tbody></table>
|
||||
|
@ -100,9 +106,8 @@
|
|||
<td class="text-center" style="line-height:1.3em;">
|
||||
2021 Season — <strong>NR</strong><br>
|
||||
<small>
|
||||
(3-6 • 2-3 MWC/4<sup>th</sup> Mountain)<br><br>
|
||||
Last — L (17-31) at Wyoming<br>
|
||||
Next — 11/13 vs. Air Force
|
||||
(3-9 • 2-6 MWC/5<sup>th</sup> Mountain)<br><br>
|
||||
Last — L (10-52) at Nevada
|
||||
</small>
|
||||
</td>
|
||||
</tr></tbody></table>
|
||||
|
|
Loading…
Reference in New Issue
Block a user