Skip to content

Commit

Permalink
Merge further work into release branch
Browse files Browse the repository at this point in the history
  • Loading branch information
amalloy committed May 16, 2011
2 parents 5c2e47d + 0c9c6de commit 49fc87a
Show file tree
Hide file tree
Showing 7 changed files with 140 additions and 73 deletions.
20 changes: 16 additions & 4 deletions resources/public/css/style.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ body {
font-size: 12px;
font-family: Verdana, Arial, Helvetica, SunSans-Regular, Sans-Serif;
color:#564b47;
margin: 20px 140px 20px 140px;
margin: 20px 0;
text-align: center;
}

Expand Down Expand Up @@ -42,8 +42,8 @@ img {border:none}
}

#content {
width: 95%;
margin: 15px;
width: 85%;
margin: 15px auto;
padding: 15px 0px 15px 0px;
text-align: left;
background-color: #fff;
Expand All @@ -64,8 +64,9 @@ img {border:none}
}

#top {
width: 95%;
width: 85%;
padding: 15px 0px 15px 0px;
margin: 0 auto;
}
div#top a {
border: 0;
Expand All @@ -82,6 +83,17 @@ h3 {
color: #fff;
}

#lower-menu {
background-color: darkblue;
padding: 10px 5px 10px;
color: #7CFC00;
}
#lower-menu a:link {color: #fff;}
#lower-menu a:visited {color: #fff;}
#lower-menu a:active {color: #445599;}
#lower-menu a:hover {color: #7CFC00;}
#lower-menu a {text-decoration: none; font-size: 1.1em; font-weight:bold; padding: 0 20px;}

a.novisited {color: #00e;}

#menu a:link {color: #fff;}
Expand Down
14 changes: 12 additions & 2 deletions resources/public/vendor/script/foreclojure.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ $(document).ready(function() {
}
});

$("form#run-code button#edit-button").live("click", function(e) {
e.preventDefault();
$(this).parents("form").attr("action", "/problem/edit").submit();
});

});


Expand All @@ -29,6 +34,7 @@ function configureDataTables(){
null,
null,
null,
null,
null
]
} );
Expand Down Expand Up @@ -67,13 +73,17 @@ function configureCodeBox(){
editor.setTheme("ace/theme/textmate");

var ClojureMode = require("ace/mode/clojure").Mode;
editor.getSession().setMode(new ClojureMode());
var session = editor.getSession();
session.setMode(new ClojureMode());
session.setUseSoftTabs(true);
session.setTabSize(2);

document.getElementById('editor').style.fontSize='13px';
$("#run-button").click(function(){
var text = editor.getSession().getValue();
$('#code').val(text);
});
}
}
}

function configureGolf(){
Expand Down
17 changes: 16 additions & 1 deletion src/foreclojure/data_set.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
(defn load-problems []
(do
(mongo! :db :mydb)

db.seq.insert({"_id":"problems", "seq":new NumberLong(86)});

(insert! :problems
{:_id 1
:title "Nothing but the Truth"
Expand Down Expand Up @@ -978,8 +981,20 @@ number of prime numbers."
"(= (__ #{1 2 3})\n #{#{} #{1} #{2} #{3} #{1 2} #{1 3} #{2 3} #{1 2 3}})"
"(= (count (__ (into #{} (range 10)))) 1024)"]})

(insert! :problems
(insert! :problems
{:_id 86
:title "Happy numbers"
:times-solved 0
:description "Happy numbers are positive integers that follow a particular formula: take each individual digit, square it, and then sum the squares to get a new number. Repeat with the new number and eventually, you might get to a number whose squared sum is 1. This is a happy number. An unhappy number (or sad number) is one that loops endlessly. Write a function that determines if a number is happy or not."
:tags ["easy" "math"]
:approved true
:tests ["(= (__ 7) true)"
"(= (__ 986543210) true)"
"(= (__ 2) false)"
"(= (__ 3) false)"]})

(insert! :problems
{:_id 87
:title "Create an Equation"
:times-solved 0
:description "Write a function which takes three or more integers. Using these integers, your function should generate clojure code representing an equation. The following rules for the equation must be satisfied:\n\n 1. All integers must be used once and only once.\n 2. The order of the integers must be maintained when reading the equation left-to-right.\n 3. The only functions you may use are +, *, or =.\n 4. The equation must use the minimum number of parentheses.\n 5. If no satisfying equation exists, return nil."
Expand Down
13 changes: 7 additions & 6 deletions src/foreclojure/graphs.clj
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,16 @@
chart (chart/histogram chart-data
:title (str "League scores: problem " id)
:x-label "Solution length"
:y-label "How often")]
:y-label "How often"
:nbins 25)]
(when best
(chart/add-pointer chart best (freqs best 0)
:text "best"
:angle :se))
(chart/add-pointer chart best 0
:text "your best"
:angle :ne))
(when (and curr (not= curr best))
(chart/add-pointer chart curr (freqs curr 0)
(chart/add-pointer chart curr 0
:text "this"
:angle :se))
:angle :ne))
(when-not (> (count freqs) 1)
(chart/add-text chart best (freqs best 0)
"Very little golfing data - chart may suck"))
Expand Down
16 changes: 1 addition & 15 deletions src/foreclojure/login.clj
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
[amalloy.utils :only [rand-in-range]]
somnium.congomongo)
(:require [sandbar.stateful-session :as session]
[ring.util.response :as response])
(:import org.apache.commons.mail.SimpleEmail))
[ring.util.response :as response]))

