Skip to content
Browse files

Merge branch 'release/1.5.3'

  • Loading branch information...
2 parents f0e1c24 + 86bf236 commit 05bec4e9cf6e25842ade5557a07b4f2572363a3b @amalloy amalloy committed
View
2 project.clj
@@ -1,4 +1,4 @@
-(defproject foreclojure "1.5.2.3"
+(defproject foreclojure "1.5.3"
:description "4clojure - a website for learning Clojure"
:dependencies [[clojure "1.2.1"]
[clojure-contrib "1.2.0"]
View
15 resources/public/css/style.css
@@ -199,9 +199,18 @@ img.gravatar{
#totalcount {
float: right;
- padding: 8px;
- font-size: 20px;
- background-color: aliceblue;
+ padding: 8px 8px 2px 8px;
+ margin: 0 0 10px 5px;
+ font-size: 25px;
+ line-height: 35px;
+ background-color: #eee;
+ border: 1px solid #aaa;
+ color: #000;
+ font-weight: normal;
+ font-family: Helvetica, Arial, Sans-serif;
+}
+#totalcount p {
+ margin: 0 0;
}
#footer{
View
BIN resources/public/images/flipCounter-medium.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
View
37 resources/public/script/foreclojure.js
@@ -1,9 +1,14 @@
+var updateProblemCountDelay = 4000; // milliseconds
+
$(document).ready(function() {
configureDataTables();
configureCodeBox();
configureGolf();
+ if($("#totalcount").length > 0)
+ configureCounter();
+
$("form#run-code button#approve-button").live("click", function(e) {
e.preventDefault();
if(confirm("Are you sure you want to mark this problem as approved?"))
@@ -305,3 +310,35 @@ function configureGolf(){
});
}
+
+function configureCounter() {
+ $("#totalcounter").html("");
+ $("#totalcounter").flipCounter({
+ number:parseInt($('#counter-value').val()),
+ numFractionalDigits:0,
+ digitClass:"counter-digit",
+ digitHeight:40,
+ digitWidth:22.5,
+ imagePath:"/images/flipCounter-medium.png",
+ easing: jQuery.easing.easeOutCubic
+ });
+ setTimeout("updateProblemCount()", updateProblemCountDelay);
+}
+
+function updateProblemCount() {
+ var updateDuration = updateProblemCountDelay > 2500 ? 2500 : (updateProblemCountDelay - 500);
+
+ if($("#totalcount").length > 0) {
+ $.get("/problems/solved", function(data) {
+ if($("#totalcounter").flipCounter("getNumber") != data) {
+ $("#totalcounter").flipCounter("stopAnimation")
+ $("#totalcounter").flipCounter("startAnimation", {
+ number: parseInt(data),
+ duration: updateDuration,
+ easing: jQuery.easing.easeOutCubic
+ });
+ }
+ });
+ setTimeout("updateProblemCount()", updateProblemCountDelay);
+ }
+}
View
205 resources/public/vendor/script/jquery.easing.1.3.js
@@ -0,0 +1,205 @@
+/*
+ * jQuery Easing v1.3 - http://gsgd.co.uk/sandbox/jquery/easing/
+ *
+ * Uses the built in easing capabilities added In jQuery 1.1
+ * to offer multiple easing options
+ *
+ * TERMS OF USE - jQuery Easing
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright © 2008 George McGinley Smith
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+*/
+
+// t: current time, b: begInnIng value, c: change In value, d: duration
+jQuery.easing['jswing'] = jQuery.easing['swing'];
+
+jQuery.extend( jQuery.easing,
+{
+ def: 'easeOutQuad',
+ swing: function (x, t, b, c, d) {
+ //alert(jQuery.easing.default);
+ return jQuery.easing[jQuery.easing.def](x, t, b, c, d);
+ },
+ easeInQuad: function (x, t, b, c, d) {
+ return c*(t/=d)*t + b;
+ },
+ easeOutQuad: function (x, t, b, c, d) {
+ return -c *(t/=d)*(t-2) + b;
+ },
+ easeInOutQuad: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t + b;
+ return -c/2 * ((--t)*(t-2) - 1) + b;
+ },
+ easeInCubic: function (x, t, b, c, d) {
+ return c*(t/=d)*t*t + b;
+ },
+ easeOutCubic: function (x, t, b, c, d) {
+ return c*((t=t/d-1)*t*t + 1) + b;
+ },
+ easeInOutCubic: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t*t + b;
+ return c/2*((t-=2)*t*t + 2) + b;
+ },
+ easeInQuart: function (x, t, b, c, d) {
+ return c*(t/=d)*t*t*t + b;
+ },
+ easeOutQuart: function (x, t, b, c, d) {
+ return -c * ((t=t/d-1)*t*t*t - 1) + b;
+ },
+ easeInOutQuart: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
+ return -c/2 * ((t-=2)*t*t*t - 2) + b;
+ },
+ easeInQuint: function (x, t, b, c, d) {
+ return c*(t/=d)*t*t*t*t + b;
+ },
+ easeOutQuint: function (x, t, b, c, d) {
+ return c*((t=t/d-1)*t*t*t*t + 1) + b;
+ },
+ easeInOutQuint: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
+ return c/2*((t-=2)*t*t*t*t + 2) + b;
+ },
+ easeInSine: function (x, t, b, c, d) {
+ return -c * Math.cos(t/d * (Math.PI/2)) + c + b;
+ },
+ easeOutSine: function (x, t, b, c, d) {
+ return c * Math.sin(t/d * (Math.PI/2)) + b;
+ },
+ easeInOutSine: function (x, t, b, c, d) {
+ return -c/2 * (Math.cos(Math.PI*t/d) - 1) + b;
+ },
+ easeInExpo: function (x, t, b, c, d) {
+ return (t==0) ? b : c * Math.pow(2, 10 * (t/d - 1)) + b;
+ },
+ easeOutExpo: function (x, t, b, c, d) {
+ return (t==d) ? b+c : c * (-Math.pow(2, -10 * t/d) + 1) + b;
+ },
+ easeInOutExpo: function (x, t, b, c, d) {
+ if (t==0) return b;
+ if (t==d) return b+c;
+ if ((t/=d/2) < 1) return c/2 * Math.pow(2, 10 * (t - 1)) + b;
+ return c/2 * (-Math.pow(2, -10 * --t) + 2) + b;
+ },
+ easeInCirc: function (x, t, b, c, d) {
+ return -c * (Math.sqrt(1 - (t/=d)*t) - 1) + b;
+ },
+ easeOutCirc: function (x, t, b, c, d) {
+ return c * Math.sqrt(1 - (t=t/d-1)*t) + b;
+ },
+ easeInOutCirc: function (x, t, b, c, d) {
+ if ((t/=d/2) < 1) return -c/2 * (Math.sqrt(1 - t*t) - 1) + b;
+ return c/2 * (Math.sqrt(1 - (t-=2)*t) + 1) + b;
+ },
+ easeInElastic: function (x, t, b, c, d) {
+ var s=1.70158;var p=0;var a=c;
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
+ return -(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
+ },
+ easeOutElastic: function (x, t, b, c, d) {
+ var s=1.70158;var p=0;var a=c;
+ if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
+ return a*Math.pow(2,-10*t) * Math.sin( (t*d-s)*(2*Math.PI)/p ) + c + b;
+ },
+ easeInOutElastic: function (x, t, b, c, d) {
+ var s=1.70158;var p=0;var a=c;
+ if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
+ if (a < Math.abs(c)) { a=c; var s=p/4; }
+ else var s = p/(2*Math.PI) * Math.asin (c/a);
+ if (t < 1) return -.5*(a*Math.pow(2,10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )) + b;
+ return a*Math.pow(2,-10*(t-=1)) * Math.sin( (t*d-s)*(2*Math.PI)/p )*.5 + c + b;
+ },
+ easeInBack: function (x, t, b, c, d, s) {
+ if (s == undefined) s = 1.70158;
+ return c*(t/=d)*t*((s+1)*t - s) + b;
+ },
+ easeOutBack: function (x, t, b, c, d, s) {
+ if (s == undefined) s = 1.70158;
+ return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
+ },
+ easeInOutBack: function (x, t, b, c, d, s) {
+ if (s == undefined) s = 1.70158;
+ if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
+ return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
+ },
+ easeInBounce: function (x, t, b, c, d) {
+ return c - jQuery.easing.easeOutBounce (x, d-t, 0, c, d) + b;
+ },
+ easeOutBounce: function (x, t, b, c, d) {
+ if ((t/=d) < (1/2.75)) {
+ return c*(7.5625*t*t) + b;
+ } else if (t < (2/2.75)) {
+ return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
+ } else if (t < (2.5/2.75)) {
+ return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
+ } else {
+ return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
+ }
+ },
+ easeInOutBounce: function (x, t, b, c, d) {
+ if (t < d/2) return jQuery.easing.easeInBounce (x, t*2, 0, c, d) * .5 + b;
+ return jQuery.easing.easeOutBounce (x, t*2-d, 0, c, d) * .5 + c*.5 + b;
+ }
+});
+
+/*
+ *
+ * TERMS OF USE - EASING EQUATIONS
+ *
+ * Open source under the BSD License.
+ *
+ * Copyright © 2001 Robert Penner
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * Neither the name of the author nor the names of contributors may be used to endorse
+ * or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
+ * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
View
1 resources/public/vendor/script/jquery.flipCounter.1.1.pack.js
@@ -0,0 +1 @@
+eval(function(p,a,c,k,e,d){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('(e($){$.2m.D=e(M){g W=m;g 18=m;g f=m;g 1M={h:0,1V:1,1r:0,V:\'1K-X\',Q:\'1K-w\',1w:2N,p:2G,1v:\'2H/D-2u.2C\',G:1F,z:2D,F:m,B:m,E:m,T:m};g 16={1I:e(k){n o.C(e(){f=$(o);g 1x=$.1y(1M,k);g 1z=f.y(\'D\');k=$.1y(1z,1x);f.y(\'D\',k);l(k.h===m||k.h==0){(1b()!==m)?k.h=1b():k.h=0;j(\'h\',k.h)}j(\'H\',m);f.1f(\'1e\',e(1i,k){1X(k)});f.1f(\'1a\',e(1i){1D()});f.1f(\'1j\',e(1i){1p()});1Q();O()})},2B:e(w){n o.C(e(){f=$(o);j(\'h\',w);O()})},2A:e(w){n o.C(e(){f=$(o);j(\'h\',w);O()})},2v:e(){g A=m;o.C(e(){f=$(o);A=a(\'h\')});n A},1e:e(k){n o.C(e(){f=$(o);f.1c(\'1e\',k)})},1j:e(){n o.C(e(){f=$(o);f.1c(\'1j\')})},1a:e(){n o.C(e(){f=$(o);f.1c(\'1a\')})}};l(16[M]){n 16[M].1n(o,2b.24.27.15(1G,1))}I l(v M===\'2l\'||!M){n 16.1I.1n(o,1G)}I{$.1d(\'2k \'+M+\' 2i 1S 2g 2h 1h.D\')}e a(Y){g y=f.y(\'D\');g w=y[Y];l(v w!==\'1m\'){n w}n m}e j(Y,w){g y=f.y(\'D\');y[Y]=w;f.y(\'D\',y)}e 1P(){l(f.R(\'[U="\'+a(\'Q\')+\'"]\').S<1){f.2p(\'<2n 2o="2f" U="\'+a(\'Q\')+\'" w="\'+a(\'h\')+\'" />\')}g P=1l();g Z=19().S;2e(Z!=P){l(Z>P){f.25(\'<1E 23="\'+a(\'V\')+\'" 1N="\'+W+18[\'0\']+\'">0</1E>\')}I l(Z<P){f.R(\'.\'+a(\'V\')+\':26-28(1)\').2d()}P=1l()}}e O(){1P();g h=19();g 1O=1k();g 1g=0;$.C(1O,e(2Y,w){X=h.1t().2O(1g);$(o).2t(\'1N\',W+18[X]);$(o).1B(X.2K(\' \',\'&2L;\').1t());1g++});1Z()}e 1Q(){W="2W:"+a(\'1w\')+"r;2X:"+a(\'p\')+"r;q-2V:2U(\'"+a(\'1v\')+"\');q-1R:2T-1R;1B-2I: -2y;2z:2x-2w;";18={\'1\':\'q-s: \'+a(\'p\')*0+\'r u;\',\'2\':\'q-s: -\'+a(\'p\')*1+\'r u;\',\'3\':\'q-s: -\'+a(\'p\')*2+\'r u;\',\'4\':\'q-s: -\'+a(\'p\')*3+\'r u;\',\'5\':\'q-s: -\'+a(\'p\')*4+\'r u;\',\'6\':\'q-s: -\'+a(\'p\')*5+\'r u;\',\'7\':\'q-s: -\'+a(\'p\')*6+\'r u;\',\'8\':\'q-s: -\'+a(\'p\')*7+\'r u;\',\'9\':\'q-s: -\'+a(\'p\')*8+\'r u;\',\'0\':\'q-s: -\'+a(\'p\')*9+\'r u;\',\'.\':\'q-s: -\'+a(\'p\')*10+\'r u;\',\'-\':\'q-s: -\'+a(\'p\')*11+\'r u;\',\',\':\'q-s: -\'+a(\'p\')*12+\'r u;\',\' \':\'q-s: -\'+a(\'p\')*13+\'r u;\'}}e 1k(){n f.R(\'.\'+a(\'V\'))}e 1l(){n 1k().S}e 1b(){g A=2J(f.R(\'[U="\'+a(\'Q\')+\'"]\').A());l(A==A==m)n m;n A}e 1Z(){f.R(\'[U="\'+a(\'Q\')+\'"]\').A(a(\'h\'))}e 19(){g h=a(\'h\');l(v h!==\'h\'){$.1d(\'2Q 1u 2M 2P-2q w.\');n\'0\'}g N=\'\';l(a(\'T\')){l($.1W){N=$.1W(h,a(\'T\'))}I{$.1d(\'22 21 1h 1Y 20 1S 2j. 2s 1Y 20 29 1u 2c 2a T 2R.\')}}I{l(h>=0){g 1U=a(\'1V\');g 1T=1U-h.1q().1t().S;2S(g i=0;i<1T;i++){N+=\'0\'}N+=h.1q(a(\'1r\'))}I{N=\'-\'+2F.2E(h.1q(a(\'1r\')))}}n N}e 1X(k){l(v k==\'1m\'&&m==a(\'H\'))n m;l(v k!==\'1m\'){l(v k.G==\'e\')j(\'G\',k.G);l(v k.F==\'e\')j(\'F\',k.F);l(v k.B==\'e\')j(\'B\',k.B);l(v k.E==\'e\')j(\'E\',k.E);l(v k.z==\'h\')j(\'z\',k.z)}l(a(\'1s\')===K){j(\'1s\',m);j(\'H\',K);j(\'17\',1A(1o,1))}I{j(\'L\',a(\'h\'));j(\'14\',k.h);j(\'J\',0);j(\'z\',a(\'z\')/10); j(\'H\',K);j(\'17\',1A(1o,1))}g F=a(\'F\');l(v F==\'e\')F.15(f,f)}e 1o(){g J=a(\'J\');g L=a(\'L\');g 1C=a(\'14\')-L;g z=a(\'z\');g G=a(\'G\');g 1L=G.1n(f,[m,J,L,1C,z]);j(\'h\',1L);O();l(J>=z){1p()}j(\'J\',J+1)}e 1p(){l(K!==a(\'H\'))n m;1H(a(\'17\'));j(\'h\',a(\'14\'));j(\'L\',1J);j(\'14\',1J);j(\'2r\',0);j(\'H\',m);g B=a(\'B\');l(v B==\'e\')B.15(f,f)}e 1D(){l(K!==a(\'H\'))n m;j(\'1s\',K);1H(a(\'17\'));g E=a(\'E\');l(v E==\'e\')E.15(f,f)}e 1F(x,t,b,c,d){n t/d*c+b}}})(1h);',62,185,'||||||||||_getOption||||function|obj|var|number||_setOption|options|if|false|return|this|digitWidth|background|px|position||0px|typeof|value||data|duration|val|onAnimationStopped|each|flipCounter|onAnimationPaused|onAnimationStarted|easing|animating|else|time|true|start_number|method|str_number|_renderCounter|digits_length|counterFieldName|children|length|formatNumberOptions|name|digitClass|style_digit|digit|option|num_digits_needed|||||end_number|call|methods|interval|style_character|_getNumberFormatted|pauseAnimation|_getCounterValue|trigger|error|startAnimation|bind|pos|jQuery|event|stopAnimation|_getDigits|_getDigitsLength|undefined|apply|_doAnimation|_stopAnimation|toFixed|numFractionalDigits|paused|toString|to|imagePath|digitHeight|new_options|extend|old_options|setInterval|text|number_change|_pauseAnimation|span|_noEasing|arguments|clearInterval|init|null|counter|new_num|defaults|style|digits|_setupCounter|_setupStyles|repeat|not|num_extra_zeros|num_integral_digits|numIntegralDigits|formatNumber|_startAnimation|plugin|_setCounterValue|is|numberformatter|The|class|prototype|prepend|nth|slice|child|required|the|Array|use|remove|while|hidden|exist|on|does|loaded|Method|object|fn|input|type|append|numeric|timer|This|attr|medium|getNumber|block|inline|999em|display|setNumber|renderCounter|png|10000|abs|Math|30|img|indent|parseFloat|replace|nbsp|render|40|charAt|non|Attempting|setting|for|no|url|image|height|width|index'.split('|'),0,{}))
View
1 src/foreclojure/mongo.clj
@@ -31,6 +31,7 @@
(defn prepare-users []
(add-index! :users [:user] :unique true)
(add-index! :users [[:solved -1]])
+ (add-index! :users [:email])
(update! :users
{:user {:$in (:contributors config)}}
{:$set {:contributor true}}
View
5 src/foreclojure/problems.clj
@@ -574,9 +574,12 @@ Return a map, {:message, :error, :url, :num-tests-passed}."
(flash-msg "/problems" (str "Problem " id " was rejected and deleted.")))
(flash-error "/problems" "You do not have permission to access this page")))
+(defn total-solved-count []
+ (html (:total @solved-stats)))
+
(defroutes problems-routes
(GET "/problems" [] (problem-list-page))
- (GET "/problems/solved" [] (:total @solved-stats))
+ (GET "/problems/solved" [] (total-solved-count))
(GET "/problem/:id" [id]
(if-let [id-int (as-int id)]
(problem-page id-int)
View
8 src/foreclojure/register.clj
@@ -4,7 +4,7 @@
(:import [org.jasypt.util.password StrongPasswordEncryptor])
(:use [hiccup.form-helpers :only [form-to text-field password-field]]
[compojure.core :only [defroutes GET POST]]
- [foreclojure.utils :only [form-row assuming flash-error]]
+ [foreclojure.utils :only [form-row assuming flash-error plausible-email?]]
[foreclojure.template :only [def-page]]
[somnium.congomongo :only [insert! fetch-one]]))
@@ -36,8 +36,10 @@
"Password must be at least seven characters long",
(= pwd repeat-pwd)
"Passwords don't match",
- (not (empty? email))
- "Please enter a valid email address"]
+ (plausible-email? email)
+ "Please enter a valid email address"
+ (nil? (fetch-one :users :where {:email email}))
+ "User with this email address already exists"]
(do
(insert! :users
{:user lower-user
View
10 src/foreclojure/settings.clj
@@ -3,7 +3,7 @@
[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 with-user form-row assuming send-email login-url plausible-email?]]
[foreclojure.template :only [def-page content-page]]
[foreclojure.users :only [disable-codebox? hide-solutions? gravatar-img]]
[compojure.core :only [defroutes GET POST]]
@@ -83,8 +83,10 @@
(or (empty? new-pwd)
(.checkPassword encryptor old-pwd pwd))
"Current password incorrect"
- (not (empty? email))
- "Please enter a valid email address"]
+ (plausible-email? email)
+ "Please enter a valid email address"
+ (nil? (fetch-one :users :where {:email email :user {:$ne user}}))
+ "User with this email address already exists"]
(do
(update! :users {:user user}
{:$set {:pwd (if (not-empty new-pwd) new-pwd-hash pwd) :user new-lower-user :email email
@@ -98,4 +100,4 @@
(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)))
+ (do-update-settings! new-username old-pwd pwd repeat-pwd email disable-codebox hide-solutions)))
View
7 src/foreclojure/static.clj
@@ -3,7 +3,8 @@
[foreclojure.problems :only [solved-stats]]
[foreclojure.config :only [repo-url]]
[foreclojure.ring-utils :only [static-url]]
- [foreclojure.template :only [def-page]]))
+ [foreclojure.template :only [def-page]]
+ [hiccup.form-helpers :only [hidden-field]]))
(def df
(let [df (java.text.DecimalFormat.)
@@ -18,7 +19,9 @@
:content
[:div#welcome
[:div#totalcount
- (.format df (:total @solved-stats)) " problems solved and counting!"]
+ (hidden-field :counter-value (:total @solved-stats))
+ [:p
+ [:span#totalcounter (.format df (:total @solved-stats))] " problems solved and counting!"]]
[:div
[:h3 "What is 4Clojure?"]
[:p "4Clojure is a resource to help fledgling clojurians learn the language through interactive problems. The first few problems are easy enough that even someone with no prior experience should find the learning curve forgiving. See 'Help' for more information."]]
View
2 src/foreclojure/template.clj
@@ -21,7 +21,7 @@
[:style {:type "text/css"}
".syntaxhighlighter { overflow-y: hidden !important; }"]
(css "css/style.css" "css/demo_table.css" "css/shCore.css" "css/shThemeDefault.css")
- (js "vendor/script/jquery-1.5.2.min.js" "vendor/script/jquery.dataTables.min.js")
+ (js "vendor/script/jquery-1.5.2.min.js" "vendor/script/jquery.dataTables.min.js" "vendor/script/jquery.flipCounter.1.1.pack.js" "vendor/script/jquery.easing.1.3.js")
(js "script/foreclojure.js")
(js "vendor/script/xregexp.js" "vendor/script/shCore.js" "vendor/script/shBrushClojure.js")
(js "vendor/script/ace/ace.js" "vendor/script/ace/mode-clojure.js")
View
3 src/foreclojure/utils.clj
@@ -95,6 +95,9 @@
(link-to (login-url location)
text))))
+(defn plausible-email? [address]
+ (re-find #"^.+@\S+\.\S{2,4}$" address))
+
;; Assuming that it will always need SSL. Will make it more flexible later.
(defn send-email [{:keys [from to subject html text reply-to]}]
(let [{:keys [host port user pass]} config

0 comments on commit 05bec4e

Please sign in to comment.
Something went wrong with that request. Please try again.