diff of 8c1a36f826e20675707c0a6fa4e11b007b844985

8c1a36f826e20675707c0a6fa4e11b007b844985
diff --git a/elm-frontti/src/Ajax_cmds.elm b/elm-frontti/src/Ajax_cmds.elm
index 930b36f..4f69634 100644
--- a/elm-frontti/src/Ajax_cmds.elm
+++ b/elm-frontti/src/Ajax_cmds.elm
@@ -8,6 +8,7 @@ import Message exposing (..)
 import Http exposing (..)
 import Image as Image
 import Settings
+import Logs
 import Json.Decode as Json
 
 getSession =
@@ -180,3 +181,8 @@ postExcerpt excerpt feed_id =
         { url = " /api/posts/excerpt/" ++ feed_id
         , body = Http.stringBody "text/plain" excerpt
         , expect = Http.expectJson NewPostGenerated Json.int}
+
+getAdminLogs =
+    Http.get
+        { url = "/api/logs"
+        , expect = Http.expectJson GotAdminLogs (Json.list Logs.decoder)}
diff --git a/elm-frontti/src/Logs.elm b/elm-frontti/src/Logs.elm
new file mode 100644
index 0000000..9440c92
--- /dev/null
+++ b/elm-frontti/src/Logs.elm
@@ -0,0 +1,12 @@
+module Logs exposing (..)
+
+import Article exposing (decodeApply)
+import Json.Decode as Decode exposing (Decoder, succeed)
+
+type alias Log =
+    { row : String              -- let's keep them as just dumb lines for now and add smarter analytics later...
+          }
+
+
+rowDecoder = Decode.field "row" Decode.string
+decoder = Decode.succeed Log |> decodeApply rowDecoder             
diff --git a/elm-frontti/src/Main.elm b/elm-frontti/src/Main.elm
index 722a8e7..26e415a 100644
--- a/elm-frontti/src/Main.elm
+++ b/elm-frontti/src/Main.elm
@@ -15,7 +15,6 @@ import Page as P
 import Settings
 import Message exposing (..)
 import User
-import Topbar
 import PostsAdmin
 import PostEditor
 import SettingsEditor
@@ -118,6 +117,9 @@ viewStatePerUrl url =
                                             , getSettings
                                             , getFeeds False 
                                             , getFeedMeta ])
+        RouteParser.Logs -> (Loading, [ getSession
+                                      , getAdminLogs 
+                                      , getTitles])
     
 init _ url key =
     let (viewstate, cmds) = (viewStatePerUrl url)
@@ -709,6 +711,15 @@ update msg model =
         ExcerptCreated (excerpt, feed_id) ->
             ( model
             , postExcerpt excerpt feed_id)
