Merge remote-tracking branch 'refs/remotes/origin/develop'
Conflicts: src/clj/youyesyet/routes/services.clj
This commit is contained in:
commit
62ab37de47
52 changed files with 1922 additions and 484 deletions
|
|
@ -1,4 +1,6 @@
|
|||
(ns youyesyet.config
|
||||
(ns ^{:doc "Read configuration."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.config
|
||||
(:require [cprop.core :refer [load-config]]
|
||||
[cprop.source :as source]
|
||||
[mount.core :refer [args defstate]]))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
(ns youyesyet.db.core
|
||||
(ns ^{:doc "Database access functions."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.db.core
|
||||
(:require
|
||||
[cheshire.core :refer [generate-string parse-string]]
|
||||
[clojure.java.jdbc :as jdbc]
|
||||
|
|
@ -15,12 +17,10 @@
|
|||
Timestamp
|
||||
PreparedStatement]))
|
||||
|
||||
(def ^:dynamic *db* {:name "java:comp/env/jdbc/EmployeeDB"})
|
||||
;; (defstate ^:dynamic *db*
|
||||
;; :start (conman/connect! {:jdbc-url-env (env :database-url)
|
||||
;; :jdbc-url "jdbc:postgresql://127.0.0.1/youyesyet_dev?user=youyesyet&password=thisisnotsecure"
|
||||
;; :driver-class-name "org.postgresql.Driver"})
|
||||
;; :stop (conman/disconnect! *db*))
|
||||
(defstate ^:dynamic *db*
|
||||
:start (conman/connect! {:jdbc-url (env :database-url)
|
||||
:driver-class-name "org.postgresql.Driver"})
|
||||
:stop (conman/disconnect! *db*))
|
||||
|
||||
(conman/bind-connection *db* "sql/queries.sql")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
(ns youyesyet.db.schema
|
||||
(ns ^{:doc "Korma-flavour database setup, now obsolete but retained for documentation."
|
||||
:author "Simon Brooke"} youyesyet.db.schema
|
||||
(:require [clojure.java.jdbc :as sql]
|
||||
[korma.core :as kc]
|
||||
[youyesyet.db.core :as yyydb]))
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
(ns youyesyet.handler
|
||||
(ns ^{:doc "Handlers for starting and stopping the webapp."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.handler
|
||||
(:require [compojure.core :refer [routes wrap-routes]]
|
||||
[youyesyet.layout :refer [error-page]]
|
||||
[youyesyet.routes.authenticated :refer [authenticated-routes]]
|
||||
[youyesyet.routes.home :refer [home-routes]]
|
||||
[youyesyet.routes.oauth :refer [oauth-routes]]
|
||||
[compojure.route :as route]
|
||||
|
|
@ -10,6 +13,29 @@
|
|||
[clojure.tools.logging :as log]
|
||||
[youyesyet.config :refer [env]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.handler: handlers for starting and stopping the webapp.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(mount/defstate init-app
|
||||
:start ((or (:init defaults) identity))
|
||||
:stop ((or (:stop defaults) identity)))
|
||||
|
|
@ -38,6 +64,7 @@
|
|||
(wrap-routes middleware/wrap-csrf)
|
||||
(wrap-routes middleware/wrap-formats))
|
||||
#'oauth-routes
|
||||
#'authenticated-routes
|
||||
(route/not-found
|
||||
(:body
|
||||
(error-page {:status 404
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
(ns youyesyet.layout
|
||||
(ns^{:doc "Render web pages using Selmer tamplating markup."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.layout
|
||||
(:require [selmer.parser :as parser]
|
||||
[selmer.filters :as filters]
|
||||
[markdown.core :refer [md-to-html-string]]
|
||||
|
|
@ -12,6 +14,7 @@
|
|||
(parser/add-tag! :csrf-field (fn [_ _] (anti-forgery-field)))
|
||||
(filters/add-filter! :markdown (fn [content] [:safe (md-to-html-string content)]))
|
||||
|
||||
|
||||
(defn render
|
||||
"renders the HTML template located relative to resources/templates"
|
||||
[template & [params]]
|
||||
|
|
@ -26,6 +29,7 @@
|
|||
:version (System/getProperty "youyesyet.version"))))
|
||||
"text/html; charset=utf-8"))
|
||||
|
||||
|
||||
(defn error-page
|
||||
"error-details should be a map containing the following keys:
|
||||
:status - error status
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
(ns youyesyet.middleware
|
||||
(ns ^{:doc "Plumbing, mainly boilerplate from Luminus."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.middleware
|
||||
(:require [youyesyet.env :refer [defaults]]
|
||||
[clojure.tools.logging :as log]
|
||||
[youyesyet.layout :refer [*app-context* error-page]]
|
||||
|
|
|
|||
11
src/clj/youyesyet/routes/administrator.clj
Normal file
11
src/clj/youyesyet/routes/administrator.clj
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
(ns ^{:doc "Routes/pages available to administrators, only."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.routes.administrator
|
||||
(:require [clojure.java.io :as io]
|
||||
[clojure.walk :refer [keywordize-keys]]
|
||||
[compojure.core :refer [defroutes GET POST]]
|
||||
[noir.response :as nresponse]
|
||||
[noir.util.route :as route]
|
||||
[ring.util.http-response :as response]
|
||||
[youyesyet.layout :as layout]
|
||||
[youyesyet.db.core :as db]))
|
||||
75
src/clj/youyesyet/routes/authenticated.clj
Normal file
75
src/clj/youyesyet/routes/authenticated.clj
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
(ns ^{:doc "Routes/pages available to all authenticated users."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.routes.authenticated
|
||||
(:require [clojure.java.io :as io]
|
||||
[clojure.walk :refer [keywordize-keys]]
|
||||
[compojure.core :refer [defroutes GET POST]]
|
||||
[noir.response :as nresponse]
|
||||
[noir.util.route :as route]
|
||||
[ring.util.http-response :as response]
|
||||
[youyesyet.layout :as layout]
|
||||
[youyesyet.db.core :as db]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.routes.authenticated: routes and pages for authenticated users.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; This code adapted from http://www.luminusweb.net/docs#accessing_the_database
|
||||
|
||||
(defn post?
|
||||
"Return true if the argument is a ring request which is a post request"
|
||||
[request]
|
||||
true)
|
||||
|
||||
(defn canvasser-page
|
||||
"Process this canvasser request, and render the canvasser page"
|
||||
[request]
|
||||
(let [canvasser (if
|
||||
(:params request)
|
||||
(let [params (:params request)]
|
||||
(if (:id params)
|
||||
(if (post? request)
|
||||
(db/update-canvasser! params)
|
||||
(db/create-canvasser! params))
|
||||
(db/get-canvasser (:id params)))
|
||||
))]
|
||||
(layout/render
|
||||
"canvasser.html"
|
||||
{:title (if canvasser
|
||||
(str
|
||||
"Edit canvasser "
|
||||
(:fullname canvasser)
|
||||
" "
|
||||
(:email canvasser))
|
||||
"Add new canvasser")
|
||||
:canvasser canvasser
|
||||
:address (if (:address_id canvasser) (db/get-address (:address_id canvasser)))})))
|
||||
|
||||
(defn routing-page
|
||||
"Render the routing page, which offers routes according to the user's roles"
|
||||
[]
|
||||
(layout/render "routing.html"))
|
||||
|
||||
(defroutes authenticated-routes
|
||||
(GET "/edit-canvasser" request (canvasser-page request))
|
||||
(POST "/edit-canvasser" request (canvasser-page request))
|
||||
(GET "/routing" [] (routing-page)))
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
(ns youyesyet.routes.home
|
||||
(ns ^{:doc "Routes/pages available to unauthenticated users."
|
||||
:author "Simon Brooke"} youyesyet.routes.home
|
||||
(:require [clojure.walk :refer [keywordize-keys]]
|
||||
[noir.response :as nresponse]
|
||||
[noir.util.route :as route]
|
||||
|
|
@ -8,12 +9,37 @@
|
|||
[ring.util.http-response :as response]
|
||||
[clojure.java.io :as io]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.routes.home: routes and pages for unauthenticated users.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(defn app-page []
|
||||
(layout/render "app.html"))
|
||||
|
||||
|
||||
(defn about-page []
|
||||
(layout/render "about.html"))
|
||||
|
||||
|
||||
(defn call-me-page [request]
|
||||
(if
|
||||
request
|
||||
|
|
@ -25,28 +51,53 @@
|
|||
;; TODO: Issues need to be fetched from the database
|
||||
:concerns nil})))
|
||||
|
||||
|
||||
(defn roles-page [request]
|
||||
(let
|
||||
[session (:session request)
|
||||
username (:user session)
|
||||
user (if username (db-core/get-canvasser-by-username db-core/*db* {:username username}))
|
||||
roles (if user (db-core/get-roles-by-canvasser db-core/*db* {:canvasser (:id user)}))]
|
||||
(cond
|
||||
roles (layout/render "roles.html"
|
||||
{:title (str "Welcome " (:fullname user) ", what do you want to do?")
|
||||
:user user
|
||||
:roles roles})
|
||||
(empty? roles)(response/found "/app")
|
||||
true (assoc (response/found "/login") :session (dissoc session :user))
|
||||
)))
|
||||
|
||||
|
||||
(defn home-page []
|
||||
(layout/render "home.html" {:title "You Yes Yet?"}))
|
||||
|
||||
|
||||
(defn login-page
|
||||
"This is very temporary. We're going to do authentication by oauth."
|
||||
[request]
|
||||
(let [params (keywordize-keys (:form-params request))
|
||||
session (:session request)
|
||||
username (:username params)
|
||||
user (if username (db-core/get-canvasser-by-username db-core/*db* {:username username}))
|
||||
password (:password params)
|
||||
redirect-to (or (:redirect-to params) "app")]
|
||||
(if
|
||||
(and (= username "test") (= password "test"))
|
||||
(do
|
||||
(assoc (response/found redirect-to) :session (assoc session :user username)))
|
||||
(layout/render "login.html" {:title "Please log in" :redirect-to redirect-to}))))
|
||||
redirect-to (or (:redirect-to params) "roles")]
|
||||
(cond
|
||||
;; this is obviously, ABSURDLY, insecure. I don't want to put just-about-good-enough,
|
||||
;; it-will-do-for-now security in place; instead, I want this to be test code only
|
||||
;; until we have o-auth properly working.
|
||||
(and user (= username password))
|
||||
(assoc (response/found redirect-to) :session (assoc session :user username))
|
||||
user
|
||||
(layout/render "login.html" {:title (str "User " username " is unknown") :redirect-to redirect-to})
|
||||
true
|
||||
(layout/render "login.html" {:title "Please log in" :redirect-to redirect-to}))))
|
||||
|
||||
|
||||
(defroutes home-routes
|
||||
(GET "/" [] (home-page))
|
||||
(GET "/home" [] (home-page))
|
||||
(GET "/about" [] (about-page))
|
||||
(GET "/roles" request (route/restricted (roles-page request)))
|
||||
(GET "/app" [] (route/restricted (app-page)))
|
||||
(GET "/call-me" [] (call-me-page nil))
|
||||
(POST "/call-me" request (call-me-page request))
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
(ns youyesyet.routes.oauth
|
||||
(ns ^{:doc "OAuth authentication routes - not finished, does not work yet."
|
||||
:author "Simon Brooke"} youyesyet.routes.oauth
|
||||
(:require [compojure.core :refer [defroutes GET]]
|
||||
[ring.util.http-response :refer [ok found]]
|
||||
[clojure.java.io :as io]
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
(ns youyesyet.outqueue
|
||||
(ns ^{:doc "Queue of messages waiting to be sent to the server."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.outqueue
|
||||
(:require
|
||||
#?(:clj [clojure.core]
|
||||
:cljs [reagent.core :refer [atom]])))
|
||||
|
|
@ -41,6 +43,7 @@
|
|||
(reverse items)
|
||||
(list items))})))
|
||||
|
||||
|
||||
(defn add!
|
||||
"Add this item to the queue."
|
||||
[q item]
|
||||
|
|
@ -49,7 +52,9 @@
|
|||
(assoc a :items
|
||||
(cons item (:items a))))))
|
||||
|
||||
(defn q?
|
||||
|
||||
(defn queue?
|
||||
"True if x is a queue, else false."
|
||||
[x]
|
||||
(try
|
||||
(let [q (deref x)
|
||||
|
|
@ -61,21 +66,25 @@
|
|||
#?(:clj (print (.getMessage any))
|
||||
:cljs (js/console.log (str any))))))
|
||||
|
||||
|
||||
(defn peek
|
||||
"Look at the next item which could be removed from the queue."
|
||||
[q]
|
||||
(last (:items (deref q))))
|
||||
|
||||
|
||||
(defn locked?
|
||||
[q]
|
||||
(:locked (deref q)))
|
||||
|
||||
|
||||
(defn unlock!
|
||||
([q ]
|
||||
(unlock! q true))
|
||||
([q value]
|
||||
(swap! q (fn [a] (assoc a :locked (not (true? value)))))))
|
||||
|
||||
|
||||
(defn lock!
|
||||
[q]
|
||||
(unlock! q false))
|
||||
|
|
@ -86,6 +95,7 @@
|
|||
[q]
|
||||
(count (deref q)))
|
||||
|
||||
|
||||
(defn take!
|
||||
"Return the first item from the queue, rebind the queue to the remaining
|
||||
items. If the queue is empty return nil."
|
||||
|
|
@ -97,12 +107,13 @@
|
|||
(assoc (assoc a :items new-queue) :v item))))
|
||||
(:v (deref q)))
|
||||
|
||||
|
||||
(defn maybe-process-next
|
||||
"Apply this process, assumed to be a function of one argument, to the next
|
||||
item in the queue, if the queue is not currently locked; return the value
|
||||
returned by process."
|
||||
[q process]
|
||||
(if (and (q? q)(not (locked? q)))
|
||||
(if (and (queue? q)(not (locked? q)))
|
||||
(try
|
||||
(lock! q)
|
||||
(let [v (apply process (list (peek q)))]
|
||||
|
|
|
|||
|
|
@ -1,3 +1,26 @@
|
|||
(ns youyesyet.validation
|
||||
(:require [bouncer.core :as b]
|
||||
[bouncer.validators :as v]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.validation:
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
(ns youyesyet.ajax
|
||||
(:require [ajax.core :as ajax]))
|
||||
|
||||
(defn local-uri? [{:keys [uri]}]
|
||||
(not (re-find #"^\w+?://" uri)))
|
||||
|
||||
(defn default-headers [request]
|
||||
(if (local-uri? request)
|
||||
(-> request
|
||||
(update :uri #(str js/context %))
|
||||
(update :headers #(merge {"x-csrf-token" js/csrfToken} %)))
|
||||
request))
|
||||
|
||||
(defn load-interceptors! []
|
||||
(swap! ajax/default-interceptors
|
||||
conj
|
||||
(ajax/to-interceptor {:name "default headers"
|
||||
:request default-headers})))
|
||||
|
||||
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
(ns youyesyet.views.building
|
||||
(:require [re-frame.core :refer [reg-sub]]))
|
||||
(ns ^{:doc "Canvasser app transciever for ajax packets."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.canvasser-app.ajax
|
||||
(:require [ajax.core :as ajax]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.views.building: building view for youyesyet.
|
||||
;;;; youyesyet.canvasser-app.ajax: transciever for ajax packets.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
|
|
@ -25,13 +27,20 @@
|
|||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
;;; The pattern from the re-com demo (https://github.com/Day8/re-com) is to have
|
||||
;;; one source file/namespace per view. Each namespace contains a function 'panel'
|
||||
;;; whose output is an enlive-style specification of the view to be redered.
|
||||
;;; I propose to follow this pattern. This file will (eventually) provide the building view.
|
||||
(defn local-uri? [{:keys [uri]}]
|
||||
(not (re-find #"^\w+?://" uri)))
|
||||
|
||||
(defn default-headers [request]
|
||||
(if (local-uri? request)
|
||||
(-> request
|
||||
(update :uri #(str js/context %))
|
||||
(update :headers #(merge {"x-csrf-token" js/csrfToken} %)))
|
||||
request))
|
||||
|
||||
(defn load-interceptors! []
|
||||
(swap! ajax/default-interceptors
|
||||
conj
|
||||
(ajax/to-interceptor {:name "default headers"
|
||||
:request default-headers})))
|
||||
|
||||
|
||||
(defn panel
|
||||
"Generate the building panel."
|
||||
[]
|
||||
[])
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
(ns youyesyet.core
|
||||
(ns ^{:doc "Canvasser app navigation and routing."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.canvasser-app.core
|
||||
(:require cljsjs.react-leaflet
|
||||
[ajax.core :refer [GET POST]]
|
||||
[goog.events :as events]
|
||||
|
|
@ -7,21 +9,22 @@
|
|||
[reagent.core :as r]
|
||||
[re-frame.core :as rf]
|
||||
[secretary.core :as secretary]
|
||||
[youyesyet.ajax :refer [load-interceptors!]]
|
||||
[youyesyet.handlers]
|
||||
[youyesyet.subscriptions]
|
||||
[youyesyet.ui-utils :as ui]
|
||||
[youyesyet.views.about :as about]
|
||||
[youyesyet.views.electors :as electors]
|
||||
[youyesyet.views.followup :as followup]
|
||||
[youyesyet.views.issue :as issue]
|
||||
[youyesyet.views.issues :as issues]
|
||||
[youyesyet.views.map :as maps])
|
||||
[youyesyet.canvasser-app.ajax :refer [load-interceptors!]]
|
||||
[youyesyet.canvasser-app.handlers]
|
||||
[youyesyet.canvasser-app.subscriptions]
|
||||
[youyesyet.canvasser-app.ui-utils :as ui]
|
||||
[youyesyet.canvasser-app.views.about :as about]
|
||||
[youyesyet.canvasser-app.views.building :as building]
|
||||
[youyesyet.canvasser-app.views.electors :as electors]
|
||||
[youyesyet.canvasser-app.views.followup :as followup]
|
||||
[youyesyet.canvasser-app.views.issue :as issue]
|
||||
[youyesyet.canvasser-app.views.issues :as issues]
|
||||
[youyesyet.canvasser-app.views.map :as maps])
|
||||
(:import goog.History))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.core: core of the app.
|
||||
;;;; youyesyet.canvasser-app.core: core of the app.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
|
|
@ -48,6 +51,9 @@
|
|||
(defn about-page []
|
||||
(about/panel))
|
||||
|
||||
(defn building-page []
|
||||
(building/panel))
|
||||
|
||||
(defn electors-page []
|
||||
(electors/panel))
|
||||
|
||||
|
|
@ -65,6 +71,7 @@
|
|||
|
||||
(def pages
|
||||
{:about #'about-page
|
||||
:building #'building-page
|
||||
:electors #'electors-page
|
||||
:followup #'followup-page
|
||||
:issues #'issues-page
|
||||
|
|
@ -103,10 +110,10 @@
|
|||
(secretary/defroute "/about" []
|
||||
(rf/dispatch [:set-active-page :about]))
|
||||
|
||||
(secretary/defroute "/electors" []
|
||||
(rf/dispatch [:set-active-page :electors]))
|
||||
(secretary/defroute "/electors/:dwelling" {dwelling-id :dwelling}
|
||||
(rf/dispatch [:set-dwelling dwelling-id]))
|
||||
|
||||
(secretary/defroute "/electors/:address" {address-id :address}
|
||||
(secretary/defroute "/building/:address" {address-id :address}
|
||||
(rf/dispatch [:set-address address-id]))
|
||||
|
||||
(secretary/defroute "/followup" []
|
||||
|
|
@ -1,7 +1,9 @@
|
|||
(ns youyesyet.handlers
|
||||
(ns ^{:doc "Canvasser app event handlers."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.canvasser-app.handlers
|
||||
(:require [cljs.reader :refer [read-string]]
|
||||
[re-frame.core :refer [dispatch reg-event-db]]
|
||||
[youyesyet.db :as db]
|
||||
[youyesyet.canvasser-app.state :as db]
|
||||
))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
@ -55,32 +57,56 @@
|
|||
|
||||
|
||||
(reg-event-db
|
||||
:send-intention
|
||||
(fn [db [_ args]]
|
||||
(let [intention (:intention args)
|
||||
elector-id (:elector-id args)
|
||||
elector
|
||||
(first
|
||||
(remove nil?
|
||||
(map
|
||||
#(if (= elector-id (:id %)) %)
|
||||
(:electors (:address db)))))
|
||||
old-address (:address db)
|
||||
new-address (assoc old-address :electors (cons (assoc elector :intention intention) (remove #(= % elector) (:electors old-address))))]
|
||||
(cond
|
||||
(nil? elector)
|
||||
(assoc db :error "No elector found; not setting intention")
|
||||
(= intention (:intention elector)) (do (js/console.log "Elector's intention hasn't changed; not setting intention") db)
|
||||
true
|
||||
(do
|
||||
(js/console.log (str "Setting intention of elector " elector " to " intention))
|
||||
(merge
|
||||
(clear-messages db)
|
||||
{:addresses
|
||||
(cons new-address (remove old-address (:addresses db)))
|
||||
:address new-address
|
||||
:elector elector
|
||||
:outqueue (cons (assoc args :action :set-intention) (:outqueue db))}))))))
|
||||
:send-intention
|
||||
(fn [db [_ args]]
|
||||
(let [intention (:intention args)
|
||||
elector-id (:elector-id args)
|
||||
old-elector (first
|
||||
(remove nil?
|
||||
(map
|
||||
#(if (= elector-id (:id %)) %)
|
||||
(:electors (:dwelling db)))))
|
||||
new-elector (assoc old-elector :intention intention)
|
||||
old-dwelling (:dwelling db)
|
||||
new-dwelling (assoc
|
||||
old-dwelling
|
||||
:electors
|
||||
(cons
|
||||
new-elector
|
||||
(remove
|
||||
#(= % old-elector)
|
||||
(:electors old-dwelling))))
|
||||
old-address (:address db)
|
||||
new-address (assoc
|
||||
old-address
|
||||
:dwellings
|
||||
(cons
|
||||
new-dwelling
|
||||
(remove
|
||||
#(= % old-dwelling)
|
||||
(:dwellings old-address))))]
|
||||
(cond
|
||||
(nil? old-elector)
|
||||
(assoc db :error "No elector found; not setting intention")
|
||||
(= intention (:intention old-elector))
|
||||
(do
|
||||
(js/console.log "Elector's intention hasn't changed; not setting intention")
|
||||
db)
|
||||
true
|
||||
(do
|
||||
(js/console.log (str "Setting intention of elector " old-elector " to " intention))
|
||||
(merge
|
||||
(clear-messages db)
|
||||
{:addresses
|
||||
(cons
|
||||
new-address
|
||||
(remove #(= % old-address) (:addresses db)))
|
||||
:address new-address
|
||||
:dwelling new-dwelling
|
||||
:elector new-elector
|
||||
:outqueue (cons
|
||||
(assoc args :action :set-intention)
|
||||
(:outqueue db))}))))))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
|
|
@ -110,7 +136,29 @@
|
|||
(fn [db [_ address-id]]
|
||||
(let [id (read-string address-id)
|
||||
address (first (remove nil? (map #(if (= id (:id %)) %) (:addresses db))))]
|
||||
(assoc (clear-messages db) :address address :page :electors))))
|
||||
(if
|
||||
(= (count (:dwellings address)) 1)
|
||||
(assoc (clear-messages db)
|
||||
:address address
|
||||
:dwelling (first (:dwellings address))
|
||||
:page :electors)
|
||||
(assoc (clear-messages db)
|
||||
:address address
|
||||
:dwelling nil
|
||||
:page :building)))))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
:set-dwelling
|
||||
(fn [db [_ dwelling-id]]
|
||||
(let [id (read-string dwelling-id)
|
||||
dwelling (first
|
||||
(remove
|
||||
nil?
|
||||
(map
|
||||
#(if (= id (:id %)) %)
|
||||
(mapcat :dwellings (:addresses db)))))]
|
||||
(assoc (clear-messages db) :dwelling dwelling :page :electors))))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
|
|
@ -145,8 +193,34 @@
|
|||
(assoc (clear-messages db) :issue issue)))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
:set-latitude
|
||||
(fn [db [_ issue]]
|
||||
(assoc db :latitude issue)))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
:set-longitude
|
||||
(fn [db [_ issue]]
|
||||
(assoc db :longitude issue)))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
:set-telephone
|
||||
(fn [db [_ telephone]]
|
||||
(js/console.log (str "Setting telephone to " telephone))
|
||||
(assoc (clear-messages db) :telephone telephone)))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
:set-view
|
||||
(fn [db [_ view]]
|
||||
(assoc db :view view)))
|
||||
|
||||
|
||||
(reg-event-db
|
||||
:set-zoom
|
||||
(fn [db [_ zoom]]
|
||||
(if (integer? zoom)
|
||||
(assoc db :zoom zoom)
|
||||
db)))
|
||||
89
src/cljs/youyesyet/canvasser_app/state.cljs
Normal file
89
src/cljs/youyesyet/canvasser_app/state.cljs
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
(ns ^{:doc "Canvasser app client state."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.canvasser-app.state)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.canvasser-app.state: the state of the app.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; This is the constructor for the atom in which the state of the user interface is held.
|
||||
;;; The atom gets updated by 'events' registered in handler.cljs, q.v.
|
||||
;;;
|
||||
;;; not wonderfully happy with 'db' as a name for this namespace; will probably change to
|
||||
;;; 'client-state'.
|
||||
|
||||
(def default-db
|
||||
{;;; the currently selected address, if any.
|
||||
:address {:id 1 :address "13 Imaginary Terrace, IM1 3TE" :latitude 55.8253043 :longitude -4.2569057
|
||||
:dwellings [{:id 1
|
||||
:electors [{:id 1 :name "Alan Anderson" :gender :male :intention :no}
|
||||
{:id 2 :name "Ann Anderson" :gender :female}
|
||||
{:id 3 :name "Alex Anderson" :gender :fluid :intention :yes}
|
||||
{:id 4 :name "Andy Anderson" :intention :yes}]}]}
|
||||
;;; a list of the addresses in the current location at which there
|
||||
;;; are electors registered.
|
||||
:addresses [{:id 1 :address "13 Imaginary Terrace, IM1 3TE" :latitude 55.8253043 :longitude -4.2570944
|
||||
:dwellings [{:id 1
|
||||
:electors [{:id 1 :name "Alan Anderson" :gender :male :intention :no}
|
||||
{:id 2 :name "Ann Anderson" :gender :female}
|
||||
{:id 3 :name "Alex Anderson" :gender :fluid :intention :yes}
|
||||
{:id 4 :name "Andy Anderson" :intention :yes}]}]}
|
||||
{:id 2 :address "15 Imaginary Terrace, IM1 3TE" :latitude 55.8252354 :longitude -4.2572778
|
||||
:dwellings [{:id 2
|
||||
:electors [{:id 1 :name "Beryl Brown" :gender :female}
|
||||
{:id 2 :name "Betty Black" :gender :female}]}]}
|
||||
|
||||
{:id 3 :address "17 Imaginary Terrace, IM1 3TE" :latitude 55.825166 :longitude -4.257026
|
||||
:dwellings [{:id 3 :sub-address "Flat 1"
|
||||
:electors [{:id 1 :name "Catriona Crathie" :gender :female :intention :yes}
|
||||
{:id 2 :name "Colin Caruthers" :gender :male :intention :yes}
|
||||
{:id 3 :name "Calum Crathie" :intention :yes}]}
|
||||
{:id 4 :sub-address "Flat 2"
|
||||
:electors [{:id 1 :name "David Dewar" :gender :male :intention :no}]}]}]
|
||||
;;; electors at the currently selected dwelling
|
||||
:electors [{:id 1 :name "Alan Anderson" :gender :male :intention :no}
|
||||
{:id 2 :name "Ann Anderson" :gender :female}
|
||||
{:id 3 :name "Alex Anderson" :gender :fluid :intention :yes}
|
||||
{:id 4 :name "Andy Anderson" :intention :yes}]
|
||||
;;; any error to display
|
||||
:error nil
|
||||
;;; the issue from among the issues which is currently selected.
|
||||
;;; any confirmation message to display
|
||||
:feedback nil
|
||||
;;; the currently selected issue
|
||||
:issue "Currency"
|
||||
;;; the issues selected for the issues page on this day.
|
||||
:issues {"Currency" "Scotland could keep the Pound, or use the Euro. But we could also set up a new currency of our own. Yada yada yada"
|
||||
"Monarchy" "Scotland could keep the Queen. This is an issue to be decided after independence. Yada yada yada"
|
||||
"Defence" "Scotland will not have nuclear weapons, and will probably not choose to engage in far-off wars. But we could remain members of NATO"}
|
||||
;;; message of the day
|
||||
:motd "This is a test version only. There is no real data."
|
||||
;;; the options from among which electors can select.
|
||||
:options [{:id :yes :description "Yes"} {:id :no :description "No"}]
|
||||
;;; the queue of items waiting to be transmitted.
|
||||
:outqueue ()
|
||||
;;; the currently displayed page within the app.
|
||||
:page :home
|
||||
:view nil
|
||||
:latitude 55.82
|
||||
:longitude -4.25
|
||||
:zoom 12})
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
(ns youyesyet.subscriptions
|
||||
(ns ^{:doc "Canvasser app event subscriptions."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.canvasser-app.subscriptions
|
||||
(:require [re-frame.core :refer [reg-sub]]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
|
@ -44,6 +46,11 @@
|
|||
(fn [db _]
|
||||
(:changes db)))
|
||||
|
||||
(reg-sub
|
||||
:dwelling
|
||||
(fn [db _]
|
||||
(:dwelling db)))
|
||||
|
||||
(reg-sub
|
||||
:elector
|
||||
(fn [db _]
|
||||
|
|
@ -69,6 +76,16 @@
|
|||
(fn [db _]
|
||||
(:issues db)))
|
||||
|
||||
(reg-sub
|
||||
:latitude
|
||||
(fn [db _]
|
||||
(:latitude db)))
|
||||
|
||||
(reg-sub
|
||||
:longitude
|
||||
(fn [db _]
|
||||
(:longitude db)))
|
||||
|
||||
(reg-sub
|
||||
:page
|
||||
(fn [db _]
|
||||
|
|
@ -84,3 +101,12 @@
|
|||
(fn [db _]
|
||||
(:outqueue db)))
|
||||
|
||||
(reg-sub
|
||||
:view
|
||||
(fn [db _]
|
||||
(:view db)))
|
||||
|
||||
(reg-sub
|
||||
:zoom
|
||||
(fn [db _]
|
||||
(:zoom db)))
|
||||
|
|
@ -1,4 +1,6 @@
|
|||
(ns youyesyet.ui-utils
|
||||
(ns ^{:doc "Canvasser app user interface widgets."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.canvasser-app.ui-utils
|
||||
(:require [reagent.core :as r]
|
||||
[re-frame.core :as rf]))
|
||||
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
(ns youyesyet.views.about
|
||||
(ns ^{:doc "Canvasser app about panel."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.canvasser-app.views.about
|
||||
(:require [re-frame.core :refer [reg-sub subscribe]]
|
||||
[markdown.core :refer [md->html]]
|
||||
[youyesyet.ui-utils :as ui]))
|
||||
[youyesyet.canvasser-app.ui-utils :as ui]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.views.about: about/credits view for youyesyet.
|
||||
;;;; youyesyet.canvasser-app.views.about: about/credits view for youyesyet.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
54
src/cljs/youyesyet/canvasser_app/views/building.cljs
Normal file
54
src/cljs/youyesyet/canvasser_app/views/building.cljs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
(ns ^{:doc "Canvasser app households in building panel."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.canvasser-app.views.building
|
||||
(:require [re-frame.core :refer [reg-sub subscribe]]
|
||||
[youyesyet.canvasser-app.ui-utils :as ui]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.canvasser-app.views.building: building view for youyesyet.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
|
||||
;;; The pattern from the re-com demo (https://github.com/Day8/re-com) is to have
|
||||
;;; one source file/namespace per view. Each namespace contains a function 'panel'
|
||||
;;; whose output is an enlive-style specification of the view to be redered.
|
||||
;;; I propose to follow this pattern. This file will provide the building view.
|
||||
|
||||
(defn panel
|
||||
"Generate the building panel."
|
||||
[]
|
||||
(let [address @(subscribe [:address])
|
||||
dwellings (:dwellings address)]
|
||||
[:div
|
||||
[:h1 (str "Flats at " (:address address))]
|
||||
[:div.container {:id "main-container"}
|
||||
(ui/back-link)
|
||||
[:div {:id "dwelling-list"}
|
||||
(map
|
||||
(fn
|
||||
[dwelling]
|
||||
(ui/big-link
|
||||
(:sub-address dwelling)
|
||||
(str "#/electors/" (:id dwelling))) )
|
||||
(sort
|
||||
#(< (:sub-address %1) (:sub-address %2))
|
||||
(:dwellings address)))]]]))
|
||||
|
|
@ -1,11 +1,13 @@
|
|||
(ns youyesyet.views.electors
|
||||
(ns ^{:doc "Canvasser app electors in household panel."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.canvasser-app.views.electors
|
||||
(:require [reagent.core :refer [atom]]
|
||||
[re-frame.core :refer [reg-sub subscribe dispatch]]
|
||||
[youyesyet.ui-utils :as ui]))
|
||||
[youyesyet.canvasser-app.ui-utils :as ui]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.views.electors: electors view for youyesyet.
|
||||
;;;; youyesyet.canvasser-app.views.electors: electors view for youyesyet.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
|
|
@ -30,7 +32,7 @@
|
|||
;;; The pattern from the re-com demo (https://github.com/Day8/re-com) is to have
|
||||
;;; one source file/namespace per view. Each namespace contains a function 'panel'
|
||||
;;; whose output is an enlive-style specification of the view to be redered.
|
||||
;;; I propose to follow this pattern. This file will (eventually) provide the electors view.
|
||||
;;; I propose to follow this pattern. This file will provide the electors view.
|
||||
|
||||
;;; See https://github.com/simon-brooke/youyesyet/blob/master/doc/specification/userspec.md#electors-view
|
||||
|
||||
|
|
@ -105,14 +107,16 @@
|
|||
(defn panel
|
||||
"Generate the electors panel."
|
||||
[]
|
||||
(let [address @(subscribe [:address])
|
||||
addresses @(subscribe [:addresses])
|
||||
electors (sort-by :id (:electors address))
|
||||
options @(subscribe [:options])
|
||||
changes @(subscribe [:changes])]
|
||||
(let [dwelling @(subscribe [:dwelling])
|
||||
address @(subscribe [:address])
|
||||
sub-address (:sub-address dwelling)
|
||||
electors (sort-by :id (:electors dwelling))
|
||||
options @(subscribe [:options])]
|
||||
(if address
|
||||
[:div
|
||||
[:h1 (:address address)]
|
||||
[:h1 (if sub-address
|
||||
(str sub-address ", " (:address address))
|
||||
(:address address))]
|
||||
[:div.container {:id "main-container"}
|
||||
[:table
|
||||
[:tbody
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
(ns youyesyet.views.followup
|
||||
(ns ^{:doc "Canvasser followup request form panel."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.canvasser-app.views.followup
|
||||
(:require [re-frame.core :refer [reg-sub subscribe dispatch]]
|
||||
[youyesyet.ui-utils :as ui]))
|
||||
[youyesyet.canvasser-app.ui-utils :as ui]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.views.followup-request: followup-request view for youyesyet.
|
||||
;;;; youyesyet.canvasser-app.views.followup-request: followup-request view for youyesyet.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
(ns youyesyet.views.issue
|
||||
(ns ^{:doc "Canvasser app current issue detail panel."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.canvasser-app.views.issue
|
||||
(:require [re-frame.core :refer [reg-sub subscribe]]
|
||||
[markdown.core :refer [md->html]]
|
||||
[youyesyet.ui-utils :as ui]
|
||||
[youyesyet.views.issues :as issues]))
|
||||
[youyesyet.canvasser-app.ui-utils :as ui]
|
||||
[youyesyet.canvasser-app.views.issues :as issues]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
(ns youyesyet.views.issues
|
||||
(ns ^{:doc "Canvasser app current issues list panel."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.canvasser-app.views.issues
|
||||
(:require [re-frame.core :refer [reg-sub subscribe]]
|
||||
[youyesyet.ui-utils :as ui]))
|
||||
[youyesyet.canvasser-app.ui-utils :as ui]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.views.issues: issues view for youyesyet.
|
||||
;;;; youyesyet.canvasser-app.views.issues: issues view for youyesyet.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
|
|
@ -29,7 +31,7 @@
|
|||
;;; The pattern from the re-com demo (https://github.com/Day8/re-com) is to have
|
||||
;;; one source file/namespace per view. Each namespace contains a function 'panel'
|
||||
;;; whose output is an enlive-style specification of the view to be redered.
|
||||
;;; I propose to follow this pattern. This file will (eventually) provide the issues view.
|
||||
;;; I propose to follow this pattern. This file will provide the issues view.
|
||||
|
||||
;;; See https://github.com/simon-brooke/youyesyet/blob/master/doc/specification/userspec.md#issues-view
|
||||
|
||||
|
|
@ -1,10 +1,12 @@
|
|||
(ns youyesyet.views.map
|
||||
(ns ^{:doc "Canvasser app map view panel."
|
||||
:author "Simon Brooke"}
|
||||
youyesyet.canvasser-app.views.map
|
||||
(:require [re-frame.core :refer [reg-sub subscribe dispatch]]
|
||||
[reagent.core :as reagent]))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.views.map: map view for youyesyet.
|
||||
;;;; youyesyet.canvasser-app.views.map: map view for youyesyet.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
|
|
@ -55,7 +57,14 @@
|
|||
(defn pin-image
|
||||
"select the name of a suitable pin image for this address"
|
||||
[address]
|
||||
(let [intentions (set (remove nil? (map #(:intention %) (:electors address))))]
|
||||
(let [intentions
|
||||
(set
|
||||
(remove
|
||||
nil?
|
||||
(map
|
||||
:intention
|
||||
(mapcat :electors
|
||||
(:dwellings address)))))]
|
||||
(case (count intentions)
|
||||
0 "unknown-pin"
|
||||
1 (str (name (first intentions)) "-pin")
|
||||
|
|
@ -68,7 +77,12 @@
|
|||
so back links work."
|
||||
[id]
|
||||
(js/console.log (str "Click handler for address #" id))
|
||||
(set! window.location.href (str "#electors/" id)))
|
||||
(let [view @(subscribe [:view])
|
||||
centre (.getCenter view)]
|
||||
(dispatch [:set-zoom (.getZoom view)])
|
||||
(dispatch [:set-latitude (.-lat centre)])
|
||||
(dispatch [:set-longitude (.-lng centre)]))
|
||||
(set! window.location.href (str "#building/" id)))
|
||||
;; This way is probably more idiomatic React, but history doesn't work:
|
||||
;; (defn map-pin-click-handler
|
||||
;; [id]
|
||||
|
|
@ -112,7 +126,10 @@
|
|||
(defn map-did-mount-osm
|
||||
"Did-mount function loading map tile data from Open Street Map."
|
||||
[]
|
||||
(let [view (.setView (.map js/L "map" (clj->js {:zoomControl false})) #js [55.82 -4.25] 13)
|
||||
(let [view (.setView
|
||||
(.map js/L "map" (clj->js {:zoomControl false}))
|
||||
#js [@(subscribe [:latitude]) @(subscribe [:longitude])]
|
||||
@(subscribe [:zoom]))
|
||||
addresses @(subscribe [:addresses])]
|
||||
(js/console.log (str "Adding " (count addresses) " pins"))
|
||||
(doall (map #(add-map-pin % view) addresses))
|
||||
|
|
@ -120,7 +137,8 @@
|
|||
(clj->js {:attribution osm-attrib
|
||||
:maxZoom 18}))
|
||||
view)
|
||||
))
|
||||
(dispatch [:set-view view])
|
||||
view))
|
||||
|
||||
|
||||
(defn map-did-mount
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
(ns youyesyet.db)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;;;;
|
||||
;;;; youyesyet.db: the state of the app.
|
||||
;;;;
|
||||
;;;; This program is free software; you can redistribute it and/or
|
||||
;;;; modify it under the terms of the GNU General Public License
|
||||
;;;; as published by the Free Software Foundation; either version 2
|
||||
;;;; of the License, or (at your option) any later version.
|
||||
;;;;
|
||||
;;;; This program is distributed in the hope that it will be useful,
|
||||
;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;;;; GNU General Public License for more details.
|
||||
;;;;
|
||||
;;;; You should have received a copy of the GNU General Public License
|
||||
;;;; along with this program; if not, write to the Free Software
|
||||
;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
;;;; USA.
|
||||
;;;;
|
||||
;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
|
||||
;;;;
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;;; This is the constructor for the atom in which the state of the user interface is held.
|
||||
;;; The atom gets updated by 'events' registered in handler.cljs, q.v.
|
||||
;;;
|
||||
;;; not wonderfully happy with 'db' as a name for this namespace; will probably change to
|
||||
;;; 'client-state'.
|
||||
|
||||
(def default-db
|
||||
{;;; the currently selected address, if any.
|
||||
:address {:id 1 :address "13 Imaginary Terrace, IM1 3TE" :latitude 55.8253043 :longitude -4.2569057
|
||||
:electors [{:id 1 :name "Alan Anderson" :gender :male :intention :no}
|
||||
{:id 2 :name "Ann Anderson" :gender :female}
|
||||
{:id 3 :name "Alex Anderson" :gender :fluid :intention :yes}
|
||||
{:id 4 :name "Andy Anderson" :intention :yes}]}
|
||||
;;; a list of the addresses in the current location at which there
|
||||
;;; are electors registered.
|
||||
:addresses [{:id 1 :address "13 Imaginary Terrace, IM1 3TE" :latitude 55.8253043 :longitude -4.2570944
|
||||
:electors [{:id 1 :name "Alan Anderson" :gender :male :intention :no}
|
||||
{:id 2 :name "Ann Anderson" :gender :female}
|
||||
{:id 3 :name "Alex Anderson" :gender :fluid :intention :yes}
|
||||
{:id 4 :name "Andy Anderson" :intention :yes}]}
|
||||
{:id 2 :address "15 Imaginary Terrace, IM1 3TE" :latitude 55.8252354 :longitude -4.2572778
|
||||
:electors [{:id 1 :name "Beryl Brown" :gender :female}
|
||||
{:id 2 :name "Betty Black" :gender :female}]}
|
||||
{:id 3 :address "17 Imaginary Terrace, IM1 3TE" :latitude 55.825166 :longitude -4.257026
|
||||
:electors [{:id 1 :name "Catriona Crathie" :gender :female :intention :yes}
|
||||
{:id 2 :name "Colin Caruthers" :gender :male :intention :yes}
|
||||
{:id 3 :name "Calum Crathie" :intention :yes}]}
|
||||
{:id 4 :address "19 Imaginary Terrace, IM1 3TE" :latitude 55.82506950000001 :longitude -4.2570239
|
||||
:electors [{:id 1 :name "David Dewar" :gender :male :intention :no}]}]
|
||||
;;; electors at the currently selected address
|
||||
:electors [{:id 1 :name "Alan Anderson" :gender :male :intention :no}
|
||||
{:id 2 :name "Ann Anderson" :gender :female}
|
||||
{:id 3 :name "Alex Anderson" :gender :fluid :intention :yes}
|
||||
{:id 4 :name "Andy Anderson" :intention :yes}]
|
||||
;;; any error to display
|
||||
:error nil
|
||||
;;; the issue from among the issues which is currently selected.
|
||||
;;; any confirmation message to display
|
||||
:feedback nil
|
||||
;;; the currently selected issue
|
||||
:issue "Currency"
|
||||
;;; the issues selected for the issues page on this day.
|
||||
:issues {"Currency" "Scotland could keep the Pound, or use the Euro. But we could also set up a new currency of our own. Yada yada yada"
|
||||
"Monarchy" "Scotland could keep the Queen. This is an issue to be decided after independence. Yada yada yada"
|
||||
"Defence" "Scotland will not have nuclear weapons, and will probably not choose to engage in far-off wars. But we could remain members of NATO"}
|
||||
;;; message of the day
|
||||
:motd "This is a test version only. There is no real data."
|
||||
;;; the options from among which electors can select.
|
||||
:options [{:id :yes :description "Yes"} {:id :no :description "No"}]
|
||||
;;; the queue of items waiting to be transmitted.
|
||||
:outqueue ()
|
||||
;;; the currently displayed page within the app.
|
||||
:page :home
|
||||
})
|
||||
Loading…
Add table
Add a link
Reference in a new issue