aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app/api.clj6
-rw-r--r--src/app/handler.clj19
-rw-r--r--src/app/rpc.cljs17
-rw-r--r--src/index.cljs.hl73
4 files changed, 115 insertions, 0 deletions
diff --git a/src/app/api.clj b/src/app/api.clj
new file mode 100644
index 0000000..e83f187
--- /dev/null
+++ b/src/app/api.clj
@@ -0,0 +1,6 @@
+(ns app.api
+ (:require [castra.core :refer [defrpc]]
+ [simpledb.core :as db]))
+
+(defrpc get-scoreboard []
+ (db/get :scoreboard))
diff --git a/src/app/handler.clj b/src/app/handler.clj
new file mode 100644
index 0000000..a5878b5
--- /dev/null
+++ b/src/app/handler.clj
@@ -0,0 +1,19 @@
+(ns app.handler
+ (:require [castra.middleware :as castra]
+ [compojure.core :as c]
+ [compojure.route :as route]
+ [ring.middleware.defaults :as d]
+ [ring.util.response :as response]
+ [simpledb.core :as db]))
+
+(c/defroutes app-routes
+ (c/GET "/" req (response/content-type (response/resource-response "index.html") "text/html"))
+ (route/resources "/" {:root ""}))
+
+(def app
+ (-> app-routes
+ (castra/wrap-castra 'app.api)
+ (castra/wrap-castra-session "a 16-byte secret")
+ (d/wrap-defaults d/api-defaults)))
+
+(db/init)
diff --git a/src/app/rpc.cljs b/src/app/rpc.cljs
new file mode 100644
index 0000000..464809c
--- /dev/null
+++ b/src/app/rpc.cljs
@@ -0,0 +1,17 @@
+(ns app.rpc
+ (:require-macros
+ [javelin.core :refer [defc defc=]])
+ (:require
+ [javelin.core]
+ [castra.core :refer [mkremote]]))
+
+(defc scoreboard nil)
+(defc error nil)
+(defc loading [])
+
+(def get-scoreboard
+ (mkremote 'app.api/get-scoreboard scoreboard error loading))
+
+(defn init []
+ (get-scoreboard)
+ (js/setInterval get-scoreboard 1000))
diff --git a/src/index.cljs.hl b/src/index.cljs.hl
new file mode 100644
index 0000000..8ecbc8c
--- /dev/null
+++ b/src/index.cljs.hl
@@ -0,0 +1,73 @@
+(page "index.html"
+ (:require [app.rpc :as rpc]))
+
+(defc= scoreboard (merge (sorted-map) rpc/scoreboard))
+(defc= problems (mapcat (fn [[id person]]
+ (map (partial vector id) (:problems person)))
+ scoreboard))
+(defc= scores
+ (reverse (sort
+ (map (fn [[id person]]
+ [(apply
+ +
+ (concat
+ (map (fn [[prob state]]
+ (if (and
+ (= :solved state)
+ (not (contains? (:problems person) prob)))
+ 1
+ 0))
+ (:scores person))
+ (map (fn [prob]
+ (if (some (fn [[id2 person2]]
+ (and
+ (= :solved
+ (get (:scores person) prob))
+ (= :solved
+ (get (:scores person2) prob))
+ (not= id id2)))
+ scoreboard)
+ 1
+ 0))
+ (:problems person))))
+ id])
+ scoreboard))))
+
+(rpc/init)
+
+(html
+ (head
+ (link :rel "stylesheet" :type "text/css" :href "css/main.css")
+ (title "Potluck CTF"))
+ (body
+ (h1 "Potluck CTF")
+ (text "Login/Register?")
+ (h2 "Scoreboard")
+ (table
+ (thead
+ (tr
+ (th)
+ (th)
+ (loop-tpl :bindings [probs (cell= (partition-by first problems))]
+ (th :text (cell= (:name (get scoreboard
+ (first (first probs)))))
+ :colspan (cell= (count probs)))))
+ (tr
+ (th "Player")
+ (th "Score")
+ (loop-tpl :bindings [[owner name] problems]
+ (th :text name))))
+ (tbody
+ (loop-tpl :bindings [[score id] scores]
+ (let [player (cell= (get scoreboard id))]
+ (tr
+ (td :text (cell= (:name player)))
+ (td :text score)
+ (loop-tpl :bindings [[owner _name] problems]
+ (td :text (cell=
+ (name (get (:scores player)
+ _name
+ :unsolved))))))))
+ ))))
+
+;; vim: set expandtab ts=2 sw=2 filetype=clojure :