+        GotAdminLogs result ->
+            case result of
+                Ok logs ->
+                    ({ model | view_state = Logs logs}
+                    , Cmd.none)
+                Err error ->
+                    ( { model | view_state = ShowError (errToString error) }
+                    , Cmd.none)
+                           
                     
 doGoHome_ model other_cmds =
     (model, Cmd.batch (List.append [ getSettings
@@ -758,6 +769,8 @@ page_wrapper comp =
         [ div [class "page"]
               comp]
 
+unknown_state = [ div [] [ text "Unknown viewstate in blog_tab"] ]            
+
 blog_tab settings model =
     div [] 
     (case model.view_state of
@@ -784,8 +797,17 @@ blog_tab settings model =
             [pre [] [text err]]
         TaggedPostsView articles ->
             (List.map (articleView settings model.loginState model.zone) articles)
-        _ ->
-            [ div [] [ text "Unknown viewstate in blog_tab"] ])
+        Logs logs ->
+         [ div [] [text <| "Logs " ++ Debug.toString logs]]
+
+        -- ignored cases (that should maybe be removed from the enumeration?) that are inlined here to make compiler yell about new unimplemented enumerations
+        PostEditorList _ -> unknown_state
+        PostEditor -> unknown_state
+        MediaList -> unknown_state
+        SettingsEditor -> unknown_state
+        Feeds _ _ -> unknown_state
+         
+    )
 
 rss_tab model settings =
     div []
@@ -811,6 +833,10 @@ settings_tab settings model =
             SettingsEditor -> [ SettingsEditor.editor settings]
             _ -> [ div [] [ text "Unknown viewstate in settings_tab"] ])
 
+logs_tab settings model =
+    div []
+        [ text "Logs tab"]
+            
 posteditor_tab settings model =
     div [ class "posteditor-tab" ]
     (case model.view_state of 
@@ -864,6 +890,11 @@ view model =
                                                  (settings_tab settings model)
                                                  (Just (PushUrl "/blog/settings"))
                                                  ["update-settings"])
+                                           , ("SettingLogs"
+                                             , TabEntry "Logs"
+                                                 (logs_tab settings model)
+                                                 (Just (PushUrl "/blog/logs"))
+                                                 ["update-settings"])
                                            , ("PostEditTab"
                                              , TabEntry "Post editor"
                                                  (posteditor_tab settings model)
diff --git a/elm-frontti/src/Message.elm b/elm-frontti/src/Message.elm
index ecec903..f3aa5e1 100644
--- a/elm-frontti/src/Message.elm
+++ b/elm-frontti/src/Message.elm
@@ -14,6 +14,7 @@ import Url
 import Title
 import Feeds
 import Image exposing (Image, ReferencingPost)
+import Logs 
 
 import File exposing (File)
 import UUID exposing (UUID)
@@ -31,6 +32,7 @@ type ViewState
     | TaggedPostsView (List Article.Article)
     | SettingsEditor
     | Feeds (List Feeds.Feed) Bool -- <- show_archived?
+    | Logs (List Logs.Log)
 
 -- a simplified version of ViewState type for the main.elm's tabcomponent 
 type TabState
@@ -53,6 +55,7 @@ viewstate_to_tabstate vs =
         TaggedPostsView _ -> Blog
         SettingsEditor -> SettingsTab
         Feeds _ _ -> RssFeeds
+        Logs _ -> Blog
 
 tabstate_to_str tb =
     case tb of
@@ -215,6 +218,7 @@ type Msg
   | SelectExcerpt UUID
   | CreateExcerptPost String UUID 
   | ExcerptCreated (String, String)
+  | GotAdminLogs (Result Http.Error (List Logs.Log))
 
 -- ports
 port reallySetupAce : String -> Cmd msg
diff --git a/elm-frontti/src/RouteParser.elm b/elm-frontti/src/RouteParser.elm
index e40ea92..8e70a36 100644
--- a/elm-frontti/src/RouteParser.elm
+++ b/elm-frontti/src/RouteParser.elm
@@ -15,6 +15,7 @@ type Route
     | SettingsEditor
     | FeedReader
     | Home
+    | Logs 
     | NotFound
 
 routeParser =
@@ -28,6 +29,7 @@ routeParser =
         , map MediaManager (s "blog" </> (s "mediamanager"))
         , map SettingsEditor (s "blog" </> (s "settings"))
         , map TaggedPosts (s "blog" </> (s "tags" </> string))
+        , map Logs (s "blog" </> (s "logs"))
         , map PostAdmin (s "blog" </> (s "postadmin"))
         , map FeedReader (s "blog" </> (s "feeds"))]
 
diff --git a/elm-frontti/src/Topbar.elm b/elm-frontti/src/Topbar.elm
deleted file mode 100644
index fe49d1b..0000000
--- a/elm-frontti/src/Topbar.elm
+++ /dev/null
@@ -1,36 +0,0 @@
-module Topbar exposing (..)
-
-import Message exposing (..)
-import User
-import Article exposing (..)
-import Creator exposing (..)
-import Ajax_cmds exposing (..)
-
-import Html exposing (..)
-import Html.Attributes exposing (..)
-import Html.Events exposing (..)
-import Browser.Navigation as Nav
-
-import Button exposing (murja_button)
-
-topbar_list =
-    [ li [] [ murja_button [ onClick GoHome, attribute "data-testid" "home"]
-                  [text "Home"]]
-    , li [] [ murja_button [ onClick (PushUrl "/blog/feeds") ] [ text "RSS Feeds" ]]
-    , li [] [ murja_button [ onClick (PushUrl "/blog/postadmin"), attribute "data-testid" "manage-posts-btn" ]
-                  [text "Manage posts"]]
-    , li [] [ murja_button [ onClick (PushUrl "/blog/mediamanager")]
-                  [text "Manage media"]]
-    , li [] [ murja_button [ onClick (PushUrl "/blog/settings")]
-                  [ text "Settings" ]]
-    , li [] [ murja_button [ onClick GenNewPost
-                           , attribute "data-testid" "new-post-btn" ]
-                  [text "New post!"]]]
-    
-topbar state =
-    case state of
-        LoggedIn user ->                               
-            div [class "left-sidebar"] [ span [] [text ("Welcome, " ++ user.nickname)]
-                                       , User.user_avatar user
-                                       , ul [] topbar_list ]
-        _ -> div [] []
diff --git a/src/main.lisp b/src/main.lisp
index 969a21a..e3060f3 100644
--- a/src/main.lisp
+++ b/src/main.lisp
@@ -26,22 +26,31 @@
 				     :secure secure
 				     :http-only http-only
 				     :reply reply))))
