Save RSS settings
- Add route for custom feed deletion - Add ID for custom feed
This commit is contained in:
parent
50179ffab9
commit
46d6c4f5f1
|
@ -20,6 +20,13 @@ type CommentIdConverter () =
|
||||||
override _.ReadJson (reader : JsonReader, _ : Type, _ : CommentId, _ : bool, _ : JsonSerializer) =
|
override _.ReadJson (reader : JsonReader, _ : Type, _ : CommentId, _ : bool, _ : JsonSerializer) =
|
||||||
(string >> CommentId) reader.Value
|
(string >> CommentId) reader.Value
|
||||||
|
|
||||||
|
type CustomFeedIdConverter () =
|
||||||
|
inherit JsonConverter<CustomFeedId> ()
|
||||||
|
override _.WriteJson (writer : JsonWriter, value : CustomFeedId, _ : JsonSerializer) =
|
||||||
|
writer.WriteValue (CustomFeedId.toString value)
|
||||||
|
override _.ReadJson (reader : JsonReader, _ : Type, _ : CustomFeedId, _ : bool, _ : JsonSerializer) =
|
||||||
|
(string >> CustomFeedId) reader.Value
|
||||||
|
|
||||||
type CustomFeedSourceConverter () =
|
type CustomFeedSourceConverter () =
|
||||||
inherit JsonConverter<CustomFeedSource> ()
|
inherit JsonConverter<CustomFeedSource> ()
|
||||||
override _.WriteJson (writer : JsonWriter, value : CustomFeedSource, _ : JsonSerializer) =
|
override _.WriteJson (writer : JsonWriter, value : CustomFeedSource, _ : JsonSerializer) =
|
||||||
|
@ -91,6 +98,7 @@ let all () : JsonConverter seq =
|
||||||
// Our converters
|
// Our converters
|
||||||
CategoryIdConverter ()
|
CategoryIdConverter ()
|
||||||
CommentIdConverter ()
|
CommentIdConverter ()
|
||||||
|
CustomFeedIdConverter ()
|
||||||
CustomFeedSourceConverter ()
|
CustomFeedSourceConverter ()
|
||||||
ExplicitRatingConverter ()
|
ExplicitRatingConverter ()
|
||||||
MarkupTextConverter ()
|
MarkupTextConverter ()
|
||||||
|
|
|
@ -731,12 +731,28 @@ module WebLog =
|
||||||
resultOption; withRetryOptionDefault
|
resultOption; withRetryOptionDefault
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update web log settings (updates all values)
|
/// Update RSS options for a web log
|
||||||
|
let updateRssOptions (webLog : WebLog) =
|
||||||
|
rethink {
|
||||||
|
withTable Table.WebLog
|
||||||
|
get webLog.id
|
||||||
|
update [ "rss", webLog.rss :> obj ]
|
||||||
|
write; withRetryDefault; ignoreResult
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update web log settings (from settings page)
|
||||||
let updateSettings (webLog : WebLog) =
|
let updateSettings (webLog : WebLog) =
|
||||||
rethink {
|
rethink {
|
||||||
withTable Table.WebLog
|
withTable Table.WebLog
|
||||||
get webLog.id
|
get webLog.id
|
||||||
replace webLog
|
update [
|
||||||
|
"name", webLog.name :> obj
|
||||||
|
"subtitle", webLog.subtitle
|
||||||
|
"defaultPage", webLog.defaultPage
|
||||||
|
"postsPerPage", webLog.postsPerPage
|
||||||
|
"timeZone", webLog.timeZone
|
||||||
|
"themePath", webLog.themePath
|
||||||
|
]
|
||||||
write; withRetryDefault; ignoreResult
|
write; withRetryDefault; ignoreResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -187,6 +187,22 @@ module PostId =
|
||||||
let create () = PostId (newId ())
|
let create () = PostId (newId ())
|
||||||
|
|
||||||
|
|
||||||
|
/// An identifier for a custom feed
|
||||||
|
type CustomFeedId = CustomFeedId of string
|
||||||
|
|
||||||
|
/// Functions to support custom feed IDs
|
||||||
|
module CustomFeedId =
|
||||||
|
|
||||||
|
/// An empty custom feed ID
|
||||||
|
let empty = CustomFeedId ""
|
||||||
|
|
||||||
|
/// Convert a custom feed ID to a string
|
||||||
|
let toString = function CustomFeedId pi -> pi
|
||||||
|
|
||||||
|
/// Create a new custom feed ID
|
||||||
|
let create () = CustomFeedId (newId ())
|
||||||
|
|
||||||
|
|
||||||
/// The source for a custom feed
|
/// The source for a custom feed
|
||||||
type CustomFeedSource =
|
type CustomFeedSource =
|
||||||
/// A feed based on a particular category
|
/// A feed based on a particular category
|
||||||
|
@ -274,7 +290,10 @@ type PodcastOptions =
|
||||||
|
|
||||||
/// A custom feed
|
/// A custom feed
|
||||||
type CustomFeed =
|
type CustomFeed =
|
||||||
{ /// The source for the custom feed
|
{ /// The ID of the custom feed
|
||||||
|
id : CustomFeedId
|
||||||
|
|
||||||
|
/// The source for the custom feed
|
||||||
source : CustomFeedSource
|
source : CustomFeedSource
|
||||||
|
|
||||||
/// The path for the custom feed
|
/// The path for the custom feed
|
||||||
|
|
|
@ -26,6 +26,34 @@ type DisplayCategory =
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// A display version of a custom feed definition
|
||||||
|
type DisplayCustomFeed =
|
||||||
|
{ /// The ID of the custom feed
|
||||||
|
id : string
|
||||||
|
|
||||||
|
/// The source of the custom feed
|
||||||
|
source : string
|
||||||
|
|
||||||
|
/// The relative path at which the custom feed is served
|
||||||
|
path : string
|
||||||
|
|
||||||
|
/// Whether this custom feed is for a podcast
|
||||||
|
isPodcast : bool
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a display version from a custom feed
|
||||||
|
static member fromFeed (cats : DisplayCategory[]) (feed : CustomFeed) : DisplayCustomFeed =
|
||||||
|
let source =
|
||||||
|
match feed.source with
|
||||||
|
| Category (CategoryId catId) -> $"Category: {(cats |> Array.find (fun cat -> cat.id = catId)).name}"
|
||||||
|
| Tag tag -> $"Tag: {tag}"
|
||||||
|
{ id = CustomFeedId.toString feed.id
|
||||||
|
source = source
|
||||||
|
path = Permalink.toString feed.path
|
||||||
|
isPodcast = Option.isSome feed.podcast
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Details about a page used to display page lists
|
/// Details about a page used to display page lists
|
||||||
[<NoComparison; NoEquality>]
|
[<NoComparison; NoEquality>]
|
||||||
type DisplayPage =
|
type DisplayPage =
|
||||||
|
@ -255,6 +283,50 @@ type EditPostModel =
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// View model to edit RSS settings
|
||||||
|
[<CLIMutable; NoComparison; NoEquality>]
|
||||||
|
type EditRssModel =
|
||||||
|
{ /// Whether the site feed of posts is enabled
|
||||||
|
feedEnabled : bool
|
||||||
|
|
||||||
|
/// The name of the file generated for the site feed
|
||||||
|
feedName : string
|
||||||
|
|
||||||
|
/// Override the "posts per page" setting for the site feed
|
||||||
|
itemsInFeed : int
|
||||||
|
|
||||||
|
/// Whether feeds are enabled for all categories
|
||||||
|
categoryEnabled : bool
|
||||||
|
|
||||||
|
/// Whether feeds are enabled for all tags
|
||||||
|
tagEnabled : bool
|
||||||
|
|
||||||
|
/// A copyright string to be placed in all feeds
|
||||||
|
copyright : string
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create an edit model from a set of RSS options
|
||||||
|
static member fromRssOptions (rss : RssOptions) =
|
||||||
|
{ feedEnabled = rss.feedEnabled
|
||||||
|
feedName = rss.feedName
|
||||||
|
itemsInFeed = defaultArg rss.itemsInFeed 0
|
||||||
|
categoryEnabled = rss.categoryEnabled
|
||||||
|
tagEnabled = rss.tagEnabled
|
||||||
|
copyright = defaultArg rss.copyright ""
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update RSS options from values in this mode
|
||||||
|
member this.updateOptions (rss : RssOptions) =
|
||||||
|
{ rss with
|
||||||
|
feedEnabled = this.feedEnabled
|
||||||
|
feedName = this.feedName
|
||||||
|
itemsInFeed = if this.itemsInFeed = 0 then None else Some this.itemsInFeed
|
||||||
|
categoryEnabled = this.categoryEnabled
|
||||||
|
tagEnabled = this.tagEnabled
|
||||||
|
copyright = if this.copyright.Trim () = "" then None else Some (this.copyright.Trim ())
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// View model to edit a tag mapping
|
/// View model to edit a tag mapping
|
||||||
[<CLIMutable; NoComparison; NoEquality>]
|
[<CLIMutable; NoComparison; NoEquality>]
|
||||||
type EditTagMapModel =
|
type EditTagMapModel =
|
||||||
|
@ -305,6 +377,8 @@ type EditUserModel =
|
||||||
newPassword = ""
|
newPassword = ""
|
||||||
newPasswordConfirm = ""
|
newPasswordConfirm = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// The model to use to allow a user to log on
|
/// The model to use to allow a user to log on
|
||||||
[<CLIMutable; NoComparison; NoEquality>]
|
[<CLIMutable; NoComparison; NoEquality>]
|
||||||
type LogOnModel =
|
type LogOnModel =
|
||||||
|
|
|
@ -15,10 +15,10 @@ open MyWebLog.ViewModels
|
||||||
|
|
||||||
/// The type of feed to generate
|
/// The type of feed to generate
|
||||||
type FeedType =
|
type FeedType =
|
||||||
| StandardFeed
|
| StandardFeed of string
|
||||||
| CategoryFeed of CategoryId
|
| CategoryFeed of CategoryId * string
|
||||||
| TagFeed of string
|
| TagFeed of string * string
|
||||||
| Custom of CustomFeed
|
| Custom of CustomFeed * string
|
||||||
|
|
||||||
/// Derive the type of RSS feed requested
|
/// Derive the type of RSS feed requested
|
||||||
let deriveFeedType (ctx : HttpContext) feedPath : (FeedType * int) option =
|
let deriveFeedType (ctx : HttpContext) feedPath : (FeedType * int) option =
|
||||||
|
@ -27,21 +27,21 @@ let deriveFeedType (ctx : HttpContext) feedPath : (FeedType * int) option =
|
||||||
let postCount = defaultArg webLog.rss.itemsInFeed webLog.postsPerPage
|
let postCount = defaultArg webLog.rss.itemsInFeed webLog.postsPerPage
|
||||||
// Standard feed
|
// Standard feed
|
||||||
match webLog.rss.feedEnabled && feedPath = name with
|
match webLog.rss.feedEnabled && feedPath = name with
|
||||||
| true -> Some (StandardFeed, postCount)
|
| true -> Some (StandardFeed feedPath, postCount)
|
||||||
| false ->
|
| false ->
|
||||||
// Category feed
|
// Category feed
|
||||||
match CategoryCache.get ctx |> Array.tryFind (fun cat -> cat.slug = feedPath.Replace (name, "")) with
|
match CategoryCache.get ctx |> Array.tryFind (fun cat -> cat.slug = feedPath.Replace (name, "")) with
|
||||||
| Some cat -> Some (CategoryFeed (CategoryId cat.id), postCount)
|
| Some cat -> Some (CategoryFeed (CategoryId cat.id, feedPath), postCount)
|
||||||
| None ->
|
| None ->
|
||||||
// Tag feed
|
// Tag feed
|
||||||
match feedPath.StartsWith "/tag/" with
|
match feedPath.StartsWith "/tag/" with
|
||||||
| true -> Some (TagFeed (feedPath.Replace("/tag/", "").Replace(name, "")), postCount)
|
| true -> Some (TagFeed (feedPath.Replace("/tag/", "").Replace(name, ""), feedPath), postCount)
|
||||||
| false ->
|
| false ->
|
||||||
// Custom feed
|
// Custom feed
|
||||||
match webLog.rss.customFeeds
|
match webLog.rss.customFeeds
|
||||||
|> List.tryFind (fun it -> (Permalink.toString it.path).EndsWith feedPath) with
|
|> List.tryFind (fun it -> (Permalink.toString it.path).EndsWith feedPath) with
|
||||||
| Some feed ->
|
| Some feed ->
|
||||||
Some (Custom feed,
|
Some (Custom (feed, feedPath),
|
||||||
feed.podcast |> Option.map (fun p -> p.itemsInFeed) |> Option.defaultValue postCount)
|
feed.podcast |> Option.map (fun p -> p.itemsInFeed) |> Option.defaultValue postCount)
|
||||||
| None ->
|
| None ->
|
||||||
// No feed
|
// No feed
|
||||||
|
@ -50,10 +50,10 @@ let deriveFeedType (ctx : HttpContext) feedPath : (FeedType * int) option =
|
||||||
/// Determine the function to retrieve posts for the given feed
|
/// Determine the function to retrieve posts for the given feed
|
||||||
let private getFeedPosts (webLog : WebLog) feedType =
|
let private getFeedPosts (webLog : WebLog) feedType =
|
||||||
match feedType with
|
match feedType with
|
||||||
| StandardFeed -> Data.Post.findPageOfPublishedPosts webLog.id 1
|
| StandardFeed _ -> Data.Post.findPageOfPublishedPosts webLog.id 1
|
||||||
| CategoryFeed catId -> Data.Post.findPageOfCategorizedPosts webLog.id [ catId ] 1
|
| CategoryFeed (catId, _) -> Data.Post.findPageOfCategorizedPosts webLog.id [ catId ] 1
|
||||||
| TagFeed tag -> Data.Post.findPageOfTaggedPosts webLog.id tag 1
|
| TagFeed (tag, _) -> Data.Post.findPageOfTaggedPosts webLog.id tag 1
|
||||||
| Custom feed ->
|
| Custom (feed, _) ->
|
||||||
match feed.source with
|
match feed.source with
|
||||||
| Category catId -> Data.Post.findPageOfCategorizedPosts webLog.id [ catId ] 1
|
| Category catId -> Data.Post.findPageOfCategorizedPosts webLog.id [ catId ] 1
|
||||||
| Tag tag -> Data.Post.findPageOfTaggedPosts webLog.id tag 1
|
| Tag tag -> Data.Post.findPageOfTaggedPosts webLog.id tag 1
|
||||||
|
@ -213,6 +213,16 @@ let private addPodcast webLog (rssFeed : SyndicationFeed) (feed : CustomFeed) =
|
||||||
rssFeed.ElementExtensions.Add ("explicit", "itunes", ExplicitRating.toString podcast.explicit)
|
rssFeed.ElementExtensions.Add ("explicit", "itunes", ExplicitRating.toString podcast.explicit)
|
||||||
rssFeed.ElementExtensions.Add ("subscribe", "rawvoice", feedUrl)
|
rssFeed.ElementExtensions.Add ("subscribe", "rawvoice", feedUrl)
|
||||||
|
|
||||||
|
/// Get the feed's self reference and non-feed link
|
||||||
|
let private selfAndLink webLog feedType =
|
||||||
|
match feedType with
|
||||||
|
| StandardFeed path -> path
|
||||||
|
| CategoryFeed (_, path) -> path
|
||||||
|
| TagFeed (_, path) -> path
|
||||||
|
| Custom (_, path) -> path
|
||||||
|
|> function
|
||||||
|
| path -> Permalink path, Permalink (path.Replace ($"/{webLog.rss.feedName}", ""))
|
||||||
|
|
||||||
/// Create a feed with a known non-zero-length list of posts
|
/// Create a feed with a known non-zero-length list of posts
|
||||||
let createFeed (feedType : FeedType) posts : HttpHandler = fun next ctx -> backgroundTask {
|
let createFeed (feedType : FeedType) posts : HttpHandler = fun next ctx -> backgroundTask {
|
||||||
let webLog = ctx.WebLog
|
let webLog = ctx.WebLog
|
||||||
|
@ -220,7 +230,7 @@ let createFeed (feedType : FeedType) posts : HttpHandler = fun next ctx -> backg
|
||||||
let! authors = Post.getAuthors webLog posts conn
|
let! authors = Post.getAuthors webLog posts conn
|
||||||
let! tagMaps = Post.getTagMappings webLog posts conn
|
let! tagMaps = Post.getTagMappings webLog posts conn
|
||||||
let cats = CategoryCache.get ctx
|
let cats = CategoryCache.get ctx
|
||||||
let podcast = match feedType with Custom feed when Option.isSome feed.podcast -> Some feed | _ -> None
|
let podcast = match feedType with Custom (feed, _) when Option.isSome feed.podcast -> Some feed | _ -> None
|
||||||
|
|
||||||
let toItem post =
|
let toItem post =
|
||||||
let item = toFeedItem webLog authors cats tagMaps post
|
let item = toFeedItem webLog authors cats tagMaps post
|
||||||
|
@ -230,6 +240,8 @@ let createFeed (feedType : FeedType) posts : HttpHandler = fun next ctx -> backg
|
||||||
| _ -> item
|
| _ -> item
|
||||||
|
|
||||||
let feed = SyndicationFeed ()
|
let feed = SyndicationFeed ()
|
||||||
|
addNamespace feed "content" "http://purl.org/rss/1.0/modules/content/"
|
||||||
|
|
||||||
feed.Title <- TextSyndicationContent webLog.name
|
feed.Title <- TextSyndicationContent webLog.name
|
||||||
feed.Description <- TextSyndicationContent <| defaultArg webLog.subtitle webLog.name
|
feed.Description <- TextSyndicationContent <| defaultArg webLog.subtitle webLog.name
|
||||||
feed.LastUpdatedTime <- DateTimeOffset <| (List.head posts).updatedOn
|
feed.LastUpdatedTime <- DateTimeOffset <| (List.head posts).updatedOn
|
||||||
|
@ -239,10 +251,10 @@ let createFeed (feedType : FeedType) posts : HttpHandler = fun next ctx -> backg
|
||||||
feed.Id <- webLog.urlBase
|
feed.Id <- webLog.urlBase
|
||||||
webLog.rss.copyright |> Option.iter (fun copy -> feed.Copyright <- TextSyndicationContent copy)
|
webLog.rss.copyright |> Option.iter (fun copy -> feed.Copyright <- TextSyndicationContent copy)
|
||||||
|
|
||||||
// TODO: adjust this link for non-root feeds
|
let self, link = selfAndLink webLog feedType
|
||||||
feed.Links.Add (SyndicationLink (Uri $"{webLog.urlBase}/feed.xml", "self", "", "application/rss+xml", 0L))
|
feed.Links.Add (SyndicationLink (Uri (WebLog.absoluteUrl webLog self), "self", "", "application/rss+xml", 0L))
|
||||||
addNamespace feed "content" "http://purl.org/rss/1.0/modules/content/"
|
feed.ElementExtensions.Add ("link", "", WebLog.absoluteUrl webLog link)
|
||||||
feed.ElementExtensions.Add ("link", "", webLog.urlBase)
|
|
||||||
podcast |> Option.iter (addPodcast webLog feed)
|
podcast |> Option.iter (addPodcast webLog feed)
|
||||||
|
|
||||||
use mem = new MemoryStream ()
|
use mem = new MemoryStream ()
|
||||||
|
@ -270,12 +282,54 @@ open DotLiquid
|
||||||
|
|
||||||
// GET: /admin/rss/settings
|
// GET: /admin/rss/settings
|
||||||
let editSettings : HttpHandler = fun next ctx -> task {
|
let editSettings : HttpHandler = fun next ctx -> task {
|
||||||
// TODO: stopped here
|
let webLog = ctx.WebLog
|
||||||
|
let feeds =
|
||||||
|
webLog.rss.customFeeds
|
||||||
|
|> List.map (DisplayCustomFeed.fromFeed (CategoryCache.get ctx))
|
||||||
|
|> Array.ofList
|
||||||
return!
|
return!
|
||||||
Hash.FromAnonymousObject
|
Hash.FromAnonymousObject
|
||||||
{| csrf = csrfToken ctx
|
{| csrf = csrfToken ctx
|
||||||
model = ctx.WebLog.rss
|
|
||||||
page_title = "RSS Settings"
|
page_title = "RSS Settings"
|
||||||
|
model = EditRssModel.fromRssOptions webLog.rss
|
||||||
|
custom_feeds = feeds
|
||||||
|}
|
|}
|
||||||
|> viewForTheme "admin" "rss-settings" next ctx
|
|> viewForTheme "admin" "rss-settings" next ctx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// POST: /admin/rss/settings
|
||||||
|
let saveSettings : HttpHandler = fun next ctx -> task {
|
||||||
|
let conn = ctx.Conn
|
||||||
|
let! model = ctx.BindFormAsync<EditRssModel> ()
|
||||||
|
match! Data.WebLog.findById ctx.WebLog.id conn with
|
||||||
|
| Some webLog ->
|
||||||
|
let webLog = { webLog with rss = model.updateOptions webLog.rss }
|
||||||
|
do! Data.WebLog.updateRssOptions webLog conn
|
||||||
|
WebLogCache.set webLog
|
||||||
|
do! addMessage ctx { UserMessage.success with message = "RSS settings updated successfully" }
|
||||||
|
return! redirectToGet (WebLog.relativeUrl webLog (Permalink "admin/settings/rss")) next ctx
|
||||||
|
| None -> return! Error.notFound next ctx
|
||||||
|
}
|
||||||
|
|
||||||
|
// POST /admin/rss/{id}/delete
|
||||||
|
let deleteCustomFeed feedId : HttpHandler = fun next ctx -> task {
|
||||||
|
let conn = ctx.Conn
|
||||||
|
match! Data.WebLog.findById ctx.WebLog.id conn with
|
||||||
|
| Some webLog ->
|
||||||
|
let customId = CustomFeedId feedId
|
||||||
|
if webLog.rss.customFeeds |> List.exists (fun f -> f.id = customId) then
|
||||||
|
let webLog = {
|
||||||
|
webLog with
|
||||||
|
rss = {
|
||||||
|
webLog.rss with
|
||||||
|
customFeeds = webLog.rss.customFeeds |> List.filter (fun f -> f.id <> customId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
do! Data.WebLog.updateRssOptions webLog conn
|
||||||
|
WebLogCache.set webLog
|
||||||
|
do! addMessage ctx { UserMessage.success with message = "Custom feed deleted successfully" }
|
||||||
|
else
|
||||||
|
do! addMessage ctx { UserMessage.warning with message = "Post not found; nothing deleted" }
|
||||||
|
return! redirectToGet (WebLog.relativeUrl webLog (Permalink "admin/settings/rss")) next ctx
|
||||||
|
| None -> return! Error.notFound next ctx
|
||||||
|
}
|
||||||
|
|
|
@ -120,6 +120,10 @@ let router : HttpHandler = choose [
|
||||||
])
|
])
|
||||||
subRoute "/settings" (choose [
|
subRoute "/settings" (choose [
|
||||||
route "" >=> Admin.saveSettings
|
route "" >=> Admin.saveSettings
|
||||||
|
subRoute "/rss" (choose [
|
||||||
|
route "" >=> Feed.saveSettings
|
||||||
|
routef "/%s/delete" Feed.deleteCustomFeed
|
||||||
|
])
|
||||||
subRoute "/tag-mapping" (choose [
|
subRoute "/tag-mapping" (choose [
|
||||||
route "/save" >=> Admin.saveMapping
|
route "/save" >=> Admin.saveMapping
|
||||||
routef "/%s/delete" Admin.deleteMapping
|
routef "/%s/delete" Admin.deleteMapping
|
||||||
|
|
|
@ -220,10 +220,10 @@ let main args =
|
||||||
[ // Domain types
|
[ // Domain types
|
||||||
typeof<CustomFeed>; typeof<MetaItem>; typeof<Page>; typeof<RssOptions>; typeof<TagMap>; typeof<WebLog>
|
typeof<CustomFeed>; typeof<MetaItem>; typeof<Page>; typeof<RssOptions>; typeof<TagMap>; typeof<WebLog>
|
||||||
// View models
|
// View models
|
||||||
typeof<DashboardModel>; typeof<DisplayCategory>; typeof<DisplayPage>; typeof<EditCategoryModel>
|
typeof<DashboardModel>; typeof<DisplayCategory>; typeof<DisplayCustomFeed>; typeof<DisplayPage>
|
||||||
typeof<EditPageModel>; typeof<EditPostModel>; typeof<EditTagMapModel>; typeof<EditUserModel>
|
typeof<EditCategoryModel>; typeof<EditPageModel>; typeof<EditPostModel>; typeof<EditRssModel>
|
||||||
typeof<LogOnModel>; typeof<ManagePermalinksModel>; typeof<PostDisplay>; typeof<PostListItem>
|
typeof<EditTagMapModel>; typeof<EditUserModel>; typeof<LogOnModel>; typeof<ManagePermalinksModel>
|
||||||
typeof<SettingsModel>; typeof<UserMessage>
|
typeof<PostDisplay>; typeof<PostListItem>; typeof<SettingsModel>; typeof<UserMessage>
|
||||||
// Framework types
|
// Framework types
|
||||||
typeof<AntiforgeryTokenSet>; typeof<int option>; typeof<KeyValuePair>; typeof<MetaItem list>
|
typeof<AntiforgeryTokenSet>; typeof<int option>; typeof<KeyValuePair>; typeof<MetaItem list>
|
||||||
typeof<string list>; typeof<string option>; typeof<TagMap list>
|
typeof<string list>; typeof<string option>; typeof<TagMap list>
|
||||||
|
|
|
@ -45,7 +45,7 @@
|
||||||
<div class="col-12 col-md-5 col-xl-4 pb-3">
|
<div class="col-12 col-md-5 col-xl-4 pb-3">
|
||||||
<div class="form-floating">
|
<div class="form-floating">
|
||||||
<input type="text" name="copyright" id="copyright" class="form-control" placeholder="Copyright String"
|
<input type="text" name="copyright" id="copyright" class="form-control" placeholder="Copyright String"
|
||||||
{% if model.copyright %}value="{{ model.copyright.value }}"{% endif %}>
|
value="{{ model.copyright }}">
|
||||||
<label for="copyright">Copyright String</label>
|
<label for="copyright">Copyright String</label>
|
||||||
<span class="form-text">
|
<span class="form-text">
|
||||||
Can be a
|
Can be a
|
||||||
|
@ -69,18 +69,30 @@
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="col">Source</th>
|
<th scope="col">Source</th>
|
||||||
<th scope="col">Path</th>
|
<th scope="col">Relative Path</th>
|
||||||
<th scope="col">Podcast?</th>
|
<th scope="col">Podcast?</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
{%- assign feed_count = model.custom_feeds | size -%}
|
{%- assign feed_count = custom_feeds | size -%}
|
||||||
{% if feed_count > 0 %}
|
{% if feed_count > 0 %}
|
||||||
{% for feed in model.custom_feeds %}
|
{% for feed in custom_feeds %}
|
||||||
<tr>
|
<tr>
|
||||||
<td>
|
<td>
|
||||||
{{ feed.source }}
|
{{ feed.source }}<br>
|
||||||
<!-- TODO: view / edit / delete -->
|
<small>
|
||||||
|
<a href="{{ feed.path | relative_link }}" target="_blank">View Feed</a>
|
||||||
|
<span class="text-muted"> • </span>
|
||||||
|
{%- capture feed_edit %}admin/rss/{{ feed.id }}/edit{% endcapture -%}
|
||||||
|
<a href="{{ feed_edit | relative_link }}">Edit</a>
|
||||||
|
<span class="text-muted"> • </span>
|
||||||
|
{%- capture feed_del %}admin/rss/{{ feed.id }}/delete{% endcapture -%}
|
||||||
|
{%- capture feed_del_link %}{{ feed_del | relative_link }}{% endcapture -%}
|
||||||
|
<a href="{{ feed_del_link }}" class="text-danger"
|
||||||
|
onclick="return Admin.deleteCustomFeed('{{ feed.source }}', '{{ feed_del_link }}')">
|
||||||
|
Delete
|
||||||
|
</a>
|
||||||
|
</small>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ feed.path }}</td>
|
<td>{{ feed.path }}</td>
|
||||||
<td>{% if feed.is_podcast %}Yes{% else %}No{% endif %}</td>
|
<td>{% if feed.is_podcast %}Yes{% else %}No{% endif %}</td>
|
||||||
|
@ -93,4 +105,7 @@
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
<form method="post" id="deleteForm">
|
||||||
|
<input type="hidden" name="{{ csrf.form_field_name }}" value="{{ csrf.request_token }}">
|
||||||
|
</form>
|
||||||
</article>
|
</article>
|
||||||
|
|
|
@ -178,6 +178,15 @@
|
||||||
return this.deleteItem(`category "${name}"`, url)
|
return this.deleteItem(`category "${name}"`, url)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Confirm and delete a custom RSS feed
|
||||||
|
* @param source The source for the feed to be deleted
|
||||||
|
* @param url The URL to which the form should be posted
|
||||||
|
*/
|
||||||
|
deleteCustomFeed(source, url) {
|
||||||
|
return this.deleteItem(`custom RSS feed based on ${source}`, url)
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Confirm and delete a page
|
* Confirm and delete a page
|
||||||
* @param title The title of the page to be deleted
|
* @param title The title of the page to be deleted
|
||||||
|
|
Loading…
Reference in New Issue
Block a user