Add slug and upload dest to settings (#2)
This commit is contained in:
parent
1d096d696b
commit
355ade8c87
|
@ -888,12 +888,14 @@ type RethinkDbData (conn : Net.IConnection, config : DataConfig, log : ILogger<R
|
||||||
get webLog.id
|
get webLog.id
|
||||||
update [
|
update [
|
||||||
"name", webLog.name :> obj
|
"name", webLog.name :> obj
|
||||||
|
"slug", webLog.slug
|
||||||
"subtitle", webLog.subtitle
|
"subtitle", webLog.subtitle
|
||||||
"defaultPage", webLog.defaultPage
|
"defaultPage", webLog.defaultPage
|
||||||
"postsPerPage", webLog.postsPerPage
|
"postsPerPage", webLog.postsPerPage
|
||||||
"timeZone", webLog.timeZone
|
"timeZone", webLog.timeZone
|
||||||
"themePath", webLog.themePath
|
"themePath", webLog.themePath
|
||||||
"autoHtmx", webLog.autoHtmx
|
"autoHtmx", webLog.autoHtmx
|
||||||
|
"uploads", webLog.uploads
|
||||||
]
|
]
|
||||||
write; withRetryDefault; ignoreResult conn
|
write; withRetryDefault; ignoreResult conn
|
||||||
}
|
}
|
||||||
|
|
|
@ -856,6 +856,9 @@ type SettingsModel =
|
||||||
{ /// The name of the web log
|
{ /// The name of the web log
|
||||||
name : string
|
name : string
|
||||||
|
|
||||||
|
/// The slug of the web log
|
||||||
|
slug : string
|
||||||
|
|
||||||
/// The subtitle of the web log
|
/// The subtitle of the web log
|
||||||
subtitle : string
|
subtitle : string
|
||||||
|
|
||||||
|
@ -873,29 +876,36 @@ type SettingsModel =
|
||||||
|
|
||||||
/// Whether to automatically load htmx
|
/// Whether to automatically load htmx
|
||||||
autoHtmx : bool
|
autoHtmx : bool
|
||||||
|
|
||||||
|
/// The default location for uploads
|
||||||
|
uploads : string
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a settings model from a web log
|
/// Create a settings model from a web log
|
||||||
static member fromWebLog (webLog : WebLog) =
|
static member fromWebLog (webLog : WebLog) =
|
||||||
{ name = webLog.name
|
{ name = webLog.name
|
||||||
|
slug = webLog.slug
|
||||||
subtitle = defaultArg webLog.subtitle ""
|
subtitle = defaultArg webLog.subtitle ""
|
||||||
defaultPage = webLog.defaultPage
|
defaultPage = webLog.defaultPage
|
||||||
postsPerPage = webLog.postsPerPage
|
postsPerPage = webLog.postsPerPage
|
||||||
timeZone = webLog.timeZone
|
timeZone = webLog.timeZone
|
||||||
themePath = webLog.themePath
|
themePath = webLog.themePath
|
||||||
autoHtmx = webLog.autoHtmx
|
autoHtmx = webLog.autoHtmx
|
||||||
|
uploads = UploadDestination.toString webLog.uploads
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update a web log with settings from the form
|
/// Update a web log with settings from the form
|
||||||
member this.update (webLog : WebLog) =
|
member this.update (webLog : WebLog) =
|
||||||
{ webLog with
|
{ webLog with
|
||||||
name = this.name
|
name = this.name
|
||||||
|
slug = this.slug
|
||||||
subtitle = if this.subtitle = "" then None else Some this.subtitle
|
subtitle = if this.subtitle = "" then None else Some this.subtitle
|
||||||
defaultPage = this.defaultPage
|
defaultPage = this.defaultPage
|
||||||
postsPerPage = this.postsPerPage
|
postsPerPage = this.postsPerPage
|
||||||
timeZone = this.timeZone
|
timeZone = this.timeZone
|
||||||
themePath = this.themePath
|
themePath = this.themePath
|
||||||
autoHtmx = this.autoHtmx
|
autoHtmx = this.autoHtmx
|
||||||
|
uploads = UploadDestination.parse this.uploads
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -475,11 +475,15 @@ let settings : HttpHandler = fun next ctx -> task {
|
||||||
|> List.map (fun p -> KeyValuePair.Create (PageId.toString p.id, p.title))
|
|> List.map (fun p -> KeyValuePair.Create (PageId.toString p.id, p.title))
|
||||||
}
|
}
|
||||||
|> Array.ofSeq
|
|> Array.ofSeq
|
||||||
themes = themes
|
themes =
|
||||||
|> Seq.ofList
|
themes
|
||||||
|> Seq.map (fun it ->
|
|> Seq.ofList
|
||||||
KeyValuePair.Create (ThemeId.toString it.id, $"{it.name} (v{it.version})"))
|
|> Seq.map (fun it -> KeyValuePair.Create (ThemeId.toString it.id, $"{it.name} (v{it.version})"))
|
||||||
|> Array.ofSeq
|
|> Array.ofSeq
|
||||||
|
upload_values =
|
||||||
|
[| KeyValuePair.Create (UploadDestination.toString Database, "Database")
|
||||||
|
KeyValuePair.Create (UploadDestination.toString Disk, "Disk")
|
||||||
|
|]
|
||||||
web_log = webLog
|
web_log = webLog
|
||||||
page_title = "Web Log Settings"
|
page_title = "Web Log Settings"
|
||||||
|}
|
|}
|
||||||
|
@ -493,12 +497,19 @@ let saveSettings : HttpHandler = fun next ctx -> task {
|
||||||
let! model = ctx.BindFormAsync<SettingsModel> ()
|
let! model = ctx.BindFormAsync<SettingsModel> ()
|
||||||
match! data.WebLog.findById webLog.id with
|
match! data.WebLog.findById webLog.id with
|
||||||
| Some webLog ->
|
| Some webLog ->
|
||||||
let webLog = model.update webLog
|
let oldSlug = webLog.slug
|
||||||
|
let webLog = model.update webLog
|
||||||
do! data.WebLog.updateSettings webLog
|
do! data.WebLog.updateSettings webLog
|
||||||
|
|
||||||
// Update cache
|
// Update cache
|
||||||
WebLogCache.set webLog
|
WebLogCache.set webLog
|
||||||
|
|
||||||
|
if oldSlug <> webLog.slug then
|
||||||
|
// Rename disk directory if it exists
|
||||||
|
let uploadRoot = Path.Combine ("wwwroot", "upload")
|
||||||
|
let oldDir = Path.Combine (uploadRoot, oldSlug)
|
||||||
|
if Directory.Exists oldDir then Directory.Move (oldDir, Path.Combine (uploadRoot, webLog.slug))
|
||||||
|
|
||||||
do! addMessage ctx { UserMessage.success with message = "Web log settings saved successfully" }
|
do! addMessage ctx { UserMessage.success with message = "Web log settings saved successfully" }
|
||||||
return! redirectToGet (WebLog.relativeUrl webLog (Permalink "admin/settings")) next ctx
|
return! redirectToGet (WebLog.relativeUrl webLog (Permalink "admin/settings")) next ctx
|
||||||
| None -> return! Error.notFound next ctx
|
| None -> return! Error.notFound next ctx
|
||||||
|
|
|
@ -8,26 +8,33 @@
|
||||||
<input type="hidden" name="{{ csrf.form_field_name }}" value="{{ csrf.request_token }}">
|
<input type="hidden" name="{{ csrf.form_field_name }}" value="{{ csrf.request_token }}">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-12 col-md-6 col-xl-4 offset-xl-1 pb-3">
|
<div class="col-12 col-md-6 col-xl-4 pb-3">
|
||||||
<div class="form-floating">
|
<div class="form-floating">
|
||||||
<input type="text" name="name" id="name" class="form-control" value="{{ model.name }}" required autofocus>
|
<input type="text" name="name" id="name" class="form-control" placeholder="Name" required autofocus
|
||||||
|
value="{{ model.name }}">
|
||||||
<label for="name">Name</label>
|
<label for="name">Name</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-6 col-xl-4 pb-3">
|
<div class="col-12 col-md-6 col-xl-4 pb-3">
|
||||||
<div class="form-floating">
|
<div class="form-floating">
|
||||||
<input type="text" name="subtitle" id="subtitle" class="form-control" value="{{ model.subtitle }}">
|
<input type="text" name="slug" id="slug" class="form-control" placeholder="Slug" required
|
||||||
|
value="{{ model.slug }}">
|
||||||
|
<label for="slug">Slug</label>
|
||||||
|
<span class="form-text">
|
||||||
|
<span class="badge rounded-pill bg-warning text-dark">WARNING</span> changing this value may break links
|
||||||
|
(<a href="https://bitbadger.solutions/open-source/myweblog/configuring.html#blog-settings"
|
||||||
|
target="_blank">more</a>)
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="col-12 col-md-6 col-xl-4 pb-3">
|
||||||
|
<div class="form-floating">
|
||||||
|
<input type="text" name="subtitle" id="subtitle" class="form-control" placeholder="Subtitle"
|
||||||
|
value="{{ model.subtitle }}">
|
||||||
<label for="subtitle">Subtitle</label>
|
<label for="subtitle">Subtitle</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-4 col-xl-2 pb-3">
|
<div class="col-12 col-md-6 col-xl-4 offset-xl-1 pb-3">
|
||||||
<div class="form-floating">
|
|
||||||
<input type="number" name="postsPerPage" id="postsPerPage" class="form-control" min="0" max="50" required
|
|
||||||
value="{{ model.posts_per_page }}">
|
|
||||||
<label for="postsPerPage">Posts per Page</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-md-4 col-xl-3 pb-3">
|
|
||||||
<div class="form-floating">
|
<div class="form-floating">
|
||||||
<select name="themePath" id="themePath" class="form-control" required>
|
<select name="themePath" id="themePath" class="form-control" required>
|
||||||
{% for theme in themes -%}
|
{% for theme in themes -%}
|
||||||
|
@ -39,19 +46,12 @@
|
||||||
<label for="themePath">Theme</label>
|
<label for="themePath">Theme</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-12 col-md-4 col-xl-3 pb-3">
|
<div class="col-12 col-md-6 offset-md-1 col-xl-4 offset-xl-0 pb-3">
|
||||||
<div class="form-floating">
|
|
||||||
<input type="text" name="timeZone" id="timeZone" class="form-control" required
|
|
||||||
value="{{ model.time_zone }}">
|
|
||||||
<label for="timeZone">Time Zone</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="col-12 col-md-4 pb-3">
|
|
||||||
<div class="form-floating">
|
<div class="form-floating">
|
||||||
<select name="defaultPage" id="defaultPage" class="form-control" required>
|
<select name="defaultPage" id="defaultPage" class="form-control" required>
|
||||||
{% for pg in pages -%}
|
{% for pg in pages -%}
|
||||||
<option value="{{ pg[0] }}"
|
<option value="{{ pg[0] }}"
|
||||||
{%- if pg[0] == model.default_page %} selected="selected"{% endif %}>
|
{%- if pg[0] == model.default_page %} selected="selected"{% endif %}>
|
||||||
{{ pg[1] }}
|
{{ pg[1] }}
|
||||||
</option>
|
</option>
|
||||||
{%- endfor %}
|
{%- endfor %}
|
||||||
|
@ -59,6 +59,22 @@
|
||||||
<label for="defaultPage">Default Page</label>
|
<label for="defaultPage">Default Page</label>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-12 col-md-4 col-xl-2 pb-3">
|
||||||
|
<div class="form-floating">
|
||||||
|
<input type="number" name="postsPerPage" id="postsPerPage" class="form-control" min="0" max="50" required
|
||||||
|
value="{{ model.posts_per_page }}">
|
||||||
|
<label for="postsPerPage">Posts per Page</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-12 col-md-4 col-xl-3 offset-xl-2 pb-3">
|
||||||
|
<div class="form-floating">
|
||||||
|
<input type="text" name="timeZone" id="timeZone" class="form-control" placeholder="Time Zone" required
|
||||||
|
value="{{ model.time_zone }}">
|
||||||
|
<label for="timeZone">Time Zone</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="col-12 col-md-4 col-xl-2">
|
<div class="col-12 col-md-4 col-xl-2">
|
||||||
<div class="form-check form-switch">
|
<div class="form-check form-switch">
|
||||||
<input type="checkbox" name="autoHtmx" id="autoHtmx" class="form-check-input" value="true"
|
<input type="checkbox" name="autoHtmx" id="autoHtmx" class="form-check-input" value="true"
|
||||||
|
@ -69,6 +85,16 @@
|
||||||
<a href="https://htmx.org" target="_blank" rel="noopener">What is this?</a>
|
<a href="https://htmx.org" target="_blank" rel="noopener">What is this?</a>
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-12 col-md-4 col-xl-3 pb-3">
|
||||||
|
<div class="form-floating">
|
||||||
|
<select name="uploads" id="uploads" class="form-control">
|
||||||
|
{%- for it in upload_values %}
|
||||||
|
<option value="{{ it[0] }}"{% if model.uploads == it[0] %} selected{% endif %}>{{ it[1] }}</option>
|
||||||
|
{%- endfor %}
|
||||||
|
</select>
|
||||||
|
<label for="uploads">Default Upload Destination</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="row pb-3">
|
<div class="row pb-3">
|
||||||
<div class="col text-center">
|
<div class="col text-center">
|
||||||
|
|
Loading…
Reference in New Issue
Block a user