Compare commits

..

6 commits

Author SHA1 Message Date
Simon Brooke 0d21259845 #2: Tighten up security on consumer_secret 2018-08-08 16:27:29 +01:00
Simon Brooke f438803723 #2: I'm getting something back!
That's probably as far as I can get inside the firewall. Now it has to go out!
2018-08-08 16:22:05 +01:00
Simon Brooke 2806d3c28c Merge branch 'develop' into feature/2 2018-08-08 12:48:09 +01:00
Simon Brooke f6d7f238e9 Handle error messages 2018-08-08 12:47:49 +01:00
Simon Brooke a6abeaa679 #2: Started work, not yet working. 2018-08-08 12:45:49 +01:00
Simon Brooke 130d12975d Safety commit
Ran out of electricity last night when I'd almost but not quite got creation working properly. Frustrating! I don't have much electricity this morning so I'm pushing this up to GitHub for safety.
2018-08-06 09:29:56 +01:00
132 changed files with 582 additions and 4071 deletions

6
.gitignore vendored
View file

@ -43,9 +43,3 @@ resources/sql/youyesyet\.postgres\.sql
/dumps/ /dumps/
youyesyet\.canonical\.adl\.xml youyesyet\.canonical\.adl\.xml
youyesyet\.dump\.20180816
*.tar
src/clj/youyesyet/cache\.clj

View file