+(defun stop-server ()
+  (hunchentoot:stop *server*))
 
-(defun start-server (&key (port 3010))
+(defun start-server (&key (port 3010) stream)
   (format t "Starting murja server~%")
   (with-db
       (migrate))
   (let ((server (make-instance 'easy-routes:easy-routes-acceptor :port port)))
+
+    (when stream
+      (setf (hunchentoot:acceptor-access-log-destination server) stream))
+    
     (when (equalp 3010 port)
       (setf *server* server))
+    
     (hunchentoot:start server)
     (format t "Started murja server on ~a ~%" port)
     server))
 
 (defun main (&key (port 3010))
-  (start-server :port port)
-  (handler-case
-      (loop do (sleep 1000))
-    (condition () nil)))
+  (with-open-file (f murja.routes.settings-routes:*log-file* :direction :output :if-does-not-exist :create)
+    (let ((*standard-output* f))
+      (start-server :port port :stream f)
+      (handler-case
+	  (loop do (sleep 1000))
+	(condition () nil)))))
 
 ;; (start-server :port 3010)
diff --git a/src/routes/root-routes.lisp b/src/routes/root-routes.lisp
index 3f586e1..a09a432 100644
--- a/src/routes/root-routes.lisp
+++ b/src/routes/root-routes.lisp
@@ -115,6 +115,9 @@
 (defroute ddddddd ("/blog/settings" :method :get) ()
   *root*)
 
+(defroute asjdisdjfiosd ("/blog/logs" :method :get) ()
+  *root*)
+
 
 (defroute ddddddd ("/blog/page/:page" :method :get) ()
   *root*)
diff --git a/src/routes/settings-routes.lisp b/src/routes/settings-routes.lisp
index f0608e7..670714f 100644
--- a/src/routes/settings-routes.lisp
+++ b/src/routes/settings-routes.lisp
@@ -1,11 +1,12 @@
 (defpackage murja.routes.settings-routes
   (:use :cl)
   (:import-from :com.inuoe.jzon :stringify :parse)
+  (:import-from :binding-arrows :->>)
   (:import-from :murja.middleware.auth :@authenticated :*user* :@can?)
   (:import-from :murja.middleware.json :@json)
   (:import-from :murja.middleware.db :@transaction)
   (:import-from :easy-routes :defroute)
-  (:export :get-settings))
+  (:export :get-settings :*log-file*))
 
 (in-package :murja.routes.settings-routes)
 
@@ -37,3 +38,26 @@
 		(postmodern:execute "UPDATE blog.Settings SET value = $2 WHERE key = $1" k (stringify v)))))
     (setf (hunchentoot:return-code*) 204)
     ""))
+
+(defvar *log-file* (asdf:system-relative-pathname :aggressive-murja "murja.log"))
+
+(defroute api-logs ("/api/logs" :method :get
+				:decorators (@transaction
+					     @json
+					     @authenticated
+					     (@can? "update-settings"))) ()
+  (log:info "~a is asking for logs ~%" *user*)
+  (labels ((logify (l)
+	     (let ((ht (make-hash-table)))
+	       (setf (gethash "row" ht) l)
+	       ht)))
+    (if (uiop:file-exists-p *log-file*)
+	(->>
+	  (lisp-fixup:slurp-utf-8 *log-file*)
+	  (str:lines)
+	  (mapcar #'logify)
+	  stringify)
+	(->>
+	  (list "no logs found")
+	  (mapcar #'logify)
+	  stringify))))