diff of ede920d982a21cf320dd825bf2f1b7de60ca55bd
ede920d982a21cf320dd825bf2f1b7de60ca55bd
diff --git a/aggressive-murja.asd b/aggressive-murja.asd
index d454b01..7f7c47b 100644
--- a/aggressive-murja.asd
+++ b/aggressive-murja.asd
@@ -21,7 +21,11 @@
"xml-emitter"
"drakma"
"xmls"
- "cl-date-time-parser")
+ ;; works in cl universal time (epoch at 1900)
+ "cl-date-time-parser"
+ ;; transforms those to unix time
+ "cl-epoch"
+ )
:description "A rewrite of the <a href=\"https://github.com/feuery/murja-blog/\">murja blogging engine</a> in lisp"
:components ((:module "src"
:components
diff --git a/elm-frontti/elm.json b/elm-frontti/elm.json
index f1094e1..d6285c7 100644
--- a/elm-frontti/elm.json
+++ b/elm-frontti/elm.json
@@ -22,7 +22,8 @@
"elm-community/dict-extra": "2.4.0",
"elm-community/string-extra": "4.0.1",
"mhoare/elm-stack": "3.1.2",
- "waratuman/json-extra": "1.0.2"
+ "waratuman/json-extra": "1.0.2",
+ "waratuman/time-extra": "1.1.0"
},
"indirect": {
"TSFoster/elm-bytes-extra": "1.3.0",
@@ -35,8 +36,7 @@
"elm/virtual-dom": "1.0.2",
"justinmimbs/timezone-data": "2.1.4",
"rtfeldman/elm-hex": "1.0.0",
- "rtfeldman/elm-iso8601-date-strings": "1.1.3",
- "waratuman/time-extra": "1.1.0"
+ "rtfeldman/elm-iso8601-date-strings": "1.1.3"
}
},
"test-dependencies": {
diff --git a/elm-frontti/src/FeedView.elm b/elm-frontti/src/FeedView.elm
index fd5115c..3713a7e 100644
--- a/elm-frontti/src/FeedView.elm
+++ b/elm-frontti/src/FeedView.elm
@@ -2,16 +2,26 @@ module FeedView exposing (..)
import DateFormat as Df
import Feeds exposing (NewFeed)
+import Time
import Message exposing (..)
import Html exposing (..)
import Html.Attributes exposing (..)
import Html.Events exposing (onInput, onClick)
import Button exposing (murja_button)
import UUID
+import Article_view exposing (formatDateTime)
import Random
-feeds fs new_feed =
+feed_item time_format zone item =
+ li [] [ h1 [] [ text item.title]
+ , h4 [] [ text (formatDateTime time_format zone item.pubdate)]
+ , div [ class "feed-author"] [ text <| "By " ++ item.author]
+ , div [ class "feed-item"
+ , dangerouslySetInnerHTML item.description] []]
+
+
+feeds settings zone fs new_feed =
let new_feed_state = Maybe.withDefault (NewFeed "" "") new_feed
in
div []
@@ -19,7 +29,12 @@ feeds fs new_feed =
(List.map (\feed ->
li [ class "feed" ]
[ header [] [ text feed.name ]
- , a [ href feed.url ] [ text feed.url ]]) fs)
+ , a [ href feed.url ] [ text feed.url ]
+ , ul [ class "feed-items" ]
+ (feed.items
+ |> List.sortBy (Time.posixToMillis << .pubdate)
+ |> List.reverse
+ |> List.map (feed_item settings.time_format zone))]) fs)
, h3 [] [ text "Add new feed?"]
, div []
[ label [ for "name" ] [ text "Feed name" ]
diff --git a/elm-frontti/src/Feeds.elm b/elm-frontti/src/Feeds.elm
index dd97bcb..7c70631 100644
--- a/elm-frontti/src/Feeds.elm
+++ b/elm-frontti/src/Feeds.elm
@@ -5,17 +5,29 @@ import Json.Encode.Extra exposing (..)
import Json.Decode as Decode exposing (Decoder, succeed)
import Json.Decode.Pipeline exposing (required)
import Json.Decode.Extra as Extra
+import Time
import UUID exposing (UUID)
import Article exposing (decodeApply)
import Creator exposing (Creator)
+
+type alias Item =
+ { id: UUID
+ , fetched: Time.Posix
+ , title: String
+ , description: String
+ , link: String
+ , author: String
+ , pubdate: Time.Posix}
+
type alias Feed =
{ id: UUID
, name: String
, url: String
- , creator: Creator}
+ , creator: Creator
+ , items: List Item}
type alias NewFeed =
{ name: String
@@ -26,6 +38,27 @@ urlDecoder = Decode.field "url" Decode.string
nameDecoder = (Decode.field "name" Decode.string)
idDecoder = (Decode.field "id" UUID.jsonDecoder)
+-- itemDecoder
+fetchedDecoder = Decode.field "fetched" Extra.iso8601
+titleDecoder = Decode.field "title" Decode.string
+descriptionDecoder = Decode.field "description" Decode.string
+linkDecoder = Decode.field "link" Decode.string
+authorDecoder = Decode.field "author" Decode.string
+pubdateDecoder = Decode.field "pubdate" Extra.iso8601
+
+itemDecoder =
+ Decode.succeed Item
+ |> decodeApply idDecoder
+ |> decodeApply fetchedDecoder
+ |> decodeApply titleDecoder
+ |> decodeApply descriptionDecoder
+ |> decodeApply linkDecoder
+ |> decodeApply authorDecoder
+ |> decodeApply pubdateDecoder
+
+itemsDecoder =
+ Decode.field "items" (Decode.list itemDecoder)
+
feedDecoder: Decoder Feed
feedDecoder =
Decode.succeed Feed
@@ -33,6 +66,7 @@ feedDecoder =
|> decodeApply nameDecoder
|> decodeApply urlDecoder
|> decodeApply creatorDecoder
+ |> decodeApply itemsDecoder
newFeedDecoder: Decoder NewFeed
newFeedDecoder =
diff --git a/elm-frontti/src/Main.elm b/elm-frontti/src/Main.elm
index 475ed4a..406c3c5 100644
--- a/elm-frontti/src/Main.elm
+++ b/elm-frontti/src/Main.elm
@@ -693,7 +693,7 @@ view model =
Nothing -> [ div [] [ text "No post loaded" ]]
MediaList -> [ medialist model.loadedImages model.medialist_state ]
SettingsEditor -> [ SettingsEditor.editor settings]
- Feeds feeds -> [ FeedView.feeds feeds model.new_feed ])
+ Feeds feeds -> [ FeedView.feeds settings model.zone feeds model.new_feed ])
, div [id "sidebar"] [ User.loginView model.loginState
, (sidebarHistory model.titles )
, (case model.view_state of
diff --git a/resources/css/murja.css b/resources/css/murja.css
index c3e3c10..43237f5 100644
--- a/resources/css/murja.css
+++ b/resources/css/murja.css
@@ -299,6 +299,23 @@ header {
display: block;
}
+.feed-items {
+ height: 500px;
+ overflow-y: scroll;
+}
+
+.feed-items li {
+ list-style: none;
+}
+
+.feed-author {
+ margin-left: 1em;
+}
+
+.feed-item {
+ margin-left: 2em;
+}
+
@media only screen and (max-device-width:480px)
{
body {
diff --git a/resources/sql/reader-fns.sql b/resources/sql/reader-fns.sql
index 5bd6af1..7c058e1 100644
--- a/resources/sql/reader-fns.sql
+++ b/resources/sql/reader-fns.sql
@@ -6,10 +6,13 @@ SELECT fs.id, fs.name, fs.url,
'nickname',
u.Nickname,
'img_location',
- u.Img_location) as "creator"
+ u.Img_location) as "creator",
+ json_agg(row_to_json(fi.*)) as "items"
FROM blog.feed_subscription fs
JOIN blog.Users u ON u.ID = fs.owner
-WHERE owner = $1;
+JOIN blog.feed_item fi ON fs.id = fi.feed
+WHERE owner = $1
+GROUP BY fs.id, u.username, u.nickname, u.img_location;
-- name: get-all-feeds
-- returns: :array-hash
diff --git a/src/routes/rss-reader-routes.lisp b/src/routes/rss-reader-routes.lisp
index 25ce0b7..f316875 100644
--- a/src/routes/rss-reader-routes.lisp
+++ b/src/routes/rss-reader-routes.lisp
@@ -32,7 +32,8 @@
""))
;; This will be called by cron/curl
-(defroute update-feeds-rotue ("/api/rss/update" :method :get) ()
+(defroute update-feeds-rotue ("/api/rss/update" :method :get
+ :decorators (@transaction)) ()
(update-feeds)
(setf (hunchentoot:return-code*) 204)
"")
diff --git a/src/rss/reader-db.lisp b/src/rss/reader-db.lisp
index 39b4d7b..650dd17 100644
--- a/src/rss/reader-db.lisp
+++ b/src/rss/reader-db.lisp
@@ -1,7 +1,7 @@
(defpackage murja.rss.reader-db
(:use :cl :postmodern :binding-arrows)
(:import-from :halisql :defqueries)
- (:import-from :lisp-fixup :partial)
+ (:import-from :lisp-fixup :partial :compose)
(:import-from :cl-date-time-parser :parse-date-time)
(:export :get-user-feeds :subscribe-to-feed))
@@ -16,7 +16,9 @@
(defun get-user-feeds (user-id)
(let ((feeds (coerce (get-user-feeds* user-id) 'list)))
- (mapcar (partial #'parse "creator") feeds)))
+ (mapcar (compose (partial #'parse "items")
+ (partial #'parse "creator"))
+ feeds)))
(defun subscribe-to-feed (feed-name feed-url owner)
(insert-feed feed-name feed-url (gethash "id" owner)))
@@ -59,7 +61,11 @@ pipes it through trivial-utf-8:utf-8-bytes-to-string"
(get-child-item-value "author" (xmls:node-children item))
;; author seems to be optional value, let's get title from <channel> if missing
(get-child-item-value "title" (xmls:node-children channel))))
- (pubDate (parse-date-time (get-child-item-value "pubDate" (xmls:node-children item)))))
+ (pubDate (cl-epoch:universal->unix-time
+ (parse-date-time (get-child-item-value "pubDate" (xmls:node-children item))))))
+ (log:info "Parsed ~a as ~a"
+ (get-child-item-value "pubDate" (xmls:node-children item))
+ pubdate)
(insert-feed-item title link description author pubDate feed-id)))))
(defun current-hour ()
@@ -73,9 +79,11 @@ pipes it through trivial-utf-8:utf-8-bytes-to-string"
(defvar *last-updated* nil)
(defun update-feeds ()
+ (setf *last-updated* nil)
(when (or (not *last-updated*)
;; hourly rate limit
(> (- (current-hour) *last-updated*) 1))
+ (log:info "Updating all feeds")
(dolist (feed (coerce (get-all-feeds) 'list))
(update-feed feed))