Merge branch 'develop' of github.com:simon-brooke/youyesyet into develop

This commit is contained in:
Simon Brooke 2018-09-23 22:37:19 +01:00
commit dcba862b27
48 changed files with 232 additions and 88 deletions

View file

@ -75,18 +75,26 @@ Note that:
The map view shows a map of the streets immediately around their current location, overlaid, on dwellings where canvas has already been done, with icons indicating the voting preference expressed, and with the dwellings where canvassing is still required marked with an icon indicating this: The map view shows a map of the streets immediately around their current location, overlaid, on dwellings where canvas has already been done, with icons indicating the voting preference expressed, and with the dwellings where canvassing is still required marked with an icon indicating this:
![Map View](https://raw.githubusercontent.com/simon-brooke/youyesyet/master/dummies/mapview_800.png) ![Map View](https://raw.githubusercontent.com/simon-brooke/youyesyet/master/dummies/mapview.png)
Selecting a building on the map leads to Selecting a building on the map leads to
1. On buildings with multiple flats, a schematic view of the flats in the building (I haven't yet really got a good idea how to do this; it may be just a list). Selecting a flat from this view leads to the *Electors View*; 1. On buildings with multiple flats, the *Building View*;
2. On buildings with only one dwelling, the *Electors View*. 2. On buildings with only one dwelling, the *Electors View*.
## Building View
A list of dwellings in a building.
![Building View](https://raw.githubusercontent.com/simon-brooke/youyesyet/master/dummies/building.png)
Selecting a flat from this view leads to the *Electors View*.
## Electors View ## Electors View
The *Electors View* shows a schematic of the registered electors in a dwelling: The *Electors View* shows a schematic of the registered electors in a dwelling:
![Electors View](https://raw.githubusercontent.com/simon-brooke/youyesyet/master/dummies/occupants_800.png) ![Electors View](https://raw.githubusercontent.com/simon-brooke/youyesyet/master/dummies/occupants.png)
One figure is shown for each elector, labelled with their name. In the dummy pages I've shown gendered stick figures, because I believe that in many casesthis will help the canvasser identify the person who has answered the door; but this may be seen as excluding electors with non-binary gender, and, in any case, I believe we don't actually get gender data (other than salutation) in the electoral roll data. So this may have to be reconsidered. One figure is shown for each elector, labelled with their name. In the dummy pages I've shown gendered stick figures, because I believe that in many casesthis will help the canvasser identify the person who has answered the door; but this may be seen as excluding electors with non-binary gender, and, in any case, I believe we don't actually get gender data (other than salutation) in the electoral roll data. So this may have to be reconsidered.
@ -112,9 +120,18 @@ The *Issues View* is a simple list of issues:
| Other | | Other |
+------------------------------------------------+ +------------------------------------------------+
![Issues View](https://raw.githubusercontent.com/simon-brooke/youyesyet/master/dummies/issues.png)
This list will not be hard-coded but will be dynamic; thus, if we find an issue we didn't predict is regularly coming up on the doorstep an *Administrator* can add it to the list. This list will not be hard-coded but will be dynamic; thus, if we find an issue we didn't predict is regularly coming up on the doorstep an *Administrator* can add it to the list.
Selecting the back button from the *Issues View* returns to the *Electors View*. Selecting any option from the Issues view leads to a single page giving top level points the canvasser can make to the elector on the doorstep, and a link to a *Followup Request* form. There is also a 'back' button allowing the user to return to the *Issues View* Selecting the back button from the *Issues View* returns to the *Electors View*. Selecting any option from the Issues view leads to the *Issue View*.
## Issue View
A single page giving top level points the canvasser can make to the elector on the doorstep, regarding the selected issue; and a link to a *Followup Request* form. There is also a 'back' button allowing the user to return to the *Issues View*.
![Issue View](https://raw.githubusercontent.com/simon-brooke/youyesyet/master/dummies/issue.png)
## Followup Request form ## Followup Request form
@ -132,6 +149,8 @@ The *Followup Request* form is a simple form which allows the canvasser to recor
| | | |
+------------------------------------------------+ +------------------------------------------------+
![Followup Request Form](https://raw.githubusercontent.com/simon-brooke/youyesyet/master/dummies/followup.png)
## How Street Canvassers will use the system ## How Street Canvassers will use the system
Street Canvassers will typically use the system by Street Canvassers will typically use the system by

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

BIN
dummies/building.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
dummies/building.xcf Normal file

Binary file not shown.

BIN
dummies/followup.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
dummies/followup.xcf Normal file

Binary file not shown.

BIN
dummies/issue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
dummies/issue.xcf Normal file

Binary file not shown.

BIN
dummies/issues.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

BIN
dummies/issues.xcf Normal file

Binary file not shown.

View file

@ -45,7 +45,6 @@ h1 {
width: 100%; width: 100%;
_position: absolute; _position: absolute;
_top: expression(document.documentElement.scrollTop); _top: expression(document.documentElement.scrollTop);
z-index: 149;
background:rgba(7,27,51,0.8); background:rgba(7,27,51,0.8);
} }
@ -57,6 +56,7 @@ h1 {
#nav-menu { #nav-menu {
margin: 0; margin: 0;
padding: 0; padding: 0;
z-index: 02110-1301;
} }
#nav menu li { #nav menu li {
@ -103,6 +103,7 @@ h1 {
#nav:hover #nav-menu { #nav:hover #nav-menu {
display: block; display: block;
list-style-type: none; list-style-type: none;
z-index: 148;
width: 100%; width: 100%;
} }
@ -141,7 +142,7 @@ h1 {
margin: 0; margin: 0;
padding: 0; padding: 0;
position: fixed; position: fixed;
z-index: 149; z-index: 600;
color: silver; color: silver;
background:rgba(40,40,40,0.9); background:rgba(40,40,40,0.9);
} }
@ -149,6 +150,7 @@ h1 {
#nav:hover #nav-menu { #nav:hover #nav-menu {
display: block; display: block;
list-style-type: none; list-style-type: none;
z-index: 500;
width: 100%; width: 100%;
} }

View file

@ -212,7 +212,7 @@ th {
width: 30%; width: 30%;
float: right; float: right;
position: fixed; position: fixed;
bottom: 3.5em; bottom: 2em;
right: 0; right: 0;
z-index: 175; z-index: 175;
background: transparent; background: transparent;
@ -399,6 +399,10 @@ th {
padding-bottom: 2em; padding-bottom: 2em;
} }
#issue-text {
font-size: 200%;
}
#main-container { #main-container {
width: 100%; width: 100%;
margin: 0; margin: 0;

View file

@ -0,0 +1,60 @@
<!DOCTYPE html>
<html>
<head>
<!-- a page which can be served as static (by nginx) if Tomcat has crashed -->
<!-- head: if you want entire custom head content, override this block. -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="referrer" content="same-origin">
<link href="../css/yyy-common.css" rel="stylesheet" type="text/css" />
<link href="../css/yyy-site.css" rel="stylesheet" type="text/css" />
<link href="https://fonts.googleapis.com/css?family=Archivo+Black|Archivo+Narrow" rel="stylesheet"/>
<title>Project Hope: 502 Bad Gateway</title>
<!-- extra-head: put any additional markup to go into the head of your document into this block -->
<!-- e.g. script tags, link tags -->
</head>
<body>
<!-- whole-page: if you want an entire custom page layout, override this block. -->
<header>
<h1>Sorry, we have a problem</h1>
</header>
<div id="main-container" class="container">
<h2><span class="text-danger">Error: 502 Bad Gateway</span></h2>
<p>
We are suffering an intermittent problem causing an occasional crash of
the Project Hope canvassing application. We apologise for this, and are
working on a permanent fix.
</p>
<p>
The application will restart automatically
within five minutes, please take a short break.
</p>
</div>
<br clear="both"/>
</div>
<!-- foot: override this block if you don't want the standard footer -->
<footer>
<div id="credits">
<div>
<img height="16" width="16" alt="Clojure" src="/img/credits/luminus-logo.png"/>Built with <a href="http://www.luminusweb.net/">LuminusWeb</a> ||
<img height="16" width="16" alt="Clojure" src="/img/credits/clojure-icon.gif"/> Powered by <a href="http://clojure.org">Clojure</a> ||
<img height="16" width="16" alt="GitHub" src="/img/credits/github-logo-transparent.png"/>Find me/fork me on <a href="https://github.com/simon-brooke/youyesyet">Github</a> ||
<img height="16" width="16" alt="Free Software Foundation" src="/img/credits/gnu.small.png"/>Licensed under the <a href="http://www.gnu.org/licenses/gpl-2.0.html">GNU General Public License version 2.0</a>
</div>
</div>
</footer>
</body>
</html>

View file

@ -85,3 +85,13 @@ WHERE roles.id = ln_canvassers_roles.role_id
AND ln_canvassers_roles.canvasser_id = :id AND ln_canvassers_roles.canvasser_id = :id
ORDER BY roles.name, ORDER BY roles.name,
roles.id roles.id
-- :name list-elector-intentions :? :*
-- :doc short form of `list-intentions-by-elector`, returning far less data, for use in `youyesyet.routes.rest/get-local-data`, q.v.
-- TODO: should be limited to visits in the past 24 hours, to prevent the app being
-- used to harrass NO voters. See https://github.com/simon-brooke/youyesyet/issues/58
SELECT intentions.id, intentions.option_id, visits.date
FROM intentions, visits
WHERE intentions.visit_id = visits.id
AND intentions.elector_id = :id
ORDER BY visits.date DESC

View file

@ -27,7 +27,7 @@
<img id="nav-icon" src="{{servlet-context}}/img/threelines.png" alt="Menu"/> <img id="nav-icon" src="{{servlet-context}}/img/threelines.png" alt="Menu"/>
<menu id="nav-menu" class="nav"> <menu id="nav-menu" class="nav">
<li class=""><a href="{{servlet-context}}/home">Home</a></li> <li class=""><a href="{{servlet-context}}/home">Home</a></li>
<li class=""><a href="{{servlet-context}}/library">Library</a></li> <li class=""><a href="https://library.projecthope.scot/">Library</a></li>
{% if user %} {% if user %}
<li class=""><a href="{{servlet-context}}/roles">Roles</a></li> <li class=""><a href="{{servlet-context}}/roles">Roles</a></li>
<li class=""><a href="{{servlet-context}}/logout">Logout</a></li> <li class=""><a href="{{servlet-context}}/logout">Logout</a></li>
@ -68,18 +68,31 @@
<!-- content: put your main page content into this block --> <!-- content: put your main page content into this block -->
{% endblock %} {% endblock %}
</div> </div>
<div id="cookies">
<div id="more-about-cookies">
This website stores session information as a 'cookie' on your browser.
This helps us show you the content you want to see. This cookie does
not identify you, and cannot be read by other websites. It is deleted
by your browser as soon as you leave this site. This website does not
use any third party cookies, so your visit here cannot be tracked by
other websites.
</div>
<div id="about-cookies">
About cookies
</div>
</div>
<br clear="both"/> <br clear="both"/>
</div> </div>
{% block foot %} {% block foot %}
<!-- foot: override this block if you don't want the standard footer --> <!-- foot: override this block if you don't want the standard footer -->
<footer> <footer>
<div id="credits"> <div id="credits">
<div> <!-- div>
<img src="{{servlet-context}}/img/credits/ric-logo.png" width="24" height="24"/> <img src="{{servlet-context}}/img/credits/ric-logo.png" width="24" height="24"/>
A project of the A project of the
<a href="https://radical.scot/">Radical Independence Campaign</a> || <a href="https://radical.scot/">Radical Independence Campaign</a> ||
Version {{version}} Version {{version}}
</div> </div -->
<div> <div>
<img height="16" width="16" alt="Clojure" src="{{servlet-context}}/img/credits/luminus-logo.png"/>Built with <a href="http://www.luminusweb.net/">LuminusWeb</a> || <img height="16" width="16" alt="Clojure" src="{{servlet-context}}/img/credits/luminus-logo.png"/>Built with <a href="http://www.luminusweb.net/">LuminusWeb</a> ||
<img height="16" width="16" alt="Clojure" src="{{servlet-context}}/img/credits/clojure-icon.gif"/> Powered by <a href="http://clojure.org">Clojure</a> || <img height="16" width="16" alt="Clojure" src="{{servlet-context}}/img/credits/clojure-icon.gif"/> Powered by <a href="http://clojure.org">Clojure</a> ||

View file

@ -2,24 +2,12 @@
{% block big-links %} {% block big-links %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
<body> {% if status %}
<div class="container-fluid"> <h2>Error: {{status}}</h2>
<div class="row-fluid"> {% endif %}
<div class="col-lg-12"> <hr>
<div class="centering text-center"> {% if error %}
<div class="text-center"> <p>{{error}}</p>
<h1><span class="text-danger">Error: {{status}}</span></h1> {% endif %}
<hr>
{% if title %}
<h2 class="without-margin">{{title}}</h2>
{% endif %}
{% if message %}
<h4 class="text-danger">{{message}}</h4>
{% endif %}
</div>
</div>
</div>
</div>
</div>
{% endblock %} {% endblock %}

View file

@ -1,4 +1 @@
(ns ^{:doc "Field-level authorisation. Messy."
:author "Simon Brooke"}
youyesyet.authorisation
(:require [youyesyet.env :refer [defaults]]))

View file

@ -89,19 +89,19 @@
"renders the HTML `template` located relative to resources/templates in "renders the HTML `template` located relative to resources/templates in
the context of this session and with these parameters." the context of this session and with these parameters."
[template & [params]] [template & [params]]
(log/debug (str "layout/render: template: '" template "'")) (log/debug (str "layout/render: template: '" template "'"))
(content-type (content-type
(ok (ok
(parser/render-file (parser/render-file
template template
(merge params (merge params
{:page template {:page template
:csrf-token *anti-forgery-token* :csrf-token *anti-forgery-token*
:user *user* :user *user*
:user-roles (get-user-roles *user*) :user-roles (get-user-roles *user*)
:site-title (:site-title env) :site-title (:site-title env)
:version (System/getProperty "youyesyet.version")}))) :version (System/getProperty "youyesyet.version")})))
"text/html; charset=utf-8")) "text/html; charset=utf-8"))
@ -113,6 +113,16 @@
returns a response map with the error page as the body returns a response map with the error page as the body
and the status specified by the status key" and the status specified by the status key"
[error-details] [error-details]
(log/debug "Showing error page: " error-details)
{:status (:status error-details) {:status (:status error-details)
:headers {"Content-Type" "text/html; charset=utf-8"} :headers {"Content-Type" "text/html; charset=utf-8"}
:body (render "error.html" {} error-details)}) :body (parser/render-file
"error.html"
(assoc
error-details
:site-title (:site-title env)
:title
(str "Apologies, we have a problem: "
(:title error-details))
:error (:message error-details)
:message nil))})

