Add commenting feature #9
This commit is contained in:
parent
4d4f403508
commit
54c2e25b5b
6 changed files with 101 additions and 16 deletions
|
@ -72,10 +72,11 @@ VALUES (:image_id, :author, :comment)
|
||||||
-- :name get-comments-for-image :? :*
|
-- :name get-comments-for-image :? :*
|
||||||
SELECT * FROM comments
|
SELECT * FROM comments
|
||||||
WHERE image_id = :image_id
|
WHERE image_id = :image_id
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at ASC
|
||||||
|
|
||||||
-- :name get-recent-comments :? :*
|
-- :name get-recent-comments :? :*
|
||||||
SELECT * FROM comments
|
SELECT comments.*, images.title FROM comments
|
||||||
|
LEFT JOIN images ON images.id = comments.image_id
|
||||||
ORDER BY created_at DESC
|
ORDER BY created_at DESC
|
||||||
LIMIT :num-comments
|
LIMIT :num-comments
|
||||||
|
|
||||||
|
|
|
@ -2,5 +2,31 @@
|
||||||
|
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<h1>Kommentarstream</h1>
|
<h1>Kommentarstream</h1>
|
||||||
<img src="/img/warning_clojure.png">
|
|
||||||
|
<ul class="list-unlisted">
|
||||||
|
{% for comment in comments %}
|
||||||
|
<hr/>
|
||||||
|
<li class="media mb-3">
|
||||||
|
<img src="https://robohash.org/{{ comment.author }}?size=40x40" class="d-flex mr-3"/>
|
||||||
|
<div class="media-body">
|
||||||
|
|
||||||
|
<i>{{ comment.created_at|parse-date|date:"dd-MM-yyyy HH:mm" }} Uhr</i>
|
||||||
|
von <strong>{{ comment.author }}</strong>
|
||||||
|
<br/>
|
||||||
|
<small><a href="/show/{{ comment.image_id }}#{{ comment.id }}">
|
||||||
|
{% if comment.title %}
|
||||||
|
{{ comment.title }}
|
||||||
|
{% else %}
|
||||||
|
Zum Bild
|
||||||
|
{% endif %}
|
||||||
|
</a>
|
||||||
|
</small>
|
||||||
|
<div>
|
||||||
|
{{ comment.comment|markdown-to-html|safe }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -65,4 +65,39 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
<ul class="list-unlisted">
|
||||||
|
{% for comment in comments %}
|
||||||
|
<li class="media mb-3">
|
||||||
|
<a name="{{ comment.id }}"></a>
|
||||||
|
<img src="https://robohash.org/{{ comment.author }}?size=50x50" class="d-flex mr-3"/>
|
||||||
|
<div class="media-body">
|
||||||
|
<h5 class="mt-0 mb-1">{{ comment.author }}</h5>
|
||||||
|
{{ comment.comment|markdown-to-html|safe }}
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
{% endfor %}
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<form action="/add-comment/{{ image.id }}" method="POST" class="form-horizontal">
|
||||||
|
{% csrf-field %}
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="author">Name</label>
|
||||||
|
<input type="text" name="author" class="form-control"
|
||||||
|
value="{{ saved-author }}"
|
||||||
|
placeholder="Bitte einen Namen wählen (wird beim nächsten Mal gespeichert)">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="comment">Kommentar</label>
|
||||||
|
<textarea name="comment" class="form-control" rows="3"
|
||||||
|
placeholder="Es kann auch Markdown-Syntax verwendet werden"></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" class="btn btn-success">
|
||||||
|
<span class="fa fa-floppy-o"></span>
|
||||||
|
Kommentar hinzufügen
|
||||||
|
</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
[ring.middleware.format :refer [wrap-restful-format]]
|
[ring.middleware.format :refer [wrap-restful-format]]
|
||||||
[yenu.config :refer [env]]
|
[yenu.config :refer [env]]
|
||||||
[ring.middleware.flash :refer [wrap-flash]]
|
[ring.middleware.flash :refer [wrap-flash]]
|
||||||
|
[ring.middleware.cookies :refer [wrap-cookies]]
|
||||||
[immutant.web.middleware :refer [wrap-session]]
|
[immutant.web.middleware :refer [wrap-session]]
|
||||||
[ring.middleware.defaults :refer [site-defaults wrap-defaults]]
|
[ring.middleware.defaults :refer [site-defaults wrap-defaults]]
|
||||||
[buddy.auth.middleware :refer [wrap-authentication wrap-authorization]]
|
[buddy.auth.middleware :refer [wrap-authentication wrap-authorization]]
|
||||||
|
@ -65,13 +66,6 @@
|
||||||
;; since they're not compatible with this middleware
|
;; since they're not compatible with this middleware
|
||||||
((if (:websocket? request) handler wrapped) request))))
|
((if (:websocket? request) handler wrapped) request))))
|
||||||
|
|
||||||
(defn wrap-auth [handler]
|
|
||||||
(let [backend (session-backend)]
|
|
||||||
(-> handler
|
|
||||||
(wrap-access-rules {:rules rules :on-error on-error})
|
|
||||||
(wrap-authentication backend)
|
|
||||||
(wrap-authorization backend))))
|
|
||||||
|
|
||||||
(defn on-error [request response]
|
(defn on-error [request response]
|
||||||
(redirect "/login"))
|
(redirect "/login"))
|
||||||
|
|
||||||
|
@ -87,11 +81,19 @@
|
||||||
{:pattern #"^/.*"
|
{:pattern #"^/.*"
|
||||||
:handler authenticated?}])
|
:handler authenticated?}])
|
||||||
|
|
||||||
|
(defn wrap-auth [handler]
|
||||||
|
(let [backend (session-backend)]
|
||||||
|
(-> handler
|
||||||
|
(wrap-access-rules {:rules rules :on-error on-error})
|
||||||
|
(wrap-authentication backend)
|
||||||
|
(wrap-authorization backend))))
|
||||||
|
|
||||||
(defn wrap-base [handler]
|
(defn wrap-base [handler]
|
||||||
(-> ((:middleware defaults) handler)
|
(-> ((:middleware defaults) handler)
|
||||||
wrap-webjars
|
wrap-webjars
|
||||||
wrap-flash
|
wrap-flash
|
||||||
(wrap-session {:cookie-attrs {:http-only true}})
|
(wrap-session {:cookie-attrs {:http-only true}})
|
||||||
|
wrap-cookies
|
||||||
(wrap-defaults
|
(wrap-defaults
|
||||||
(-> site-defaults
|
(-> site-defaults
|
||||||
(assoc-in [:security :anti-forgery] false)
|
(assoc-in [:security :anti-forgery] false)
|
||||||
|
|
|
@ -41,6 +41,10 @@
|
||||||
(db/delete-image-comments! {:id id})
|
(db/delete-image-comments! {:id id})
|
||||||
(images/delete-image! (:hash image))))
|
(images/delete-image! (:hash image))))
|
||||||
|
|
||||||
|
(defn comment-stream []
|
||||||
|
(let [comments (db/get-recent-comments {:num-comments 20})]
|
||||||
|
(layout/render "comments.html" {:comments comments})))
|
||||||
|
|
||||||
(defroutes admin-routes
|
(defroutes admin-routes
|
||||||
(GET "/upload" [:as request]
|
(GET "/upload" [:as request]
|
||||||
(-> (layout/render
|
(-> (layout/render
|
||||||
|
@ -61,4 +65,4 @@
|
||||||
(GET "/statistics" []
|
(GET "/statistics" []
|
||||||
(layout/render "statistics.html"))
|
(layout/render "statistics.html"))
|
||||||
(GET "/comments" []
|
(GET "/comments" []
|
||||||
(layout/render "comments.html")))
|
(comment-stream)))
|
||||||
|
|
|
@ -21,29 +21,46 @@
|
||||||
:pages (range 1 (inc pages))
|
:pages (range 1 (inc pages))
|
||||||
:flash (:flash request)})))
|
:flash (:flash request)})))
|
||||||
|
|
||||||
(defn detail-page [image-id]
|
(defn detail-page [image-id request]
|
||||||
(let [image (db/get-image {:id image-id})
|
(let [image (db/get-image {:id image-id})
|
||||||
next-img (db/get-next-image {:image-date (:created_at image)})
|
next-img (db/get-next-image {:image-date (:created_at image)})
|
||||||
prev-img (db/get-prev-image {:image-date (:created_at image)})]
|
prev-img (db/get-prev-image {:image-date (:created_at image)})
|
||||||
|
saved-author (get-in request [:cookies "author" :value])]
|
||||||
(layout/render "detail.html"
|
(layout/render "detail.html"
|
||||||
{:image image
|
{:image image
|
||||||
:next-image next-img
|
:next-image next-img
|
||||||
:prev-image prev-img
|
:prev-image prev-img
|
||||||
:tags (db/get-tags-for-image {:id (:id image)})
|
:tags (db/get-tags-for-image {:id (:id image)})
|
||||||
|
:saved-author saved-author
|
||||||
:comments (db/get-comments-for-image {:image_id (:id image)})})))
|
:comments (db/get-comments-for-image {:image_id (:id image)})})))
|
||||||
|
|
||||||
|
(defn add-comment! [image-id request]
|
||||||
|
(let [author (:author (:params request))
|
||||||
|
comment (:comment (:params request))]
|
||||||
|
(db/create-comment! {:image_id image-id
|
||||||
|
:author author
|
||||||
|
:comment comment})
|
||||||
|
(-> (redirect (str "/show/" image-id))
|
||||||
|
(assoc-in [:cookies "author"]
|
||||||
|
{:value author
|
||||||
|
:path "/"
|
||||||
|
:max-age (* 60 60 24 30 12)}))))
|
||||||
|
|
||||||
(defn image-file [type hash ext]
|
(defn image-file [type hash ext]
|
||||||
(let [filename (str hash "." ext)]
|
(let [filename (str hash "." ext)]
|
||||||
(file-response (images/data-path "gallery" type filename))))
|
(file-response (images/data-path "gallery" type filename))))
|
||||||
|
|
||||||
|
|
||||||
(defroutes core-routes
|
(defroutes core-routes
|
||||||
(GET "/" []
|
(GET "/" []
|
||||||
(redirect "/page/1"))
|
(redirect "/page/1"))
|
||||||
(GET "/page/:page-number" [page-number :as request]
|
(GET "/page/:page-number" [page-number :as request]
|
||||||
(index-page (Integer. page-number) request))
|
(index-page (Integer. page-number) request))
|
||||||
(GET "/show/:image-id" [image-id]
|
(GET "/show/:image-id" [image-id :as request]
|
||||||
(detail-page image-id))
|
(detail-page image-id request))
|
||||||
|
|
||||||
|
(POST "/add-comment/:image-id" [image-id :as request]
|
||||||
|
(add-comment! image-id request))
|
||||||
|
|
||||||
(GET ["/images/:type/:hash.:ext"
|
(GET ["/images/:type/:hash.:ext"
|
||||||
;;:type #"(normal|raw|thumbnails)"
|
;;:type #"(normal|raw|thumbnails)"
|
||||||
;;:hash #"[0-9]+-[^.]+"
|
;;:hash #"[0-9]+-[^.]+"
|
||||||
|
|
Loading…
Reference in a new issue