Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
179 lines (160 sloc) 6.29 KB
(ns foreclojure.problems
(:use (foreclojure utils
[social :only [tweet-link gist!]]
[feeds :only [create-feed]])
[clojail core testers]
(hiccup form-helpers page-helpers core)
[amalloy.utils.debug :only [?]]
(:require [sandbar.stateful-session :as session]
[clojure.string :as s]))
(def total-solved (agent 0))
(defn get-solved [user]
(:solved (from-mongo
(fetch-one :users
:where {:user user}
:only [:solved])))))
(defn get-problem [x]
(fetch-one :problems :where {:_id x})))
(defn get-problem-list []
(fetch :problems
:only [:_id :title :tags :times-solved]
:sort {:_id 1})))
(defn next-unsolved-problem [solved-problems]
(when-let [unsolved (->> (get-problem-list)
(remove (comp (set solved-problems) :_id))
(apply min-key :_id unsolved)))
(defn next-problem-link [completed-problem-id]
(when-let [{:keys [solved]} (get-user (session/session-get :user))]
(if-let [{:keys [_id title]} (next-unsolved-problem solved)]
(str "Now try <a href='/problem/" _id "'>" title "</a>!")
"You've solved them all! Come back later for more!")))
(defn get-recent-problems [n]
(map get-problem (map :_id (take-last n (get-problem-list)))))
(defn problem-feed [n]
(reduce (fn [feed v]
(conj feed [:item
[:guid (str "" (:_id v))]
[:title (:title v)]
[:description (:description v)]]))
(get-recent-problems n)))
(defn mark-completed [id code & [user]]
(let [user (or user (session/session-get :user))
gist-link (html [:div.share
[:a.novisited {:href "/share/code"} "Share"]
" this solution with your friends!"])
(if user
(when (not-any? #{id} (get-solved user))
(update! :users {:user user} {:$addToSet {:solved id}})
(update! :problems {:_id id} {:$inc {:times-solved 1}})
(send total-solved inc))
(str "Congratulations, you've solved the problem!"
"<br />" (next-problem-link id)))
"You've solved the problem! If you log in we can track your progress.")]
(session/session-put! :code [id code])
(flash-msg (str message " " gist-link) (str "/problem/" id))))
(def restricted-list '[use require in-ns future agent send send-off pmap pcalls])
(defn get-tester [restricted]
(into secure-tester (concat restricted-list (map symbol restricted))))
(def sb (sandbox*))
(defn run-code [id raw-code]
(let [code (.trim raw-code)
{:keys [tests restricted]} (get-problem id)
sb-tester (get-tester restricted)
this-url (str "/problem/" id)]
(session/flash-put! :code code)
(if (empty? code)
(flash-msg "Empty input is not allowed" this-url)
(loop [[test & more] tests
i 0]
(session/flash-put! :failing-test i)
(if-not test
(mark-completed id code)
(let [testcase (s/replace test "__" (str code))]
(if (sb sb-tester (safe-read testcase))
(recur more (inc i))
(flash-msg "You failed the unit tests." this-url)))))
(catch Exception e
(flash-msg (.getMessage e) this-url))))))
(def-page code-box [id]
(let [problem (get-problem (Integer. id))]
[:span {:id "prob-title"} (problem :title)]
[:div {:id "tags"} "Tags: "
(s/join " " (problem :tags))]
[:div {:id "prob-desc"}
(problem :description)[:br]
[:table {:class "testcases"}
(let [tests (:tests problem)]
(for [i (range (count tests))]
(let [f (session/flash-get :failing-test)]
(cond (or (nil? f) (> i f)) [:img {:src "/images/bluelight.png"}]
(= i f) [:img {:src "/images/redlight.png"}]
:else [:img {:src "/images/greenlight.png"}]))]
[:pre {:class "brush: clojure;gutter: false;toolbar: false;light: true"}
(nth tests i)]]]))]
(if-let [restricted (problem :restricted)]
[:div {:id "restrictions"}
[:u "Special Restrictions"] [:br]
(map (partial vector :li) restricted)])]
[:div.message (session/flash-get :message)]
[:b "Code which fills in the blank:" [:br]]]
(form-to [:post "/run-code"]
(text-area {:id "code-box"
:spellcheck "false"}
:code (session/flash-get :code))
(hidden-field :id id)
[:button.large {:id "run-button" :type "submit"} "Run"])]))
(def-page problem-page []
(link-to "/problems/rss" [:div {:class "rss"}])
[:th "Title"]
[:th "Tags"]
[:th "Times Solved"]
[:th "Solved?"]]]
(let [solved (get-solved (session/session-get :user))
problems (get-problem-list)]
(fn [x {:keys [title times-solved tags], id :_id}]
[:tr (row-class x)
[:a {:href (str "/problem/" id)}
(s/join " " (map #(str "<span class='tag'>" % "</span>")
[:td.centered (int times-solved)]
[:img {:src (if (contains? solved id)
(defroutes problems-routes
(GET "/problems" [] (problem-page))
(GET "/problem/:id" [id] (code-box id))
(GET "/problems/rss" [] (create-feed
"4Clojure: Recent Problems"
"Recent problems at"
(problem-feed 20)))
(POST "/run-code" {{:strs [id code]} :form-params}
(run-code (Integer. id) code)))
Jump to Line
Something went wrong with that request. Please try again.