View file

@ -115,7 +115,7 @@
(defn handle-logout (defn handle-logout
[request] [request]
(let [r (response/found (str (:servlet-context request) "/home"))] (let [r (response/found "/home")]
(assoc r :session (dissoc (:session r) :user)))) (assoc r :session (dissoc (:session r) :user))))

View file

@ -69,7 +69,7 @@
(fn [e] (fn [e]
(assoc e (assoc e
:intentions :intentions
(db/list-intentions-by-elector db/*db* {:id (:id e)}))) (db/list-elector-intentions db/*db* {:id (:id e)})))
(db/list-electors-by-dwelling db/*db* {:id (:id d)})))) (db/list-electors-by-dwelling db/*db* {:id (:id d)}))))
(db/list-dwellings-by-address db/*db* {:id (:id a)})))) (db/list-dwellings-by-address db/*db* {:id (:id a)}))))
addresses))) addresses)))

View file

@ -2,6 +2,7 @@
:author "Simon Brooke"} :author "Simon Brooke"}
youyesyet.canvasser-app.gis youyesyet.canvasser-app.gis
(:require [cljs.reader :refer [read-string]] (:require [cljs.reader :refer [read-string]]
[clojure.string :refer [lower-case]]
[cemerick.url :refer (url url-encode)] [cemerick.url :refer (url url-encode)]
[day8.re-frame.http-fx] [day8.re-frame.http-fx]
[re-frame.core :refer [dispatch reg-event-db reg-event-fx subscribe]] [re-frame.core :refer [dispatch reg-event-db reg-event-fx subscribe]]
@ -66,13 +67,14 @@
(set (set
(remove (remove
nil? nil?
(map (map :option_id
:intention (mapcat
(mapcat :electors :intentions
(:dwellings address)))))] (mapcat :electors
(:dwellings address))))))]
(case (count intentions) (case (count intentions)
0 "unknown-pin" 0 "unknown-pin"
1 (str (name (first intentions)) "-pin") 1 (lower-case (str (name (first intentions)) "-pin"))
"mixed-pin"))) "mixed-pin")))

View file

@ -51,6 +51,16 @@
:anchor nil)) :anchor nil))
(defn handle-forbidden
"If response has status 403 (forbidden) redirect to the login page."
[response & forms]
(if
(= (str (:status response)) "403")
(do
(js/console.log "Forbidden! redirecting")
(set! (.-location js/document) "/login"))
(apply 'do forms)))
(defn compose-packet (defn compose-packet
[item] [item]
"Convert this `item` into a URI which can be sent as a GET call" "Convert this `item` into a URI which can be sent as a GET call"
@ -181,6 +191,7 @@
;; TODO: why is this an `-fx`? Does it need to be? ;; TODO: why is this an `-fx`? Does it need to be?
(fn (fn
[{db :db} [_ response]] [{db :db} [_ response]]
(js/console.log (str ":process-locality: " response))
(js/console.log (str "Updating locality data: " (count response) " addresses " )) (js/console.log (str "Updating locality data: " (count response) " addresses " ))
(refresh-map-pins) (refresh-map-pins)
{:db (assoc {:db (assoc
@ -194,12 +205,14 @@
(fn (fn
[{db :db} [_ response]] [{db :db} [_ response]]
;; TODO: signal something has failed? It doesn't matter very much, unless it keeps failing. ;; TODO: signal something has failed? It doesn't matter very much, unless it keeps failing.
(js/console.log "Failed to fetch locality data") (js/console.log (str "Failed to fetch locality data" response))
;; loop to do it again ;; loop to do it again
(dispatch [:dispatch-later [{:ms 60000 :dispatch [:fetch-locality]}]]) (handle-forbidden
{:db (assoc response
(remove-from-feedback db :fetch-locality) (dispatch [:dispatch-later [{:ms 60000 :dispatch [:fetch-locality]}]])
:error (cons :fetch-locality (:error db)))})) {:db (assoc
(remove-from-feedback db :fetch-locality)
:error (cons :fetch-locality (:error db)))})))
(reg-event-fx (reg-event-fx

16
tomcat-restart.sh Normal file
View file

@ -0,0 +1,16 @@
#!/bin/bash
# There's a problem with YouYesYet which causes Tomcat to fall over
# from time to time; it needs fixed. This is a temporary stopgap
# simon, 20180918
wget -S https://www.projecthope.scot 2>&1 | grep 'HTTP/1.1 5'
if [ "$?" = "0" ]
then
header=`wget -S https://www.projecthope.scot 2>&1 | grep 'HTTP/1.1 5'`
timestamp=`date`
echo "${timestamp} : ${header} : Restarting Tomcat"
service tomcat8 restart
fi