@ -1,10 +0,0 @@
# Change Log
All notable changes to this project will be documented in this file. This change log is intended to follow the conventions of [keepachangelog.com](http://keepachangelog.com/).
# 0.2.1, 2018-09-21
(Hopefully) fixed map regression in 0.2.0
# 0.2.0, 2018-09-20
Second public alpha, most features complete.

View file

@ -43,30 +43,6 @@ If you're thinking of joining in development on this I'd strongly recommend you
You should also read the [User-Oriented Specification](doc/specification/userspec.md) and any other documentation which appears under the *doc/specification* hierarchy. You should also read the [User-Oriented Specification](doc/specification/userspec.md) and any other documentation which appears under the *doc/specification* hierarchy.
## Building this
This application is built using [Application Description Language](https://github.com/simon-brooke/adl/). The `adl` pre-processor is run as a prep task to building the `uberjar`, which in turn is preparatory to building the `uberwar`.
This will generate a large number of the source files required by YouYesYet, **including** the database initialisation scripts. These generated source files are not, as a matter of policy, held in the repository.
### What is auto-generated, and how to override it
The following files are generated from the master file `youyesyet.adl.xml`:
* `resources/sql/queries.auto.sql` - [HugSQL](https://www.hugsql.org/) queries for selection, insertion, modification and deletion of records of all entities described in the ADL file.
* `resources/sql/[application-name].postgres.sql` - [Postgres](https://www.postgresql.org/) database initialisation script including tables for all entities, convenience views for all entities, all necessary link tables and referential integrity constraints.
* `resources/templates/auto/*.html` - [Selmer](https://github.com/yogthos/Selmer) templates for each form or list list specified in the ADL file (pages are not yet handled).
* `src/clj/[application-name]/routes/auto.clj` - [Compojure]() routes for each form or list list specified in the ADL file (pages are not yet handled).
* `src/clj/[application-name]/routes/auto-json.clj` - [Compojure]() routes returning JSON responses for each query generated in `resources/sql/queries.auto.sql`.
*You are strongly advised never to edit any of these files*.
* To override any query, add that query to a file `resources/sql/queries.sql`
* To add additional material (for example reference data) to the database initialisation, add it to a separate file or a family of separate files.
* To override any template, copy the template file from `resources/templates/auto/` to `resources/templates/` and edit it there.
* To override any route, write a function of the same name in the namespace `[application-name].routes.manual`.
## Getting the database up ## Getting the database up
You'll need a file *profiles.clj*, with content similar to the following; it's not in the repository because it contains passwords. You'll need a file *profiles.clj*, with content similar to the following; it's not in the repository because it contains passwords.
@ -83,19 +59,11 @@ Do get the database initialised, run
createdb youyesyet_dev createdb youyesyet_dev
I'm no longer using Migratus as I'm using [Application Description Language](https://github.com/simon-brooke/adl/) I'm no longer using Migratus as I'm using [Application Description Language]()
to generate the majority of the application, and, as changes are made to the application to generate the majority of the application, and, as changes are made to the application
description, new database schemas are generated. The database initialisation script will description, new database schemas are generated. The database initialisation script will
be found at `resources/sql/youyesyet.postgres.sql`. Manually maintained overrides are found in be found at `resources/sql/youyesyet.postgres.sql`. Reference data initialisation scripts
`resources/sql/youyesyet.postgres.overrides.sql`. So to initialise the database, invoke will in due course be stored in the same directory.
psql youyesyet_dev < resources/sql/youyesyet.postgres.sql
followed by
psql youyesyet_dev < resources/sql/youyesyet.postgres.overrides.sql
Reference data initialisation scripts will in due course be stored in the same directory.
Once we have a more or less finished application it may be worth going back to Once we have a more or less finished application it may be worth going back to
[Migratus](https://github.com/yogthos/migratus); I might have a go at generating migrations from [Migratus](https://github.com/yogthos/migratus); I might have a go at generating migrations from
@ -107,33 +75,23 @@ To run in a dev environment, checkout the *develop* branch
To download and install Javascript delendencies, run To download and install Javascript delendencies, run
cd youyesyet
lein npm install lein npm install
To start a development web server for the application, run: To start a development web server for the application, run:
Then lein run
lein repl If you're wanting to work on cljs development, you need two terminal sessions. In one run
Wait for the clojure `user=>` prompt to appear, and enter lein run
(mount/start) as above; in the other, run
This will get the application running for development; ideally, open a new terminal and invoke
lein figwheel lein figwheel
which will aid in work on the ClojureScript components.
## Running in a production environment ## Running in a production environment
Either Doesn't really work yet; if you want to try it, see [Bug #36](https://github.com/simon-brooke/youyesyet/issues/36) and check out the associated feature branch.
1. run `lein uberjar` and execute the resulting jar file directly; or
2. run `lein uberwar` and serve the resulting war file from a servlet container.
The [beta production server](https://www.projecthope.scot/) currently runs an uberwar build in Tomcat behind Nginx.
## Working on this project ## Working on this project
@ -164,7 +122,7 @@ Note that all tools recommended in this document are free for non-commercial use
### Editors/IDEs ### Editors/IDEs
I (Simon) use, like and recommend [LightTable](http://lighttable.com/) as my editor; I used to use Emacs, and there is excellent Clojure tooling for Emacs, but these days Emacs ways of working seem just too far from everything else to be comfortable to me. [NightCode](https://sekao.net/nightcode/) is a lighter-weight Clojure IDE which you may like. There's also [Cursive](https://cursive-ide.com/) but it isn't free and I have so far found it more annoying than helpful; or [Counterclockwise](https://github.com/ccw-ide/ccw) which I don't have recent experience of. I (Simon) use, like and recommend [LightTable](http://lighttable.com/) as my editor; I used to use Emacs, and there is excellent Clojure tooling for Emacs, but these days Emacs ways of working seem just too far from everything else to be comfortable to me. [NightCode](https://sekao.net/nightcode/) is a lighter-weight Clojure IDE which you may like. There's also [Cursive](https://cursive-ide.com/) but it isn't free and I haven't tried it.
### Git ### Git

View file

@ -75,26 +75,18 @@ 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.png) ![Map View](https://raw.githubusercontent.com/simon-brooke/youyesyet/master/dummies/mapview_800.png)
Selecting a building on the map leads to Selecting a building on the map leads to
1. On buildings with multiple flats, the *Building View*; 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*;
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.png) ![Electors View](https://raw.githubusercontent.com/simon-brooke/youyesyet/master/dummies/occupants_800.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.
@ -120,18 +112,9 @@ 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 the *Issue View*. 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*
## 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
@ -149,8 +132,6 @@ 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

View file

@ -1,551 +0,0 @@
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 15px;
}
pre, code {
font-family: Monaco, DejaVu Sans Mono, Consolas, monospace;
font-size: 9pt;
margin: 15px 0;
}
h1 {
font-weight: normal;
font-size: 29px;
margin: 10px 0 2px 0;
padding: 0;
}
h2 {
font-weight: normal;
font-size: 25px;
}
h5.license {
margin: 9px 0 22px 0;
color: #555;
font-weight: normal;
font-size: 12px;
font-style: italic;
}
.document h1, .namespace-index h1 {
font-size: 32px;
margin-top: 12px;
}
#header, #content, .sidebar {
position: fixed;
}
#header {
top: 0;
left: 0;
right: 0;
height: 22px;
color: #f5f5f5;
padding: 5px 7px;
}
#content {
top: 32px;
right: 0;
bottom: 0;
overflow: auto;
background: #fff;
color: #333;
padding: 0 18px;
}
.sidebar {
position: fixed;
top: 32px;
bottom: 0;
overflow: auto;
}
.sidebar.primary {
background: #e2e2e2;
border-right: solid 1px #cccccc;
left: 0;
width: 250px;
}
.sidebar.secondary {
background: #f2f2f2;
border-right: solid 1px #d7d7d7;
left: 251px;
width: 200px;
}
#content.namespace-index, #content.document {
left: 251px;
}
#content.namespace-docs {
left: 452px;
}
#content.document {
padding-bottom: 10%;
}
#header {
background: #3f3f3f;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.4);
z-index: 100;
}
#header h1 {
margin: 0;
padding: 0;
font-size: 18px;
font-weight: lighter;
text-shadow: -1px -1px 0px #333;
}
#header h1 .project-version {
font-weight: normal;
}
.project-version {
padding-left: 0.15em;
}
#header a, .sidebar a {
display: block;
text-decoration: none;
}
#header a {
color: #f5f5f5;
}
.sidebar a {
color: #333;
}
#header h2 {
float: right;
font-size: 9pt;
font-weight: normal;
margin: 4px 3px;
padding: 0;
color: #bbb;
}
#header h2 a {
display: inline;
}
.sidebar h3 {
margin: 0;
padding: 10px 13px 0 13px;
font-size: 19px;
font-weight: lighter;
}
.sidebar h3 a {
color: #444;
}
.sidebar h3.no-link {
color: #636363;
}
.sidebar ul {
padding: 7px 0 6px 0;
margin: 0;
}
.sidebar ul.index-link {
padding-bottom: 4px;
}
.sidebar li {
display: block;
vertical-align: middle;
}
.sidebar li a, .sidebar li .no-link {
border-left: 3px solid transparent;
padding: 0 10px;
white-space: nowrap;
}
.sidebar li .no-link {
display: block;
color: #777;
font-style: italic;
}
.sidebar li .inner {
display: inline-block;
padding-top: 7px;
height: 24px;
}
.sidebar li a, .sidebar li .tree {
height: 31px;
}
.depth-1 .inner { padding-left: 2px; }
.depth-2 .inner { padding-left: 6px; }
.depth-3 .inner { padding-left: 20px; }
.depth-4 .inner { padding-left: 34px; }
.depth-5 .inner { padding-left: 48px; }
.depth-6 .inner { padding-left: 62px; }
.sidebar li .tree {
display: block;
float: left;
position: relative;
top: -10px;
margin: 0 4px 0 0;
padding: 0;
}
.sidebar li.depth-1 .tree {
display: none;
}
.sidebar li .tree .top, .sidebar li .tree .bottom {
display: block;
margin: 0;
padding: 0;
width: 7px;
}
.sidebar li .tree .top {
border-left: 1px solid #aaa;
border-bottom: 1px solid #aaa;
height: 19px;
}
.sidebar li .tree .bottom {
height: 22px;
}
.sidebar li.branch .tree .bottom {
border-left: 1px solid #aaa;
}
.sidebar.primary li.current a {
border-left: 3px solid #a33;
color: #a33;
}
.sidebar.secondary li.current a {
border-left: 3px solid #33a;
color: #33a;
}
.namespace-index h2 {
margin: 30px 0 0 0;
}
.namespace-index h3 {
font-size: 16px;
font-weight: bold;
margin-bottom: 0;
}
.namespace-index .topics {
padding-left: 30px;
margin: 11px 0 0 0;
}
.namespace-index .topics li {
padding: 5px 0;
}
.namespace-docs h3 {
font-size: 18px;
font-weight: bold;
}
.public h3 {
margin: 0;
float: left;
}
.usage {
clear: both;
}
.public {
margin: 0;
border-top: 1px solid #e0e0e0;
padding-top: 14px;
padding-bottom: 6px;
}
.public:last-child {
margin-bottom: 20%;
}
.members .public:last-child {
margin-bottom: 0;
}
.members {
margin: 15px 0;
}
.members h4 {
color: #555;
font-weight: normal;
font-variant: small-caps;
margin: 0 0 5px 0;
}
.members .inner {
padding-top: 5px;
padding-left: 12px;
margin-top: 2px;
margin-left: 7px;
border-left: 1px solid #bbb;
}
#content .members .inner h3 {
font-size: 12pt;
}
.members .public {
border-top: none;
margin-top: 0;
padding-top: 6px;
padding-bottom: 0;
}
.members .public:first-child {
padding-top: 0;
}
h4.type,
h4.dynamic,
h4.added,
h4.deprecated {
float: left;
margin: 3px 10px 15px 0;
font-size: 15px;
font-weight: bold;
font-variant: small-caps;
}
.public h4.type,
.public h4.dynamic,
.public h4.added,
.public h4.deprecated {
font-size: 13px;
font-weight: bold;
margin: 3px 0 0 10px;
}
.members h4.type,
.members h4.added,
.members h4.deprecated {
margin-top: 1px;
}
h4.type {
color: #717171;
}
h4.dynamic {
color: #9933aa;
}
h4.added {
color: #508820;
}
h4.deprecated {
color: #880000;
}
.namespace {
margin-bottom: 30px;
}
.namespace:last-child {
margin-bottom: 10%;
}
.index {
padding: 0;
font-size: 80%;
margin: 15px 0;
line-height: 16px;
}
.index * {
display: inline;
}
.index p {
padding-right: 3px;
}
.index li {
padding-right: 5px;
}
.index ul {
padding-left: 0;
}
.type-sig {
clear: both;
color: #088;
}
.type-sig pre {
padding-top: 10px;
margin: 0;
}
.usage code {
display: block;
color: #008;
margin: 2px 0;
}
.usage code:first-child {
padding-top: 10px;
}
p {
margin: 15px 0;
}
.public p:first-child, .public pre.plaintext {
margin-top: 12px;
}
.doc {
margin: 0 0 26px 0;
clear: both;
}
.public .doc {
margin: 0;
}
.namespace-index .doc {
margin-bottom: 20px;
}
.namespace-index .namespace .doc {
margin-bottom: 10px;
}
.markdown p, .markdown li, .markdown dt, .markdown dd, .markdown td {
line-height: 22px;
}
.markdown li {
padding: 2px 0;
}
.markdown h2 {
font-weight: normal;
font-size: 25px;
margin: 30px 0 10px 0;
}
.markdown h3 {
font-weight: normal;
font-size: 20px;
margin: 30px 0 0 0;
}
.markdown h4 {
font-size: 15px;
margin: 22px 0 -4px 0;
}
.doc, .public, .namespace .index {
max-width: 680px;
overflow-x: visible;
}
.markdown pre > code {
display: block;
padding: 10px;
}
.markdown pre > code, .src-link a {
border: 1px solid #e4e4e4;
border-radius: 2px;
}
.markdown code:not(.hljs), .src-link a {
background: #f6f6f6;
}
pre.deps {
display: inline-block;
margin: 0 10px;
border: 1px solid #e4e4e4;
border-radius: 2px;
padding: 10px;
background-color: #f6f6f6;
}
.markdown hr {
border-style: solid;
border-top: none;
color: #ccc;
}
.doc ul, .doc ol {
padding-left: 30px;
}
.doc table {
border-collapse: collapse;
margin: 0 10px;
}
.doc table td, .doc table th {
border: 1px solid #dddddd;
padding: 4px 6px;
}
.doc table th {
background: #f2f2f2;
}
.doc dl {
margin: 0 10px 20px 10px;
}
.doc dl dt {
font-weight: bold;
margin: 0;
padding: 3px 0;
border-bottom: 1px solid #ddd;
}
.doc dl dd {
padding: 5px 0;
margin: 0 0 5px 10px;
}
.doc abbr {
border-bottom: 1px dotted #333;
font-variant: none;
cursor: help;
}
.src-link {
margin-bottom: 15px;
}
.src-link a {
font-size: 70%;
padding: 1px 4px;
text-decoration: none;
color: #5555bb;
}

