(ns user (:use clojure.contrib.sql compojure cache-dot-clj.cache utils)) (defstruct user-struct :nick :user_id :avatar :last-seen) (defn user-struct-from-session [session] (struct user-struct (session :nick) (session :user_id) (session :avatar) (System/currentTimeMillis))) (def *nick-regex* #"^[A-Za-z0-9\-_âˆb˚†]*$") (defn is-invalid-nick? [n] (cond (< (count n) 3) "NICK_TOO_SHORT" (> (count n) 16) "NICK_TOO_LONG" (not (re-matches *nick-regex* n)) "NICK_INVALID_CHARS")) ;;; User info cache (defn-cached fetch-nick-cached (lru-cache-strategy 2000) "Retrieves user info from database" [nick] (first (do-select ["SELECT * FROM users WHERE lower(nick) = ? LIMIT 1" (lower-case nick)]))) (def fetch-nick (comp fetch-nick-cached lower-case)) (defn-cached nick-from-user-id (lru-cache-strategy 10000) "Retrieves nick for user id" [uid] (:nick (first (do-select ["SELECT nick FROM users WHERE user_id = ? LIMIT 1" uid])))) (def fetch-user-id (comp fetch-nick nick-from-user-id)) (def user-id-from-nick (comp :user_id fetch-nick)) ;; user login (defn authorize-nick-hash [nick hash] (if-let [db-user (fetch-nick nick)] (and (= (db-user :hash) hash) db-user))) (defn update-nick-hash [nick hash] (do-update :users ["nick=?" nick] {:hash hash})) ;; user pw reset (defn reset-token [nick hash ts] (sha1-hash nick hash ts)) (defn reset-link [nick token ts] (url-params "http://dump.fm/reset" {"nick" nick "ts" ts "token" token})) (defn valid-reset-link? [nick token ts] (if-let [info (and nick (fetch-nick nick))] (and (= token (reset-token (info :nick) (info :hash) ts)) (>= ts (ms-ago (days 2)))))) ;; user db update & cache invalidation (defn update-user-info! [nick user-id attr val] (with-connection *db* (update-values "users" ["user_id = ?" user-id] {attr val})) (invalidate-cache fetch-nick-cached (lower-case nick)))