#31, #44, #45: GDPR workflow complete; started on locality data

This commit is contained in:
Simon Brooke 2018-07-03 10:04:59 +01:00
parent b42a593e34
commit 6b44b70330
15 changed files with 223 additions and 384 deletions

View file

@ -22,7 +22,7 @@
:driver-class-name "org.postgresql.Driver"})
:stop (conman/disconnect! *db*))
(conman/bind-connection *db* "sql/queries.auto.sql")
(conman/bind-connection *db* "sql/queries.auto.sql" "sql/queries.sql")
(defn to-date [^java.sql.Date sql-date]
(-> sql-date (.getTime) (java.util.Date.)))

View file

@ -13,6 +13,7 @@
[youyesyet.routes.oauth :refer [oauth-routes]]
[youyesyet.routes.auto-json :refer [auto-rest-routes]]
[youyesyet.routes.auto :refer [auto-selmer-routes]]
[youyesyet.routes.rest :refer [rest-routes]]
[youyesyet.env :refer [defaults]]))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -71,6 +72,8 @@
(-> #'auto-selmer-routes
(wrap-routes middleware/wrap-csrf)
(wrap-routes middleware/wrap-formats))
(-> #'rest-routes
(wrap-routes middleware/wrap-formats))
'oauth-routes
(route/resources "/")
(route/not-found

View file

@ -3,10 +3,13 @@
(:require [clojure.walk :refer [keywordize-keys]]
[noir.response :as nresponse]
[noir.util.route :as route]
[youyesyet.db.core :as db-core]
[youyesyet.db.core :as db]
[compojure.core :refer [defroutes GET POST]]
[ring.util.http-response :as response]
[clojure.java.io :as io]))
[clojure.java.io :as io]
[youyesyet.locality :as l]
[youyesyet.utils :refer :all]
))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
@ -36,14 +39,29 @@
"Get data local to the user of the canvasser app. Expects arguments `lat` and
`long`. Returns a block of data for that locality"
[request]
)
(let
[{latitude :latitude longitude :longitude} (keywordize-keys (:params request))
neighbourhood (l/neighbouring-localities
(l/locality
(coerce-to-number latitude)
(coerce-to-number longitude)))
addresses (flatten
(map
#(db/list-addresses-by-locality db/*db* {:locality %})
neighbourhood))]
addresses
))
(defn get-issues
"Get current issues. No arguments expected."
[request])
;; (defroutes rest-routes
;; (GET "/rest/get-local-data" request (route/restricted (get-local-data request)))
(defroutes rest-routes
(GET "/rest/get-local-data" request (get-local-data request))
;; (GET "/rest/get-issues" request (route/restricted (get-issues request)))
;; (GET "/rest/set-intention" request (route/restricted (set-intention request)))
;; (GET "/rest/request-followup" request (route/restricted (request-followup request))))
)

View file

@ -0,0 +1,54 @@
(ns youyesyet.locality)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; youyesyet.locality: compute localities.
;;;;
;;;; 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
;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;; See also resources/sql/locality-trigger.sql
(defn locality
"Compute the locality index for this `latitude`/`longitude` pair."
[latitude longitude]
(+
(* 10000 ;; left-shift the latitude component four digits
(int
(* latitude 1000)))
(- ;; invert the sign of the longitude component, since
(int ;; we're interested in localities West of Greenwich.
(* longitude 1000)))))
(defn neighbouring-localities
"Return this locality with the localities immediately
north east, north, north west, east, west, south west,
south and south east of it."
;; TODO: I'm not absolutely confident of my arithmetic here!
[locality]
(list
(- locality 9999)
(- locality 10000)
(- locality 10001)
(- locality 1)
locality
(+ locality 1)
(+ locality 9999)
(+ locality 10000)
(+ locality 10001)))

View file

@ -0,0 +1,35 @@
(ns youyesyet.utils
#?(:clj (require [clojure.tools.logging :as log]))
)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;
;;;; youyesyet.locality: small utility functions.
;;;;
;;;; 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 coerce-to-number [v]
"If it is possible to do so, coerce `v` to a number"
(if (number? v) v
(try
(read-string (str v))
#?(:clj (catch Exception any
(log/error (str "Could not coerce '" v "' to number: " any)))
:cljs (js/console.log (str "Could not coerce '" v "' to number: " any))))))

View file

@ -134,6 +134,18 @@
(secretary/defroute "/building/:address" {address-id :address}
(log-and-dispatch [:set-address address-id]))
(secretary/defroute "/elector" []
(log-and-dispatch [:set-active-page :elector]))
(secretary/defroute "/elector/:elector" {elector-id :elector}
(log-and-dispatch [:set-elector-and-page {:elector-id elector-id :page :elector}]))
(secretary/defroute "/elector/:elector/:consent" {elector-id :elector consent :consent}
(log-and-dispatch [:set-consent-and-page {:elector-id elector-id :consent (and true consent) :page :elector}]))
(secretary/defroute "/elector" []
(log-and-dispatch [:set-active-page :elector]))
(secretary/defroute "/followup" []
(log-and-dispatch [:set-active-page :followup]))