View file

@ -1,97 +0,0 @@
/*
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #333;
background: #f8f8f8;
}
.hljs-comment,
.hljs-quote {
color: #998;
font-style: italic;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-subst {
color: #333;
font-weight: bold;
}
.hljs-number,
.hljs-literal,
.hljs-variable,
.hljs-template-variable,
.hljs-tag .hljs-attr {
color: #008080;
}
.hljs-string,
.hljs-doctag {
color: #d14;
}
.hljs-title,
.hljs-section,
.hljs-selector-id {
color: #900;
font-weight: bold;
}
.hljs-subst {
font-weight: normal;
}
.hljs-type,
.hljs-class .hljs-title {
color: #458;
font-weight: bold;
}
.hljs-tag,
.hljs-name,
.hljs-attribute {
color: #000080;
font-weight: normal;
}
.hljs-regexp,
.hljs-link {
color: #009926;
}
.hljs-symbol,
.hljs-bullet {
color: #990073;
}
.hljs-built_in,
.hljs-builtin-name {
color: #0086b3;
}
.hljs-meta {
color: #999;
font-weight: bold;
}
.hljs-deletion {
background: #fdd;
}
.hljs-addition {
background: #dfd;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

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

View file

@ -1,112 +0,0 @@
function visibleInParent(element) {
var position = $(element).position().top
return position > -50 && position < ($(element).offsetParent().height() - 50)
}
function hasFragment(link, fragment) {
return $(link).attr("href").indexOf("#" + fragment) != -1
}
function findLinkByFragment(elements, fragment) {
return $(elements).filter(function(i, e) { return hasFragment(e, fragment)}).first()
}
function scrollToCurrentVarLink(elements) {
var elements = $(elements);
var parent = elements.offsetParent();
if (elements.length == 0) return;
var top = elements.first().position().top;
var bottom = elements.last().position().top + elements.last().height();
if (top >= 0 && bottom <= parent.height()) return;
if (top < 0) {
parent.scrollTop(parent.scrollTop() + top);
}
else if (bottom > parent.height()) {
parent.scrollTop(parent.scrollTop() + bottom - parent.height());
}
}
function setCurrentVarLink() {
$('.secondary a').parent().removeClass('current')
$('.anchor').
filter(function(index) { return visibleInParent(this) }).
each(function(index, element) {
findLinkByFragment(".secondary a", element.id).
parent().
addClass('current')
});
scrollToCurrentVarLink('.secondary .current');
}
var hasStorage = (function() { try { return localStorage.getItem } catch(e) {} }())
function scrollPositionId(element) {
var directory = window.location.href.replace(/[^\/]+\.html$/, '')
return 'scroll::' + $(element).attr('id') + '::' + directory
}
function storeScrollPosition(element) {
if (!hasStorage) return;
localStorage.setItem(scrollPositionId(element) + "::x", $(element).scrollLeft())
localStorage.setItem(scrollPositionId(element) + "::y", $(element).scrollTop())
}
function recallScrollPosition(element) {
if (!hasStorage) return;
$(element).scrollLeft(localStorage.getItem(scrollPositionId(element) + "::x"))
$(element).scrollTop(localStorage.getItem(scrollPositionId(element) + "::y"))
}
function persistScrollPosition(element) {
recallScrollPosition(element)
$(element).scroll(function() { storeScrollPosition(element) })
}
function sidebarContentWidth(element) {
var widths = $(element).find('.inner').map(function() { return $(this).innerWidth() })
return Math.max.apply(Math, widths)
}
function calculateSize(width, snap, margin, minimum) {
if (width == 0) {
return 0
}
else {
return Math.max(minimum, (Math.ceil(width / snap) * snap) + (margin * 2))
}
}
function resizeSidebars() {
var primaryWidth = sidebarContentWidth('.primary')
var secondaryWidth = 0
if ($('.secondary').length != 0) {
secondaryWidth = sidebarContentWidth('.secondary')
}
// snap to grid
primaryWidth = calculateSize(primaryWidth, 32, 13, 160)
secondaryWidth = calculateSize(secondaryWidth, 32, 13, 160)
$('.primary').css('width', primaryWidth)
$('.secondary').css('width', secondaryWidth).css('left', primaryWidth + 1)
if (secondaryWidth > 0) {
$('#content').css('left', primaryWidth + secondaryWidth + 2)
}
else {
$('#content').css('left', primaryWidth + 1)
}
}
$(window).ready(resizeSidebars)
$(window).ready(setCurrentVarLink)
$(window).ready(function() { persistScrollPosition('.primary')})
$(window).ready(function() {
$('#content').scroll(setCurrentVarLink)
$(window).resize(setCurrentVarLink)
})

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

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

View file

@ -1,551 +0,0 @@
body {
font-family: Helvetica, Arial, sans-serif;
font-size: 15px;
}
pre, code {
font-family: Monaco, DejaVu Sans Mono, Consolas, monospace;
font-size: 9pt;
margin: 15px 0;
}
h1 {
font-weight: normal;
font-size: 29px;
margin: 10px 0 2px 0;
padding: 0;
}
h2 {
font-weight: normal;
font-size: 25px;
}
h5.license {
margin: 9px 0 22px 0;
color: #555;
font-weight: normal;
font-size: 12px;
font-style: italic;
}
.document h1, .namespace-index h1 {
font-size: 32px;
margin-top: 12px;
}
#header, #content, .sidebar {
position: fixed;
}
#header {
top: 0;
left: 0;
right: 0;
height: 22px;
color: #f5f5f5;
padding: 5px 7px;
}
#content {
top: 32px;
right: 0;
bottom: 0;
overflow: auto;
background: #fff;
color: #333;
padding: 0 18px;
}
.sidebar {
position: fixed;
top: 32px;
bottom: 0;
overflow: auto;
}
.sidebar.primary {
background: #e2e2e2;
border-right: solid 1px #cccccc;
left: 0;
width: 250px;
}
.sidebar.secondary {
background: #f2f2f2;
border-right: solid 1px #d7d7d7;
left: 251px;
width: 200px;
}
#content.namespace-index, #content.document {
left: 251px;
}
#content.namespace-docs {
left: 452px;
}
#content.document {
padding-bottom: 10%;
}
#header {
background: #3f3f3f;
box-shadow: 0 0 8px rgba(0, 0, 0, 0.4);
z-index: 100;
}
#header h1 {
margin: 0;
padding: 0;
font-size: 18px;
font-weight: lighter;
text-shadow: -1px -1px 0px #333;
}
#header h1 .project-version {
font-weight: normal;
}
.project-version {
padding-left: 0.15em;
}
#header a, .sidebar a {
display: block;
text-decoration: none;
}
#header a {
color: #f5f5f5;
}
.sidebar a {
color: #333;
}
#header h2 {
float: right;
font-size: 9pt;
font-weight: normal;
margin: 4px 3px;
padding: 0;
color: #bbb;
}
#header h2 a {
display: inline;
}
.sidebar h3 {
margin: 0;
padding: 10px 13px 0 13px;
font-size: 19px;
font-weight: lighter;
}
.sidebar h3 a {
color: #444;
}
.sidebar h3.no-link {
color: #636363;
}
.sidebar ul {
padding: 7px 0 6px 0;
margin: 0;
}
.sidebar ul.index-link {
padding-bottom: 4px;
}
.sidebar li {
display: block;
vertical-align: middle;
}
.sidebar li a, .sidebar li .no-link {
border-left: 3px solid transparent;
padding: 0 10px;
white-space: nowrap;
}
.sidebar li .no-link {
display: block;
color: #777;
font-style: italic;
}
.sidebar li .inner {
display: inline-block;
padding-top: 7px;
height: 24px;
}
.sidebar li a, .sidebar li .tree {
height: 31px;
}
.depth-1 .inner { padding-left: 2px; }
.depth-2 .inner { padding-left: 6px; }
.depth-3 .inner { padding-left: 20px; }
.depth-4 .inner { padding-left: 34px; }
.depth-5 .inner { padding-left: 48px; }
.depth-6 .inner { padding-left: 62px; }
.sidebar li .tree {
display: block;
float: left;
position: relative;
top: -10px;
margin: 0 4px 0 0;
padding: 0;
}
.sidebar li.depth-1 .tree {
display: none;
}
.sidebar li .tree .top, .sidebar li .tree .bottom {
display: block;
margin: 0;
padding: 0;
width: 7px;
}
.sidebar li .tree .top {
border-left: 1px solid #aaa;
border-bottom: 1px solid #aaa;
height: 19px;
}
.sidebar li .tree .bottom {
height: 22px;
}
.sidebar li.branch .tree .bottom {
border-left: 1px solid #aaa;
}
.sidebar.primary li.current a {
border-left: 3px solid #a33;
color: #a33;
}
.sidebar.secondary li.current a {
border-left: 3px solid #33a;
color: #33a;
}
.namespace-index h2 {
margin: 30px 0 0 0;
}
.namespace-index h3 {
font-size: 16px;
font-weight: bold;
margin-bottom: 0;
}
.namespace-index .topics {
padding-left: 30px;
margin: 11px 0 0 0;
}
.namespace-index .topics li {
padding: 5px 0;
}
.namespace-docs h3 {
font-size: 18px;
font-weight: bold;
}
.public h3 {
margin: 0;
float: left;
}
.usage {
clear: both;
}
.public {
margin: 0;
border-top: 1px solid #e0e0e0;
padding-top: 14px;
padding-bottom: 6px;
}
.public:last-child {
margin-bottom: 20%;
}
.members .public:last-child {
margin-bottom: 0;
}
.members {
margin: 15px 0;
}
.members h4 {
color: #555;
font-weight: normal;
font-variant: small-caps;
margin: 0 0 5px 0;
}
.members .inner {
padding-top: 5px;
padding-left: 12px;
margin-top: 2px;
margin-left: 7px;
border-left: 1px solid #bbb;
}
#content .members .inner h3 {
font-size: 12pt;
}
.members .public {
border-top: none;
margin-top: 0;
padding-top: 6px;
padding-bottom: 0;
}
.members .public:first-child {
padding-top: 0;
}
h4.type,
h4.dynamic,
h4.added,
h4.deprecated {
float: left;
margin: 3px 10px 15px 0;
font-size: 15px;
font-weight: bold;
font-variant: small-caps;
}
.public h4.type,
.public h4.dynamic,
.public h4.added,
.public h4.deprecated {
font-size: 13px;
font-weight: bold;
margin: 3px 0 0 10px;
}
.members h4.type,
.members h4.added,
.members h4.deprecated {
margin-top: 1px;
}
h4.type {
color: #717171;
}
h4.dynamic {
color: #9933aa;
}
h4.added {
color: #508820;
}
h4.deprecated {
color: #880000;
}
.namespace {
margin-bottom: 30px;
}
.namespace:last-child {
margin-bottom: 10%;
}
.index {
padding: 0;
font-size: 80%;
margin: 15px 0;
line-height: 16px;
}
.index * {
display: inline;
}
.index p {
padding-right: 3px;
}
.index li {
padding-right: 5px;
}
.index ul {
padding-left: 0;
}
.type-sig {
clear: both;
color: #088;
}
.type-sig pre {
padding-top: 10px;
margin: 0;
}
.usage code {
display: block;
color: #008;
margin: 2px 0;
}
.usage code:first-child {
padding-top: 10px;
}
p {
margin: 15px 0;
}
.public p:first-child, .public pre.plaintext {
margin-top: 12px;
}
.doc {
margin: 0 0 26px 0;
clear: both;
}
.public .doc {
margin: 0;
}
.namespace-index .doc {
margin-bottom: 20px;
}
.namespace-index .namespace .doc {
margin-bottom: 10px;
}
.markdown p, .markdown li, .markdown dt, .markdown dd, .markdown td {
line-height: 22px;
}
.markdown li {
padding: 2px 0;
}
.markdown h2 {
font-weight: normal;
font-size: 25px;
margin: 30px 0 10px 0;
}
.markdown h3 {
font-weight: normal;
font-size: 20px;
margin: 30px 0 0 0;
}
.markdown h4 {
font-size: 15px;
margin: 22px 0 -4px 0;
}
.doc, .public, .namespace .index {
max-width: 680px;
overflow-x: visible;
}
.markdown pre > code {
display: block;
padding: 10px;
}
.markdown pre > code, .src-link a {
border: 1px solid #e4e4e4;
border-radius: 2px;
}
.markdown code:not(.hljs), .src-link a {
background: #f6f6f6;
}
pre.deps {
display: inline-block;
margin: 0 10px;
border: 1px solid #e4e4e4;
border-radius: 2px;
padding: 10px;
background-color: #f6f6f6;
}
.markdown hr {
border-style: solid;
border-top: none;
color: #ccc;
}
.doc ul, .doc ol {
padding-left: 30px;
}
.doc table {
border-collapse: collapse;
margin: 0 10px;
}
.doc table td, .doc table th {
border: 1px solid #dddddd;
padding: 4px 6px;
}
.doc table th {
background: #f2f2f2;
}
.doc dl {
margin: 0 10px 20px 10px;
}
.doc dl dt {
font-weight: bold;
margin: 0;
padding: 3px 0;
border-bottom: 1px solid #ddd;
}
.doc dl dd {
padding: 5px 0;
margin: 0 0 5px 10px;
}
.doc abbr {
border-bottom: 1px dotted #333;
font-variant: none;
cursor: help;
}
.src-link {
margin-bottom: 15px;
}
.src-link a {
font-size: 70%;
padding: 1px 4px;
text-decoration: none;
color: #5555bb;
}

View file

@ -1,97 +0,0 @@
/*
github.com style (c) Vasily Polovnyov <vast@whiteants.net>
*/
.hljs {
display: block;
overflow-x: auto;
padding: 0.5em;
color: #333;
background: #f8f8f8;
}
.hljs-comment,
.hljs-quote {
color: #998;
font-style: italic;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-subst {
color: #333;
font-weight: bold;
}
.hljs-number,
.hljs-literal,
.hljs-variable,
.hljs-template-variable,
.hljs-tag .hljs-attr {
color: #008080;
}
.hljs-string,
.hljs-doctag {
color: #d14;
}
.hljs-title,
.hljs-section,
.hljs-selector-id {
color: #900;
font-weight: bold;
}
.hljs-subst {
font-weight: normal;
}
.hljs-type,
.hljs-class .hljs-title {
color: #458;
font-weight: bold;
}
.hljs-tag,
.hljs-name,
.hljs-attribute {
color: #000080;
font-weight: normal;
}
.hljs-regexp,
.hljs-link {
color: #009926;
}
.hljs-symbol,
.hljs-bullet {
color: #990073;
}
.hljs-built_in,
.hljs-builtin-name {
color: #0086b3;
}
.hljs-meta {
color: #999;
font-weight: bold;
}
.hljs-deletion {
background: #fdd;
}
.hljs-addition {
background: #dfd;
}
.hljs-emphasis {
font-style: italic;
}
.hljs-strong {
font-weight: bold;
}

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

View file

@ -1,112 +0,0 @@
function visibleInParent(element) {
var position = $(element).position().top
return position > -50 && position < ($(element).offsetParent().height() - 50)
}
function hasFragment(link, fragment) {
return $(link).attr("href").indexOf("#" + fragment) != -1
}
function findLinkByFragment(elements, fragment) {
return $(elements).filter(function(i, e) { return hasFragment(e, fragment)}).first()
}
function scrollToCurrentVarLink(elements) {
var elements = $(elements);
var parent = elements.offsetParent();
if (elements.length == 0) return;
var top = elements.first().position().top;
var bottom = elements.last().position().top + elements.last().height();
if (top >= 0 && bottom <= parent.height()) return;
if (top < 0) {
parent.scrollTop(parent.scrollTop() + top);
}
else if (bottom > parent.height()) {
parent.scrollTop(parent.scrollTop() + bottom - parent.height());
}
}
function setCurrentVarLink() {
$('.secondary a').parent().removeClass('current')
$('.anchor').
filter(function(index) { return visibleInParent(this) }).
each(function(index, element) {
findLinkByFragment(".secondary a", element.id).
parent().
addClass('current')
});
scrollToCurrentVarLink('.secondary .current');
}
var hasStorage = (function() { try { return localStorage.getItem } catch(e) {} }())
function scrollPositionId(element) {
var directory = window.location.href.replace(/[^\/]+\.html$/, '')
return 'scroll::' + $(element).attr('id') + '::' + directory
}
function storeScrollPosition(element) {
if (!hasStorage) return;
localStorage.setItem(scrollPositionId(element) + "::x", $(element).scrollLeft())
localStorage.setItem(scrollPositionId(element) + "::y", $(element).scrollTop())
}
function recallScrollPosition(element) {
if (!hasStorage) return;
$(element).scrollLeft(localStorage.getItem(scrollPositionId(element) + "::x"))
$(element).scrollTop(localStorage.getItem(scrollPositionId(element) + "::y"))
}
function persistScrollPosition(element) {
recallScrollPosition(element)
$(element).scroll(function() { storeScrollPosition(element) })
}
function sidebarContentWidth(element) {
var widths = $(element).find('.inner').map(function() { return $(this).innerWidth() })
return Math.max.apply(Math, widths)
}
function calculateSize(width, snap, margin, minimum) {
if (width == 0) {
return 0
}
else {
return Math.max(minimum, (Math.ceil(width / snap) * snap) + (margin * 2))
}
}
function resizeSidebars() {
var primaryWidth = sidebarContentWidth('.primary')
var secondaryWidth = 0
if ($('.secondary').length != 0) {
secondaryWidth = sidebarContentWidth('.secondary')
}
// snap to grid
primaryWidth = calculateSize(primaryWidth, 32, 13, 160)
secondaryWidth = calculateSize(secondaryWidth, 32, 13, 160)
$('.primary').css('width', primaryWidth)
$('.secondary').css('width', secondaryWidth).css('left', primaryWidth + 1)
if (secondaryWidth > 0) {
$('#content').css('left', primaryWidth + secondaryWidth + 2)
}
else {
$('#content').css('left', primaryWidth + 1)
}
}
$(window).ready(resizeSidebars)
$(window).ready(setCurrentVarLink)
$(window).ready(function() { persistScrollPosition('.primary')})
$(window).ready(function() {
$('#content').scroll(setCurrentVarLink)
$(window).resize(setCurrentVarLink)
})

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

View file

@ -1,58 +1,50 @@
(defproject youyesyet "0.2.2" (defproject youyesyet "0.2.0-SNAPSHOT"
:description "Canvassing tool for referenda" :description "Canvassing tool for referenda"
:license {:name "GNU General Public License,version 2.0 or (at your option) any later version"
:url "https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html"}
:url "https://github.com/simon-brooke/youyesyet" :url "https://github.com/simon-brooke/youyesyet"
:dependencies [[adl-support "0.1.6"] :dependencies [[adl-support "0.1.4-SNAPSHOT"]
[bouncer "1.0.1"] [bouncer "1.0.1"]
[ch.qos.logback/logback-classic "1.2.3"] [ch.qos.logback/logback-classic "1.2.3"]
[clj-oauth "1.5.5"] [clj-oauth "1.5.5"]
[cljsjs/react-leaflet "1.6.5-0"] [cljsjs/react-leaflet "1.6.5-0"]
;; [cljsjs/react-leaflet "2.0.1-0"] is available but doesn't seem to work fully [cljs-ajax "0.7.4"]
[cljs-ajax "0.8.0"]
[com.andrewmcveigh/cljs-time "0.5.2"]
[clojure.java-time "0.3.2"] [clojure.java-time "0.3.2"]
[com.cemerick/url "0.1.1"] [com.cemerick/url "0.1.1"]
[compojure "1.6.1"] [compojure "1.6.1"]
[conman "0.8.3"] [conman "0.8.2"]
[cprop "0.1.13"] [cprop "0.1.11"]
[day8.re-frame/http-fx "0.1.6"] [day8.re-frame/http-fx "0.1.6"]
[korma "0.4.3"] [korma "0.4.3"]
[lib-noir "0.9.9" :exclusions [org.clojure/tools.reader]] [lib-noir "0.9.9" :exclusions [org.clojure/tools.reader]]
[luminus/ring-ttl-session "0.3.2"] [luminus/ring-ttl-session "0.3.2"]
[luminus-nrepl "0.1.6"] [luminus-nrepl "0.1.4"]
[luminus-migrations "0.6.5"] [luminus-migrations "0.5.2"]
[luminus-immutant "0.2.5"] [luminus-immutant "0.2.4"]
[markdown-clj "1.0.8"] [markdown-clj "1.0.2"]
[metosin/compojure-api "1.1.12"] [metosin/compojure-api "1.1.12"]
[metosin/ring-http-response "0.9.1"] [metosin/ring-http-response "0.9.0"]
[migratus "1.2.3"] [migratus "1.0.8"]
[mount "0.1.16"] [mount "0.1.12"]
[org.clojure/clojure "1.9.0"] [org.clojure/clojure "1.9.0"]
[org.clojure/clojurescript "1.10.520" :scope "provided"] [org.clojure/clojurescript "1.10.339" :scope "provided"]
[org.clojure/core.memoize "0.7.1"] [org.clojure/core.memoize "0.7.1"]
;;[org.clojure/spec.alpha "0.2.168"] ;;[org.clojure/spec.alpha "0.2.168"]
[org.clojure/tools.cli "0.4.2"] [org.clojure/tools.cli "0.3.7"]
[org.clojure/tools.logging "0.4.1"] [org.clojure/tools.logging "0.4.1"]
[org.postgresql/postgresql "42.2.5"] [org.postgresql/postgresql "42.2.4"]
[org.webjars/bootstrap "4.3.1"] [org.webjars/bootstrap "4.1.2"]
[org.webjars/font-awesome "5.8.1"] [org.webjars/font-awesome "5.1.0"]
[org.webjars.bower/tether "1.4.4"] [org.webjars.bower/tether "1.4.4"]
[postgre-types "0.0.4"] [re-frame "0.10.5"]
[re-frame "0.10.6"]
[reagent "0.8.1"] [reagent "0.8.1"]
[reagent-utils "0.3.2"] [reagent-utils "0.3.1"]
[ring-middleware-format "0.7.4"] [ring-middleware-format "0.7.2"]
[ring/ring-defaults "0.3.2"] [ring/ring-defaults "0.3.2"]
[ring/ring-servlet "1.7.1"] [ring/ring-servlet "1.6.3"]
[ring-webjars "0.2.0"] [ring-webjars "0.2.0"]
[secretary "1.2.3"] [secretary "1.2.3"]
[selmer "1.12.12"]] [selmer "1.11.8"]]
:deploy-repositories [["releases" :clojars]
["snapshots" :clojars]]
:min-lein-version "2.0.0" :min-lein-version "2.0.0"
@ -64,27 +56,23 @@
:main ^:skip-aot youyesyet.core :main ^:skip-aot youyesyet.core
:migratus {:store :database :db ~(get (System/getenv) "DATABASE_URL")} :migratus {:store :database :db ~(get (System/getenv) "DATABASE_URL")}
:plugins [[lein-adl "0.1.7"] :plugins [;;[lein-adl ["0.1.2"]]
[lein-cljsbuild "1.1.7"] [lein-cljsbuild "1.1.7"]
[lein-codox "0.10.7-multilang"] [lein-codox "0.10.4"]
[lein-cprop "1.0.3"] [lein-cprop "1.0.3"]
[lein-kibit "0.1.6"] [lein-kibit "0.1.6"]
[lein-less "1.7.5"] [lein-less "1.7.5"]
[lein-npm "0.6.2"] [lein-npm "0.6.2"]
[lein-release "1.0.5"] [lein-release "1.1.3"]
[lein-uberwar "0.2.0"] [lein-uberwar "0.2.0"]
[migratus-lein "0.5.9"] [migratus-lein "0.5.9"]
[org.clojars.punkisdead/lein-cucumber "1.0.7"]] [org.clojars.punkisdead/lein-cucumber "1.0.7"]]
:cucumber-feature-paths ["test/clj/features"] :cucumber-feature-paths ["test/clj/features"]
:codox {:metadata {:doc "**TODO**: write docs" :codox {:metadata {:doc "FIXME: write docs"}
:doc/format :markdown}
:languages [:clojure :clojurescript] :languages [:clojure :clojurescript]
:source-paths ["src/clj" "src/cljc" "src/cljs"] :source-paths ["src/clj" "src/cljc" "src/cljs"]}
:source-uri "https://github.com/simon-brooke/youyesyet/blob/master/{filepath}#L{line}"
:output-path "docs"}
:npm {:dependencies [[datatables.net "1.10.19"] :npm {:dependencies [[datatables.net "1.10.19"]
[datatables.net-dt "1.10.19"] [datatables.net-dt "1.10.19"]
@ -95,15 +83,15 @@
[simplemde "1.11.2"]] [simplemde "1.11.2"]]
:root "resources/public/js/lib"} :root "resources/public/js/lib"}
;; `lein release` doesn't play nice with `git flow release`. Run `lein release` in the
;; `develop` branch, then reset the `master` branch to the release tag.
:release-tasks [["vcs" "assert-committed"] :release-tasks [["vcs" "assert-committed"]
["change" "version" "leiningen.release/bump-version" "release"] ["change" "version" "leiningen.release/bump-version" "release"]
["adl"]
["vcs" "commit"] ["vcs" "commit"]
;; ["vcs" "tag"] -- not working, problems with secret key
["clean"] ["clean"]
["npm" "install"]
["uberjar"] ["uberjar"]
["uberwar"] [uberwar]
["docker" "build"] ["docker" "build"]
["docker" "push"] ["docker" "push"]
["change" "version" "leiningen.release/bump-version"] ["change" "version" "leiningen.release/bump-version"]
@ -124,10 +112,9 @@
:profiles {:uberjar {:omit-source true :profiles {:uberjar {:omit-source true
:prep-tasks ["adl" :prep-tasks [;;"adl"
"compile" "compile"
["npm" "install"] ["cljsbuild" "once" "min"]]
["cljsbuild" "once" "min"]]
:cljsbuild :cljsbuild
{:builds {:builds
{:min {:min
@ -148,21 +135,21 @@
:test [:project/dev :project/test :profiles/test] :test [:project/dev :project/test :profiles/test]
:project/dev {:dependencies [[prone "1.6.3"] :project/dev {:dependencies [[prone "1.1.4"]
[ring/ring-mock "0.4.0"] [ring/ring-mock "0.3.2"]
[ring/ring-devel "1.7.1"] [ring/ring-devel "1.6.3"]
[org.webjars/webjars-locator-jboss-vfs "0.1.0"] [org.webjars/webjars-locator-jboss-vfs "0.1.0"]
[luminus-immutant "0.2.5"] [luminus-immutant "0.2.4"]
[pjstadig/humane-test-output "0.9.0"] [pjstadig/humane-test-output "0.8.3"]
[binaryage/devtools "0.9.10"] [binaryage/devtools "0.9.10"]
[com.cemerick/piggieback "0.2.2"] [com.cemerick/piggieback "0.2.2"]
[directory-naming/naming-java "0.8"] [directory-naming/naming-java "0.8"]
[doo "0.1.11"] [doo "0.1.10"]
[figwheel-sidecar "0.5.18"]] [figwheel-sidecar "0.5.16"]]
:plugins [[com.jakemccrary/lein-test-refresh "0.23.0"] :plugins [[com.jakemccrary/lein-test-refresh "0.23.0"]
[lein-doo "0.1.10"] [lein-doo "0.1.10"]
[lein-figwheel "0.5.16"] [lein-figwheel "0.5.16"]
[org.clojure/clojurescript "1.10.520"]] [org.clojure/clojurescript "1.9.495"]]
:cljsbuild {:builds :cljsbuild {:builds
{:app {:app
{:source-paths ["src/cljs" "src/cljc" "env/dev/cljs"] {:source-paths ["src/cljs" "src/cljc" "env/dev/cljs"]

View file

@ -45,6 +45,7 @@ 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);
} }
@ -56,7 +57,6 @@ h1 {
#nav-menu { #nav-menu {
margin: 0; margin: 0;
padding: 0; padding: 0;
z-index: 02110-1301;
} }
#nav menu li { #nav menu li {
@ -103,7 +103,6 @@ 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%;
} }
@ -142,7 +141,7 @@ h1 {
margin: 0; margin: 0;
padding: 0; padding: 0;
position: fixed; position: fixed;
z-index: 600; z-index: 149;
color: silver; color: silver;
background:rgba(40,40,40,0.9); background:rgba(40,40,40,0.9);
} }
@ -150,7 +149,6 @@ 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: 2em; bottom: 3.5em;
right: 0; right: 0;
z-index: 175; z-index: 175;
background: transparent; background: transparent;
@ -362,6 +362,7 @@ th {
/* content of the current page in the Wiki - editable, provided by users. Within main-container */ /* content of the current page in the Wiki - editable, provided by users. Within main-container */
#content { #content {
border: thin solid silver;
width: 80%; width: 80%;
float: right; float: right;
padding-bottom: 5em; padding-bottom: 5em;
@ -395,14 +396,11 @@ th {
/* content of the current in the Wiki - editable, provided by users. Within main-container */ /* content of the current in the Wiki - editable, provided by users. Within main-container */
#content { #content {
border: thin solid silver;
width: 100%; width: 100%;
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

@ -1,60 +0,0 @@
<!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

@ -43,7 +43,7 @@ SELECT DISTINCT request.*,
addresses.address ||', '|| addresses.postcode ||', '|| visits.date AS visit_id_expanded, addresses.address ||', '|| addresses.postcode ||', '|| visits.date AS visit_id_expanded,
request.issue_id as issue_id_expanded, request.issue_id as issue_id_expanded,
request.method_id AS method_id_expanded, request.method_id AS method_id_expanded,
visits.date AS raised visits.date
FROM followuprequests as request, FROM followuprequests as request,
ln_experts_issues_canvassers as expertise, ln_experts_issues_canvassers as expertise,
canvassers as experts, canvassers as experts,
@ -53,13 +53,12 @@ FROM followuprequests as request,
where not exists (select * from followupactions as action where not exists (select * from followupactions as action
where action.request_id = request.id where action.request_id = request.id
and action.closed = true) and action.closed = true)
and request.locked_by is null
and request.elector_id = electors.id and request.elector_id = electors.id
and request.visit_id = visits.id and request.visit_id = visits.id
and visits.address_id = addresses.id and visits.address_id = addresses.id
and request.issue_id = expertise.issue_id and request.issue_id = expertise.issue_id
and expertise.canvasser_id = :expert and expertise.canvasser_id = :expert
ORDER BY raised ORDER BY visits.date desc
--:name get-last-visit-by-canvasser :? :1 --:name get-last-visit-by-canvasser :? :1
--:doc returns the most recent visit record of the canvasser with the specified `:id` --:doc returns the most recent visit record of the canvasser with the specified `:id`
@ -68,20 +67,13 @@ WHERE canvasser_id = :id
ORDER BY date desc ORDER BY date desc
LIMIT 1 LIMIT 1
--:name get-locality-for-visit :? :1 -- I don't know why this next one isn't autogenerating, but it isn't and it's critical.
--:doc returns the locality of the address of this visit
SELECT addresses.locality
FROM addresses, visits
WHERE visits.address_id = addresses.id
AND visits.id = :id
-- :name list-roles-by-canvasser :? :*
-- :name list-elector-intentions :? :* -- :doc links all existing canvasser records related to a given role
-- :doc short form of `list-intentions-by-elector`, returning far less data, for use in `youyesyet.routes.rest/get-local-data`, q.v. SELECT roles.*
-- TODO: should be limited to visits in the past 24 hours, to prevent the app being FROM roles, ln_canvassers_roles
-- used to harrass NO voters. See https://github.com/simon-brooke/youyesyet/issues/58 WHERE roles.id = ln_canvassers_roles.role_id
SELECT intentions.id, intentions.option_id, visits.date AND ln_canvassers_roles.canvasser_id = :id
FROM intentions, visits ORDER BY roles.name,
WHERE intentions.visit_id = visits.id roles.id
AND intentions.elector_id = :id
ORDER BY visits.date DESC

View file

@ -1,53 +0,0 @@
------------------------------------------------------------------------
-- User `youyesyet` (the app, and less secure parts of the site)
-- must have the permissions of `canvassers`.
------------------------------------------------------------------------
DO
$do$
BEGIN
IF NOT EXISTS (
SELECT -- SELECT list can stay empty for this
FROM pg_catalog.pg_roles
WHERE rolname = 'youyesyet') THEN
CREATE ROLE youyesyet LOGIN PASSWORD 'thisisnotsecure';
END IF;
END
$do$;
grant canvassers to youyesyet;
------------------------------------------------------------------------
-- convenience view lv_followupactions of entity followupactions for
-- lists, et cetera
-- ADL is not yet correctly chaining tables when generating convenience
-- views, so the auto-generated convenience view is a horrible
-- cross-product join
------------------------------------------------------------------------
DROP VIEW lv_followupactions;
CREATE VIEW lv_followupactions AS
SELECT electors.name ||', '|| addresses.address ||', '|| addresses.postcode ||', '|| visits.date ||', '|| issues.id AS request_id_expanded,
followupactions.request_id,
canvassers.username ||', '|| canvassers.fullname ||', '|| addresses.address ||', '|| addresses.postcode ||', '|| canvassers.phone ||', '|| canvassers.email AS actor_expanded,
followupactions.actor,
canvassers.fullname AS actor_name,
followupactions.date,
followupactions.notes,
followupactions.closed,
followupactions.id
FROM followuprequests, visits, canvassers, addresses, followupactions, issues, electors
WHERE followupactions.request_id = followuprequests.id
AND followuprequests.elector_id = electors.id
AND followuprequests.visit_id = visits.id
AND followuprequests.issue_id = issues.id
AND visits.address_id = addresses.id
AND followupactions.actor = canvassers.id
;
GRANT SELECT ON lv_followupactions TO canvassers, issueexperts;
------------------------------------------------------------------------
-- request locking
------------------------------------------------------------------------
ALTER TABLE followuprequests ADD COLUMN locked_by INTEGER REFERENCES canvassers(id) ON DELETE SET NULL;
ALTER TABLE followuprequests ADD COLUMN locked TIMESTAMP;

View file

@ -5,7 +5,6 @@
<!-- head: if you want entire custom head content, override this block. --> <!-- head: if you want entire custom head content, override this block. -->
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/> <meta name="viewport" content="width=device-width, initial-scale=1"/>
<meta name="referrer" content="same-origin">
{% style "/css/yyy-common.css" %} {% style "/css/yyy-common.css" %}
{% style "/css/yyy-site.css" %} {% style "/css/yyy-site.css" %}
{% style "/css/spinner.css" %} {% style "/css/spinner.css" %}
@ -27,14 +26,10 @@
<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="https://library.projecthope.scot/">Library</a></li> <li class=""><a href="{{servlet-context}}/library">Library</a></li>
{% if user %}
<li class=""><a href="{{servlet-context}}/roles">Roles</a></li>
<li class=""><a href="{{servlet-context}}/logout">Logout</a></li>
{% else %}
<li class=""><a href="{{servlet-context}}/register">Register</a></li> <li class=""><a href="{{servlet-context}}/register">Register</a></li>
<li class=""><a href="{{servlet-context}}/login">Login</a></li> <li class="">{% if user %}<a href="{{servlet-context}}/logout">Logout</a>
{% endif %} {% else %}<a href="{{servlet-context}}/login">Login</a>{% endif %}</li>
<li class=""><a href="{{servlet-context}}/about">About</a></li> <li class=""><a href="{{servlet-context}}/about">About</a></li>
{% if user %} {% if user %}
<li id="user"><a href="{{servlet-context}}/profile">Logged in as {{user.username}}</a></li> <li id="user"><a href="{{servlet-context}}/profile">Logged in as {{user.username}}</a></li>
@ -68,31 +63,18 @@
<!-- 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,12 +2,23 @@
{% block big-links %} {% block big-links %}
{% endblock %} {% endblock %}
{% block content %} {% block content %}
{% 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,9 +1,5 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block extra-head %}
<meta http-equiv="refresh" content="60">
{% endblock %}
{% block back-links %} {% block back-links %}
<div> <div>
<div class='back-link-container'> <div class='back-link-container'>
@ -40,16 +36,19 @@ Add a new Followuprequest
<thead> <thead>
<tr> <tr>
<th> <th>
Elector Id
</th> </th>
<th> <th>
Raised Elector_id
</th> </th>
<th> <th>
Issue Visit_id
</th> </th>
<th> <th>
Method Issue_id
</th>
<th>
Method_id
</th> </th>
<th> <th>
&nbsp; &nbsp;
@ -57,10 +56,13 @@ Method
</tr> </tr>
<tr> <tr>
<th> <th>
<input id='id' type='text' name='id' value='{{ params.id }}'/>
</th>
<th>
<input id='elector_id' type='text' name='elector_id' value='{{ params.elector_id }}'/> <input id='elector_id' type='text' name='elector_id' value='{{ params.elector_id }}'/>
</th> </th>
<th> <th>
<input id='raised' type='text' name='raised' value='{{ params.raised }}'/> <input id='visit_id' type='text' name='visit_id' value='{{ params.visit_id }}'/>
</th> </th>
<th> <th>
<input id='issue_id' type='text' name='issue_id' value='{{ params.issue_id }}'/> <input id='issue_id' type='text' name='issue_id' value='{{ params.issue_id }}'/>
@ -77,21 +79,22 @@ Method
{% for record in records %} {% for record in records %}
<tr> <tr>
<td> <td>
{{ record.id }}
</td>
<td>
<a href='{{servlet-context}}/form-electors-Elector?id={{ record.elector_id }}'> <a href='{{servlet-context}}/form-electors-Elector?id={{ record.elector_id }}'>
{{ record.elector_id_expanded }} {{ record.elector_id_expanded }}
</a> </a>
</td> </td>
<td> <td>
{{ record.raised }} <a href='{{servlet-context}}/form-visits-Visit?id={{ record.visit_id }}'>
{{ record.visit_id_expanded }}
</a>
</td> </td>
<td> <td>
{% ifequal record.issue_id "Other" %} <a href='{{servlet-context}}/form-issues-Issue?id={{ record.issue_id }}'>
{{ record.issue_detail }} {{ record.issue_id_expanded }}
{% else %} </a>
<a href='{{servlet-context}}/form-issues-Issue?id={{ record.issue_id }}'>
{{ record.issue_id }}
</a>
{% endifequal %}
</td> </td>
<td> <td>
<a href='{{servlet-context}}/form-followupmethods-Followupmethod?id={{ record.method_id }}'> <a href='{{servlet-context}}/form-followupmethods-Followupmethod?id={{ record.method_id }}'>

View file

@ -13,19 +13,16 @@
<form action='{{servlet-context}}/issue-expert/followup-action' method='POST'> <form action='{{servlet-context}}/issue-expert/followup-action' method='POST'>
{% csrf-field %} {% csrf-field %}
<input id='id' name='id' type='hidden' value='{{record.id}}'/> <input id='id' name='id' type='hidden' value='{{record.id}}'/>
<input id='request_id' name='request_id' type='hidden' value='{{record.id}}'/>
<input id='elector_id' name='elector_id' type='hidden' value='{{record.elector_id}}'/>
<input id='visit_id' name='visit_id' type='hidden' value='{{record.visit_id}}'/>
<p class='widget'> <p class='widget'>
<label for='elector_id'> <label for='elector_id'>
Elector Elector
</label> </label>
{% ifmemberof canvassers teamorganisers issueexperts analysts issueeditors admin %} {% ifmemberof canvassers teamorganisers issueexperts analysts issueeditors admin %}
<span id='elector' name='elector' class='pseudo-widget disabled'> <span id='elector_id' name='elector_id' class='pseudo-widget disabled'>
{{elector.name}} ({{elector.gender}}) {{elector.name}} ({{elector.gender}})
</span> </span>
{% else %} {% else %}
<span id='elector' name='elector' class='pseudo-widget not-authorised'> <span id='elector_id' name='elector_id' class='pseudo-widget not-authorised'>
You are not permitted to view elector of followuprequests You are not permitted to view elector of followuprequests
</span> </span>
{% endifmemberof %} {% endifmemberof %}
@ -36,7 +33,7 @@
</label> </label>
{% ifmemberof issueexperts analysts issueeditors admin %} {% ifmemberof issueexperts analysts issueeditors admin %}
<span id='visit' name='visit' class='pseudo-widget disabled'> <span id='visit' name='visit' class='pseudo-widget disabled'>
by {{visit.canvasser_id_expanded}} on {{visit.date}} by {{visit.canvasser_id_expanded}} at {{visit.date}}
</span> </span>
{% else %} {% else %}
<span id='visit_id' name='visit_id' class='pseudo-widget not-authorised'> <span id='visit_id' name='visit_id' class='pseudo-widget not-authorised'>
@ -46,17 +43,8 @@
</p> </p>
<p class='widget'> <p class='widget'>
<label for='issue_id'> <label for='issue_id'>
Issue {{issue.id}}
</label> </label>
{% ifmemberof issueexperts analysts issueeditors admin %}
<span id='issue_id' name='issue_id' class='pseudo-widget disabled'>
{{issue.id}} <em>{{record.issue_detail}}</em>
</span>
{% else %}
<span id='issue_id' name='issue_id' class='pseudo-widget not-authorised'>
You are not permitted to view issue of followuprequests
</span>
{% endifmemberof %}
{% ifmemberof issueexperts admin %} {% ifmemberof issueexperts admin %}
<div id="issue-brief"> <div id="issue-brief">
{{issue.brief|safe}} {{issue.brief|safe}}
@ -104,7 +92,7 @@
<tbody> <tbody>
{% for action in actions %} {% for action in actions %}
<tr> <tr>
<td><a href="{{servlet-context}}/form-canvassers-Canvasser?id={{action.actor}}">{{action.actor_name}}</a></td> <td>{{action.actor}}</td>
<td>{{action.date}}</td> <td>{{action.date}}</td>
<td>{{action.closed}}</td> <td>{{action.closed}}</td>
</tr> </tr>
@ -116,13 +104,13 @@
</table> </table>
</p> </p>
{% endif %} {% endif %}
{% if not closed %}
<p class='widget'> <p class='widget'>
<label for='notes'> <label for='notes'>
Your notes Your notes
</label> </label>
{% ifmemberof admin issueexperts %} {% ifmemberof admin issueexperts %}
<textarea rows='8' cols='60' id='notes' name='notes'></textarea> <textarea rows='8' cols='60' id='notes' name='notes'>
</textarea>
{% endifmemberof %} {% endifmemberof %}
</p> </p>
<p class='widget'> <p class='widget'>
@ -133,21 +121,7 @@
<input id='closed' name='closed' type='checkbox' maxlength='' size='16'/> <input id='closed' name='closed' type='checkbox' maxlength='' size='16'/>
{% endifmemberof %} {% endifmemberof %}
</p> </p>
<p class='widget'>
<label for='intention'>
What is the elector's voting intention now?
</label>
{% ifmemberof admin issueexperts %}
<select id='option_id' name='option_id'>
<option value="">Not stated</option>
{% for option in options %}
<img src="{{servlet-context}}/img/option/{{option.id}}-{% ifequal record.option_id option.id %}selected{% else %}unselected{% endifequal %}.png" alt="{{option.id}}"/>
<option value='{{option.id}}' {% ifequal record.option_id option.id%}selected='selected'{% endifequal %} style="background-image: url('{{servlet-context}}/img/option/{{option.id}}-{% ifequal record.option_id option.id %}selected{% else %}unselected{% endifequal %}.png')">
{{option.id}}</option>
{% endfor %}
</select>
{% endifmemberof %}
</p>
{% ifmemberof admin issueexperts %} {% ifmemberof admin issueexperts %}
<p class='widget action-safe'> <p class='widget action-safe'>
<label for='save-button' class='action-safe'> <label for='save-button' class='action-safe'>
@ -156,7 +130,6 @@
<input id='save-button' name='save-button' class='action-safe' type='submit' value='Save!'/> <input id='save-button' name='save-button' class='action-safe' type='submit' value='Save!'/>
</p> </p>
{% endifmemberof %} {% endifmemberof %}
{% endif %}
</form> </form>
</div> </div>

Some files were not shown because too many files have changed in this diff Show more