mirror of
https://github.com/journeyman-cc/smeagol.git
synced 2026-04-12 18:05:06 +00:00
Woohoo! Users can now change their own passwords. More work on tidying
up stylesheets.
This commit is contained in:
parent
72ed9e5536
commit
1d87595a64
10 changed files with 183 additions and 61 deletions
|
|
@ -1,2 +1 @@
|
||||||
{:admin {:password "admin" :email "admin@localhost"}}
|
{:admin {:password "admin", :email "admin@localhost"}}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,10 @@ body {
|
||||||
float: right;
|
float: right;
|
||||||
padding: 0.1em 0.75em;
|
padding: 0.1em 0.75em;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
#user a {
|
||||||
color: silver;
|
color: silver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -110,13 +114,12 @@ li.nav-item a:active { background: gray; color: white; }
|
||||||
#footer {
|
#footer {
|
||||||
clear: both;
|
clear: both;
|
||||||
font-size: smaller;
|
font-size: smaller;
|
||||||
padding: 0 2em;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
color:white;
|
color:white;
|
||||||
background:rgba(128,128,128,0.95);
|
background:rgba(128,128,128,0.95);
|
||||||
width: 100%;
|
width: 100%;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0.1em 10%;
|
/* padding: 0.1em 10%; */
|
||||||
bottom:0;
|
bottom:0;
|
||||||
position:fixed;
|
position:fixed;
|
||||||
z-index:150;
|
z-index:150;
|
||||||
|
|
@ -135,6 +138,7 @@ li.nav-item a:active { background: gray; color: white; }
|
||||||
border: thin solid white;
|
border: thin solid white;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
.minor-controls {
|
.minor-controls {
|
||||||
|
|
@ -144,6 +148,10 @@ li.nav-item a:active { background: gray; color: white; }
|
||||||
font-size: 66%;
|
font-size: 66%;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.message {
|
||||||
|
border: thin solid red;
|
||||||
|
}
|
||||||
|
|
||||||
.wiki {
|
.wiki {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
}
|
}
|
||||||
|
|
@ -156,8 +164,12 @@ form {
|
||||||
border: thin solid silver;
|
border: thin solid silver;
|
||||||
}
|
}
|
||||||
|
|
||||||
div.content, form, p, pre, ul, ol, dl, menu, h1, h2, h3, h4, h5 {
|
div.content, form, p, pre, h1, h2, h3, h4, h5 {
|
||||||
padding: 0.25em 10%;
|
padding: 0.25em 5%;
|
||||||
|
}
|
||||||
|
|
||||||
|
dl, menu, ol, table, ul {
|
||||||
|
margin: 0.25em 5%;
|
||||||
}
|
}
|
||||||
|
|
||||||
input {
|
input {
|
||||||
|
|
@ -179,7 +191,7 @@ input.required:after {
|
||||||
}
|
}
|
||||||
|
|
||||||
label {
|
label {
|
||||||
width: 30em;
|
width: 20%;
|
||||||
min-width: 20em;
|
min-width: 20em;
|
||||||
border-right: thin solid gray;
|
border-right: thin solid gray;
|
||||||
}
|
}
|
||||||
|
|
@ -192,12 +204,23 @@ menu li::before {
|
||||||
content: "|| ";
|
content: "|| ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
table {
|
||||||
|
border: 2px solid black;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
table.music-ruled tr:nth-child(odd) {
|
table.music-ruled tr:nth-child(odd) {
|
||||||
background-color: silver;
|
background-color: silver;
|
||||||
}
|
}
|
||||||
|
|
||||||
th, td {
|
th, td {
|
||||||
text-align: left;
|
text-align: left;
|
||||||
padding: 0 0.25em;
|
vertical-align: top;
|
||||||
|
padding: 0.15em 1.5em;
|
||||||
|
border: 1px solid gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: silver;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -126,11 +126,16 @@ h1, h2, h3, h4, h5 {
|
||||||
color: white;
|
color: white;
|
||||||
}
|
}
|
||||||
|
|
||||||
p, pre, ul, ol, dl, h1, h2, h3, h4, h5 {
|
p, pre, h1, h2, h3, h4, h5 {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 0.25em 1em;
|
padding: 0.25em 1em;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dl, menu, ol, table, ul {
|
||||||
|
margin: 0.15em 3%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
input {
|
input {
|
||||||
background-color: white;
|
background-color: white;
|
||||||
}
|
}
|
||||||
|
|
@ -165,3 +170,24 @@ menu li::before {
|
||||||
content: "|| ";
|
content: "|| ";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
table {
|
||||||
|
border: 2px solid black;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.music-ruled tr:nth-child(odd) {
|
||||||
|
background-color: silver;
|
||||||
|
}
|
||||||
|
|
||||||
|
th, td {
|
||||||
|
text-align: left;
|
||||||
|
vertical-align: top;
|
||||||
|
padding: 0.15em 1.5em;
|
||||||
|
border: 1px solid gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
th {
|
||||||
|
background-color: silver;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +0,0 @@
|
||||||
{% extends "templates/base.html" %}
|
|
||||||
{% block content %}
|
|
||||||
<p>this is the story of smeagol... work in progress</p>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="content" class="auth">
|
<div id="content" class="auth">
|
||||||
<form action="{{servlet-context}}/auth" method="POST">
|
<form action="{{servlet-context}}/auth" method="POST">
|
||||||
|
<input type="hidden" name="redirect-to" value="{{redirect-to}}"/>
|
||||||
{% if user %}
|
{% if user %}
|
||||||
<p class="widget">
|
<p class="widget">
|
||||||
<label for="submit">To finish editing</label>
|
<label for="submit">To finish editing</label>
|
||||||
|
|
@ -10,11 +11,11 @@
|
||||||
{% else %}
|
{% else %}
|
||||||
<p class="widget">
|
<p class="widget">
|
||||||
<label for="username">Your username</label>
|
<label for="username">Your username</label>
|
||||||
<input name="username" id="username" type="text"/>
|
<input name="username" id="username" type="text" required/>
|
||||||
</p>
|
</p>
|
||||||
<p class="widget">
|
<p class="widget">
|
||||||
<label for="password">Your password</label>
|
<label for="password">Your password</label>
|
||||||
<input name="password" id="password" type="password"/>
|
<input name="password" id="password" type="password" required/>
|
||||||
</p>
|
</p>
|
||||||
<p class="widget">
|
<p class="widget">
|
||||||
<label for="submit">To edit this wiki</label>
|
<label for="submit">To edit this wiki</label>
|
||||||
|
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
<!-- navbar -->
|
<!-- navbar -->
|
||||||
<div id="nav">
|
<div id="nav">
|
||||||
{% if user %}
|
{% if user %}
|
||||||
<p class="user" id="user">You are logged in as {{user}}</p>
|
<p class="user" id="user">You are logged in as {{user}} | <a href="passwd">change password</a></p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<img id="nav-icon" src="{{servlet-context}}/img/threelines.png" alt="Menu"/>
|
<img id="nav-icon" src="{{servlet-context}}/img/threelines.png" alt="Menu"/>
|
||||||
<ul id="nav-menu" class="nav">
|
<ul id="nav-menu" class="nav">
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
<p class="widget">
|
<p class="widget">
|
||||||
<label for="summary">What have you changed?</label>
|
<label for="summary">What have you changed?</label>
|
||||||
<input name="summary" id="summary" type="text"
|
<input name="summary" id="summary" type="text"
|
||||||
value="{%if exists%}{%else%}New file {{title}}{%endif%}"/>
|
value="{%if exists%}{%else%}New file {{title}}{%endif%}" required/>
|
||||||
</p>
|
</p>
|
||||||
<p class="widget">
|
<p class="widget">
|
||||||
<label for="submit">When you have finished editing</label>
|
<label for="submit">When you have finished editing</label>
|
||||||
|
|
|
||||||
23
resources/templates/passwd.html
Normal file
23
resources/templates/passwd.html
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
{% extends "templates/base.html" %}
|
||||||
|
{% block content %}
|
||||||
|
<div id="content" class="auth">
|
||||||
|
<form action="{{servlet-context}}/passwd" method="POST">
|
||||||
|
<p class="widget">
|
||||||
|
<label for="password">Your password</label>
|
||||||
|
<input name="oldpass" id="oldpass" type="password" required/>
|
||||||
|
</p>
|
||||||
|
<p class="widget">
|
||||||
|
<label for="password">New password</label>
|
||||||
|
<input name="pass1" id="pass1" type="password" required/>
|
||||||
|
</p>
|
||||||
|
<p class="widget">
|
||||||
|
<label for="password">And again</label>
|
||||||
|
<input name="pass2" id="pass2" type="password" required/>
|
||||||
|
</p>
|
||||||
|
<p class="widget">
|
||||||
|
<label for="submit">To edit this wiki</label>
|
||||||
|
<input name="action" id="action" type="submit" class="action" value="Login!"/>
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
|
@ -20,6 +20,13 @@
|
||||||
;; along with this program; if not, write to the Free Software
|
;; along with this program; if not, write to the Free Software
|
||||||
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
;;
|
||||||
|
;; All functions which relate to the passwd file are in this namespace, in order
|
||||||
|
;; that it can reasonably simply swapped out for a more secure replacement
|
||||||
|
;;
|
||||||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||||
|
|
||||||
(defn authenticate
|
(defn authenticate
|
||||||
"Return `true` if this `username`/`password` pair match, `false` otherwise"
|
"Return `true` if this `username`/`password` pair match, `false` otherwise"
|
||||||
[username password]
|
[username password]
|
||||||
|
|
@ -36,3 +43,25 @@
|
||||||
users (read-string (slurp path))
|
users (read-string (slurp path))
|
||||||
user ((keyword username) users)]
|
user ((keyword username) users)]
|
||||||
(if user (:email user))))
|
(if user (:email user))))
|
||||||
|
|
||||||
|
(defn change-pass
|
||||||
|
"Change the password for the user with this `username` and `oldpass` to this `newpass`.
|
||||||
|
Return `true` if password was successfully changed."
|
||||||
|
[username oldpass newpass]
|
||||||
|
(timbre/info (format "Changing password for user %s" username))
|
||||||
|
(let [path (str (io/resource-path) "../passwd")
|
||||||
|
users (read-string (slurp path))
|
||||||
|
keywd (keyword username)
|
||||||
|
user (if users (keywd users))
|
||||||
|
email (:email user)]
|
||||||
|
(try
|
||||||
|
(cond
|
||||||
|
(and user (.equals (:password user) oldpass))
|
||||||
|
(do
|
||||||
|
(spit path (assoc (dissoc users keywd) keywd {:password newpass :email email}))
|
||||||
|
true))
|
||||||
|
(catch Exception any
|
||||||
|
(timbre/error
|
||||||
|
(format "Changing password failed for user %s failed: %s (%s)"
|
||||||
|
username (.getName (.getClass any)) (.getMessage any)))
|
||||||
|
false))))
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,8 @@
|
||||||
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
|
||||||
(ns smeagol.routes.wiki
|
(ns smeagol.routes.wiki
|
||||||
(:use clojure.walk)
|
(:use clojure.walk
|
||||||
|
clojure.pprint)
|
||||||
(:require [compojure.core :refer :all]
|
(:require [compojure.core :refer :all]
|
||||||
[clj-jgit.porcelain :as git]
|
[clj-jgit.porcelain :as git]
|
||||||
[markdown.core :as md]
|
[markdown.core :as md]
|
||||||
|
|
@ -40,7 +41,7 @@
|
||||||
|
|
||||||
(defn process-source
|
(defn process-source
|
||||||
"Process `source-text` and save it to the specified `file-path`, committing it
|
"Process `source-text` and save it to the specified `file-path`, committing it
|
||||||
to Git and finally redirecting to wiki-page."
|
to Git and finally redirecting to wiki-page."
|
||||||
[params]
|
[params]
|
||||||
(let [source-text (:src params)
|
(let [source-text (:src params)
|
||||||
page (:page params)
|
page (:page params)
|
||||||
|
|
@ -55,8 +56,8 @@
|
||||||
(spit file-path source-text)
|
(spit file-path source-text)
|
||||||
(if (not exists?) (git/git-add git-repo file-name))
|
(if (not exists?) (git/git-add git-repo file-name))
|
||||||
(git/git-commit git-repo summary {:name user :email email})
|
(git/git-commit git-repo summary {:name user :email email})
|
||||||
(response/redirect (str "/wiki?" page))
|
(response/redirect (str "/wiki?page=" page))
|
||||||
))
|
))
|
||||||
|
|
||||||
(defn edit-page
|
(defn edit-page
|
||||||
"Render a page in a text-area for editing. This could have been done in the same function as wiki-page,
|
"Render a page in a text-area for editing. This could have been done in the same function as wiki-page,
|
||||||
|
|
@ -70,13 +71,13 @@
|
||||||
(cond src-text (process-source params)
|
(cond src-text (process-source params)
|
||||||
true
|
true
|
||||||
(layout/render "edit.html"
|
(layout/render "edit.html"
|
||||||
{:title (str "Edit " page)
|
{:title (str "Edit " page)
|
||||||
:page page
|
:page page
|
||||||
:left-bar (local-links (util/md->html "/content/_edit-left-bar.md"))
|
:left-bar (local-links (util/md->html "/content/_edit-left-bar.md"))
|
||||||
:header (local-links (util/md->html "/content/_header.md"))
|
:header (local-links (util/md->html "/content/_header.md"))
|
||||||
:content (if exists? (io/slurp-resource (str "/content/" page ".md")) "")
|
:content (if exists? (io/slurp-resource (str "/content/" page ".md")) "")
|
||||||
:user (session/get :user)
|
:user (session/get :user)
|
||||||
:exists exists?}))))
|
:exists exists?}))))
|
||||||
|
|
||||||
(defn wiki-page
|
(defn wiki-page
|
||||||
"Render the markdown page specified in this `request`, if any. If none found, redirect to edit-page"
|
"Render the markdown page specified in this `request`, if any. If none found, redirect to edit-page"
|
||||||
|
|
@ -87,18 +88,18 @@
|
||||||
file-path (str (io/resource-path) file-name)
|
file-path (str (io/resource-path) file-name)
|
||||||
exists? (.exists (clojure.java.io/as-file file-path))]
|
exists? (.exists (clojure.java.io/as-file file-path))]
|
||||||
(cond exists?
|
(cond exists?
|
||||||
(layout/render "wiki.html"
|
(layout/render "wiki.html"
|
||||||
{:title page
|
{:title page
|
||||||
:page page
|
:page page
|
||||||
:left-bar (local-links (util/md->html "/content/_left-bar.md"))
|
:left-bar (local-links (util/md->html "/content/_left-bar.md"))
|
||||||
:header (local-links (util/md->html "/content/_header.md"))
|
:header (local-links (util/md->html "/content/_header.md"))
|
||||||
:content (local-links (util/md->html file-name))
|
:content (local-links (util/md->html file-name))
|
||||||
:user (session/get :user)})
|
:user (session/get :user)})
|
||||||
true (response/redirect (str "/edit?page=" page)))))
|
true (response/redirect (str "/edit?page=" page)))))
|
||||||
|
|
||||||
(defn history-page
|
(defn history-page
|
||||||
"Render the history for the markdown page specified in this `request`,
|
"Render the history for the markdown page specified in this `request`,
|
||||||
if any. If none, error?"
|
if any. If none, error?"
|
||||||
[request]
|
[request]
|
||||||
(let [params (keywordize-keys (:params request))
|
(let [params (keywordize-keys (:params request))
|
||||||
page (or (:page params) "Introduction")
|
page (or (:page params) "Introduction")
|
||||||
|
|
@ -123,13 +124,13 @@
|
||||||
{:title (str "Version " version " of " page)
|
{:title (str "Version " version " of " page)
|
||||||
:page page
|
:page page
|
||||||
:left-bar (local-links
|
:left-bar (local-links
|
||||||
(util/md->html "/content/_left-bar.md"))
|
(util/md->html "/content/_left-bar.md"))
|
||||||
:header (local-links
|
:header (local-links
|
||||||
(util/md->html "/content/_header.md"))
|
(util/md->html "/content/_header.md"))
|
||||||
:content (local-links
|
:content (local-links
|
||||||
(md/md-to-html-string
|
(md/md-to-html-string
|
||||||
(hist/fetch-version
|
(hist/fetch-version
|
||||||
repo-path file-name version)))
|
repo-path file-name version)))
|
||||||
:user (session/get :user)})))
|
:user (session/get :user)})))
|
||||||
|
|
||||||
(defn diff-page
|
(defn diff-page
|
||||||
|
|
@ -144,39 +145,61 @@
|
||||||
{:title (str "Changes since version " version " of " page)
|
{:title (str "Changes since version " version " of " page)
|
||||||
:page page
|
:page page
|
||||||
:left-bar (local-links
|
:left-bar (local-links
|
||||||
(util/md->html "/content/_left-bar.md"))
|
(util/md->html "/content/_left-bar.md"))
|
||||||
:header (local-links
|
:header (local-links
|
||||||
(util/md->html "/content/_header.md"))
|
(util/md->html "/content/_header.md"))
|
||||||
:content (d2h/diff2html (hist/diff repo-path file-name version))
|
:content (d2h/diff2html (hist/diff repo-path file-name version))
|
||||||
:user (session/get :user)})))
|
:user (session/get :user)})))
|
||||||
|
|
||||||
(defn auth-page
|
(defn auth-page
|
||||||
"Render the auth page"
|
"Render the auth page"
|
||||||
[request]
|
[request]
|
||||||
|
(pprint request)
|
||||||
(let [params (keywordize-keys (:form-params request))
|
(let [params (keywordize-keys (:form-params request))
|
||||||
username (:username params)
|
username (:username params)
|
||||||
password (:password params)
|
password (:password params)
|
||||||
action (:action params)
|
action (:action params)
|
||||||
user (session/get :user)]
|
user (session/get :user)
|
||||||
|
redirect-to (or (:redirect-to params) "/wiki")]
|
||||||
(cond
|
(cond
|
||||||
(= action "Logout!")
|
(= action "Logout!")
|
||||||
(do
|
(do
|
||||||
(timbre/info (str "User " user " logging out"))
|
(timbre/info (str "User " user " logging out"))
|
||||||
(session/remove! :user)
|
(session/remove! :user)
|
||||||
(response/redirect "/wiki"))
|
(response/redirect redirect-to))
|
||||||
(and username password (auth/authenticate username password))
|
(and username password (auth/authenticate username password))
|
||||||
(do
|
(do
|
||||||
(session/put! :user username)
|
(session/put! :user username)
|
||||||
(response/redirect "/wiki"))
|
(response/redirect redirect-to))
|
||||||
true
|
true
|
||||||
(layout/render "auth.html"
|
(layout/render "auth.html"
|
||||||
{:title (if user (str "Logout " user) "Log in")
|
{:title (if user (str "Logout " user) "Log in")
|
||||||
|
:redirect-to ((:headers request) "referer")
|
||||||
|
:left-bar (local-links (util/md->html "/content/_left-bar.md"))
|
||||||
|
:header (local-links (util/md->html "/content/_header.md"))
|
||||||
|
:user user}))))
|
||||||
|
|
||||||
|
(defn passwd-page
|
||||||
|
"Render a page to change the user password"
|
||||||
|
[request]
|
||||||
|
(let [params (keywordize-keys (:form-params request))
|
||||||
|
oldpass (:oldpass params)
|
||||||
|
pass1 (:pass1 params)
|
||||||
|
pass2 (:pass2 params)
|
||||||
|
user (session/get :user)
|
||||||
|
length (if pass1 (count pass1) 0)
|
||||||
|
message (cond
|
||||||
|
(nil? oldpass) nil
|
||||||
|
(and pass1 (>= length 8) (.equals pass1 pass2) (auth/change-pass user oldpass pass2))
|
||||||
|
"Your password was changed"
|
||||||
|
(< length 8) "You proposed password wasn't long enough: 8 characters required"
|
||||||
|
(not (= pass1 pass2)) "Your proposed passwords don't match"
|
||||||
|
true "Your password was not changed")] ;; but I don't know why...
|
||||||
|
(layout/render "passwd.html"
|
||||||
|
{:title (str "Change passord for " user)
|
||||||
:left-bar (local-links (util/md->html "/content/_left-bar.md"))
|
:left-bar (local-links (util/md->html "/content/_left-bar.md"))
|
||||||
:header (local-links (util/md->html "/content/_header.md"))
|
:header (local-links (util/md->html "/content/_header.md"))
|
||||||
:user user}))))
|
:message message})))
|
||||||
|
|
||||||
(defn about-page []
|
|
||||||
(layout/render "about.html"))
|
|
||||||
|
|
||||||
(defroutes wiki-routes
|
(defroutes wiki-routes
|
||||||
(GET "/wiki" request (wiki-page request))
|
(GET "/wiki" request (wiki-page request))
|
||||||
|
|
@ -188,4 +211,6 @@
|
||||||
(GET "/changes" request (diff-page request))
|
(GET "/changes" request (diff-page request))
|
||||||
(GET "/auth" request (auth-page request))
|
(GET "/auth" request (auth-page request))
|
||||||
(POST "/auth" request (auth-page request))
|
(POST "/auth" request (auth-page request))
|
||||||
(GET "/about" [] (about-page)))
|
(GET "/passwd" request (passwd-page request))
|
||||||
|
(POST "/passwd" request (passwd-page request))
|
||||||
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue