diff of 43d4dfae8c414d7e7664f501f816fb0fad3a9a54
43d4dfae8c414d7e7664f501f816fb0fad3a9a54
diff --git a/elm-frontti/src/Ajax_cmds.elm b/elm-frontti/src/Ajax_cmds.elm
index c637693..cbebc54 100644
--- a/elm-frontti/src/Ajax_cmds.elm
+++ b/elm-frontti/src/Ajax_cmds.elm
@@ -156,3 +156,13 @@ markFeedItemRead feed_id item_id =
{ url = "/api/user/feeds/" ++ feed_id ++ "/" ++ item_id ++ "/mark-read"
, body = Http.emptyBody
, expect = Http.expectWhatever FeedItemReadResponse}
+
+deleteFeed feed_id =
+ Http.request
+ { url = "/api/user/feeds/" ++ feed_id
+ , method = "DELETE"
+ , headers = []
+ , expect = Http.expectWhatever FeedDeleted
+ , body = Http.emptyBody
+ , timeout = Nothing
+ , tracker = Nothing}
diff --git a/elm-frontti/src/FeedManager.elm b/elm-frontti/src/FeedManager.elm
new file mode 100644
index 0000000..7f437f0
--- /dev/null
+++ b/elm-frontti/src/FeedManager.elm
@@ -0,0 +1,18 @@
+module FeedManager exposing (..)
+
+import Message exposing (..)
+import Html exposing (..)
+import Html.Attributes exposing (..)
+import Html.Events exposing (onInput, onClick)
+import Button exposing (murja_button)
+
+feedmanager feeds =
+ ul [ class "feed-manager-container" ]
+ ( feeds
+ |> List.map (\f ->
+ li [ class "feed-manager" ]
+ [ span [] [ text <| f.name ++ " ("
+ , a [ href f.url] [ text f.url ]
+ , text ")"]
+ , murja_button [ onClick <| DeleteFeed f.id ]
+ [ text "Delete feed" ]]))
diff --git a/elm-frontti/src/FeedView.elm b/elm-frontti/src/FeedView.elm
index 1a0e794..cd5320d 100644
--- a/elm-frontti/src/FeedView.elm
+++ b/elm-frontti/src/FeedView.elm
@@ -11,6 +11,7 @@ import Html.Events exposing (onInput, onClick)
import Button exposing (murja_button)
import UUID
import Article_view exposing (formatDateTime)
+import FeedManager exposing (feedmanager)
import Tab exposing (tabs)
import Random
@@ -59,6 +60,7 @@ readerState_str state =
case state of
PerFeed -> "PerFeed"
SingleFeed -> "SingleFeed"
+ FeedManager -> "FeedManager"
feeds feedReaderState show_archived settings zone fs new_feed =
let new_feed_state = Maybe.withDefault (NewFeed "" "") new_feed
@@ -70,9 +72,11 @@ feeds feedReaderState show_archived settings zone fs new_feed =
, text "Show read items"]
, tabs "rss-feed-tab" (readerState_str feedReaderState)
(Dict.fromList [ ("PerFeed", "Group by feed")
- , ("SingleFeed", "Show all in a feed")])
+ , ("SingleFeed", "Show all in a feed")
+ , ("FeedManager", "Manage feeds")])
(Dict.fromList [ ("PerFeed", perFeedView show_archived settings zone fs new_feed_state)
- , ("SingleFeed", singleFeedView show_archived settings zone fs)])
+ , ("SingleFeed", singleFeedView show_archived settings zone fs)
+ , ("FeedManager", feedmanager fs)])
, h3 [] [ text "Add new feed?"]
, label [ for "name" ] [ text "Feed name" ]
diff --git a/elm-frontti/src/Main.elm b/elm-frontti/src/Main.elm
index 7d95970..e58f29e 100644
--- a/elm-frontti/src/Main.elm
+++ b/elm-frontti/src/Main.elm
@@ -602,13 +602,6 @@ update msg model =
Err error ->
( { model | view_state = ShowError (errToString error) }
, Cmd.none)
- SetPerFeedView ->
- let state = model.feedReaderState in
- ({ model
- | feedReaderState = case state of
- PerFeed -> SingleFeed
- SingleFeed -> PerFeed}
- , Cmd.none)
SelectTab tab_id selected_tab ->
case tab_id of
"rss-feed-tab" ->
@@ -627,6 +620,7 @@ update msg model =
| show_preview = selected_tab == "PreviewArticle"})
model.postEditorSettings}
, Cmd.none)
+
_ -> ( model
, alert <| "Unknown tab " ++ tab_id)
ReadFeedItem feed_id item_id is_read ->
@@ -661,6 +655,15 @@ update msg model =
, Cmd.none)
Err error -> ( { model | view_state = ShowError (errToString error) }
, Cmd.none)
+ DeleteFeed id ->
+ ( model
+ , deleteFeed <| UUID.toString id)
+ FeedDeleted result ->
+ case result of
+ Ok _ -> ( model
+ , getFeeds)
+ Err error -> ( { model | view_state = ShowError (errToString error) }
+ , Cmd.none)
doGoHome_ model other_cmds =
diff --git a/elm-frontti/src/Message.elm b/elm-frontti/src/Message.elm
index 634b344..19b0808 100644
--- a/elm-frontti/src/Message.elm
+++ b/elm-frontti/src/Message.elm
@@ -66,11 +66,13 @@ type alias PostEditorSettings =
type FeedReaderState
= PerFeed
| SingleFeed
+ | FeedManager
str_to_readerState str =
case str of
"PerFeed" -> Just PerFeed
"SingleFeed" -> Just SingleFeed
+ "FeedManager" -> Just FeedManager
_ -> Nothing
type alias Model =
@@ -161,11 +163,12 @@ type Msg
| SetFeedName String
| AddFeed Feeds.NewFeed
| FeedAdded (Result Http.Error ())
- | SetPerFeedView
| SelectTab String String
| ReadFeedItem UUID UUID Bool
| ShowArchivedFeedItems Bool
| FeedItemReadResponse (Result Http.Error ())
+ | DeleteFeed UUID
+ | FeedDeleted (Result Http.Error ())
-- ports
port reallySetupAce : String -> Cmd msg
diff --git a/resources/css/murja.css b/resources/css/murja.css
index f9996b9..a9eb426 100644
--- a/resources/css/murja.css
+++ b/resources/css/murja.css
@@ -341,6 +341,20 @@ header {
width: 100%;
}
+.feed-manager-container {
+ display: flex;
+ flex-direction: column;
+ justify-content: space-evenly;
+ list-style: none;
+}
+
+.feed-manager {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ /* border: 2px solid #333; */
+}
+
@media only screen and (max-device-width:480px)
{
body {
diff --git a/resources/sql/reader-fns.sql b/resources/sql/reader-fns.sql
index 581f69a..fb956d9 100644
--- a/resources/sql/reader-fns.sql
+++ b/resources/sql/reader-fns.sql
@@ -10,9 +10,14 @@ SELECT fs.id, fs.name, fs.url,
json_agg(row_to_json(fi.*)) as "items"
FROM blog.feed_subscription fs
JOIN blog.Users u ON u.ID = fs.owner
-JOIN blog.feed_item fi ON fs.id = fi.feed
+LEFT JOIN blog.feed_item fi ON fs.id = fi.feed
WHERE owner = $1
-GROUP BY fs.id, u.username, u.nickname, u.img_location;
+GROUP BY fs.id, u.username, u.nickname, u.img_location
+ORDER BY fs.name;
+
+-- name: delete-feed
+DELETE FROM blog.feed_subscription
+WHERE id = $1 AND owner = $2;
-- name: get-all-feeds
-- returns: :array-hash
diff --git a/src/routes/rss-reader-routes.lisp b/src/routes/rss-reader-routes.lisp
index f5c5bbf..4e645f9 100644
--- a/src/routes/rss-reader-routes.lisp
+++ b/src/routes/rss-reader-routes.lisp
@@ -38,6 +38,13 @@
(setf (hunchentoot:return-code*) 204)
"")
+(defroute delete-feed ("/api/user/feeds/:feed-id" :method :delete
+ :decorators (@transaction
+ @authenticated)) ()
+ (murja.rss.reader-db:delete-feed feed-id (gethash "id" *user*))
+ (setf (hunchentoot:return-code*) 204)
+ "")
+
;; This will be called by cron/curl
(defroute update-feeds-rotue ("/api/rss/update" :method :get
:decorators (@transaction)) ()
diff --git a/src/rss/reader-db.lisp b/src/rss/reader-db.lisp
index d320a86..554e9f4 100644
--- a/src/rss/reader-db.lisp
+++ b/src/rss/reader-db.lisp
@@ -3,7 +3,7 @@
(:import-from :halisql :defqueries)
(:import-from :lisp-fixup :partial :compose)
(:import-from :cl-date-time-parser :parse-date-time)
- (:export :get-user-feeds :subscribe-to-feed :mark-as-read))
+ (:export :get-user-feeds :subscribe-to-feed :mark-as-read :delete-feed))
(in-package :murja.rss.reader-db)
@@ -23,12 +23,16 @@
(dolist (feed fixed-feeds)
(setf (gethash "items" feed)
(coerce (gethash "items" feed) 'list))
- (dolist (item (gethash "items" feed))
- (setf (gethash "is_read" item)
- (not (equalp 'NULL (gethash "read_at" item))))
+
+ (if (equalp (list 'null) (gethash "items" feed))
+ (setf (gethash "items" feed) #())
+
+ (dolist (item (gethash "items" feed))
+ (setf (gethash "is_read" item)
+ (not (equalp 'NULL (gethash "read_at" item))))
- ;; frontend doesn't need this
- (remhash "read_at" item)))
+ ;; frontend doesn't need this
+ (remhash "read_at" item))))
fixed-feeds))