Added 'list uploaded files' page, only accessible if logged in.

This commit is contained in:
Simon Brooke 2020-02-07 19:01:30 +00:00
parent 84360110fc
commit da3bde16d0
8 changed files with 138 additions and 22 deletions

2
.gitignore vendored
View file

@ -18,3 +18,5 @@ smeagol.log*
/node_modules/ /node_modules/
.DS_Store .DS_Store
resources/public/content/uploads/

View file

@ -5,6 +5,7 @@
:url "https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html"} :url "https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html"}
:dependencies [[clj-jgit "0.8.10"] :dependencies [[clj-jgit "0.8.10"]
[clj-yaml "0.4.0"] [clj-yaml "0.4.0"]
[clojure.java-time "0.3.2"]
[com.cemerick/url "0.1.1"] [com.cemerick/url "0.1.1"]
[com.fzakaria/slf4j-timbre "0.3.7"] [com.fzakaria/slf4j-timbre "0.3.7"]
[com.stuartsierra/component "0.4.0"] [com.stuartsierra/component "0.4.0"]
@ -17,6 +18,7 @@
[im.chit/cronj "1.4.4"] [im.chit/cronj "1.4.4"]
[lib-noir "0.9.9" :exclusions [org.clojure/tools.reader]] [lib-noir "0.9.9" :exclusions [org.clojure/tools.reader]]
[markdown-clj "0.9.99" :exclusions [com.keminglabs/cljx]] [markdown-clj "0.9.99" :exclusions [com.keminglabs/cljx]]
[me.raynes/fs "1.4.6"]
[noir-exception "0.2.5"] [noir-exception "0.2.5"]
[org.clojars.simon_brooke/internationalisation "1.0.3"] [org.clojars.simon_brooke/internationalisation "1.0.3"]
[org.clojure/clojure "1.8.0"] [org.clojure/clojure "1.8.0"]

View file

@ -83,6 +83,8 @@
:file-upload-title "Upload a file" ;; title for the file upload page :file-upload-title "Upload a file" ;; title for the file upload page
:is-admin-prompt "Is administrator?" :is-admin-prompt "Is administrator?"
:here "here" ;; used in sanity check report :here "here" ;; used in sanity check report
:history-link "History" ;; text of the history link on the content frame
:history-title-prefix "History of" ;; prefix of the title on the history page
:home-link "Home" ;; text of the home link on the menu :home-link "Home" ;; text of the home link on the menu
:is-not-directory "is not a directory" :is-not-directory "is not a directory"
;; (of a file or directory) used in sanity check report ;; (of a file or directory) used in sanity check report
@ -90,6 +92,8 @@
;; (of a file or directory) used in sanity check report ;; (of a file or directory) used in sanity check report
:is-not-writable "is not writable" :is-not-writable "is not writable"
;; (of a file or directory) used in sanity check report ;; (of a file or directory) used in sanity check report
:list-files "List uploaded files"
;; title of the 'List uploaded Files' page
:login-label "Log in!" ;; text of the login widget on the login page :login-label "Log in!" ;; text of the login widget on the login page
:login-link "Log in" ;; text of the login link on the menu :login-link "Log in" ;; text of the login link on the menu
:login-prompt "To edit this wiki" :login-prompt "To edit this wiki"
@ -98,8 +102,7 @@
:logout-link "Log out" ;; text of the logout link on the menu :logout-link "Log out" ;; text of the logout link on the menu
:logged-in-as "You are logged in as" :logged-in-as "You are logged in as"
;; text of the 'logged in as' label on the menu ;; text of the 'logged in as' label on the menu
:history-link "History" ;; text of the history link on the content frame :matching "matching" ;; 'matching' in e.g. 'list files matching fred'
:history-title-prefix "History of" ;; prefix of the title on the history page
:new-pass-prompt "New password" ;; text of the new password widget prompt on the change :new-pass-prompt "New password" ;; text of the new password widget prompt on the change
;; password and edit user pages ;; password and edit user pages
:no-admin-users "There are no users in the 'passwd' file with administrative privileges" :no-admin-users "There are no users in the 'passwd' file with administrative privileges"

View file

@ -10,4 +10,6 @@
+ \*\***bold**\*\* + \*\***bold**\*\*
+ \__italic_\_ + \__italic_\_
More documentation [here](http://daringfireball.net/projects/markdown/syntax) More documentation [here](http://daringfireball.net/projects/markdown/syntax)
Your <a href="list-uploads">uploaded files are listed here</a>.

View file

@ -0,0 +1,34 @@
{% extends "templates/base.html" %}
{% block content %}
<div id="content" class="list-uploads">
<form action="list-uploads" method="post">
{% csrf-field %}
<p class="widget">
<label for="search">{% i18n matching %}</label>
<input name="search" id="search" type="text" value="{{search}}" required/>
</p>
</form>
<table>
<tr>
<th>Name</th>
<th>Uploaded</th>
<th>Type this</th>
<th>To get this</th>
</tr>
{% for entry in files %}
<tr>
<th>{{entry.base-name}}</th>
<td>{{entry.modified}}</td>
<td>
{% if entry.is-image %} ![{{entry.name|capitalize}}](uploads/{{entry.base-name}}) {% else %} [{{entry.name|capitalize}}](uploads/{{entry.base-name}}) {% endif %}
</td>
<td>
{% if entry.is-image %} <img src="uploads/{{entry.base-name}}" alt="{{entry.name|capitalize}}"/> {% else %} <a href="uploads/{{entry.base-name}}">link</a> {% endif %}
</td>
</tr>
{% endfor %}
</table>
</div>
{% endblock %}

View file

@ -34,5 +34,8 @@
</p> </p>
</form> </form>
{% endif %} {% endif %}
<p>
Your <a href="list-uploads">uploaded files are listed here</a>.
</p>
</div> </div>
{% endblock %} {% endblock %}

View file

@ -7,6 +7,8 @@
[clojure.string :as cs] [clojure.string :as cs]
[clojure.walk :refer :all] [clojure.walk :refer :all]
[compojure.core :refer :all] [compojure.core :refer :all]
[java-time :as jt]
[me.raynes.fs :as fs]
[noir.io :as io] [noir.io :as io]
[noir.response :as response] [noir.response :as response]
[noir.util.route :as route] [noir.util.route :as route]
@ -161,6 +163,75 @@
:page page :page page
:history (hist/find-history repo-path file-name)})))) :history (hist/find-history repo-path file-name)}))))
(def image-extns #{".gif" ".jpg" ".jpeg" ".png"})
(defn format-instant
"Format this `unix-time`, expected to be a Long, into something human readable.
If `template` is supplied, use that as the formatting template as specified for
java.time.Formatter. Assumes system default timezone. Returns a string."
([^Long unix-time]
(format-instant unix-time "EEEE, dd MMMM YYYY"))
([^Long unix-time ^String template]
(jt/format
(java-time/formatter template)
(java.time.LocalDateTime/ofInstant
(java-time/instant unix-time)
(java.time.ZoneOffset/systemDefault)))))
(defn list-uploads-page
"Render a list of all uploaded files"
[request]
(let
[params (keywordize-keys (:params request))
data-path (str util/content-dir "/uploads/")
files
(map
#(zipmap
[:base-name :is-image :modified :name]
[(fs/base-name %)
(if
(and (fs/extension %)
(image-extns (cs/lower-case (fs/extension %))))
true false)
(if
(fs/mod-time %)
(format-instant (fs/mod-time %)))
(fs/name %)])
(remove
#(or (cs/starts-with? (fs/name %) ".")
(fs/directory? %))
(file-seq (clojure.java.io/file data-path))))]
(layout/render
"list-uploads.html"
(merge (util/standard-params request)
{:title (str
(util/get-message :list-files request)
(if
(:search params)
(str " " (util/get-message :matching request))))
:search (:search params)
:files (if
(:search params)
(try
(let [pattern (re-pattern (:search params))]
(filter
#(re-find pattern (:base-name %))
files))
(catch Exception _ files))
files)
}))))
(map
#(zipmap
[:base-name :is-image :modified :name]
[(fs/base-name %)
(if
(and (fs/extension %) (image-extns (cs/lower-case (fs/extension %))))
true false)
(fs/mod-time %)
(fs/name %)])
(file-seq (clojure.java.io/file "resources/public/content/uploads")))
(defn upload-page (defn upload-page
"Render a form to allow the upload of a file." "Render a form to allow the upload of a file."
[request] [request]
@ -174,23 +245,17 @@
(if (if
uploaded uploaded
(do (do
(git/git-add git-repo uploaded) (git/git-add git-repo (str data-path (fs/name uploaded)))
(git/git-commit git-repo summary {:name user :email (auth/get-email user)}))) (git/git-commit git-repo summary {:name user :email (auth/get-email user)})))
(layout/render "upload.html" (layout/render "upload.html"
(merge (util/standard-params request) (merge (util/standard-params request)
{:title (util/get-message :file-upload-title request) {:title (util/get-message :file-upload-title request)
:uploaded uploaded :uploaded (if uploaded (fs/base-name uploaded))
:is-image (and :is-image (if
uploaded uploaded
(or (image-extns
(cs/ends-with? uploaded ".gif") (cs/lower-case
(cs/ends-with? uploaded ".jpg") (fs/extension uploaded))))}))))
(cs/ends-with? uploaded ".jpeg")
(cs/ends-with? uploaded ".png")
(cs/ends-with? uploaded ".GIF")
(cs/ends-with? uploaded ".JPG")
(cs/ends-with? uploaded ".PNG")))}))))
(defn version-page (defn version-page
"Render a specific historical version of a page" "Render a specific historical version of a page"
@ -286,8 +351,10 @@
(defroutes wiki-routes (defroutes wiki-routes
(GET "/wiki" request (wiki-page request))
(GET "/" request (wiki-page request)) (GET "/" request (wiki-page request))
(GET "/auth" request (auth-page request))
(POST "/auth" request (auth-page request))
(GET "/changes" request (diff-page request))
(GET "/delete-user" request (route/restricted (admin/delete-user request))) (GET "/delete-user" request (route/restricted (admin/delete-user request)))
(GET "/edit" request (route/restricted (edit-page request))) (GET "/edit" request (route/restricted (edit-page request)))
(POST "/edit" request (route/restricted (edit-page request))) (POST "/edit" request (route/restricted (edit-page request)))
@ -297,11 +364,12 @@
(GET "/edit-user" request (route/restricted (admin/edit-user request))) (GET "/edit-user" request (route/restricted (admin/edit-user request)))
(POST "/edit-user" request (route/restricted (admin/edit-user request))) (POST "/edit-user" request (route/restricted (admin/edit-user request)))
(GET "/history" request (history-page request)) (GET "/history" request (history-page request))
(GET "/list-uploads" request (route/restricted (list-uploads-page request)))
(POST "/list-uploads" request (route/restricted (list-uploads-page request)))
(GET "/version" request (version-page request)) (GET "/version" request (version-page request))
(GET "/changes" request (diff-page request))
(GET "/auth" request (auth-page request))
(POST "/auth" request (auth-page request))
(GET "/passwd" request (passwd-page request)) (GET "/passwd" request (passwd-page request))
(POST "/passwd" request (passwd-page request)) (POST "/passwd" request (passwd-page request))
(GET "/upload" request (route/restricted (upload-page request))) (GET "/upload" request (route/restricted (upload-page request)))
(POST "/upload" request (route/restricted (upload-page request)))) (POST "/upload" request (route/restricted (upload-page request)))
(GET "/wiki" request (wiki-page request))
)

View file

@ -49,7 +49,9 @@
"Store an upload both to the file system and to the database. "Store an upload both to the file system and to the database.
The issue with storing an upload is moving it into place. The issue with storing an upload is moving it into place.
If `params` are passed as a map, it is expected that this is a map from If `params` are passed as a map, it is expected that this is a map from
an HTTP POST operation of a form with type `multipart/form-data`." an HTTP POST operation of a form with type `multipart/form-data`.
On success, returns the file object uploaded."
[params path] [params path]
(let [upload (:upload params) (let [upload (:upload params)
tmp-file (:tempfile upload) tmp-file (:tempfile upload)
@ -63,7 +65,7 @@
(do (do
(.renameTo tmp-file (.renameTo tmp-file
(File. (str path filename))) (File. (str path filename)))
filename) (File. (str path filename)))
(catch Exception x (catch Exception x
(timbre/error (str "Failed to move " tmp-file " to " path filename "; " (type x) ": " (.getMessage x))) (timbre/error (str "Failed to move " tmp-file " to " path filename "; " (type x) ": " (.getMessage x)))
(throw x))) (throw x)))