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))