From 2c4c61c458f560220705bcf19e15f46bb6ff848e Mon Sep 17 00:00:00 2001 From: Simon Brooke Date: Fri, 27 Jul 2018 12:46:35 +0100 Subject: [PATCH] Have now (finally) inserting correctly, but not returning success(?) --- project.clj | 1 + resources/sql/youyesyet.postgres.sql | 1133 ----------------- src/clj/youyesyet/routes/rest.clj | 104 +- .../youyesyet/canvasser_app/handlers.cljs | 11 +- youyesyet.adl.xml | 6 +- youyesyet.canonical.adl.xml | 1108 ---------------- 6 files changed, 90 insertions(+), 2273 deletions(-) delete mode 100644 resources/sql/youyesyet.postgres.sql delete mode 100644 youyesyet.canonical.adl.xml 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 - - -
- - - - - - - - - - - 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