View file

@ -4,6 +4,7 @@
(:require [cljs.reader :refer [read-string]]
[re-frame.core :refer [dispatch reg-event-db]]
[youyesyet.canvasser-app.state :as db]
[youyesyet.utils :refer :all]
))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
@ -36,12 +37,6 @@
(merge state {:error nil :feedback nil}))
(defn coerce-to-number [v]
(if (number? v) v
(try
(read-string (str v))
(catch js/Object any
(js/console.log (str "Could not coerce '" v "' to number: " any))))))
(defn get-elector
@ -169,9 +164,10 @@
:set-consent-and-page
(fn [db [_ args]]
(let [page (:page args)
consent (:consent args)
elector-id (coerce-to-number (:elector-id args))
elector (get-elector elector-id db)]
(js/console.log (str "Setting page to " page ", consent to true for " elector))
(js/console.log (str "Setting page to " page ", consent to " consent " for " elector))
(assoc (clear-messages db) :elector (assoc elector :consent true) :page page))))

View file

@ -39,6 +39,7 @@
(defn big-link
[text & {:keys [target handler]}]
(js/console.log (str "Constructing big link; target is '" target "'; handler is '" handler "'"))
[:div.big-link-container {:key (gensym "big-link")}
[:a.big-link (merge
(if target {:href target}{})

View file

@ -64,6 +64,7 @@
[:send-intention {:elector-id (:id elector)
:intention optid}])}]])]))
(defn issue-row
"Generate a row containing an issue cell for a particular elector"
[elector]
@ -76,25 +77,17 @@
(defn panel
"Generate the elector panel."
[]
(let [address @(subscribe [:address])
dwelling @(subscribe [:dwelling])
elector @(subscribe [:elector])
electors [elector]
options @(subscribe [:options])
sub-address (:sub-address dwelling)]
(if address
(let [elector @(subscribe [:elector])
options @(subscribe [:options])]
(if elector
[:div
[:h1 (if sub-address
(str sub-address ", " (:address address))
(:address address))]
[:h1 (:name elector)]
[:div.container {:id "main-container"}
[:table
[:tbody
(gender-row elector)
(name-row elector)
(map
#(option-row elector %)
options)
(issue-row elector)]]
(ui/back-link)]]
(ui/error-panel "No address selected"))))
(ui/back-link "#dwelling")]]
(ui/error-panel "No elector selected"))))

View file

@ -41,11 +41,11 @@
(let [issue @(subscribe [:issue])
issues @(subscribe [:issues])
elector @(subscribe [:elector])
address @(subscribe [:address])]
dwelling @(subscribe [:dwelling])]
(js/console.log (str "Issue is " issue "; elector is " elector))
(cond
(nil? address)
(ui/error-panel "No address selected")
(nil? dwelling)
(ui/error-panel "No dwelling selected")
(nil? issues)
(ui/error-panel "No issues loaded")
true
@ -59,7 +59,7 @@
:on-change #(dispatch [:set-elector (.-value (.-target %))])}
(map
#(let []
[:option {:value (:id %) :key (:id %)} (:name %)]) (:electors address))]]
[:option {:value (:id %) :key (:id %)} (:name %)]) (:electors dwelling))]]
[:p.widget
[:label {:for "issue"} "Issue"]
;; #(reset! val (-> % .-target .-value))

View file

@ -34,12 +34,10 @@
[]
(let [elector @(subscribe [:elector])]
[:div
[:h1 "GDPR Consent"]
[:h1 "I, " (:name elector)]
[:div.container {:id "main-container"}
[:table
[:tbody
[:tr
[:th "I," (:name elector)]]
[:tr
[:td
[:p "Consent to have data about my voting intention stored by "
@ -53,13 +51,12 @@
[:canvas {:id "signature-pad"}]]]]]]
(ui/back-link "#dwelling")
(ui/big-link "I consent"
:handler #(fn [] (dispatch [:set-consent-and-page {:elector-id (:id elector)
:page :elector}])))
:target (str "#elector/" (:id elector) "/true")
:handler #(fn [] (dispatch [:set-consent-and-page {:elector-id (:id elector) :page :elector}])))
;; TODO: need to save the signature
(ui/big-link "I DO NOT consent"
:handler
#(fn [] (dispatch [:set-elector-and-page {:elector-id (:id elector)
:page :elector}])))]))
:target (str "#elector/" (:id elector) "/true"))]))
;; :handler #(fn [] (dispatch [:set-elector-and-page {:elector-id (:id elector) :page :elector}])))]))
(defn gdpr-did-mount