(def-page my-login-page [location]
(when location
Expand Down Expand Up @@ -102,19 +101,6 @@

(def pw-chars "abcdefghijklmnopqrstuvxyzABCDEFGHIJKLMNOPQRSTUVWXY1234567890")

;; Assuming that it will always need SSL. Will make it more flexible later.
(defn send-email [{:keys [from to subject body]}]
(let [{:keys [host port user pass]} config
base (doto (SimpleEmail.)
(.setHostName host)
(.setSSL true)
(.setFrom from)
(.setSubject subject)
(.setMsg body)
(.setAuthentication user pass))]
(doseq [person to] (.addTo base person))
(.send base)))

(defn do-reset-password! [email]
(if-let [{id :_id, name :user} (fetch-one :users
:where {:email email}
Expand Down
99 changes: 64 additions & 35 deletions src/foreclojure/problems.clj
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@
[amalloy.utils :only [defcomp]]
compojure.core)
(:require [sandbar.stateful-session :as session]
[clojure.string :as s]))
[clojure.string :as s]
(ring.util [response :as response])))

(def total-solved (agent 0))

Expand All @@ -28,10 +29,6 @@
:where criteria
:sort {:_id 1}))))

(defn get-next-id []
(from-mongo
(inc (count (fetch :problems)))))

