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 :? :*
|
||||
SELECT * FROM comments
|
||||
WHERE image_id = :image_id
|
||||
ORDER BY created_at DESC
|
||||
ORDER BY created_at ASC
|
||||
|
||||
-- :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
|
||||
LIMIT :num-comments
|
||||
|
||||
|
|
|
@ -2,5 +2,31 @@
|
|||
|
||||
{% block content %}
|
||||
<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 %}
|
||||
|
|
|
@ -65,4 +65,39 @@
|
|||
</div>
|
||||
{% 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 %}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
[ring.middleware.format :refer [wrap-restful-format]]
|
||||
[yenu.config :refer [env]]
|
||||
[ring.middleware.flash :refer [wrap-flash]]
|
||||
[ring.middleware.cookies :refer [wrap-cookies]]
|
||||
[immutant.web.middleware :refer [wrap-session]]
|
||||
[ring.middleware.defaults :refer [site-defaults wrap-defaults]]
|
||||
[buddy.auth.middleware :refer [wrap-authentication wrap-authorization]]
|
||||
|
@ -65,13 +66,6 @@
|
|||
;; since they're not compatible with this middleware
|
||||
((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]
|
||||
(redirect "/login"))
|
||||
|
||||
|
@ -87,11 +81,19 @@
|
|||
{:pattern #"^/.*"
|
||||
: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]
|
||||
(-> ((:middleware defaults) handler)
|
||||
wrap-webjars
|
||||
wrap-flash
|
||||
(wrap-session {:cookie-attrs {:http-only true}})
|
||||
wrap-cookies
|
||||
(wrap-defaults
|
||||
(-> site-defaults
|
||||
(assoc-in [:security :anti-forgery] false)
|
||||
|
|
|
@ -41,6 +41,10 @@
|
|||
(db/delete-image-comments! {:id id})
|
||||
(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
|
||||
(GET "/upload" [:as request]
|
||||
(-> (layout/render
|
||||
|
@ -61,4 +65,4 @@
|
|||
(GET "/statistics" []
|
||||
(layout/render "statistics.html"))
|
||||
(GET "/comments" []
|
||||
(layout/render "comments.html")))
|
||||
(comment-stream)))
|
||||
|
|
|
@ -21,29 +21,46 @@
|
|||
:pages (range 1 (inc pages))
|
||||
:flash (:flash request)})))
|
||||
|
||||
(defn detail-page [image-id]
|
||||
(defn detail-page [image-id request]
|
||||
(let [image (db/get-image {:id image-id})
|
||||
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"
|
||||
{:image image
|
||||
:next-image next-img
|
||||
:prev-image prev-img
|
||||
:tags (db/get-tags-for-image {:id (:id image)})
|
||||
:saved-author saved-author
|
||||
: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]
|
||||
(let [filename (str hash "." ext)]
|
||||
(file-response (images/data-path "gallery" type filename))))
|
||||
|
||||
|
||||
(defroutes core-routes
|
||||
(GET "/" []
|
||||
(redirect "/page/1"))
|
||||
(GET "/page/:page-number" [page-number :as request]
|
||||
(index-page (Integer. page-number) request))
|
||||
(GET "/show/:image-id" [image-id]
|
||||
(detail-page image-id))
|
||||
(GET "/show/:image-id" [image-id :as request]
|
||||
(detail-page image-id request))
|
||||
|
||||
(POST "/add-comment/:image-id" [image-id :as request]
|
||||
(add-comment! image-id request))
|
||||
|
||||
(GET ["/images/:type/:hash.:ext"
|
||||
;;:type #"(normal|raw|thumbnails)"
|
||||
;;:hash #"[0-9]+-[^.]+"
|
||||
|
|
Loading…
Reference in a new issue