diff of e2f3fcfcfb46243619af3dd36590aadaaa30dd74

e2f3fcfcfb46243619af3dd36590aadaaa30dd74
diff --git a/playwright-tests/tests/basic-tests.spec.ts b/playwright-tests/tests/basic-tests.spec.ts
index 53e2265..a899be0 100644
--- a/playwright-tests/tests/basic-tests.spec.ts
+++ b/playwright-tests/tests/basic-tests.spec.ts
@@ -17,7 +17,7 @@ const password = 'p4ssw0rd';
 // }
 
 test('basic testing', async ({ page, browser }) => {
-    await page.goto('http://localhost:3000');
+    await page.goto('http://localhost:3010');
 
     await expect(page.locator('.post')).toBeHidden();
 
@@ -42,6 +42,8 @@ test('basic testing', async ({ page, browser }) => {
     await expect(page.locator('.post')).toBeHidden()
 
     await page.getByTestId('new-post-btn').click();
+
+    await expect(page.getByTestId('article-id')).toContainText('Article: No id');
     
     await page.locator('#editor-post-title').fill('New automatic post');
 
@@ -77,23 +79,26 @@ test('basic testing', async ({ page, browser }) => {
     await page.getByTestId('home').click();
 
     // are there any posts?
-    await page.goto('http://localhost:3000');
+    await page.goto('http://localhost:3010');
     
     await expect(page.locator('.post')).toBeVisible();
     await expect(page.locator('.post')).toContainText(txt);
     await expect(page.locator('.tag')).toHaveText(tag);
 
     // edit the post
-    for(let x = 0; x < 10; x++) {
+    for(let x = 0; x < 10; x++) {	
 	await page.getByTestId('edit-post-btn').click();
 
+	await expect(page.getByTestId('article-id')).not.toContainText('Article: No id');
+
 	await expect(page.locator('#editor-post-content')).toBeVisible();
 
 	await page.evaluate(() => {
 
 	    document.querySelector('#editor-post-content').value = "edited article";
 	    console.log('success');
-	});	    
+	});
+
 	await page.locator('#editor-post-save').click();
 	await page.getByTestId('home').click();
 
@@ -116,10 +121,9 @@ test('basic testing', async ({ page, browser }) => {
     await page.getByTestId('home').click();
 
     await expect(page.locator('.post')).toBeHidden();
-
     // make it visible
 
-    await page.goto('http://localhost:3000/blog/postadmin');
+    await page.goto('http://localhost:3010/blog/postadmin');
     await expect(page.getByTestId('manager-edit-post-btn')).toBeVisible();
     
     await page.getByTestId('manager-edit-post-btn').click();
@@ -145,12 +149,11 @@ test('basic testing', async ({ page, browser }) => {
     const new_ctx = await browser.newContext();
     // Create a new page inside context.
     const anon_page = await new_ctx.newPage();
-    await anon_page.goto('http://localhost:3000');
+    await anon_page.goto('http://localhost:3010');
 
-    await expect(anon_page.locator('.meta')).toContainText('1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13');
+    await expect(anon_page.locator('.meta')).toContainText('1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 13'); 
 
     await anon_page.close();
-
     // make sure editor saves 
     await page.getByText('Edit this post').click();
 
diff --git a/resources/sql/post-fns.sql b/resources/sql/post-fns.sql
index dfb0db9..cf33748 100644
--- a/resources/sql/post-fns.sql
+++ b/resources/sql/post-fns.sql
@@ -63,13 +63,22 @@ JOIN blog.Users u ON u.ID = p.creator_id
 WHERE p.ID = $1 AND (NOT p.tags ? 'hidden' OR (p.tags ? 'hidden' AND $2))
 GROUP BY p.ID, u.ID;
 
--- name: get-versioned-by-id* 
-SELECT p.ID, p.Title, p.created_at, p.Content, p.tags, u.Username, u.Nickname, u.Img_location, p.version, COUNT(c.ID) AS "amount-of-comments"
+-- name: get-versioned-by-id*
+-- returns: :array-hash
+-- $1 == post-id
+-- $2 == version-id
+SELECT p.ID, p.Title, p.created_at, p.Content, p.tags, p.version, 0 AS "amount-of-comments", json_build_object('username',
+			 u.Username,
+			 'nickname',
+			 u.Nickname,
+			 'img_location',
+			 u.Img_location) as "creator",
+       null as "prev-post-id",
+       '[]'::json as "versions",
+       null as "next-post-id"		 
 FROM blog.Post_History p
 JOIN blog.Users u ON u.ID = p.creator_id
-LEFT JOIN blog.Comment c ON c.parent_post_id = p.ID
-WHERE p.ID = :post-id AND p.version = :version-id AND not tags ?? 'hidden'
-GROUP BY p.ID, u.ID, p.title, p.created_at, p.Content, p.tags, u.Username, u.Nickname, u.Img_location, p.version;
+WHERE p.ID = $1 AND p.version = $2 AND not tags ? 'hidden';
 
 
 -- name: get-all*
@@ -90,10 +99,11 @@ ORDER BY p.created_at DESC
 -- $3 == show-hidden?
 -- name: get-page*
 -- returns: :array-hash
-SELECT p.ID, p.Title, p.Content, p.created_at, p.tags, COUNT(c.ID) AS "amount-of-comments", json_build_object('username', u.Username, 'nickname', u.Nickname, 'img_location', u.Img_location) as "creator"
+SELECT p.ID, p.Title, p.Content, p.created_at, p.tags, COUNT(c.ID) AS "amount-of-comments", json_build_object('username', u.Username, 'nickname', u.Nickname, 'img_location', u.Img_location) as "creator", json_agg(DISTINCT version) as "versions"
 FROM blog.Post p
 JOIN blog.Users u ON u.ID = p.creator_id
 LEFT JOIN blog.Comment c ON c.parent_post_id = p.ID
+LEFT JOIN blog.Post_History ph ON (ph.id = p.id AND ((not ph.tags ? 'unlisted') OR $3) AND ((not ph.tags ? 'hidden') OR $3))
 WHERE ((NOT p.tags ? 'unlisted') OR $3)
   AND ((NOT p.tags ? 'hidden') OR $3)
 GROUP BY p.ID, u.ID
diff --git a/src/local-lib/lisp-fixup.lisp b/src/local-lib/lisp-fixup.lisp
index d157422..e8f47c8 100644
--- a/src/local-lib/lisp-fixup.lisp
+++ b/src/local-lib/lisp-fixup.lisp
@@ -47,12 +47,5 @@
   "Fixes timestamps returned from postmodern to a json-format elm can parse" 
   (multiple-value-bind (year month day hour minute second millisec)
       (simple-date:decode-timestamp timestamp)
-    (let ((obj (make-hash-table :test 'equal :size 7)))
-      (setf (gethash "year" obj) year)
-      (setf (gethash "month" obj) month)
-      (setf (gethash "day" obj) day)
-      (setf (gethash "hour" obj) hour)
-      (setf (gethash "minute" obj) minute)
-      (setf (gethash "second" obj) second)
-      (setf (gethash "millisec" obj) millisec)
-      obj)))
+    (declare (ignore millisec))
+    (format nil "~d-~2,'0d-~2,'0dT~2,'0d:~2,'0d:~2,'0dZ" year month day hour minute second)))
diff --git a/src/middleware/db.lisp b/src/middleware/db.lisp
index c015aef..b293152 100644
--- a/src/middleware/db.lisp
+++ b/src/middleware/db.lisp
@@ -19,13 +19,18 @@
 
 (defun @transaction (next)
   (destructuring-bind (&key db username password host port) (db-config)
-    (with-connection (list db username password host :port port)
+    (handler-bind ((cl-postgres:database-socket-error
+		     (lambda (c)
+		       (format t "Socket error from db: ~a~%" c)
+		       (setf (hunchentoot:return-code*) 500)
+		       (return-from @transaction "Internal Server Error"))))
+      (with-connection (list db username password host :port port)
 
-      (with-schema (:blog :if-not-exist nil)
-	(handler-bind ((cl-postgres:database-error
-			 (lambda (c)
-			   (format t "Error from db: ~a~%" c)
-			   (setf (hunchentoot:return-code*) 500)
-			   "Internal Server Error")))
-	  (with-transaction ()
-	    (funcall next)))))))
+	(with-schema (:blog :if-not-exist nil)
+	  (handler-bind ((cl-postgres:database-error
+			   (lambda (c)
+			     (format t "Error from db: ~a~%" c)
+			     (setf (hunchentoot:return-code*) 500)
+			     (return-from @transaction "Internal Server Error"))))
+	    (with-transaction ()
+	      (funcall next))))))))
diff --git a/src/posts/post-db.lisp b/src/posts/post-db.lisp
index 7592b09..a763e39 100644
--- a/src/posts/post-db.lisp
+++ b/src/posts/post-db.lisp
@@ -3,7 +3,7 @@
   (:import-from :com.inuoe.jzon :parse)
   (:import-from :halisql :defqueries)
   (:import-from :lisp-fixup :fix-timestamp)
-  (:export :get-page :get-titles-by-year :insert-post :update-post :get-post))
+  (:export :get-post-version :get-page :get-titles-by-year :insert-post :update-post :get-post))
 
 (in-package :murja.posts.post-db)
 
@@ -20,10 +20,11 @@
 	   (get-titles-by-year* allow-hidden?) 'list)))
 
 (defun fix-post (post)
-  (dolist (key (list "creator" "tags"))
-    (setf (gethash key post)
-	  (parse (gethash key post))))
-  
+  (dolist (key (list "creator" "tags" "versions"))
+    (when (gethash key post)
+      (setf (gethash key post)
+	    (parse (gethash key post)))))
+
   (setf (gethash "created_at" post)
 	(fix-timestamp (gethash "created_at" post)))
   post)
@@ -38,3 +39,7 @@
   (let ((post (aref (get-by-id* id allow-hidden?) 0)))
     (fix-post post)))
     
+(defun get-post-version (id version)
+  (let ((post (first (coerce (get-versioned-by-id* id version) 'list))))
+    (when post 
+      (fix-post post ))))
diff --git a/src/routes/post-routes.lisp b/src/routes/post-routes.lisp
index 1818b99..bbd6d86 100644
--- a/src/routes/post-routes.lisp
+++ b/src/routes/post-routes.lisp
@@ -4,7 +4,7 @@
   (:import-from :com.inuoe.jzon :stringify :parse)
   (:import-from :murja.middleware.db :@transaction)
   (:import-from :murja.middleware.auth :@authenticated :*user* :@can?)
-  (:import-from :murja.posts.post-db :get-post :get-page :get-titles-by-year)
+  (:import-from :murja.posts.post-db :get-post-version :get-post :get-page :get-titles-by-year)
    
   (:import-from :murja.middleware.json :@json)
   (:import-from :easy-routes :defroute))
@@ -44,8 +44,19 @@
   
   (let* ((show-hidden? (string= hidden "true"))
 	 (post (get-post id :allow-hidden? show-hidden?)))
+    (log:info "returning post (hidden allowed? ~a) { ~{~a~%~} }~%" hidden (alexandria:hash-table-alist post))
     (stringify post)))
 
+(defroute get-post-version-route ("/api/posts/post/:id/version/:version" :method :get
+								   :decorators (@json
+										@transaction)) ()
+  (let ((post (get-post-version id version)))
+    (if post 
+	(stringify post)
+	(progn
+	  (setf (hunchentoot:return-code*) 404)
+	  ""))))
+
 ;; routes that write to the db
 (defroute post-creation-route ("/api/posts/post" :method :post
 						 :decorators (@json
diff --git a/src/routes/root-routes.lisp b/src/routes/root-routes.lisp
index 74a8885..8e0e0f5 100644
--- a/src/routes/root-routes.lisp
+++ b/src/routes/root-routes.lisp
@@ -100,4 +100,7 @@
 (defroute mediamgr ("/blog/mediamanager" :method :get) ()
   *root*)
 
+(defroute mediamgr ("/blog/postadmin" :method :get) ()
+  *root*)
+