diff --git a/doc/specification/database.md b/doc/specification/database.md
new file mode 100644
index 0000000..2656621
--- /dev/null
+++ b/doc/specification/database.md
@@ -0,0 +1,218 @@
+# Database Specification
+
+Note that this is a work in progress. Read it in concert with the Entity-Relationship Diagram.
+
+Tables are listed in alphabetical order.
+
+## Address
+
+The postal address of a dwelling at which electors are registered.
+
+ CREATE TABLE IF NOT EXISTS addresses (
+ id integer NOT NULL,
+ address character varying(256) NOT NULL,
+ postcode character varying(16),
+ phone character varying(16),
+ district_id integer,
+ latitude real,
+ longitude real
+ );
+
+## Authority
+
+An *oauth* authority which authenticates canvassers. *Note that* there will need to be substantially more in this table but I don't yet know what.
+
+ CREATE TABLE IF NOT EXISTS authorities (
+ id character varying(32) NOT NULL
+ );
+
+
+## Canvasser
+
+A user of the system.
+
+ CREATE TABLE IF NOT EXISTS canvassers (
+ id serial,
+ username character varying(32) NOT NULL,
+ fullname character varying(64) NOT NULL,
+ elector_id integer,
+ address_id integer NOT NULL,
+ phone character varying(16),
+ email character varying(128),
+ authority_id character varying(32) NOT NULL,
+ authorised boolean
+ );
+
+
+## District
+
+An electoral district.
+
+ CREATE TABLE IF NOT EXISTS districts (
+ id integer NOT NULL,
+ name character varying(64) NOT NULL
+ );
+
+
+## Elector
+
+Someone entitled to cast a vote in the referendum.
+
+ CREATE TABLE IF NOT EXISTS electors (
+ id integer NOT NULL,
+ name character varying(64) NOT NULL,
+ address_id integer NOT NULL,
+ phone character varying(16),
+ email character varying(128)
+ );
+
+## Followup Action
+
+An action performed by an issue expert in response to a followup request.
+
+ CREATE TABLE IF NOT EXISTS followupactions (
+ id integer NOT NULL,
+ request_id integer NOT NULL,
+ actor integer NOT NULL,
+ date timestamp with time zone DEFAULT now() NOT NULL,
+ notes text,
+ closed boolean
+ );
+
+## Followup Method
+
+A method for responding to a followup request; reference data.
+
+ CREATE TABLE IF NOT EXISTS followupmethods (
+ id character varying(32) NOT NULL
+ );
+
+ insert into followupmethods values ('Telephone');
+ insert into followupmethods values ('eMail');
+ insert into followupmethods values ('Post');
+
+## Followup Request
+
+A request recorded by a canvasser for an issue expert to contact an elector with regard to a particular issue.
+
+ CREATE TABLE IF NOT EXISTS followuprequests (
+ id integer NOT NULL,
+ elector_id integer NOT NULL,
+ visit_id integer NOT NULL,
+ issue_id character varying(32) NOT NULL,
+ method_id character varying(32) NOT NULL
+ );
+
+## Intention
+
+An intention, by an elector, to vote for an option; captured by a canvasser during a visit.
+
+ CREATE TABLE IF NOT EXISTS intentions (
+ id serial not null,
+ elector integer not null references elector(id),
+ option varchar(32) not null references option(id),
+ visit integer not null references visit(id),
+ date timestamp with time zone DEFAULT now() NOT NULL
+ );
+
+
+## Issue
+
+An issue which might affect electors' decisions regarding their intention.
+
+ CREATE TABLE IF NOT EXISTS issues (
+ id character varying(32) NOT NULL,
+ url character varying(256),
+ content varchar(1024),
+ current default false
+ );
+
+
+## Issue expertise
+
+Expertise of a canvasser able to use a method, in an issue.
+
+ CREATE TABLE IF NOT EXISTS issueexpertise (
+ canvasser_id integer NOT NULL,
+ issue_id character varying(32) NOT NULL,
+ method_id character varying(32) NOT NULL
+ );
+
+
+## Option
+
+An option for which an elector may have an intention to vote.
+
+ CREATE TABLE IF NOT EXISTS options (
+ id character varying(32) NOT NULL
+ );
+
+
+## Role
+
+A role (other than basic *Canvasser*) that a user may have in the system. Reference data.
+
+ create table if not exists roles (
+ id serial primary key,
+ name varchar(64) not null
+ );
+
+
+## Role Member
+
+Membership of a user (*Canvasser*) of an additional role; link table.
+
+ create table if not exists rolememberships (
+ role_id integer not null references roles(id),
+ canvasser_id integer not null references canvassers(id)
+ );
+
+
+## Team
+
+A team of canvassers in a locality who are known to one another and frequently
+canvas together.
+
+ create table if not exists teams (
+ id serial primary key,
+ name varchar(64) not null,
+ district_id integer not null references districts(id),
+ latitude real,
+ longitude real
+ );
+
+
+## Team Member
+
+Membership of a user (*Canvasser*) of a particular team. Canvassers may join multiple teams. Link table.
+
+ create table if not exists teammemberships (
+ team_id integer not null references teams(id),
+ canvasser_id integer not null references canvassers(id)
+ );
+
+
+## Team Organiser
+
+A relationship which defines a user (*Canvasser*) as an organiser of a team. A team may
+have more than one organiser. An organiser (if they also have the role 'Recruiter', which
+they often will have) may recruit additional Canvassers as members of their team, or
+accept applications by canvassers to join their team. An organiser may promote a member of
+the team to organiser of the team, and may also exclude a member from the team.
+
+ create table if not exists teamorganiserships (
+ team_id integer not null references teams(id),
+ canvasser_id integer not null references canvassers(id)
+ );
+
+
+## Visit
+
+A visit by a canvasser to an address on a date to solicit intentions from electors.
+
+ CREATE TABLE IF NOT EXISTS visits (
+ id integer NOT NULL,
+ address_id integer NOT NULL,
+ canvasser_id integer NOT NULL,
+ date timestamp with time zone DEFAULT now() NOT NULL
+ );
diff --git a/doc/specification/entity-relationship-diagram.svg b/doc/specification/entity-relationship-diagram.svg
index 0de6cf0..7068dd2 100644
--- a/doc/specification/entity-relationship-diagram.svg
+++ b/doc/specification/entity-relationship-diagram.svg
@@ -25,9 +25,9 @@
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
- inkscape:zoom="1.979899"
- inkscape:cx="833.70674"
- inkscape:cy="324.89697"
+ inkscape:zoom="2.8"
+ inkscape:cx="764.16287"
+ inkscape:cy="256.90499"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="true"
@@ -58,12 +58,13 @@
id="layer1"
transform="translate(0,-308.26772)">
+ x="8.484766"
+ y="312.36221"
+ sodipodi:insensitive="true" />
Addresss
+ sodipodi:role="line">Address
@@ -613,14 +614,14 @@
y="394.48404"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:15px;font-family:Arial;-inkscape-font-specification:Arial">Version: 0.2Version: 0.3Date: 20170315Date: 20170401
+
+ FollowupMethod
+
+
+
+
diff --git a/resources/migrations/20170401115900-basic-reference-data-down.sql b/resources/migrations/20170401115900-basic-reference-data-down.sql
new file mode 100644
index 0000000..e69de29
diff --git a/resources/migrations/20170401115900-basic-reference-data-up.sql b/resources/migrations/20170401115900-basic-reference-data-up.sql
new file mode 100644
index 0000000..6ca3028
--- /dev/null
+++ b/resources/migrations/20170401115900-basic-reference-data-up.sql
@@ -0,0 +1,58 @@
+
+-- We don't explicitly instantiate the 'Canvasser' role since every user is
+-- deemed to be a canvasser.
+
+
+-- an 'Expert' is someone with expertise in one or more issues, who is
+-- trusted to discuss those issues in detail with electors.
+insert into roles (name) values ('Expert');
+
+
+-- an 'Administrator' is someone entitled to broadly alter reference data
+-- throughout the system.
+insert into roles (name) values ('Administrator');
+
+
+-- a 'Recruiter' is someone entitled to invite other people to become users
+-- ('Canvassers'). A Recruiter is entitled to lock the account of anyone they
+-- have recruited, recursively.
+insert into roles (name) values ('Recruiter');
+
+
+-- an 'Organiser' is someone who organises one or more local teams. An Organiser
+-- is entitled to exclude any Canvasser from any team they organise.
+insert into roles (name) values ('Organiser');
+
+
+-- an 'Editor' is someone entitled to add and edit issues.
+insert into roles (name) values ('Editor');
+
+-- issue text is local; there may still in addition be a further link to more
+-- information, but the basic issue text should be part of the issue record.
+-- The text should fit on a phone screen without scrolling, so is reasonably
+-- short.
+alter table issues add column content varchar(1024);
+
+-- an issue may be current or not current; when not current it is not deleted
+-- from the system but kept because it may become current again later. Only
+-- current issues are shown in the app. Typically not fewer than three and not
+-- more than about seven issues should be current at any time.
+alter table issues add column current default false;
+
+insert into issues (id, content, current) values ('Currency',
+ 'Scotland could keep the Pound, or use the Euro. But we could also set up a new currency of our own.',
+ true);
+
+insert into issues (id, content, current) values ('Monarchy',
+ 'Scotland could keep the Queen. This is an issue to be decided after independence.',
+ true);
+
+insert into issues (id, content, current) values ('Defence',
+ 'Scotland will not have nuclear weapons, and will probably not choose to engage in far-off wars. But we could remain members of NATO.',
+ true);
+
+
+insert into options (id) values ('Yes');
+
+insert into options (id) values ('No');
+
diff --git a/resources/sql/queries.sql b/resources/sql/queries.sql
index 4191f67..ab15d8e 100644
--- a/resources/sql/queries.sql
+++ b/resources/sql/queries.sql
@@ -19,3 +19,4 @@ WHERE id = :id
-- :doc delete a user given the id
DELETE FROM users
WHERE id = :id
+
diff --git a/resources/templates/base-authenticated.html b/resources/templates/base-authenticated.html
new file mode 100644
index 0000000..79c1558
--- /dev/null
+++ b/resources/templates/base-authenticated.html
@@ -0,0 +1,74 @@
+
+
+
+ {% endfor %}
+{% endblock %}
diff --git a/src/clj/youyesyet/db/core.clj b/src/clj/youyesyet/db/core.clj
index 536cc3b..a0eec57 100644
--- a/src/clj/youyesyet/db/core.clj
+++ b/src/clj/youyesyet/db/core.clj
@@ -15,9 +15,13 @@
Timestamp
PreparedStatement]))
+;; TODO: I am CERTANLY misunderstanding something here. We ought to be getting
+;; the database connection string and credentials fomr profiles.clj
+;; (def ^:dynamic *db* {:name "java:comp/env/jdbc/EmployeeDB"})
(defstate ^:dynamic *db*
- :start (conman/connect! {:jdbc-url (env :database-url)})
- :stop (conman/disconnect! *db*))
+ :start (conman/connect! {:jdbc-url (env :database-url)
+ :driver-class-name "org.postgresql.Driver"})
+ :stop (conman/disconnect! *db*))
(conman/bind-connection *db* "sql/queries.sql")
diff --git a/src/clj/youyesyet/handler.clj b/src/clj/youyesyet/handler.clj
index f898fe5..ad5462d 100644
--- a/src/clj/youyesyet/handler.clj
+++ b/src/clj/youyesyet/handler.clj
@@ -10,6 +10,29 @@
[clojure.tools.logging :as log]
[youyesyet.config :refer [env]]))
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;
+;;;; youyesyet.handler: handlers for starting and stopping the webapp.
+;;;;
+;;;; This program is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU General Public License
+;;;; as published by the Free Software Foundation; either version 2
+;;;; of the License, or (at your option) any later version.
+;;;;
+;;;; This program is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;;; GNU General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU General Public License
+;;;; along with this program; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+;;;; USA.
+;;;;
+;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
+;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
(mount/defstate init-app
:start ((or (:init defaults) identity))
:stop ((or (:stop defaults) identity)))
diff --git a/src/clj/youyesyet/routes/authenticated.clj b/src/clj/youyesyet/routes/authenticated.clj
new file mode 100644
index 0000000..b5c2644
--- /dev/null
+++ b/src/clj/youyesyet/routes/authenticated.clj
@@ -0,0 +1,35 @@
+(ns youyesyet.routes.authenticated
+ (:require [clojure.walk :refer [keywordize-keys]]
+ [noir.response :as nresponse]
+ [noir.util.route :as route]
+ [youyesyet.layout :as layout]
+ [youyesyet.db.core :as db-core]
+ [compojure.core :refer [defroutes GET POST]]
+ [ring.util.http-response :as response]
+ [clojure.java.io :as io]))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;
+;;;; youyesyet.routes.authenticated: routes and pages for authenticated users.
+;;;;
+;;;; This program is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU General Public License
+;;;; as published by the Free Software Foundation; either version 2
+;;;; of the License, or (at your option) any later version.
+;;;;
+;;;; This program is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;;; GNU General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU General Public License
+;;;; along with this program; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+;;;; USA.
+;;;;
+;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
+;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+;; (defn roles-page [request]
+;; (if
diff --git a/src/clj/youyesyet/routes/home.clj b/src/clj/youyesyet/routes/home.clj
index 7fbf9f7..90f2f12 100644
--- a/src/clj/youyesyet/routes/home.clj
+++ b/src/clj/youyesyet/routes/home.clj
@@ -1,15 +1,81 @@
(ns youyesyet.routes.home
- (:require [youyesyet.layout :as layout]
+ (:require [clojure.walk :refer [keywordize-keys]]
+ [noir.response :as nresponse]
+ [noir.util.route :as route]
+ [youyesyet.layout :as layout]
[youyesyet.db.core :as db-core]
- [compojure.core :refer [defroutes GET]]
+ [compojure.core :refer [defroutes GET POST]]
[ring.util.http-response :as response]
[clojure.java.io :as io]))
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;
+;;;; youyesyet.routes.home: routes and pages for unauthenticated users.
+;;;;
+;;;; This program is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU General Public License
+;;;; as published by the Free Software Foundation; either version 2
+;;;; of the License, or (at your option) any later version.
+;;;;
+;;;; This program is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;;; GNU General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU General Public License
+;;;; along with this program; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+;;;; USA.
+;;;;
+;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
+;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defn app-page []
+ (layout/render "app.html"))
+
+(defn about-page []
+ (layout/render "about.html"))
+
+(defn call-me-page [request]
+ (if
+ request
+ (do
+ ;; do something to store it in the database
+ (layout/render "call-me-accepted.html" (:params request)))
+ (layout/render "call-me.html"
+ {:title "Please call me!"
+ ;; TODO: Issues need to be fetched from the database
+ :concerns nil})))
+
(defn home-page []
- (layout/render "home.html"))
+ (layout/render "home.html" {:title "You Yes Yet?"}))
+
+(defn login-page
+ "This is very temporary. We're going to do authentication by oauth."
+ [request]
+ (let [params (keywordize-keys (:form-params request))
+ session (:session request)
+ username (:username params)
+ password (:password params)
+ redirect-to (or (:redirect-to params) "app")]
+ (if
+ (and (= username "test") (= password "test"))
+ (do
+ (assoc (response/found redirect-to) :session (assoc session :user username)))
+ (layout/render "login.html" {:title "Please log in" :redirect-to redirect-to}))))
+
(defroutes home-routes
(GET "/" [] (home-page))
- (GET "/docs" [] (-> (response/ok (-> "docs/docs.md" io/resource slurp))
- (response/header "Content-Type" "text/plain; charset=utf-8"))))
-
+ (GET "/home" [] (home-page))
+ (GET "/about" [] (about-page))
+ (GET "/app" [] (route/restricted (app-page)))
+ (GET "/call-me" [] (call-me-page nil))
+ (POST "/call-me" request (call-me-page request))
+ (GET "/auth" request (login-page request))
+ (POST "/auth" request (login-page request))
+ (GET "/notyet" [] (layout/render "notyet.html"
+ {:title "Can we persuade you?"}))
+ (GET "/supporter" [] (layout/render "supporter.html"
+ {:title "Have you signed up as a canvasser yet?"})))
diff --git a/src/cljc/youyesyet/validation.cljc b/src/cljc/youyesyet/validation.cljc
index fd01d8f..7c293dd 100644
--- a/src/cljc/youyesyet/validation.cljc
+++ b/src/cljc/youyesyet/validation.cljc
@@ -1,3 +1,26 @@
(ns youyesyet.validation
(:require [bouncer.core :as b]
[bouncer.validators :as v]))
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;
+;;;; youyesyet.validation:
+;;;;
+;;;; This program is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU General Public License
+;;;; as published by the Free Software Foundation; either version 2
+;;;; of the License, or (at your option) any later version.
+;;;;
+;;;; This program is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;;; GNU General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU General Public License
+;;;; along with this program; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+;;;; USA.
+;;;;
+;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
+;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
diff --git a/src/cljs/youyesyet/ajax.cljs b/src/cljs/youyesyet/ajax.cljs
index 07cf00d..ef3a3cb 100644
--- a/src/cljs/youyesyet/ajax.cljs
+++ b/src/cljs/youyesyet/ajax.cljs
@@ -1,6 +1,30 @@
(ns youyesyet.ajax
(:require [ajax.core :as ajax]))
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;;
+;;;; youyesyet.ajax: transciever for ajax packets.
+;;;;
+;;;; This program is free software; you can redistribute it and/or
+;;;; modify it under the terms of the GNU General Public License
+;;;; as published by the Free Software Foundation; either version 2
+;;;; of the License, or (at your option) any later version.
+;;;;
+;;;; This program is distributed in the hope that it will be useful,
+;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;;;; GNU General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU General Public License
+;;;; along with this program; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+;;;; USA.
+;;;;
+;;;; Copyright (C) 2016 Simon Brooke for Radical Independence Campaign
+;;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+
(defn local-uri? [{:keys [uri]}]
(not (re-find #"^\w+?://" uri)))