(defn next-unsolved-problem [solved-problems]
(when-let [unsolved (->> (get-problem-list)
(remove (comp (set solved-problems) :_id))
Expand Down Expand Up @@ -210,12 +207,12 @@
[:div.message
[:span#message-text (session/flash-get :message)]]
(render-golf-score)]
(form-to [:post *url*]
(form-to {:id "run-code"} [:post *url*]
[:br]
[:br]
[:p#instruct "Code which fills in the blank: "]
(text-area {:id "code-box"
:spellcheck "false"}
` :spellcheck "false"}
:code (session/flash-get :code))
[:div#golfgraph
(render-golf-chart)]
Expand All @@ -224,8 +221,8 @@
[:button.large {:id "run-button" :type "submit"} "Run"]
(when-not approved
[:span [:button.large {:id "reject-button"} "Reject"]
[:button.large {:id "approve-button"} "Approve"]]))
]))
[:button.large {:id "edit-button"} "Edit"]
[:button.large {:id "approve-button"} "Approve"]]))]))

(def-page problem-page []
[:div.message (session/flash-get :message)]
Expand All @@ -236,19 +233,21 @@
[:tr
[:th "Title"]
[:th "Tags"]
[:th "Submitted By"]
[:th "Times Solved"]
[:th "Solved?"]]]
(let [solved (get-solved (session/session-get :user))
problems (get-problem-list)]
(map-indexed
(fn [x {:keys [title times-solved tags], id :_id}]
(fn [x {:keys [title times-solved tags user], id :_id}]
[:tr (row-class x)
[:td.titlelink
[:a {:href (str "/problem/" id)}
title]]
[:td.centered
(s/join " " (map #(str "<span class='tag'>" % "</span>")
tags))]
[:td.centered user]
[:td.centered (int times-solved)]
[:td.centered
[:img {:src (if (contains? solved id)
Expand Down Expand Up @@ -287,42 +286,59 @@

(def-page problem-submission-page []
[:div.instructions
[:p "Thanks for choosing to submit a problem. Please make sure that you own the rights to the code you are submitting and that you wouldn't
mind having us use the code as a 4clojure problem."]]
[:p "Thanks for choosing to submit a problem. Please make sure that you own the rights to the code you are submitting and that you wouldn't mind having us use the code as a 4clojure problem."]]
(form-to {:id "problem-submission"} [:post "/problems/submit"]
(hidden-field :author (session/flash-get :author))
(hidden-field :prob-id (session/flash-get :prob-id))
(label :title "Problem Title")
(text-field :title)
(text-field :title (session/flash-get :title))
(label :tags "Tags (space separated)")
(text-field :tags)
(text-field :tags (session/flash-get :tags))
(label :description "Problem Description")
(text-area {:id "problem-description"} :description)
(text-area {:id "problem-description"} :description (session/flash-get :description))
[:br]
(label :code-box "Problem test cases. Use two underscores (__) for user input. Multiple tests ought to be on one line each.")
(text-area {:id "code-box" :spellcheck "false"}
:code (session/flash-get :code))
:code (session/flash-get :tests))
[:p
[:button.large {:id "run-button" :type "submit"} "Submit"]])
)
[:button.large {:id "run-button" :type "submit"} "Submit"]]))

(defn create-problem
"create a user submitted problem"
[title tags description code]
[title tags description code id author]
(let [user (session/session-get :user)]
(if (can-submit? user)
(do
(mongo! :db :mydb)
(insert! :problems
{:_id (get-next-id)
:title title
:times-solved 0
:description description
:tags (s/split tags #"\s+")
:tests (s/split-lines code)
:user user
:approved false})
(let [prob-id
(if (nil? id)
(:seq (fetch-and-modify
:seqs
{:_id "problems"}
{:$inc {:seq 1}}))
id)]
(update! :problems
{:_id prob-id}
{:_id prob-id
:title title
:times-solved 0
:description description
:tags (s/split tags #"\s+")
:tests (s/split-lines code)
:user (if (empty? author) user author)
:approved false}))
(flash-msg "Thank you for submitting a problem! Be sure to check back to see it posted." "/problems"))
(flash-error "You are not authorized to submit a problem." "/problems"))))

(defn edit-problem [id]
(let [{:keys [title user tags description tests]} (get-problem id)]
(session/flash-put! :prob-id id)
(session/flash-put! :author user)
(session/flash-put! :title title)
(session/flash-put! :tags (apply str (interpose " " tags)))
(session/flash-put! :description description)
(session/flash-put! :tests (apply str (interpose "\n" tests)))
(response/redirect "/problems/submit")))

(defn approve-problem [id]
"take a user submitted problem and approve it"
(if (approver? (session/session-get :user))
Expand All @@ -334,27 +350,40 @@
(str "/problem/" id)))
(flash-error "You don't have access to this page" "/problems")))

(defn reject-problem [id]
(defn reject-problem [id reason]
"reject a user submitted problem by deleting it from the database"
(if (approver? (session/session-get :user))
(do
(let [{:keys [user title description tags tests]} (get-problem id)
email (:email (get-user user))]
(destroy! :problems
{:_id id})
;; TODO: email submitting user
(send-email
{:from "team@4clojure.com"
:to [email]
:subject "Problem rejected"
:body
(str "A problem you've submitted has been rejected, but don't get discouraged! Check out the reason below, and try again.\n\n"
"Title: " title "\n"
"Tags: " tags "\n"
"Description: " description "\n"
"Tests: " tests "\n"
"Rejection Reason: " reason)})
(flash-msg (str "Problem " id " was rejected and deleted.") "/problems"))
(flash-error "You do not have permission to access this page" "/problems")))

(defroutes problems-routes
(GET "/problems" [] (problem-page))
(GET "/problem/:id" [id] (code-box id))
(GET "/problems/submit" [] (problem-submission-page))
(POST "/problems/submit" [title tags description code]
(create-problem title tags description code))
(POST "/problems/submit" [prob-id author title tags description code]
(create-problem title tags description code (when prob-id (Integer. prob-id)) author))
(GET "/problems/unapproved" [] (unapproved-problems))
(POST "/problem/edit" [id]
(edit-problem (Integer. id)))
(POST "/problem/approve" [id]
(approve-problem (Integer. id)))
(POST "/problem/reject" [id]
(reject-problem (Integer. id)))
(reject-problem (Integer. id) "We didn't like your problem."))
(POST "/problem/:id" [id code]
(run-code (Integer. id) code))
(GET "/problems/rss" [] (create-feed
Expand Down
Loading

0 comments on commit 49fc87a

Please sign in to comment.