From dc6b066e79b1411796a65e0c01b5dd876b7462f2 Mon Sep 17 00:00:00 2001 From: "Daniel J. Summers" Date: Sun, 30 Jul 2023 21:00:31 -0400 Subject: [PATCH] Rule add/edit/move/delete works (#39) - Begin moving auth to route definition where practical - Fix typo on post list page --- src/MyWebLog.Data/Interfaces.fs | 3 + .../Postgres/PostgresWebLogData.fs | 20 +++- src/MyWebLog.Data/PostgresData.fs | 2 +- src/MyWebLog.Data/RethinkDbData.fs | 7 ++ src/MyWebLog.Data/SQLite/SQLiteWebLogData.fs | 48 ++++---- src/MyWebLog.Domain/SupportTypes.fs | 12 ++ src/MyWebLog.Domain/ViewModels.fs | 37 +++++++ src/MyWebLog/DotLiquidBespoke.fs | 18 +-- src/MyWebLog/Handlers/Admin.fs | 104 +++++++++++++++--- src/MyWebLog/Handlers/Routes.fs | 31 ++++-- src/MyWebLog/Handlers/User.fs | 6 +- src/admin-theme/post-list.liquid | 2 +- src/admin-theme/redirect-edit.liquid | 48 ++++++++ src/admin-theme/redirect-list.liquid | 79 +++++++------ src/admin-theme/settings.liquid | 2 +- 15 files changed, 322 insertions(+), 97 deletions(-) create mode 100644 src/admin-theme/redirect-edit.liquid diff --git a/src/MyWebLog.Data/Interfaces.fs b/src/MyWebLog.Data/Interfaces.fs index f064cc4..0ec05d5 100644 --- a/src/MyWebLog.Data/Interfaces.fs +++ b/src/MyWebLog.Data/Interfaces.fs @@ -259,6 +259,9 @@ type IWebLogData = /// Find a web log by its ID abstract member FindById : WebLogId -> Task + /// Update redirect rules for a web log + abstract member UpdateRedirectRules : WebLog -> Task + /// Update RSS options for a web log abstract member UpdateRssOptions : WebLog -> Task diff --git a/src/MyWebLog.Data/Postgres/PostgresWebLogData.fs b/src/MyWebLog.Data/Postgres/PostgresWebLogData.fs index 713005b..ef6020c 100644 --- a/src/MyWebLog.Data/Postgres/PostgresWebLogData.fs +++ b/src/MyWebLog.Data/Postgres/PostgresWebLogData.fs @@ -45,11 +45,13 @@ type PostgresWebLogData (log : ILogger) = log.LogTrace "WebLog.findById" Find.byId Table.WebLog (WebLogId.toString webLogId) - /// Update settings for a web log - let updateSettings (webLog : WebLog) = - log.LogTrace "WebLog.updateSettings" - Update.full Table.WebLog (WebLogId.toString webLog.Id) webLog - + let updateRedirectRules (webLog : WebLog) = backgroundTask { + log.LogTrace "WebLog.updateRedirectRules" + match! findById webLog.Id with + | Some _ -> + do! Update.partialById Table.WebLog (WebLogId.toString webLog.Id) {| RedirectRules = webLog.RedirectRules |} + | None -> () + } /// Update RSS options for a web log let updateRssOptions (webLog : WebLog) = backgroundTask { log.LogTrace "WebLog.updateRssOptions" @@ -58,11 +60,17 @@ type PostgresWebLogData (log : ILogger) = | None -> () } + /// Update settings for a web log + let updateSettings (webLog : WebLog) = + log.LogTrace "WebLog.updateSettings" + Update.full Table.WebLog (WebLogId.toString webLog.Id) webLog + interface IWebLogData with member _.Add webLog = add webLog member _.All () = all () member _.Delete webLogId = delete webLogId member _.FindByHost url = findByHost url member _.FindById webLogId = findById webLogId - member _.UpdateSettings webLog = updateSettings webLog + member _.UpdateRedirectRules webLog = updateRedirectRules webLog member _.UpdateRssOptions webLog = updateRssOptions webLog + member _.UpdateSettings webLog = updateSettings webLog diff --git a/src/MyWebLog.Data/PostgresData.fs b/src/MyWebLog.Data/PostgresData.fs index 66ee047..0b788b0 100644 --- a/src/MyWebLog.Data/PostgresData.fs +++ b/src/MyWebLog.Data/PostgresData.fs @@ -162,7 +162,7 @@ type PostgresData (log : ILogger, ser : JsonSerializer) = /// Migrate from v2 to v2.1 let migrateV2ToV2point1 () = backgroundTask { Utils.logMigrationStep log "v2 to v2.1" "Adding empty redirect rule set to all weblogs" - do! Custom.nonQuery $"UPDATE {Table.WebLog} SET data['RedirectRules'] = '[]'::json" [] + do! Custom.nonQuery $"""UPDATE {Table.WebLog} SET data = data + '{{ "RedirectRules": [] }}'::json""" [] Utils.logMigrationStep log "v2 to v2.1" "Setting database to version 2.1" do! setDbVersion "v2.1" diff --git a/src/MyWebLog.Data/RethinkDbData.fs b/src/MyWebLog.Data/RethinkDbData.fs index ccf4ef2..73a625f 100644 --- a/src/MyWebLog.Data/RethinkDbData.fs +++ b/src/MyWebLog.Data/RethinkDbData.fs @@ -1031,6 +1031,13 @@ type RethinkDbData (conn : Net.IConnection, config : DataConfig, log : ILogger obj ] + write; withRetryDefault; ignoreResult conn + } + member _.UpdateRssOptions webLog = rethink { withTable Table.WebLog get webLog.Id diff --git a/src/MyWebLog.Data/SQLite/SQLiteWebLogData.fs b/src/MyWebLog.Data/SQLite/SQLiteWebLogData.fs index 1bcfbb1..f4b64e7 100644 --- a/src/MyWebLog.Data/SQLite/SQLiteWebLogData.fs +++ b/src/MyWebLog.Data/SQLite/SQLiteWebLogData.fs @@ -206,6 +206,33 @@ type SQLiteWebLogData (conn : SqliteConnection, ser : JsonSerializer) = return None } + /// Update redirect rules for a web log + let updateRedirectRules webLog = backgroundTask { + use cmd = conn.CreateCommand () + cmd.CommandText <- "UPDATE web_log SET redirect_rules = @redirectRules WHERE id = @id" + cmd.Parameters.AddWithValue ("@redirectRules", Utils.serialize ser webLog.RedirectRules) |> ignore + cmd.Parameters.AddWithValue ("@id", WebLogId.toString webLog.Id) |> ignore + do! write cmd + } + + /// Update RSS options for a web log + let updateRssOptions webLog = backgroundTask { + use cmd = conn.CreateCommand () + cmd.CommandText <- + "UPDATE web_log + SET is_feed_enabled = @isFeedEnabled, + feed_name = @feedName, + items_in_feed = @itemsInFeed, + is_category_enabled = @isCategoryEnabled, + is_tag_enabled = @isTagEnabled, + copyright = @copyright + WHERE id = @id" + addWebLogRssParameters cmd webLog + cmd.Parameters.AddWithValue ("@id", WebLogId.toString webLog.Id) |> ignore + do! write cmd + do! updateCustomFeeds webLog + } + /// Update settings for a web log let updateSettings webLog = backgroundTask { use cmd = conn.CreateCommand () @@ -233,29 +260,12 @@ type SQLiteWebLogData (conn : SqliteConnection, ser : JsonSerializer) = do! write cmd } - /// Update RSS options for a web log - let updateRssOptions webLog = backgroundTask { - use cmd = conn.CreateCommand () - cmd.CommandText <- - "UPDATE web_log - SET is_feed_enabled = @isFeedEnabled, - feed_name = @feedName, - items_in_feed = @itemsInFeed, - is_category_enabled = @isCategoryEnabled, - is_tag_enabled = @isTagEnabled, - copyright = @copyright - WHERE id = @id" - addWebLogRssParameters cmd webLog - cmd.Parameters.AddWithValue ("@id", WebLogId.toString webLog.Id) |> ignore - do! write cmd - do! updateCustomFeeds webLog - } - interface IWebLogData with member _.Add webLog = add webLog member _.All () = all () member _.Delete webLogId = delete webLogId member _.FindByHost url = findByHost url member _.FindById webLogId = findById webLogId - member _.UpdateSettings webLog = updateSettings webLog + member _.UpdateRedirectRules webLog = updateRedirectRules webLog member _.UpdateRssOptions webLog = updateRssOptions webLog + member _.UpdateSettings webLog = updateSettings webLog diff --git a/src/MyWebLog.Domain/SupportTypes.fs b/src/MyWebLog.Domain/SupportTypes.fs index 4a525c7..1ece831 100644 --- a/src/MyWebLog.Domain/SupportTypes.fs +++ b/src/MyWebLog.Domain/SupportTypes.fs @@ -426,12 +426,24 @@ module PostId = type RedirectRule = { /// The From string or pattern From : string + /// The To string or pattern To : string + /// Whether to use regular expressions on this rule IsRegex : bool } +/// Functions to support redirect rules +module RedirectRule = + + /// An empty redirect rule + let empty = + { From = "" + To = "" + IsRegex = false + } + /// An identifier for a custom feed type CustomFeedId = CustomFeedId of string diff --git a/src/MyWebLog.Domain/ViewModels.fs b/src/MyWebLog.Domain/ViewModels.fs index f7d204f..61ece89 100644 --- a/src/MyWebLog.Domain/ViewModels.fs +++ b/src/MyWebLog.Domain/ViewModels.fs @@ -807,6 +807,43 @@ type EditPostModel = } +/// View model to add/edit a redirect rule +[] +type EditRedirectRuleModel = + { /// The ID (index) of the rule being edited + RuleId : int + + /// The "from" side of the rule + From : string + + /// The "to" side of the rule + To : string + + /// Whether this rule uses a regular expression + IsRegex : bool + + /// Whether a new rule should be inserted at the top or appended to the end (ignored for edits) + InsertAtTop : bool + } + + /// Create a model from an existing rule + static member fromRule idx (rule : RedirectRule) = + { RuleId = idx + From = rule.From + To = rule.To + IsRegex = rule.IsRegex + InsertAtTop = false + } + + /// Update a rule with the values from this model + member this.UpdateRule (rule : RedirectRule) = + { rule with + From = this.From + To = this.To + IsRegex = this.IsRegex + } + + /// View model to edit RSS settings [] type EditRssModel = diff --git a/src/MyWebLog/DotLiquidBespoke.fs b/src/MyWebLog/DotLiquidBespoke.fs index 4cbd799..83e9a3f 100644 --- a/src/MyWebLog/DotLiquidBespoke.fs +++ b/src/MyWebLog/DotLiquidBespoke.fs @@ -224,15 +224,17 @@ let register () = Template.RegisterTag "user_links" [ // Domain types - typeof; typeof; typeof; typeof; typeof - typeof; typeof; typeof; typeof + typeof; typeof; typeof; typeof; typeof + typeof; typeof; typeof; typeof; typeof // View models - typeof; typeof; typeof; typeof - typeof; typeof; typeof; typeof - typeof; typeof; typeof; typeof - typeof; typeof; typeof; typeof - typeof; typeof; typeof; typeof - typeof; typeof; typeof + typeof; typeof; typeof + typeof; typeof; typeof + typeof; typeof; typeof + typeof; typeof; typeof + typeof; typeof; typeof + typeof; typeof; typeof + typeof; typeof; typeof + typeof; typeof; typeof // Framework types typeof; typeof; typeof; typeof typeof; typeof; typeof; typeof diff --git a/src/MyWebLog/Handlers/Admin.fs b/src/MyWebLog/Handlers/Admin.fs index 1808676..4025843 100644 --- a/src/MyWebLog/Handlers/Admin.fs +++ b/src/MyWebLog/Handlers/Admin.fs @@ -132,7 +132,7 @@ module Category = open MyWebLog.Data // GET /admin/categories - let all : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task { + let all : HttpHandler = fun next ctx -> task { match! TemplateCache.get adminTheme "category-list-body" ctx.Data with | Ok catListTemplate -> let! hash = @@ -146,14 +146,14 @@ module Category = } // GET /admin/categories/bare - let bare : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> + let bare : HttpHandler = fun next ctx -> hashForPage "Categories" |> withAntiCsrf ctx |> adminBareView "category-list-body" next ctx // GET /admin/category/{id}/edit - let edit catId : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task { + let edit catId : HttpHandler = fun next ctx -> task { let! result = task { match catId with | "new" -> return Some ("Add a New Category", { Category.empty with Id = CategoryId "new" }) @@ -173,7 +173,7 @@ module Category = } // POST /admin/category/save - let save : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task { + let save : HttpHandler = fun next ctx -> task { let data = ctx.Data let! model = ctx.BindFormAsync () let category = @@ -196,7 +196,7 @@ module Category = } // POST /admin/category/{id}/delete - let delete catId : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task { + let delete catId : HttpHandler = fun next ctx -> task { let! result = ctx.Data.Category.Delete (CategoryId catId) ctx.WebLog.Id match result with | CategoryDeleted @@ -217,8 +217,10 @@ module Category = /// ~~~ REDIRECT RULES ~~~ module RedirectRules = - // GET /admin/redirect-rules - let all : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task { + open Microsoft.AspNetCore.Http + + // GET /admin/settings/redirect-rules + let all : HttpHandler = fun next ctx -> task { return! hashForPage "Redirect Rules" |> withAntiCsrf ctx @@ -226,6 +228,82 @@ module RedirectRules = |> adminView "redirect-list" next ctx } + // GET /admin/settings/redirect-rules/[index] + let edit idx : HttpHandler = fun next ctx -> task { + if idx = -1 then + return! + hashForPage "Add Redirect Rule" + |> addToHash "model" (EditRedirectRuleModel.fromRule -1 RedirectRule.empty) + |> withAntiCsrf ctx + |> adminBareView "redirect-edit" next ctx + else + let rules = ctx.WebLog.RedirectRules + if rules.Length < idx || idx < 0 then + return! Error.notFound next ctx + else + return! + hashForPage "Edit Redirect Rule" + |> addToHash "model" (EditRedirectRuleModel.fromRule idx (List.item idx rules)) + |> withAntiCsrf ctx + |> adminBareView "redirect-edit" next ctx + } + + /// Update the web log's redirect rules in the database, the request web log, and the web log cache + let private updateRedirectRules (ctx : HttpContext) webLog = backgroundTask { + do! ctx.Data.WebLog.UpdateRedirectRules webLog + ctx.Items["webLog"] <- webLog + WebLogCache.set webLog + } + + // POST /admin/settings/redirect-rules/[index] + let save idx : HttpHandler = fun next ctx -> task { + let! model = ctx.BindFormAsync () + let isNew = idx = -1 + let rules = ctx.WebLog.RedirectRules + let rule = model.UpdateRule (if isNew then RedirectRule.empty else List.item idx rules) + let newRules = + match isNew with + | true when model.InsertAtTop -> List.insertAt 0 rule rules + | true -> List.insertAt (rules.Length) rule rules + | false -> rules |> List.removeAt idx |> List.insertAt idx rule + do! updateRedirectRules ctx { ctx.WebLog with RedirectRules = newRules } + do! addMessage ctx { UserMessage.success with Message = "Redirect rule saved successfully" } + return! all next ctx + } + + // POST /admin/settings/redirect-rules/[index]/up + let moveUp idx : HttpHandler = fun next ctx -> task { + if idx < 1 || idx >= ctx.WebLog.RedirectRules.Length then + return! Error.notFound next ctx + else + let toMove = List.item idx ctx.WebLog.RedirectRules + let newRules = ctx.WebLog.RedirectRules |> List.removeAt idx |> List.insertAt (idx - 1) toMove + do! updateRedirectRules ctx { ctx.WebLog with RedirectRules = newRules } + return! all next ctx + } + + // POST /admin/settings/redirect-rules/[index]/down + let moveDown idx : HttpHandler = fun next ctx -> task { + if idx < 0 || idx >= ctx.WebLog.RedirectRules.Length - 1 then + return! Error.notFound next ctx + else + let toMove = List.item idx ctx.WebLog.RedirectRules + let newRules = ctx.WebLog.RedirectRules |> List.removeAt idx |> List.insertAt (idx + 1) toMove + do! updateRedirectRules ctx { ctx.WebLog with RedirectRules = newRules } + return! all next ctx + } + + // POST /admin/settings/redirect-rules/[index]/delete + let delete idx : HttpHandler = fun next ctx -> task { + if idx < 0 || idx >= ctx.WebLog.RedirectRules.Length then + return! Error.notFound next ctx + else + let rules = ctx.WebLog.RedirectRules |> List.removeAt idx + do! updateRedirectRules ctx { ctx.WebLog with RedirectRules = rules } + do! addMessage ctx { UserMessage.success with Message = "Redirect rule deleted successfully" } + return! all next ctx + } + /// ~~~ TAG MAPPINGS ~~~ module TagMapping = @@ -243,7 +321,7 @@ module TagMapping = } // GET /admin/settings/tag-mappings - let all : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task { + let all : HttpHandler = fun next ctx -> task { let! hash = hashForPage "" |> withAntiCsrf ctx @@ -252,7 +330,7 @@ module TagMapping = } // GET /admin/settings/tag-mapping/{id}/edit - let edit tagMapId : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task { + let edit tagMapId : HttpHandler = fun next ctx -> task { let isNew = tagMapId = "new" let tagMap = if isNew then someTask { TagMap.empty with Id = TagMapId "new" } @@ -268,7 +346,7 @@ module TagMapping = } // POST /admin/settings/tag-mapping/save - let save : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task { + let save : HttpHandler = fun next ctx -> task { let data = ctx.Data let! model = ctx.BindFormAsync () let tagMap = @@ -283,7 +361,7 @@ module TagMapping = } // POST /admin/settings/tag-mapping/{id}/delete - let delete tagMapId : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task { + let delete tagMapId : HttpHandler = fun next ctx -> task { match! ctx.Data.TagMap.Delete (TagMapId tagMapId) ctx.WebLog.Id with | true -> do! addMessage ctx { UserMessage.success with Message = "Tag mapping deleted successfully" } | false -> do! addMessage ctx { UserMessage.error with Message = "Tag mapping not found; nothing deleted" } @@ -460,7 +538,7 @@ module WebLog = open System.IO // GET /admin/settings - let settings : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task { + let settings : HttpHandler = fun next ctx -> task { let data = ctx.Data match! TemplateCache.get adminTheme "user-list-body" data with | Ok userTemplate -> @@ -508,7 +586,7 @@ module WebLog = } // POST /admin/settings - let saveSettings : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task { + let saveSettings : HttpHandler = fun next ctx -> task { let data = ctx.Data let! model = ctx.BindFormAsync () match! data.WebLog.FindById ctx.WebLog.Id with diff --git a/src/MyWebLog/Handlers/Routes.fs b/src/MyWebLog/Handlers/Routes.fs index 0c82308..3b8f74d 100644 --- a/src/MyWebLog/Handlers/Routes.fs +++ b/src/MyWebLog/Handlers/Routes.fs @@ -107,7 +107,7 @@ let router : HttpHandler = choose [ subRoute "/admin" (requireUser >=> choose [ GET_HEAD >=> choose [ route "/administration" >=> Admin.Dashboard.admin - subRoute "/categor" (choose [ + subRoute "/categor" (requireAccess WebLogAdmin >=> choose [ route "ies" >=> Admin.Category.all route "ies/bare" >=> Admin.Category.bare routef "y/%s/edit" Admin.Category.edit @@ -130,20 +130,21 @@ let router : HttpHandler = choose [ routef "/%s/revision/%s/preview" Post.previewRevision routef "/%s/revisions" Post.editRevisions ]) - subRoute "/redirect-rules" (choose [ - route "" >=> Admin.RedirectRules.all - ]) - subRoute "/settings" (choose [ - route "" >=> Admin.WebLog.settings - routef "/rss/%s/edit" Feed.editCustomFeed - subRoute "/user" (choose [ - route "s" >=> User.all - routef "/%s/edit" User.edit + subRoute "/settings" (requireAccess WebLogAdmin >=> choose [ + route "" >=> Admin.WebLog.settings + routef "/rss/%s/edit" Feed.editCustomFeed + subRoute "/redirect-rules" (choose [ + route "" >=> Admin.RedirectRules.all + routef "/%i" Admin.RedirectRules.edit ]) subRoute "/tag-mapping" (choose [ route "s" >=> Admin.TagMapping.all routef "/%s/edit" Admin.TagMapping.edit ]) + subRoute "/user" (choose [ + route "s" >=> User.all + routef "/%s/edit" User.edit + ]) ]) subRoute "/theme" (choose [ route "/list" >=> Admin.Theme.all @@ -159,7 +160,7 @@ let router : HttpHandler = choose [ routef "/theme/%s/refresh" Admin.Cache.refreshTheme routef "/web-log/%s/refresh" Admin.Cache.refreshWebLog ]) - subRoute "/category" (choose [ + subRoute "/category" (requireAccess WebLogAdmin >=> choose [ route "/save" >=> Admin.Category.save routef "/%s/delete" Admin.Category.delete ]) @@ -180,13 +181,19 @@ let router : HttpHandler = choose [ routef "/%s/revision/%s/restore" Post.restoreRevision routef "/%s/revisions/purge" Post.purgeRevisions ]) - subRoute "/settings" (choose [ + subRoute "/settings" (requireAccess WebLogAdmin >=> choose [ route "" >=> Admin.WebLog.saveSettings subRoute "/rss" (choose [ route "" >=> Feed.saveSettings route "/save" >=> Feed.saveCustomFeed routef "/%s/delete" Feed.deleteCustomFeed ]) + subRoute "/redirect-rules" (choose [ + routef "/%i" Admin.RedirectRules.save + routef "/%i/up" Admin.RedirectRules.moveUp + routef "/%i/down" Admin.RedirectRules.moveDown + routef "/%i/delete" Admin.RedirectRules.delete + ]) subRoute "/tag-mapping" (choose [ route "/save" >=> Admin.TagMapping.save routef "/%s/delete" Admin.TagMapping.delete diff --git a/src/MyWebLog/Handlers/User.fs b/src/MyWebLog/Handlers/User.fs index 6a67a61..43d9ccc 100644 --- a/src/MyWebLog/Handlers/User.fs +++ b/src/MyWebLog/Handlers/User.fs @@ -95,7 +95,7 @@ open Giraffe.Htmx let private goAway : HttpHandler = RequestErrors.BAD_REQUEST "really?" // GET /admin/settings/users -let all : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task { +let all : HttpHandler = fun next ctx -> task { let! users = ctx.Data.WebLogUser.FindByWebLog ctx.WebLog.Id return! hashForPage "User Administration" @@ -119,7 +119,7 @@ let private showEdit (model : EditUserModel) : HttpHandler = fun next ctx -> |> adminBareView "user-edit" next ctx // GET /admin/settings/user/{id}/edit -let edit usrId : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task { +let edit usrId : HttpHandler = fun next ctx -> task { let isNew = usrId = "new" let userId = WebLogUserId usrId let tryUser = @@ -131,7 +131,7 @@ let edit usrId : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> tas } // POST /admin/settings/user/{id}/delete -let delete userId : HttpHandler = requireAccess WebLogAdmin >=> fun next ctx -> task { +let delete userId : HttpHandler = fun next ctx -> task { let data = ctx.Data match! data.WebLogUser.FindById (WebLogUserId userId) ctx.WebLog.Id with | Some user -> diff --git a/src/admin-theme/post-list.liquid b/src/admin-theme/post-list.liquid index b597187..ffb9994 100644 --- a/src/admin-theme/post-list.liquid +++ b/src/admin-theme/post-list.liquid @@ -54,7 +54,7 @@ {%- assign post_del_link = "admin/post/" | append: post.id | append: "/delete" | relative_link -%} + hx-confirm="Are you sure you want to delete the post “{{ post.title | strip_html | escape }}”? This action cannot be undone."> Delete {% endif %} diff --git a/src/admin-theme/redirect-edit.liquid b/src/admin-theme/redirect-edit.liquid new file mode 100644 index 0000000..d35172d --- /dev/null +++ b/src/admin-theme/redirect-edit.liquid @@ -0,0 +1,48 @@ +

{% if model.rule_id < 0 %}Add{% else %}Edit{% endif %} Redirect Rule

+{%- assign post_url = "admin/settings/redirect-rules/" | append: model.rule_id | relative_link -%} +
+ + +
+
+
+ + +
+
+
+
+ + +
+
+
+
+ + +
+
+
+ {% if model.rule_id < 0 %} +
+
+ +
+ + + + +
+
+
+ {% endif %} +
+
+ + Cancel +
+
+
diff --git a/src/admin-theme/redirect-list.liquid b/src/admin-theme/redirect-list.liquid index 88ff325..232ead0 100644 --- a/src/admin-theme/redirect-list.liquid +++ b/src/admin-theme/redirect-list.liquid @@ -1,7 +1,17 @@ -

Redirect Rules

+

{{ page_title }}

- « Back to Settings +

+ « Back to Settings +

+
{%- assign redir_count = redirections | size -%} @@ -13,42 +23,45 @@
RegEx?
-
+
+ -
- {% for redir in redirections -%} - {%- assign map_id = mapping_ids | value: map.tag -%} -
-
- {{ redir.from }}
- - {%- assign redir_url = "admin/settings/redirect-rules/" | append: forloop.index0 -%} - - Edit - - {% unless forloop.first %} - - {%- assign move_up = redir_url | append: "/up" | relative_link -%} - Move Up - {% endunless %} - {% unless forloop.last %} - - {%- assign move_down = redir_url | append: "/down" | relative_link -%} - Move Down - {% endunless %} + {% for redir in redirections -%} + {%- assign redir_id = "redir_" | append: forloop.index0 -%} +
+
+ {{ redir.from }}
+ + {%- assign redir_url = "admin/settings/redirect-rules/" | append: forloop.index0 -%} + + Edit + + {% unless forloop.first %} - {%- assign del_url = redir_url | append: "/delete" | relative_link -%} - Delete - -
-
{{ redir.to }}
-
{% if redir.is_regex %}Yes{% else %}No{% endif %}
+ {%- assign move_up = redir_url | append: "/up" | relative_link -%} + Move Up + {% endunless %} + {% unless forloop.last %} + + {%- assign move_down = redir_url | append: "/down" | relative_link -%} + Move Down + {% endunless %} + + {%- assign del_url = redir_url | append: "/delete" | relative_link -%} + + Delete + +
- {%- endfor %} +
{{ redir.to }}
+
{% if redir.is_regex %}Yes{% else %}No{% endif %}
+
+ {%- endfor %} {%- else -%} -
+

This web log has no redirect rules defined

{%- endif %} diff --git a/src/admin-theme/settings.liquid b/src/admin-theme/settings.liquid index 92c5649..ed75e5c 100644 --- a/src/admin-theme/settings.liquid +++ b/src/admin-theme/settings.liquid @@ -3,7 +3,7 @@

Go to: UsersRSS SettingsTag Mappings • - Redirect Rules + Redirect Rules

Web Log Settings