diff --git a/project.clj b/project.clj
index 55fb09d..541e8eb 100644
--- a/project.clj
+++ b/project.clj
@@ -9,6 +9,7 @@
[clj-oauth "1.5.5"]
[cljsjs/react-leaflet "1.6.5-0"]
[cljs-ajax "0.7.4"]
+ [clojure.java-time "0.3.2"]
[com.cemerick/url "0.1.1"]
[compojure "1.6.1"]
[conman "0.8.2"]
diff --git a/resources/sql/youyesyet.postgres.sql b/resources/sql/youyesyet.postgres.sql
deleted file mode 100644
index e54ce0e..0000000
--- a/resources/sql/youyesyet.postgres.sql
+++ /dev/null
@@ -1,1133 +0,0 @@
-------------------------------------------------------------------------
--- Database definition for application
---
--- youyesyet version 0.1.1
---
--- auto-generated by [Application Description Language framework]
---
--- (https://github.com/simon-brooke/adl) at 20180721T171142.862Z
---
--- A web-app intended to be used by canvassers
--- campaigning for a 'Yes' vote in the second independence
--- referendum. The web-app will be delivered to canvassers out
--- knocking doors primarily through an HTML5/React single-page app
--- designed to work on a mobile phone; it's possible that someone
--- else may do an Android of iPhone native app to address the same
--- back end but at present I have no plans for this. There must also
--- be an administrative interface through which privileged users can
--- set the system up and authorise canvassers, and a 'followup'
--- interface through which issue-expert specialist canvassers can
--- address particular electors' queries.
-------------------------------------------------------------------------
-
-------------------------------------------------------------------------
--- security group admin
-------------------------------------------------------------------------
-
-CREATE GROUP admin;
-
-------------------------------------------------------------------------
--- security group analysts
-------------------------------------------------------------------------
-
-CREATE GROUP analysts;
-
-------------------------------------------------------------------------
--- security group canvassers
-------------------------------------------------------------------------
-
-CREATE GROUP canvassers;
-
-------------------------------------------------------------------------
--- security group issueeditors
-------------------------------------------------------------------------
-
-CREATE GROUP issueeditors;
-
-------------------------------------------------------------------------
--- security group issueexperts
-------------------------------------------------------------------------
-
-CREATE GROUP issueexperts;
-
-------------------------------------------------------------------------
--- security group public
-------------------------------------------------------------------------
-
-CREATE GROUP public;
-
-------------------------------------------------------------------------
--- security group teamorganisers
-------------------------------------------------------------------------
-
-CREATE GROUP teamorganisers;
-
-------------------------------------------------------------------------
--- primary table addresses for entity addresses
---
--- Addresses of all buildings which contain
--- dwellings.
-------------------------------------------------------------------------
-CREATE TABLE addresses
-(
- id SERIAL NOT NULL PRIMARY KEY,
- address VARCHAR(256) NOT NULL,
- postcode VARCHAR(16) CONSTRAINT pattern_1 CHECK (postcode ~* '^([Gg][Ii][Rr] 0[Aa]{2})|((([A-Za-z][0-9]{1,2})|(([A-Za-z][A-Ha-hJ-Yj-y][0-9]{1,2})|(([AZa-z][0-9][A-Za-z])|([A-Za-z][A-Ha-hJ-Yj-y][0-9]?[A-Za-z]))))[0-9][A-Za-z]{2})$'),
- phone VARCHAR(16),
- district_id INTEGER,
- latitude DOUBLE PRECISION,
- longitude DOUBLE PRECISION,
- locality INTEGER
-);
-GRANT SELECT ON addresses TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON addresses TO admin ;
-GRANT UPDATE ON addresses TO admin ;
-GRANT DELETE ON addresses TO admin ;
-
-------------------------------------------------------------------------
--- primary table authorities for entity authorities
---
--- Authorities which may authenticate canvassers to
--- the system.
-------------------------------------------------------------------------
-CREATE TABLE authorities
-(
- id VARCHAR(32) NOT NULL PRIMARY KEY,
- request_token_uri VARCHAR(256) NOT NULL,
- access_token_uri VARCHAR(256) NOT NULL,
- authorize_uri VARCHAR(256) NOT NULL,
- consumer_key VARCHAR(32) DEFAULT 'youyesyet' NOT NULL,
- consumer_secret VARCHAR(256) NOT NULL
-);
-GRANT SELECT ON authorities TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON authorities TO admin ;
-GRANT UPDATE ON authorities TO admin ;
-GRANT DELETE ON authorities TO admin ;
-
-------------------------------------------------------------------------
--- primary table canvassers for entity canvassers
---
--- Primary users of the system: those actually
--- interviewing electors.
-------------------------------------------------------------------------
-CREATE TABLE canvassers
-(
- id SERIAL NOT NULL PRIMARY KEY,
- username VARCHAR(32) NOT NULL,
- fullname VARCHAR(64) NOT NULL,
- avatar VARCHAR(),
- bio TEXT,
- elector_id INTEGER,
- address_id INTEGER NOT NULL,
- phone VARCHAR(16),
- email VARCHAR(128),
- authority_id VARCHAR(32) NOT NULL,
- authorised BOOLEAN
-);
-GRANT SELECT ON canvassers TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON canvassers TO admin,
- canvassers,
- teamorganisers ;
-GRANT UPDATE ON canvassers TO admin,
- canvassers,
- teamorganisers ;
-GRANT DELETE ON canvassers TO admin ;
-
-------------------------------------------------------------------------
--- primary table districts for entity districts
---
--- Electoral districts: TODO: Shape (polygon)
--- information will need to be added, for use in
--- maps.
-------------------------------------------------------------------------
-CREATE TABLE districts
-(
- id SERIAL NOT NULL PRIMARY KEY,
- name VARCHAR(64) NOT NULL
-);
-GRANT SELECT ON districts TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- public,
- teamorganisers ;
-GRANT INSERT ON districts TO admin ;
-GRANT UPDATE ON districts TO admin ;
-GRANT DELETE ON districts TO admin ;
-
-------------------------------------------------------------------------
--- primary table dwellings for entity dwellings
---
--- All dwellings within addresses in the system; a
--- dwelling is a house, flat or appartment in which electors live.
--- Every address should have at least one dwelling; essentially,
--- an address maps onto a street door and dwellings map onto
--- what's behind that door. So a tenement or a block of flats
--- would be one address with many dwellings.
-------------------------------------------------------------------------
-CREATE TABLE dwellings
-(
- id SERIAL NOT NULL PRIMARY KEY,
- address_id INTEGER NOT NULL,
- sub_address VARCHAR(32)
-);
-GRANT SELECT ON dwellings TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON dwellings TO admin ;
-GRANT UPDATE ON dwellings TO admin ;
-GRANT DELETE ON dwellings TO admin ;
-
-------------------------------------------------------------------------
--- primary table electors for entity electors
---
--- All electors known to the system; electors are
--- people believed to be entitled to vote in the current
--- campaign.
-------------------------------------------------------------------------
-CREATE TABLE electors
-(
- id SERIAL NOT NULL PRIMARY KEY,
- name VARCHAR(64) NOT NULL,
- dwelling_id INTEGER NOT NULL,
- phone VARCHAR(16),
- email VARCHAR(128),
- gender VARCHAR(32) DEFAULT 'Unknown',
- signature TEXT
-);
-GRANT SELECT ON electors TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON electors TO admin ;
-GRANT UPDATE ON electors TO admin ;
-GRANT DELETE ON electors TO admin ;
-
-------------------------------------------------------------------------
--- primary table events for entity events
---
---
--- An event to which a team or teams are invited. Typically created
--- by the team organiser(s).
--- May be a training event, a social event or a canvassing
--- session.
---
-------------------------------------------------------------------------
-CREATE TABLE events
-(
- id SERIAL NOT NULL PRIMARY KEY,
- name VARCHAR(64) NOT NULL,
- date DATE,
- time TIME,
- decription TEXT,
- cancelled BOOLEAN DEFAULT false
-);
-GRANT SELECT ON events TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON events TO admin,
- teamorganisers ;
-GRANT UPDATE ON events TO admin,
- teamorganisers ;
-GRANT DELETE ON events TO admin ;
-
-------------------------------------------------------------------------
--- primary table followupactions for entity followupactions
---
--- Actions taken on followup
--- requests.
-------------------------------------------------------------------------
-CREATE TABLE followupactions
-(
- id SERIAL NOT NULL PRIMARY KEY,
- request_id INTEGER NOT NULL,
- actor INTEGER NOT NULL,
- date TIMESTAMP DEFAULT 'now()' NOT NULL,
- notes TEXT,
- closed BOOLEAN DEFAULT false
-);
-GRANT SELECT ON followupactions TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts ;
-GRANT INSERT ON followupactions TO admin,
- issueexperts ;
-GRANT UPDATE ON followupactions TO admin ;
-GRANT DELETE ON followupactions TO admin ;
-
-------------------------------------------------------------------------
--- primary table followupmethods for entity followupmethods
---
--- Methods which may be used to follow up a followup request. Reference
--- data.
-------------------------------------------------------------------------
-CREATE TABLE followupmethods
-(
- id VARCHAR(32) NOT NULL PRIMARY KEY
-);
-GRANT SELECT ON followupmethods TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON followupmethods TO admin ;
-GRANT UPDATE ON followupmethods TO admin ;
-GRANT DELETE ON followupmethods TO admin ;
-
-------------------------------------------------------------------------
--- primary table followuprequests for entity followuprequests
---
--- Requests for a followup with an issue
--- expert
-------------------------------------------------------------------------
-CREATE TABLE followuprequests
-(
- id SERIAL NOT NULL PRIMARY KEY,
- elector_id INTEGER NOT NULL,
- visit_id INTEGER NOT NULL,
- issue_id VARCHAR(32) NOT NULL,
- method_id VARCHAR(32) NOT NULL
-);
-GRANT SELECT ON followuprequests TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON followuprequests TO admin,
- canvassers ;
-
-
-
-------------------------------------------------------------------------
--- primary table genders for entity genders
---
--- All genders which may be assigned to
--- electors.
-------------------------------------------------------------------------
-CREATE TABLE genders
-(
- id VARCHAR(32) NOT NULL PRIMARY KEY
-);
-GRANT SELECT ON genders TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON genders TO admin ;
-GRANT UPDATE ON genders TO admin ;
-GRANT DELETE ON genders TO admin ;
-
-------------------------------------------------------------------------
--- primary table intentions for entity intentions
---
--- Intentions of electors to vote for options
--- elicited in visits.
-------------------------------------------------------------------------
-CREATE TABLE intentions
-(
- id SERIAL NOT NULL PRIMARY KEY,
- visit_id INTEGER NOT NULL,
- elector_id INTEGER,
- option_id VARCHAR(32) NOT NULL,
- locality INTEGER NOT NULL
-);
-GRANT SELECT ON intentions TO admin,
- analysts,
- canvassers ;
-GRANT INSERT ON intentions TO admin,
- canvassers ;
-
-
-
-------------------------------------------------------------------------
--- primary table issues for entity issues
---
--- Issues believed to be of interest to electors,
--- about which they may have questions.
-------------------------------------------------------------------------
-CREATE TABLE issues
-(
- id VARCHAR(32) NOT NULL PRIMARY KEY,
- url VARCHAR(256),
- current BOOLEAN DEFAULT true,
- brief TEXT
-);
-GRANT SELECT ON issues TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON issues TO admin,
- issueeditors ;
-GRANT UPDATE ON issues TO admin,
- issueeditors ;
-GRANT DELETE ON issues TO admin ;
-
-------------------------------------------------------------------------
--- primary table options for entity options
---
--- Options in the election or referendum being
--- canvassed on
-------------------------------------------------------------------------
-CREATE TABLE options
-(
- id VARCHAR(32) NOT NULL PRIMARY KEY
-);
-GRANT SELECT ON options TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON options TO admin ;
-GRANT UPDATE ON options TO admin ;
-GRANT DELETE ON options TO admin ;
-
-------------------------------------------------------------------------
--- primary table roles for entity roles
---
--- A role (essentially, the same as a group, but
--- application layer rather than database layer) of which a user
--- may be a member.
-------------------------------------------------------------------------
-CREATE TABLE roles
-(
- id SERIAL NOT NULL PRIMARY KEY,
- name VARCHAR(64) NOT NULL
-);
-GRANT SELECT ON roles TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON roles TO admin ;
-GRANT UPDATE ON roles TO admin ;
-GRANT DELETE ON roles TO admin ;
-
-------------------------------------------------------------------------
--- primary table teams for entity teams
-------------------------------------------------------------------------
-CREATE TABLE teams
-(
- id SERIAL NOT NULL PRIMARY KEY,
- name VARCHAR(64) NOT NULL,
- district_id INTEGER NOT NULL,
- latitude DOUBLE PRECISION,
- longitude DOUBLE PRECISION
-);
-GRANT SELECT ON teams TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON teams TO admin,
- teamorganisers ;
-GRANT UPDATE ON teams TO admin,
- teamorganisers ;
-GRANT DELETE ON teams TO admin ;
-
-------------------------------------------------------------------------
--- primary table visits for entity visits
---
--- All visits made by canvassers to dwellings in
--- which opinions were recorded.
-------------------------------------------------------------------------
-CREATE TABLE visits
-(
- id SERIAL NOT NULL PRIMARY KEY,
- address_id INTEGER NOT NULL,
- canvasser_id INTEGER NOT NULL,
- date TIMESTAMP DEFAULT 'now()' NOT NULL
-);
-GRANT SELECT ON visits TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON visits TO admin,
- canvassers,
- teamorganisers ;
-GRANT UPDATE ON visits TO admin ;
-GRANT DELETE ON visits TO admin ;
-
-------------------------------------------------------------------------
--- convenience view lv_addresses of entity addresses for lists, et cetera
-------------------------------------------------------------------------
-CREATE VIEW lv_addresses AS
-SELECT addresses.address,
- addresses.postcode,
- addresses.phone,
- districts.name AS district_id_expanded,
- addresses.district_id,
- addresses.latitude,
- addresses.longitude,
- addresses.locality,
- addresses.id
-FROM addresses, districts
-WHERE addresses.district_id = districts.id
-;
-GRANT SELECT ON lv_addresses TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-
-------------------------------------------------------------------------
--- convenience view lv_authorities of entity authorities for lists, et
--- cetera
-------------------------------------------------------------------------
-CREATE VIEW lv_authorities AS
-SELECT authorities.request_token_uri,
- authorities.access_token_uri,
- authorities.authorize_uri,
- authorities.consumer_key,
- authorities.consumer_secret,
- authorities.id
-FROM authorities
-;
-GRANT SELECT ON lv_authorities TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-
-------------------------------------------------------------------------
--- convenience view lv_canvassers of entity canvassers for lists, et
--- cetera
-------------------------------------------------------------------------
-CREATE VIEW lv_canvassers AS
-SELECT canvassers.username,
- canvassers.fullname,
- canvassers.avatar,
- canvassers.bio,
- electors.name AS elector_id_expanded,
- canvassers.elector_id,
- addresses.address ||', '|| addresses.postcode AS address_id_expanded,
- canvassers.address_id,
- canvassers.phone,
- canvassers.email,
- authorities.id AS authority_id_expanded,
- canvassers.authority_id,
- canvassers.authorised,
- canvassers.id
-FROM canvassers, authorities, addresses, electors
-WHERE canvassers.elector_id = electors.id
- AND canvassers.address_id = addresses.id
- AND canvassers.authority_id = authorities.id
-;
-GRANT SELECT ON lv_canvassers TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-
-------------------------------------------------------------------------
--- convenience view lv_districts of entity districts for lists, et cetera
-------------------------------------------------------------------------
-CREATE VIEW lv_districts AS
-SELECT districts.name,
- districts.id
-FROM districts
-;
-GRANT SELECT ON lv_districts TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- public,
- teamorganisers ;
-
-------------------------------------------------------------------------
--- convenience view lv_dwellings of entity dwellings for lists, et cetera
-------------------------------------------------------------------------
-CREATE VIEW lv_dwellings AS
-SELECT addresses.address ||', '|| addresses.postcode AS address_id_expanded,
- dwellings.address_id,
- dwellings.sub_address,
- dwellings.id
-FROM dwellings, addresses
-WHERE dwellings.address_id = addresses.id
-;
-GRANT SELECT ON lv_dwellings TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-
-------------------------------------------------------------------------
--- convenience view lv_electors of entity electors for lists, et cetera
-------------------------------------------------------------------------
-CREATE VIEW lv_electors AS
-SELECT electors.name,
- addresses.address ||', '|| addresses.postcode ||', '|| dwellings.sub_address AS dwelling_id_expanded,
- electors.dwelling_id,
- electors.phone,
- electors.email,
- genders.id AS gender_expanded,
- electors.gender,
- electors.signature,
- electors.id
-FROM dwellings, addresses, genders, electors
-WHERE electors.dwelling_id = dwellings.id
- AND electors.gender = genders.id
-;
-GRANT SELECT ON lv_electors TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-
-------------------------------------------------------------------------
--- convenience view lv_events of entity events for lists, et cetera
-------------------------------------------------------------------------
-CREATE VIEW lv_events AS
-SELECT events.name,
- events.date,
- events.time,
- events.decription,
- events.cancelled,
- events.id
-FROM events
-;
-GRANT SELECT ON lv_events TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-
-------------------------------------------------------------------------
--- convenience view lv_followupactions of entity followupactions for
--- lists, et cetera
-------------------------------------------------------------------------
-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,
- followupactions.date,
- followupactions.notes,
- followupactions.closed,
- followupactions.id
-FROM followuprequests, visits, canvassers, addresses, followupactions, issues, electors
-WHERE followupactions.request_id = followuprequests.id
- AND followupactions.actor = canvassers.id
-;
-GRANT SELECT ON lv_followupactions TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts ;
-
-------------------------------------------------------------------------
--- convenience view lv_followupmethods of entity followupmethods for
--- lists, et cetera
-------------------------------------------------------------------------
-CREATE VIEW lv_followupmethods AS
-SELECT followupmethods.id
-FROM followupmethods
-;
-GRANT SELECT ON lv_followupmethods TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-
-------------------------------------------------------------------------
--- convenience view lv_followuprequests of entity followuprequests for
--- lists, et cetera
-------------------------------------------------------------------------
-CREATE VIEW lv_followuprequests AS
-SELECT electors.name AS elector_id_expanded,
- followuprequests.elector_id,
- addresses.address ||', '|| addresses.postcode ||', '|| visits.date AS visit_id_expanded,
- followuprequests.visit_id,
- issues.id AS issue_id_expanded,
- followuprequests.issue_id,
- followupmethods.id AS method_id_expanded,
- followuprequests.method_id,
- followuprequests.id
-FROM followuprequests, visits, addresses, issues, electors, followupmethods
-WHERE followuprequests.elector_id = electors.id
- AND followuprequests.visit_id = visits.id
- AND followuprequests.issue_id = issues.id
- AND followuprequests.method_id = followupmethods.id
-;
-GRANT SELECT ON lv_followuprequests TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-
-------------------------------------------------------------------------
--- convenience view lv_genders of entity genders for lists, et cetera
-------------------------------------------------------------------------
-CREATE VIEW lv_genders AS
-SELECT genders.id
-FROM genders
-;
-GRANT SELECT ON lv_genders TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-
-------------------------------------------------------------------------
--- convenience view lv_intentions of entity intentions for lists, et
--- cetera
-------------------------------------------------------------------------
-CREATE VIEW lv_intentions AS
-SELECT addresses.address ||', '|| addresses.postcode ||', '|| visits.date AS visit_id_expanded,
- intentions.visit_id,
- electors.name AS elector_id_expanded,
- intentions.elector_id,
- options.id AS option_id_expanded,
- intentions.option_id,
- intentions.locality,
- intentions.id
-FROM visits, intentions, addresses, electors, options
-WHERE intentions.visit_id = visits.id
- AND intentions.elector_id = electors.id
- AND intentions.option_id = options.id
-;
-GRANT SELECT ON lv_intentions TO admin,
- analysts,
- canvassers ;
-
-------------------------------------------------------------------------
--- convenience view lv_issues of entity issues for lists, et cetera
-------------------------------------------------------------------------
-CREATE VIEW lv_issues AS
-SELECT issues.url,
- issues.current,
- issues.brief,
- issues.id
-FROM issues
-;
-GRANT SELECT ON lv_issues TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-
-------------------------------------------------------------------------
--- convenience view lv_options of entity options for lists, et cetera
-------------------------------------------------------------------------
-CREATE VIEW lv_options AS
-SELECT options.id
-FROM options
-;
-GRANT SELECT ON lv_options TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-
-------------------------------------------------------------------------
--- convenience view lv_roles of entity roles for lists, et cetera
-------------------------------------------------------------------------
-CREATE VIEW lv_roles AS
-SELECT roles.name,
- roles.id
-FROM roles
-;
-GRANT SELECT ON lv_roles TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-
-------------------------------------------------------------------------
--- convenience view lv_teams of entity teams for lists, et cetera
-------------------------------------------------------------------------
-CREATE VIEW lv_teams AS
-SELECT teams.name,
- districts.name AS district_id_expanded,
- teams.district_id,
- teams.latitude,
- teams.longitude,
- teams.id
-FROM teams, districts
-WHERE teams.district_id = districts.id
-;
-GRANT SELECT ON lv_teams TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-
-------------------------------------------------------------------------
--- convenience view lv_visits of entity visits for lists, et cetera
-------------------------------------------------------------------------
-CREATE VIEW lv_visits AS
-SELECT addresses.address ||', '|| addresses.postcode AS address_id_expanded,
- visits.address_id,
- canvassers.username ||', '|| canvassers.fullname ||', '|| addresses.address ||', '|| addresses.postcode ||', '|| canvassers.phone ||', '|| canvassers.email AS canvasser_id_expanded,
- visits.canvasser_id,
- visits.date,
- visits.id
-FROM visits, canvassers, addresses
-WHERE visits.address_id = addresses.id
- AND visits.canvasser_id = canvassers.id
-;
-GRANT SELECT ON lv_visits TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-
-------------------------------------------------------------------------
--- referential integrity links for primary tables
-------------------------------------------------------------------------
-
-ALTER TABLE addresses ADD CONSTRAINT ri_addresses_districts_district_id
- FOREIGN KEY( district_id )
- REFERENCES districts(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE canvassers ADD CONSTRAINT ri_canvassers_addresses_address_id
- FOREIGN KEY( address_id )
- REFERENCES addresses(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE canvassers ADD CONSTRAINT ri_canvassers_authorities_authority_id
- FOREIGN KEY( authority_id )
- REFERENCES authorities(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE canvassers ADD CONSTRAINT ri_canvassers_electors_elector_id
- FOREIGN KEY( elector_id )
- REFERENCES electors(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE dwellings ADD CONSTRAINT ri_dwellings_addresses_address_id
- FOREIGN KEY( address_id )
- REFERENCES addresses(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE electors ADD CONSTRAINT ri_electors_dwellings_dwelling_id
- FOREIGN KEY( dwelling_id )
- REFERENCES dwellings(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE electors ADD CONSTRAINT ri_electors_genders_gender
- FOREIGN KEY( gender )
- REFERENCES genders(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE followupactions ADD CONSTRAINT ri_followupactions_canvassers_actor
- FOREIGN KEY( actor )
- REFERENCES canvassers(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE followupactions ADD CONSTRAINT ri_followupactions_followuprequests_request_id
- FOREIGN KEY( request_id )
- REFERENCES followuprequests(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE followuprequests ADD CONSTRAINT ri_followuprequests_electors_elector_id
- FOREIGN KEY( elector_id )
- REFERENCES electors(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE followuprequests ADD CONSTRAINT ri_followuprequests_issues_issue_id
- FOREIGN KEY( issue_id )
- REFERENCES issues(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE followuprequests ADD CONSTRAINT ri_followuprequests_followupmethods_method_id
- FOREIGN KEY( method_id )
- REFERENCES followupmethods(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE followuprequests ADD CONSTRAINT ri_followuprequests_visits_visit_id
- FOREIGN KEY( visit_id )
- REFERENCES visits(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE intentions ADD CONSTRAINT ri_intentions_electors_elector_id
- FOREIGN KEY( elector_id )
- REFERENCES electors(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE intentions ADD CONSTRAINT ri_intentions_options_option_id
- FOREIGN KEY( option_id )
- REFERENCES options(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE intentions ADD CONSTRAINT ri_intentions_visits_visit_id
- FOREIGN KEY( visit_id )
- REFERENCES visits(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE teams ADD CONSTRAINT ri_teams_districts_district_id
- FOREIGN KEY( district_id )
- REFERENCES districts(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE visits ADD CONSTRAINT ri_visits_addresses_address_id
- FOREIGN KEY( address_id )
- REFERENCES addresses(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE visits ADD CONSTRAINT ri_visits_canvassers_canvasser_id
- FOREIGN KEY( canvasser_id )
- REFERENCES canvassers(id)
- ON DELETE NO ACTION ;
-
-------------------------------------------------------------------------
--- link table joining canvassers with issues
-------------------------------------------------------------------------
-CREATE TABLE ln_expertise_canvassers_issues
-(
- canvasser_id INTEGER,
- issue_id VARCHAR(32)
-);
-GRANT SELECT ON ln_expertise_canvassers_issues TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON ln_expertise_canvassers_issues TO admin,
- canvassers,
- teamorganisers ;
-GRANT UPDATE ON ln_expertise_canvassers_issues TO admin,
- canvassers,
- teamorganisers ;
-GRANT DELETE ON ln_expertise_canvassers_issues TO admin ;
-
-ALTER TABLE ln_expertise_canvassers_issues ADD CONSTRAINT ri_ln_expertise_canvassers_issues_canvassers_canvasser_id
- FOREIGN KEY( canvasser_id )
- REFERENCES canvassers(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE ln_expertise_canvassers_issues ADD CONSTRAINT ri_ln_expertise_canvassers_issues_issues_issue_id
- FOREIGN KEY( issue_id )
- REFERENCES issues(id)
- ON DELETE NO ACTION ;
-
-------------------------------------------------------------------------
--- link table joining canvassers with roles
-------------------------------------------------------------------------
-CREATE TABLE ln_roles_canvassers_roles
-(
- canvasser_id INTEGER,
- role_id INTEGER
-);
-GRANT SELECT ON ln_roles_canvassers_roles TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON ln_roles_canvassers_roles TO admin,
- canvassers,
- teamorganisers ;
-GRANT UPDATE ON ln_roles_canvassers_roles TO admin,
- canvassers,
- teamorganisers ;
-GRANT DELETE ON ln_roles_canvassers_roles TO admin ;
-
-ALTER TABLE ln_roles_canvassers_roles ADD CONSTRAINT ri_ln_roles_canvassers_roles_canvassers_canvasser_id
- FOREIGN KEY( canvasser_id )
- REFERENCES canvassers(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE ln_roles_canvassers_roles ADD CONSTRAINT ri_ln_roles_canvassers_roles_roles_role_id
- FOREIGN KEY( role_id )
- REFERENCES roles(id)
- ON DELETE NO ACTION ;
-
-------------------------------------------------------------------------
--- link table joining events with teams
-------------------------------------------------------------------------
-CREATE TABLE ln_teams_events_teams
-(
- event_id INTEGER,
- team_id INTEGER
-);
-GRANT SELECT ON ln_teams_events_teams TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON ln_teams_events_teams TO admin,
- teamorganisers ;
-GRANT UPDATE ON ln_teams_events_teams TO admin,
- teamorganisers ;
-GRANT DELETE ON ln_teams_events_teams TO admin ;
-
-ALTER TABLE ln_teams_events_teams ADD CONSTRAINT ri_ln_teams_events_teams_events_event_id
- FOREIGN KEY( event_id )
- REFERENCES events(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE ln_teams_events_teams ADD CONSTRAINT ri_ln_teams_events_teams_teams_team_id
- FOREIGN KEY( team_id )
- REFERENCES teams(id)
- ON DELETE NO ACTION ;
-
-------------------------------------------------------------------------
--- link table joining issues with canvassers
-------------------------------------------------------------------------
-CREATE TABLE ln_experts_issues_canvassers
-(
- issue_id VARCHAR(32),
- canvasser_id INTEGER
-);
-GRANT SELECT ON ln_experts_issues_canvassers TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON ln_experts_issues_canvassers TO admin,
- issueeditors ;
-GRANT UPDATE ON ln_experts_issues_canvassers TO admin,
- issueeditors ;
-GRANT DELETE ON ln_experts_issues_canvassers TO admin ;
-
-ALTER TABLE ln_experts_issues_canvassers ADD CONSTRAINT ri_ln_experts_issues_canvassers_canvassers_canvasser_id
- FOREIGN KEY( canvasser_id )
- REFERENCES canvassers(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE ln_experts_issues_canvassers ADD CONSTRAINT ri_ln_experts_issues_canvassers_issues_issue_id
- FOREIGN KEY( issue_id )
- REFERENCES issues(id)
- ON DELETE NO ACTION ;
-
-------------------------------------------------------------------------
--- link table joining roles with canvassers
-------------------------------------------------------------------------
-CREATE TABLE ln_members_roles_canvassers
-(
- role_id INTEGER,
- canvasser_id INTEGER
-);
-GRANT SELECT ON ln_members_roles_canvassers TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON ln_members_roles_canvassers TO admin ;
-GRANT UPDATE ON ln_members_roles_canvassers TO admin ;
-GRANT DELETE ON ln_members_roles_canvassers TO admin ;
-
-ALTER TABLE ln_members_roles_canvassers ADD CONSTRAINT ri_ln_members_roles_canvassers_canvassers_canvasser_id
- FOREIGN KEY( canvasser_id )
- REFERENCES canvassers(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE ln_members_roles_canvassers ADD CONSTRAINT ri_ln_members_roles_canvassers_roles_role_id
- FOREIGN KEY( role_id )
- REFERENCES roles(id)
- ON DELETE NO ACTION ;
-
-------------------------------------------------------------------------
--- link table joining teams with canvassers
-------------------------------------------------------------------------
-CREATE TABLE ln_members_teams_canvassers
-(
- team_id INTEGER,
- canvasser_id INTEGER
-);
-GRANT SELECT ON ln_members_teams_canvassers TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON ln_members_teams_canvassers TO admin,
- teamorganisers ;
-GRANT UPDATE ON ln_members_teams_canvassers TO admin,
- teamorganisers ;
-GRANT DELETE ON ln_members_teams_canvassers TO admin ;
-
-ALTER TABLE ln_members_teams_canvassers ADD CONSTRAINT ri_ln_members_teams_canvassers_canvassers_canvasser_id
- FOREIGN KEY( canvasser_id )
- REFERENCES canvassers(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE ln_members_teams_canvassers ADD CONSTRAINT ri_ln_members_teams_canvassers_teams_team_id
- FOREIGN KEY( team_id )
- REFERENCES teams(id)
- ON DELETE NO ACTION ;
-
-------------------------------------------------------------------------
--- link table joining teams with canvassers
-------------------------------------------------------------------------
-CREATE TABLE ln_organisers_teams_canvassers
-(
- team_id INTEGER,
- canvasser_id INTEGER
-);
-GRANT SELECT ON ln_organisers_teams_canvassers TO admin,
- analysts,
- canvassers,
- issueeditors,
- issueexperts,
- teamorganisers ;
-GRANT INSERT ON ln_organisers_teams_canvassers TO admin,
- teamorganisers ;
-GRANT UPDATE ON ln_organisers_teams_canvassers TO admin,
- teamorganisers ;
-GRANT DELETE ON ln_organisers_teams_canvassers TO admin ;
-
-ALTER TABLE ln_organisers_teams_canvassers ADD CONSTRAINT ri_ln_organisers_teams_canvassers_canvassers_canvasser_id
- FOREIGN KEY( canvasser_id )
- REFERENCES canvassers(id)
- ON DELETE NO ACTION ;
-
-ALTER TABLE ln_organisers_teams_canvassers ADD CONSTRAINT ri_ln_organisers_teams_canvassers_teams_team_id
- FOREIGN KEY( team_id )
- REFERENCES teams(id)
- ON DELETE NO ACTION ;
\ No newline at end of file
diff --git a/src/clj/youyesyet/routes/rest.clj b/src/clj/youyesyet/routes/rest.clj
index 6463827..0de54d7 100644
--- a/src/clj/youyesyet/routes/rest.clj
+++ b/src/clj/youyesyet/routes/rest.clj
@@ -3,9 +3,12 @@
(:require [adl-support.core :refer [massage-params do-or-log-error]]
[clojure.core.memoize :as memo]
[clojure.java.io :as io]
+ [clojure.string :as s]
[clojure.tools.logging :as log]
[clojure.walk :refer [keywordize-keys]]
[compojure.core :refer [defroutes GET POST]]
+ [java-time :as jt]
+ [mount.core :as mount]
[noir.response :as nresponse]
[noir.util.route :as route]
[ring.util.http-response :as response]
@@ -104,44 +107,99 @@
(:address_id params)
(:address_id last-visit))
(:id last-visit)
- (db/create-visit! db/*db* params))))
+ (db/create-visit!
+ db/*db*
+ (assoc
+ params
+ :canvasser_id (-> request :session :user :id)
+ :date (jt/to-sql-timestamp (jt/local-date-time)))))))
-;; http://localhost:3000/rest/create-intention?address_id=18&elector-id=62&elector_id=62&intention=Yes&locality=5482391
+;; (current-visit-id {:session {:user {:email "simon@journeyman.cc",
+;; :phone "07768 130255",
+;; :roles #{"analysts" "canvassers" "admin" "teamorganisers" "issueexperts" "issueeditors"},
+;; :username "simon_brooke",
+;; :fullname "Simon Brooke",
+;; :bio "Sinister pagan",
+;; :elector_id 2, :id 4, :address_id 2,
+;; :authority_id "GitHub",
+;; :authorised true}}
+;; :params {:address_id 79, :elector_id 238, :locality 5494393, :option_id "Yes"}})
+;; (current-visit-id {:session {:user {:email "simon@journeyman.cc",
+;; :phone "07768 130255",
+;; :roles #{"analysts" "canvassers" "admin" "teamorganisers" "issueexperts" "issueeditors"},
+;; :username "simon_brooke",
+;; :fullname "Simon Brooke",
+;; :bio "Sinister pagan",
+;; :elector_id 2, :id 4, :address_id 2,
+;; :authority_id "GitHub",
+;; :authorised true}}
+;; :params {:address_id 80, :elector_id 239, :locality 5494393, :option_id "Yes"}})
+
+
+(defmacro do-or-return-reason
+ "Clojure stacktraces are unreadable. We have to do better; evaluate
+ this `form` in a try-catch block; return a map. If the evaluation
+ succeeds, the map will have a key `:result` whose value is the result;
+ otherwise it will have a key `:error` which will be bound to the most
+ sensible error message we can construct."
+ ;; TODO: candidate for moving to adl-support.core
+ [form]
+ `(try
+ {:result ~form}
+ (catch Exception any#
+ (clojure.tools.logging/error
+ (str (.getName (.getClass any#))
+ ": "
+ (.getMessage any#)
+ (with-out-str
+ (-> any# .printStackTrace))))
+ {:error
+ s/join "\n\tcaused by: "
+ (reverse
+ (loop [ex# any# result# ()]
+ (if-not (nil? ex#)
+ (recur
+ (.getCause ex#)
+ (str (.getName (.getClass ex#)) ": " (.getMessage ex#)))
+ result#)))})))
+
(defn create-intention-and-visit!
"Doing visit creation logic server side; request params are expected to
- include an `option`, an `elector_id` and an `address_id`, or an `option` and
+ include an `option_id`, an `elector_id` and an `address_id`, or an `option` and
a `location`. If no `address_id` is provided, we simply create an
- `intention` record from the `option` and the `locality`; if a `address_id`
+ `intention` record from the `option_id` and the `locality`; if an `address_id`
is provided, we need to check whether the last `visit` by the current `user`
was to the same address, if so use that as the `visit_id`, if not create
a new `visit` record."
[request]
- (let [params (:params request)]
+ (let [params (massage-params request)]
(log/debug "Creating intention with params: " params)
(if (-> request :session :user)
(if
(and
- (or (:locality params)
- (and (:elector-id params)
- (:address_id params)))
- (:intention params))
- (do-or-log-error
- {:status 201
- :body (with-out-str
- (print
- (hash-map
- :id
- (db/create-intention!
- db/*db*
- (assoc
- params :visit_id (current-visit-id request))
- (db/create-intention! db/*db* params)))))}
- :error-return {:status 500
- :body "Failed to create intention record"})
+ (or (:locality params)
+ (and (:elector_id params)
+ (:address_id params)))
+ (:option_id params))
+ (let [r (do-or-return-reason
+ (db/create-intention!
+ db/*db*
+ (assoc
+ params :visit_id (current-visit-id request))))]
+ (if
+ (:result r)
+ {:status 201
+ :body (with-out-str
+ (print
+ (hash-map
+ :id (:id (:result r))
+ )))}
+ {:status 500
+ :body (:error r)}))
{:status 400
- :body "create-intention requires params: `intention` and either `locality` or both `address_id` and `elector_id`."})
+ :body "create-intention requires params: `option_id` and either `locality` or both `address_id` and `elector_id`."})
{:status 403
:body "You must be logged in to do that"})))
diff --git a/src/cljs/youyesyet/canvasser_app/handlers.cljs b/src/cljs/youyesyet/canvasser_app/handlers.cljs
index 9f4f8d0..bfa2d4c 100644
--- a/src/cljs/youyesyet/canvasser_app/handlers.cljs
+++ b/src/cljs/youyesyet/canvasser_app/handlers.cljs
@@ -322,12 +322,11 @@
(assoc
(add-to-outqueue
(clear-messages db)
- (assoc
- args
- :address_id (-> db :address :id)
- :locality (-> db :address :locality)
- :elector_id (-> db :elector :id)
- :action :create-intention))
+ {:address_id (-> db :address :id)
+ :locality (-> db :address :locality)
+ :elector_id (-> db :elector :id)
+ :option_id (:intention args)
+ :action :create-intention})
:elector (assoc (:elector db) :intention intention)
:page :elector))))))
diff --git a/youyesyet.adl.xml b/youyesyet.adl.xml
index d828eb4..e47f78a 100644
--- a/youyesyet.adl.xml
+++ b/youyesyet.adl.xml
@@ -326,7 +326,7 @@ version="0.1.1">
+ column="date" default="CURRENT_TIMESTAMP" distinct="user">
@@ -704,7 +704,7 @@ version="0.1.1">
column="method_id" entity="followupmethods" farkey="id">
-
+
Phone number or email address for followup.
@@ -983,7 +983,7 @@ version="0.1.1">
column="actor" entity="canvassers" farkey="id">
-
diff --git a/youyesyet.canonical.adl.xml b/youyesyet.canonical.adl.xml
deleted file mode 100644
index 08e3a63..0000000
--- a/youyesyet.canonical.adl.xml
+++ /dev/null
@@ -1,1108 +0,0 @@
-A web-app intended to be used by canvassers
- campaigning for a 'Yes' vote in the second independence
- referendum. The web-app will be delivered to canvassers out
- knocking doors primarily through an HTML5/React single-page app
- designed to work on a mobile phone; it's possible that someone
- else may do an Android of iPhone native app to address the same
- back end but at present I have no plans for this. There must also
- be an administrative interface through which privileged users can
- set the system up and authorise canvassers, and a 'followup'
- interface through which issue-expert specialist canvassers can
- address particular electors' queries.
-
- See
- https://assets.publishing.service.gov.uk/government/uploads/system/uploads/attachment_data/file/488478/Bulk_Data_Transfer_-_additional_validation_valid_from_12_November_2015.pdf,
- section 3
- A valid postcode.
-
-
- All users
-
-
- All users of the canvasser app Able to read and
- add canvassing data in a limited radius around their current
- position.
-
-
- Organisers of canvassing teams Able to see and
- modify data on the canvassers in the team(s) they organise;
- able to add canvassers to their team; able to update canvassers
- in their team, including resetting passwords and locking
- accounts; able to see canvass data over the whole area in which
- their team operates.
-
-
- People expert on particular issues. Able to read
- followup requests, and the electors to which they relate; able
- to access (read/write) the issues wiki; able to write followuop
- action records.
-
-
- Users entitled to see an overview of the
- canvassing data collected. Able to read canvassing data over
- the whole map, including historical data.
-
-
- Users responsible for determining what issues
- should be current at any time. Able to set current issues; able
- to add issues.
-
-
- Able to read and update canvasser records, team
- membership records, team organisership records, issue expertise
- records; able to add and update reference data
- generally.
-
-
- All electors known to the system; electors are
- people believed to be entitled to vote in the current
- campaign.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The signature of this elector, captured as SVG text,
- as evidence they have consented to us holding data on them.
- Null if they have not.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- All genders which may be assigned to
- electors.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- All dwellings within addresses in the system; a
- dwelling is a house, flat or appartment in which electors live.
- Every address should have at least one dwelling; essentially,
- an address maps onto a street door and dwellings map onto
- what's behind that door. So a tenement or a block of flats
- would be one address with many dwellings.
-
-
-
-
-
-
-
-
-
-
- The part of the address which identifies the flat or
- apartment within the building, if in a multiple occupancy
- building.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Addresses of all buildings which contain
- dwellings.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Locality indexing; see issue #44. Note that
- this property should be generated automatically from the
- latitude and longitude: (+ (* 10000 ;; left-shift the
- latitude component four digits (integer (* latitude 1000)))
- (- ;; invert the sign of the longitude component, since ;;
- we're interested in localities West of Greenwich. (integer (*
- longitude 1000)))) We'll use a trigger to insert this. I
- don't think it will ever appear in the user interface; it's
- an implementation detail, not of interest to
- users.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- All visits made by canvassers to dwellings in
- which opinions were recorded.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- But only in their immediate
- area.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Authorities which may authenticate canvassers to
- the system.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Issues believed to be of interest to electors,
- about which they may have questions.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Intentions of electors to vote for options
- elicited in visits.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The locality at which the intention was
- recorded; used where an elector does not consent to have
- polling intention stored against them. This is a locality as
- described in
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- The locality at which the intention was
- recorded; used where an elector does not consent to have
- polling intention stored against them. This is a locality
- as described in
-
-
-
-
-
- Primary users of the system: those actually
- interviewing electors.
-
-
-
-
-
-
-
-
-
-
-
-
- An image of the canvasser, so that other members of their
- team can recognise them.
-
-
-
- Information the canvasser supplies about themselves; an introduction.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Only relevant to issue experts.
-
-
-
- But only their own record
-
-
- But only canvassers in their own
- team.
-
-
- All canvassers
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- But should only be able to edit their own
- record.
-
-
-
-
-
-
-
-
- Requests for a followup with an issue
- expert
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- A role (essentially, the same as a group, but
- application layer rather than database layer) of which a user
- may be a member.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- But only their own group(s)
-
-
-
-
-
- All groups
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- An event to which a team or teams are invited. Typically created by the team organiser(s).
- May be a training event, a social event or a canvassing session.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Electoral districts: TODO: Shape (polygon)
- information will need to be added, for use in
- maps.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Actions taken on followup
- requests.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- But only for electors in their immediate
- vicinity
-
-
-
-
-
-
-
- Options in the election or referendum being
- canvassed on
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Methods which may be used to follow up a followup request. Reference data.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file