Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge branch 'feature/if-user' of https://github.com/amalloy/4clojure

…into develop

Conflicts:
	resources/public/script/foreclojure.js
  • Loading branch information...
commit d8a506f425b26666a2d81f23eeb165433b6401e6 2 parents e2911e3 + bc124ae
@amcnamara authored
View
6 project.clj
@@ -1,9 +1,9 @@
-(defproject foreclojure "1.5.0.2"
- :description "4clojure - a website for lisp beginners"
+(defproject foreclojure "1.5.1.1"
+ :description "4clojure - a website for learning Clojure"
:dependencies [[clojure "1.2.1"]
[clojure-contrib "1.2.0"]
[compojure "0.6.2"]
- [hiccup "0.2.4"]
+ [hiccup "0.3.6"]
[clojail "0.4.0-SNAPSHOT"]
[sandbar "0.4.0-SNAPSHOT"]
[org.clojars.christophermaier/congomongo "0.1.4-SNAPSHOT"]
View
21 resources/public/css/style.css
@@ -232,19 +232,12 @@ img.gravatar{
padding-bottom: 5px;;
}
-#user-table{
+#user-table, #server-user-table{
float: left;
width: 100%;
padding: 15px;
}
-#server-user-table{
- float: left;
- width: 100%;
- padding: 15px;
-}
-
-
/*
* By default only show the text label for the "Following" column on
* the users page. If they have javascript turned on (detected
@@ -267,6 +260,14 @@ img.gravatar{
display: none;
}
+/*
+ * If datatables is fetching stuff from the server, we definitely have
+ * javascript enabled, so hide the span to begin with.
+ */
+#server-user-table span.following {
+ display: none;
+}
+
span.error, div.error {
color: red;
@@ -312,7 +313,9 @@ div#main {
}
div.message #flash-text {}
-div.message #error-text {}
+div.message #error-text {
+ color: red;
+}
div#prob-title {
font-size: 15pt;
View
29 resources/public/script/foreclojure.js
@@ -41,9 +41,9 @@ $(document).ready(function() {
$("#all-users-link").html("[show <a href=\"/users/all\">all</a>]");
- $("#user-table").addClass("js-enabled");
+ $("#user-table,#server-user-table").addClass("js-enabled");
- $("#user-table input.following").live("click", function(e) {
+ $("#user-table,#server-user-table input.following").live("click", function(e) {
e.preventDefault();
var $checkbox = $(this)
var $form = $checkbox.parents("form")
@@ -59,6 +59,7 @@ $(document).ready(function() {
});
return false;
});
+
});
var difficulty = {
@@ -94,6 +95,19 @@ jQuery.fn.dataTableExt.afnSortData['user-name'] = function(oSettings, iColumn)
return aData;
}
+// See comments for above function to make sense of this mess
+jQuery.fn.dataTableExt.afnSortData['following'] = function(oSettings, iColumn)
+{
+ var aData = [];
+ $('td:eq('+iColumn+') span.following', oSettings.oApi._fnGetTrNodes(oSettings)).each(function () {
+ var followingText = $(this).text();
+ if (!followingText || followingText == "") { followingText = "no" }
+ aData.push(followingText);
+ });
+ return aData;
+}
+
+
function configureDataTables(){
$('#problem-table').dataTable( {
@@ -127,14 +141,19 @@ function configureDataTables(){
{"sType": "numeric"},
{"sSortDataType": "user-name"},
{"sType": "numeric"},
- {"sType": "string"},
- {"sType": "string"}
+ {"sSortDataType": "following"}
]
} );
$('#server-user-table').dataTable( {
- "iDisplayLength":10,
+ "aoColumns": [
+ null,
+ null,
+ null,
+ {"bSortable": false}
+ ],
+ "iDisplayLength":100,
"bProcessing": true,
"bServerSide": true,
"sAjaxSource": "/datatable/users"
View
4 src/foreclojure/core.clj
@@ -9,6 +9,7 @@
[foreclojure.datatable :only [datatable-routes]]
[foreclojure.problems :only [problems-routes]]
[foreclojure.login :only [login-routes]]
+ [foreclojure.settings :only [settings-routes]]
[foreclojure.register :only [register-routes]]
[foreclojure.golf :only [golf-routes]]
[foreclojure.ring :only [resources wrap-strip-trailing-slash wrap-url-as-file wrap-versioned-expiry split-hosts wrap-404 wrap-debug]]
@@ -46,7 +47,8 @@
graph-routes
api-routes
datatable-routes
- golf-routes)
+ golf-routes
+ settings-routes)
((if (:wrap-reload config)
#(wrap-reload % '(foreclojure.core))
identity))
View
4 src/foreclojure/datatable.clj
@@ -6,5 +6,7 @@
(def datatable-routes
(-> (routes
- (GET "/datatable/users" [& more] {:body (user-datatable-query more)}))
+ (GET "/datatable/users" [& more]
+ {:body (user-datatable-query more)
+ :status 200}))
(wrap-json)))
View
93 src/foreclojure/login.clj
@@ -3,9 +3,8 @@
[ring.util.response :as response])
(:import [org.jasypt.util.password StrongPasswordEncryptor])
(:use [hiccup.form-helpers :only [form-to label text-field password-field check-box]]
- [foreclojure.utils :only [from-mongo flash-error flash-msg with-user form-row assuming send-email login-url]]
+ [foreclojure.utils :only [from-mongo flash-error flash-msg form-row assuming send-email login-url]]
[foreclojure.template :only [def-page content-page]]
- [foreclojure.users :only [disable-codebox? set-disable-codebox hide-solutions? set-hide-solutions]]
[compojure.core :only [defroutes GET POST]]
[useful.map :only [keyed]]
[clojail.core :only [thunk-timeout]]
@@ -50,84 +49,6 @@
(response/redirect (or location "/problems")))
(flash-error "/login" "Error logging in."))))
-(defn account-settings-box [user]
- [:table
- (form-to [:post "/login/update"]
- (map form-row
- [[text-field :new-username "Username" user]
- [password-field :old-pwd "Current password"]
- [password-field :pwd "New password"]
- [password-field :repeat-pwd "Repeat password"]])
- [:tr
- [:td [:button {:type "submit"} "Reset now"]]])])
-
-(defn js-settings-box [user-obj]
- (list
- [:p "Selecting this will disable the JavaScript code entry box and just give you plain text entry"]
- (form-to [:post "/users/set-disable-codebox"]
- (check-box :disable-codebox
- (disable-codebox? user-obj))
- [:label {:for "disable-codebox"}
- "Disable JavaScript in code entry box"]
- [:br]
- [:div#button-div
- [:button {:type "submit"} "Submit"]])))
-
-(defn hide-settings-box [user-obj]
- (list
- [:p "When you solve a problem, we allow any user who has solved a problem to view your solutions to that problem. Check this box to keep your solutions private."]
- (form-to [:post "/users/set-hide-solutions"]
- (check-box :hide-solutions
- (hide-solutions? user-obj))
- [:label {:for "hide-solutions"}
- "Hide my solutions"]
- [:br]
- [:div#button-div
- [:button {:type "submit"} "Submit"]])))
-
-(def-page update-credentials-page []
- (with-user [{:keys [user] :as user-obj}]
- {:title "Change password"
- :content
- (content-page
- {:main
- (list
- [:h2 "Change password for " user]
- [:div#account-settings (account-settings-box user)]
- [:hr]
- [:h2 "Disable JavaScript Code Box"]
- [:div#settings-codebox (js-settings-box user-obj)]
- [:hr]
- [:h2 "Hide My Solutions"]
- [:div#settings-follow (hide-settings-box user-obj)])})}))
-
-(defn do-update-credentials! [new-username old-pwd new-pwd repeat-pwd]
- (with-user [{:keys [user pwd]}]
- (let [encryptor (StrongPasswordEncryptor.)
- new-pwd-hash (.encryptPassword encryptor new-pwd)
- new-lower-user (.toLowerCase new-username)]
- (assuming [(or (= new-lower-user user) (nil? (fetch-one :users :where {:user new-lower-user})))
- "User already exists",
- (< 3 (.length new-lower-user) 14)
- "Username must be 4-13 characters long",
- (= new-lower-user
- (first (re-seq #"[A-Za-z0-9_]+" new-lower-user)))
- "Username must be alphanumeric"
- (or (empty? new-pwd) (< 6 (.length new-pwd)))
- "New password must be at least seven characters long",
- (= new-pwd repeat-pwd)
- "New password was not entered identically twice"
- (.checkPassword encryptor old-pwd pwd)
- "Old password incorrect"]
- (do
- (update! :users {:user user}
- {:$set {:pwd (if (not-empty new-pwd) new-pwd-hash pwd) :user new-lower-user}}
- :upsert false)
- (session/session-put! :user new-lower-user)
- (flash-msg "/problems"
- (str "Account for " new-lower-user " updated successfully")))
- (flash-error "/login/update" why)))))
-
(def-page reset-password-page []
{:title "Reset password"
:content
@@ -196,20 +117,10 @@
(POST "/login" {{:strs [user pwd]} :form-params}
(do-login user pwd))
- (GET "/login/update" [] (update-credentials-page))
- (POST "/login/update" {{:strs [new-username old-pwd pwd repeat-pwd]} :form-params}
- (do-update-credentials! new-username old-pwd pwd repeat-pwd))
-
(GET "/login/reset" [] (reset-password-page))
(POST "/login/reset" [email]
(do-reset-password! email))
(GET "/logout" []
(do (session/session-delete-key! :user)
- (response/redirect "/")))
-
- (POST "/users/set-disable-codebox" [disable-codebox]
- (set-disable-codebox disable-codebox))
-
- (POST "/users/set-hide-solutions" [hide-solutions]
- (set-hide-solutions hide-solutions)))
+ (response/redirect "/"))))
View
30 src/foreclojure/problems.clj
@@ -5,7 +5,7 @@
[ring.util.response :as response]
[cheshire.core :as json])
(:import [org.apache.commons.mail EmailException])
- (:use [foreclojure.utils :only [from-mongo get-user get-solved login-link flash-msg flash-error row-class approver? can-submit? send-email image-builder with-user as-int maybe-update escape-html]]
+ (:use [foreclojure.utils :only [from-mongo get-user get-solved login-link flash-msg flash-error row-class approver? can-submit? send-email image-builder if-user with-user as-int maybe-update escape-html]]
[foreclojure.ring-utils :only [*url*]]
[foreclojure.template :only [def-page content-page]]
[foreclojure.social :only [tweet-link gist!]]
@@ -256,15 +256,13 @@ Return a map, {:message, :error, :url, :num-tests-passed}."
:golfChart (html (render-golf-chart))})))
(defn wants-no-javascript-codebox? []
- (when (session/session-get :user)
- (with-user [{:keys [user] :as user-obj}]
- (disable-codebox? user-obj))))
+ (if-user [{:keys [user] :as user-obj}]
+ (disable-codebox? user-obj)))
(def-page code-box [id]
(let [{:keys [_id title difficulty tags description
restricted tests approved user]}
(get-problem (Integer. id)),
- session-user (session/session-get :user)
title (str (when-not approved
"Unapproved: ")
title)]
@@ -273,12 +271,11 @@ Return a map, {:message, :error, :url, :num-tests-passed}."
:content
[:div
[:div#prob-title title]
- (if session-user
- (with-user [{:keys [solved]}]
- (if (some #{(Integer. id)} solved)
- (link-to (str "/problem/solutions/" id)
- [:button#solutions-link {:type "submit"} "Solutions"])
- [:div {:style "clear: right; margin-bottom: 15px;"} "&nbsp;"]))
+ (if-user [{:keys [solved]}]
+ (if (some #{(Integer. id)} solved)
+ (link-to (str "/problem/solutions/" id)
+ [:button#solutions-link {:type "submit"} "Solutions"])
+ [:div {:style "clear: right; margin-bottom: 15px;"} "&nbsp;"])
[:div {:style "clear: right; margin-bottom: 15px;"} "&nbsp;"])
[:hr]
[:table#tags
@@ -365,12 +362,11 @@ Return a map, {:message, :error, :url, :num-tests-passed}."
(defn show-solutions [id]
(let [problem-id (Integer. id)
user (session/session-get :user)]
- (if user
- (with-user [{:keys [solved]}]
- (if (some #{problem-id} solved)
- (show-solutions-page problem-id)
- (flash-error (str "/problem/" problem-id)
- "You must solve this problem before you can see others' solutions!")))
+ (if-user [{:keys [solved]}]
+ (if (some #{problem-id} solved)
+ (show-solutions-page problem-id)
+ (flash-error (str "/problem/" problem-id)
+ "You must solve this problem before you can see others' solutions!"))
(do
(session/session-put! :login-to *url*)
(flash-error "/login" "You must log in to see solutions!")))))
View
101 src/foreclojure/settings.clj
@@ -0,0 +1,101 @@
+(ns foreclojure.settings
+ (:require [sandbar.stateful-session :as session]
+ [ring.util.response :as response])
+ (:import [org.jasypt.util.password StrongPasswordEncryptor])
+ (:use [hiccup.form-helpers :only [form-to label text-field password-field check-box]]
+ [foreclojure.utils :only [from-mongo flash-error flash-msg with-user form-row assuming send-email login-url]]
+ [foreclojure.template :only [def-page content-page]]
+ [foreclojure.users :only [disable-codebox? hide-solutions? gravatar-img]]
+ [compojure.core :only [defroutes GET POST]]
+ [useful.map :only [keyed]]
+ [clojail.core :only [thunk-timeout]]
+ [clojure.stacktrace :only [print-cause-trace]]
+ [somnium.congomongo :only [update! fetch-one]]))
+
+(defn account-settings-box [user email]
+ (list
+ [:p "Leave new and reset password fields blank if you do not wish to change your password."]
+ [:table
+ (map form-row
+ [[text-field :new-username "Username" user]
+ [password-field :old-pwd "Current password"]
+ [password-field :pwd "New password"]
+ [password-field :repeat-pwd "Repeat password"]
+ [text-field :email "Email" email]])]))
+
+(defn js-settings-box [user-obj]
+ (list
+ [:p "Selecting this will disable the JavaScript code entry box and just give you plain text entry"]
+ (check-box :disable-codebox
+ (disable-codebox? user-obj))
+ [:label {:for "disable-codebox"}
+ "Disable JavaScript in code entry box"]
+ [:br]))
+
+(defn hide-settings-box [user-obj]
+ (list
+ [:p "When you solve a problem, we allow any user who has solved a problem to view your solutions to that problem. Check this box to keep your solutions private."]
+ (check-box :hide-solutions
+ (hide-solutions? user-obj))
+ [:label {:for "hide-solutions"}
+ "Hide my solutions"]
+ [:br]))
+
+(def-page settings-page []
+ (with-user [{:keys [user email] :as user-obj}]
+ {:title "Account settings"
+ :content
+ (content-page
+ {:main
+ (form-to [:post "/settings"]
+ (list
+ [:h2 "Change settings for " user]
+ [:div#account-settings (account-settings-box user email)]
+ [:hr]
+ [:h3 "Disable JavaScript Code Box"]
+ [:div#settings-codebox (js-settings-box user-obj)]
+ [:hr]
+ [:h3 "Hide My Solutions"]
+ [:div#settings-follow (hide-settings-box user-obj)]
+ [:hr]
+ [:h3 "Profile Image"]
+ [:div (gravatar-img {:email email :size 64})]
+ [:p "To change your profile image, visit <a href='http://gravatar.com' target='_blank'>Gravatar</a> and edit the image for '" email "'."]
+ [:div#button-div
+ [:button {:type "submit"} "Submit"]]))})}))
+
+(defn do-update-settings! [new-username old-pwd new-pwd repeat-pwd email disable-codebox hide-solutions]
+ (with-user [{:keys [user pwd]}]
+ (let [encryptor (StrongPasswordEncryptor.)
+ new-pwd-hash (.encryptPassword encryptor new-pwd)
+ new-lower-user (.toLowerCase new-username)]
+ (assuming [(or (= new-lower-user user) (nil? (fetch-one :users :where {:user new-lower-user})))
+ "User already exists",
+ (< 3 (.length new-lower-user) 14)
+ "Username must be 4-13 characters long",
+ (= new-lower-user
+ (first (re-seq #"[A-Za-z0-9_]+" new-lower-user)))
+ "Username must be alphanumeric"
+ (or (empty? new-pwd) (< 6 (.length new-pwd)))
+ "New password must be at least seven characters long",
+ (= new-pwd repeat-pwd)
+ "New password was not entered identically twice"
+ (or (empty? new-pwd)
+ (.checkPassword encryptor old-pwd pwd))
+ "Current password incorrect"
+ (not (empty? email))
+ "Please enter a valid email address"]
+ (do
+ (update! :users {:user user}
+ {:$set {:pwd (if (not-empty new-pwd) new-pwd-hash pwd) :user new-lower-user :email email
+ :disable-code-box (boolean disable-codebox) :hide-solutions (boolean hide-solutions)}}
+ :upsert false)
+ (session/session-put! :user new-lower-user)
+ (flash-msg "/problems"
+ (str "Account for " new-lower-user " updated successfully")))
+ (flash-error "/settings" why)))))
+
+(defroutes settings-routes
+ (GET "/settings" [] (settings-page))
+ (POST "/settings" {{:strs [new-username old-pwd pwd repeat-pwd email disable-codebox hide-solutions]} :form-params}
+ (do-update-settings! new-username old-pwd pwd repeat-pwd email disable-codebox hide-solutions)))
View
2  src/foreclojure/template.clj
@@ -56,7 +56,7 @@
(when user
[:div#lower-menu
[:span
- (link-to "/login/update" "Account Settings")]
+ (link-to "/settings" "Account Settings")]
(when (:golfing-active config)
[:span ; deserves its own page, but just make it discoverable for now
(link-to "/league" "Leagues")])
View
106 src/foreclojure/users.clj
@@ -3,7 +3,7 @@
[clojure.string :as string]
[sandbar.stateful-session :as session]
[cheshire.core :as json])
- (:use [foreclojure.utils :only [from-mongo row-class rank-class get-user with-user]]
+ (:use [foreclojure.utils :only [from-mongo row-class rank-class get-user if-user with-user]]
[foreclojure.template :only [def-page content-page]]
[foreclojure.ring-utils :only [*http-scheme* static-url]]
[foreclojure.config :only [config repo-url]]
@@ -103,17 +103,16 @@
(str "/user/" (if follow? "follow" "unfollow") "/" username))
(defn following-checkbox [current-user-id following user-id user]
- (when (and current-user-id (not= current-user-id user-id))
+ (if (and current-user-id (not= current-user-id user-id))
(let [following? (contains? following user-id)]
(form-to [:post (follow-url user (not following?))]
[:input.following {:type "checkbox" :checked following?}]
- [:span.following (when following? "yes")]))))
+ [:span.following (when following? "yes")]))
+ [:span.following "me"]))
(defn generate-user-list [user-set table-name]
- (let [[user-id following]
- (when (session/session-get :user)
- (with-user [{:keys [_id following]}]
- [_id (set following)]))]
+ (let [[user-id following] (if-user [{:keys [_id following]}]
+ [_id (set following)])]
(list
[:br]
[:table.my-table {:id table-name}
@@ -134,18 +133,18 @@
user-set)])))
(defn generate-datatable-users-list [user-set]
- (let [[user-id following]
- (when (session/session-get :user)
- (with-user [{:keys [_id following]}]
- [_id (set following)]))]
- (into [] (map-indexed (fn [rownum {:keys [_id email position rank user contributor solved]}]
- [rank
- (str
- (html (gravatar-img {:email email :class "gravatar"}))
- (html [:a.user-profile-link {:href (str "/user/" user)} user (when contributor [:span.contributor " *"])]))
- (count solved)
- (html (following-checkbox user-id following _id user))])
- user-set))))
+ (let [[user-id following] (if-user [{:keys [_id following]}]
+ [_id (set following)])]
+ (map-indexed
+ (fn [rownum {:keys [_id email position rank user contributor solved]}]
+ [rank
+ (html (list
+ (gravatar-img {:email email :class "gravatar"})
+ [:a.user-profile-link {:href (str "/user/" user)}
+ user (when contributor [:span.contributor " *"])]))
+ (count solved)
+ (html (following-checkbox user-id following _id user))])
+ user-set)))
(def-page all-users-page []
{:title "All 4Clojure Users"
@@ -201,15 +200,14 @@
:class "user-profile-img"
:default "images/gus-of-disapproval.png"})]
[:div.user-profile-name page-title]
- (if (session/session-get :user)
- (with-user [{:keys [_id following]}]
- (if (not= _id user-id)
- (let [[url label] (if (some #{user-id} following)
- ["unfollow" "Unfollow"]
- ["follow" "Follow"])]
- (form-to [:post (str "/user/" url "/" username)]
- [:button.user-follow-button {:type "submit"} label]))
- [:div {:style "clear: right; margin-bottom: 10px;"} "&nbsp;"]))
+ (if-user [{:keys [_id following]}]
+ (if (not= _id user-id)
+ (let [[url label] (if (some #{user-id} following)
+ ["unfollow" "Unfollow"]
+ ["follow" "Follow"])]
+ (form-to [:post (str "/user/" url "/" username)]
+ [:button.user-follow-button {:type "submit"} label]))
+ [:div {:style "clear: right; margin-bottom: 10px;"} "&nbsp;"])
[:div {:style "clear: right; margin-bottom: 10px;"} "&nbsp;"])
[:hr]
[:table
@@ -248,62 +246,46 @@
"next-action" (follow-url username (not follow?))
"next-label" (if follow? "Unfollow" "Follow")}))
-(defn set-disable-codebox [disable-flag]
- (with-user [{:keys [_id]}]
- (update! :users
- {:_id _id}
- {:$set {:disable-code-box (boolean disable-flag)}})
- (response/redirect "/problems")))
-
-(defn set-hide-solutions [hide-flag]
- (with-user [{:keys [_id]}]
- (update! :users
- {:_id _id}
- {:$set {:hide-solutions (boolean hide-flag)}})
- (response/redirect "/problems")))
-
-(defn datatable-paging [users start length]
+(defn datatable-paging [start length users]
(take length (drop start users)))
-(defn datatable-sort-cols [users sort-col]
- (case sort-col
- 0 (sort-by :rank users)
- 1 (sort-by :user users)
- 2 (sort-by (comp :solved count) users)
- users))
+(let [column-sorts [:rank :user (comp count :solved)]]
+ (defn datatable-sort-cols [sort-col users]
+ (if-let [sort-fn (get column-sorts sort-col)]
+ (sort-by sort-fn users)
+ users)))
-(defn datatable-sort-dir [users sort-dir]
+(defn datatable-sort-dir [sort-dir users]
(if (= sort-dir "asc")
users
(reverse users)))
-(defn datatable-sort [users sort-col sort-dir]
- (-> users (datatable-sort-cols sort-col) (datatable-sort-dir sort-dir)))
+(defn datatable-sort [sort-col sort-dir users]
+ (->> users (datatable-sort-cols sort-col) (datatable-sort-dir sort-dir)))
-(defn datatable-filter [users str]
- (if str
- (filter #(< -1 (.indexOf (if (:user %) (:user %) "") str)) users)
+(defn datatable-filter [search users]
+ (if search
+ (filter #(.contains (:user % "") search) users)
users))
-(defn datatable-process [users params]
+(defn datatable-process [params users]
(let [display-start (Integer. (params :iDisplayStart))
display-length (Integer. (params :iDisplayLength))
sort-col (Integer. (params :iSortCol_0))
sort-dir (params :sSortDir_0)
search-str (params :sSearch)]
- (-> users
+ (->> users
(datatable-sort sort-col sort-dir)
(datatable-paging display-start display-length)
generate-datatable-users-list)))
(defn user-datatable-query [params]
- (let [
- ranked-users (get-ranked-users)
+ (let [ranked-users (get-ranked-users)
search-str (params :sSearch)
- filtered-users (datatable-filter ranked-users search-str)
+ filtered-users (datatable-filter search-str ranked-users)
page-users (datatable-process
- filtered-users
- params)]
+ params
+ filtered-users)]
{:sEcho (params :sEcho)
:iTotalRecords (str (count ranked-users))
:iTotalDisplayRecords (str (count filtered-users))
View
25 src/foreclojure/utils.clj
@@ -122,10 +122,27 @@
(from-mongo
(fetch-one :users :where {:user username})))
-(defmacro with-user [[user-binding] & body]
- `(if-let [username# (session/session-get :user)]
- (let [~user-binding (get-user username#)]
- ~@body)
+(defmacro if-user
+ "Look for a user with the given username in the database, let-ing it
+ to the supplied binding and executing the then clause. If no such user
+ can be found, evaluate the else clause.
+
+ username defaults to the current value of (session-get :user) if not
+ specified. Callers need not verify that username is non-nil: that is
+ done for you before consulting the database."
+ ([[user-binding username] then]
+ `(if-user ~[user-binding username] ~then nil))
+ ([[user-binding username] then else]
+ (let [userexpr (or username `(session/session-get :user))]
+ `(let [username# ~userexpr]
+ (if-let [~user-binding (and username#
+ (get-user username#))]
+ ~then
+ ~else)))))
+
+(defmacro with-user [[binding expr] & body]
+ `(if-user [~binding ~expr]
+ (do ~@body)
[:span.error "You must " (login-link) " to do this."]))
(defn flash-fn [type]
Please sign in to comment.
Something went wrong with that request. Please try again.