diff --git a/.gitignore b/.gitignore index 7ff653c..99b78ef 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,5 @@ pom.xml.asc .nrepl-port /node_modules/ .DS_Store -*-init.clj \ No newline at end of file +*-init.clj +profiles\.clj diff --git a/README.md b/README.md index 5900935..a5f923c 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ I've put a [dummy site](http://www.journeyman.cc/~simon/tmp/yyy-dummy/index.html ## Prerequisites -You will need [Leiningen][1] 2.0 or above installed. The database required must be [Postgres][2]. +You will need [Leiningen][1] 2.0 or above installed. The database required must be [Postgres][2] 9.3 or above. [1]: https://github.com/technomancy/leiningen [2]: https://www.postgresql.org/ @@ -38,12 +38,27 @@ You'll also need to create your own local copy of *profiles.clj*, which should c Where *username* is the username required to access the database, and *thisisnotsecure* is the password which authenticates that username. +It will be helpful for you to have the [Zenhub](https://www.zenhub.com/) plugin in your browser, either Firefox or Chrome, as I'm using it for project planning. + ## Further Reading If you're thinking of joining in development on this I'd strongly recommend you get hold of a copy of [Dmitry Sotnikov](https://github.com/yogthos)'s [Web Development with Clojure, Second Edition](https://pragprog.com/book/dswdcloj2/web-development-with-clojure-second-edition). You should also read the [User-Oriented Specification](doc/specification/userspec.md) and any other documentation which appears under the *doc/specification* hierarchy. + +## Getting the database up + +Do get the database initialised, run + + createdb youyesyet_dev + +followed by + + lein migratus migrate + +**NOTE THAT** in the namespace *youyesyet.db.schema*, there are a series of functions *create-xxx-table!*. These are a snare and a delusion; they are how I originally bootstrapped the database, but are no longer used (and should probably be deleted). The database is now constructed using [migratus](https://github.com/yogthos/migratus). + ## Running To start a web server for the application, run: diff --git a/doc/specification/entity-relationship-diagram.svg b/doc/specification/entity-relationship-diagram.svg index 6aafafc..0de6cf0 100644 --- a/doc/specification/entity-relationship-diagram.svg +++ b/doc/specification/entity-relationship-diagram.svg @@ -25,16 +25,16 @@ borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" - inkscape:zoom="0.98994949" - inkscape:cx="473.75864" - inkscape:cy="409.50744" + inkscape:zoom="1.979899" + inkscape:cx="833.70674" + inkscape:cy="324.89697" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="true" inkscape:window-width="1920" - inkscape:window-height="996" - inkscape:window-x="0" - inkscape:window-y="28" + inkscape:window-height="1058" + inkscape:window-x="1920" + inkscape:window-y="0" inkscape:window-maximized="1"> image/svg+xml - + @@ -57,6 +57,13 @@ inkscape:groupmode="layer" id="layer1" transform="translate(0,-308.26772)"> + - - - + id="g4369"> + + + + + - - - + id="g4402"> + + + + + - - Option - - - + id="g4356" + transform="translate(-170.71578,120.20815)"> + + Option + sodipodi:nodetypes="ccccc" /> - @@ -580,7 +572,7 @@ sodipodi:nodetypes="cccc" /> @@ -598,16 +590,10 @@ sodipodi:nodetypes="ccc" /> - + sodipodi:nodetypes="cccccc" /> Version: 0.1Version: 0.2Date: 20161014Date: 20170315Copyright: (c) 2016 Simon Brooke for Radical Independence Campaign + inkscape:connector-curvature="0" + sodipodi:nodetypes="ccccc" /> Visited + y="498.31903" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:10px;line-height:125%;font-family:Arial;-inkscape-font-specification:'Arial, Normal';text-align:start;writing-mode:lr-tb;text-anchor:start">Visited Requested - For To + + + Team + + + + Organiser-ship + TeamMembership + + + + + + + + + + + Has + Has + of + of + + + + + + + + For + + RoleMembership + + + Role + + + + + + + + Is + Includes + + + + + + + diff --git a/resources/migrations/20161010155448-add-users-table.down.sql b/resources/migrations/20161010155448-add-users-table.down.sql deleted file mode 100644 index cc1f647..0000000 --- a/resources/migrations/20161010155448-add-users-table.down.sql +++ /dev/null @@ -1 +0,0 @@ -DROP TABLE users; diff --git a/resources/migrations/20161010155448-add-users-table.up.sql b/resources/migrations/20161010155448-add-users-table.up.sql deleted file mode 100644 index 05ad4af..0000000 --- a/resources/migrations/20161010155448-add-users-table.up.sql +++ /dev/null @@ -1,9 +0,0 @@ -CREATE TABLE users -(id VARCHAR(20) PRIMARY KEY, - first_name VARCHAR(30), - last_name VARCHAR(30), - email VARCHAR(30), - admin BOOLEAN, - last_login TIME, - is_active BOOLEAN, - pass VARCHAR(300)); diff --git a/resources/migrations/20161014170335-basic-setup.up.sql b/resources/migrations/20161014170335-basic-setup.up.sql index 8468728..0719e57 100644 --- a/resources/migrations/20161014170335-basic-setup.up.sql +++ b/resources/migrations/20161014170335-basic-setup.up.sql @@ -68,7 +68,7 @@ SET default_with_oids = false; -- Name: addresses; Type: TABLE; Schema: public; Owner: youyesyet; Tablespace: -- -CREATE TABLE addresses ( +CREATE TABLE IF NOT EXISTS addresses ( id integer NOT NULL, address character varying(256) NOT NULL, postcode character varying(16), @@ -106,7 +106,7 @@ ALTER SEQUENCE addresses_id_seq OWNED BY addresses.id; -- Name: authorities; Type: TABLE; Schema: public; Owner: youyesyet; Tablespace: -- -CREATE TABLE authorities ( +CREATE TABLE IF NOT EXISTS authorities ( id character varying(32) NOT NULL ); --;; @@ -117,8 +117,9 @@ ALTER TABLE public.authorities OWNER TO youyesyet; -- Name: canvassers; Type: TABLE; Schema: public; Owner: youyesyet; Tablespace: -- -CREATE TABLE canvassers ( - id character varying(32) NOT NULL, +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, @@ -135,7 +136,7 @@ ALTER TABLE public.canvassers OWNER TO youyesyet; -- Name: districts; Type: TABLE; Schema: public; Owner: youyesyet; Tablespace: -- -CREATE TABLE districts ( +CREATE TABLE IF NOT EXISTS districts ( id integer NOT NULL, name character varying(64) NOT NULL ); @@ -147,7 +148,7 @@ ALTER TABLE public.districts OWNER TO youyesyet; -- Name: electors; Type: TABLE; Schema: public; Owner: youyesyet; Tablespace: -- -CREATE TABLE electors ( +CREATE TABLE IF NOT EXISTS electors ( id integer NOT NULL, name character varying(64) NOT NULL, address_id integer NOT NULL, @@ -162,10 +163,10 @@ ALTER TABLE public.electors OWNER TO youyesyet; -- Name: followupactions; Type: TABLE; Schema: public; Owner: youyesyet; Tablespace: -- -CREATE TABLE followupactions ( +CREATE TABLE IF NOT EXISTS followupactions ( id integer NOT NULL, request_id integer NOT NULL, - actor character varying(32) NOT NULL, + actor integer NOT NULL, date timestamp with time zone DEFAULT now() NOT NULL, notes text, closed boolean @@ -199,7 +200,7 @@ ALTER SEQUENCE followupactions_id_seq OWNED BY followupactions.id; -- Name: followupmethods; Type: TABLE; Schema: public; Owner: youyesyet; Tablespace: -- -CREATE TABLE followupmethods ( +CREATE TABLE IF NOT EXISTS followupmethods ( id character varying(32) NOT NULL ); --;; @@ -218,7 +219,7 @@ insert into followupmethods values ('Post'); --;; -CREATE TABLE followuprequests ( +CREATE TABLE IF NOT EXISTS followuprequests ( id integer NOT NULL, elector_id integer NOT NULL, visit_id integer NOT NULL, @@ -258,8 +259,8 @@ ALTER SEQUENCE followuprequests_id_seq OWNED BY followuprequests.id; -- Name: issueexpertise; Type: TABLE; Schema: public; Owner: youyesyet; Tablespace: -- -CREATE TABLE issueexpertise ( - canvasser_id character varying(32) NOT NULL, +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 ); @@ -273,7 +274,7 @@ ALTER TABLE public.issueexpertise OWNER TO youyesyet; -- Name: issues; Type: TABLE; Schema: public; Owner: youyesyet; Tablespace: -- -CREATE TABLE issues ( +CREATE TABLE IF NOT EXISTS issues ( id character varying(32) NOT NULL, url character varying(256) ); @@ -287,7 +288,7 @@ ALTER TABLE public.issues OWNER TO youyesyet; -- Name: options; Type: TABLE; Schema: public; Owner: youyesyet; Tablespace: -- -CREATE TABLE options ( +CREATE TABLE IF NOT EXISTS options ( id character varying(32) NOT NULL ); --;; @@ -300,7 +301,7 @@ ALTER TABLE public.options OWNER TO youyesyet; -- Name: schema_migrations; Type: TABLE; Schema: public; Owner: youyesyet; Tablespace: -- -CREATE TABLE schema_migrations ( +CREATE TABLE IF NOT EXISTS schema_migrations ( id bigint NOT NULL ); --;; @@ -313,10 +314,10 @@ ALTER TABLE public.schema_migrations OWNER TO youyesyet; -- Name: visits; Type: TABLE; Schema: public; Owner: youyesyet; Tablespace: -- -CREATE TABLE visits ( +CREATE TABLE IF NOT EXISTS visits ( id integer NOT NULL, address_id integer NOT NULL, - canvasser_id character varying(32) NOT NULL, + canvasser_id integer NOT NULL, date timestamp with time zone DEFAULT now() NOT NULL ); --;; @@ -484,8 +485,8 @@ ALTER TABLE ONLY options -- Name: schema_migrations_id_key; Type: CONSTRAINT; Schema: public; Owner: youyesyet; Tablespace: -- -ALTER TABLE ONLY schema_migrations - ADD CONSTRAINT schema_migrations_id_key UNIQUE (id); +--ALTER TABLE ONLY schema_migrations +-- ADD CONSTRAINT schema_migrations_id_key UNIQUE (id); --;; diff --git a/resources/migrations/20170315190500-roles-and-teams.down.sql b/resources/migrations/20170315190500-roles-and-teams.down.sql new file mode 100644 index 0000000..a8bdb6a --- /dev/null +++ b/resources/migrations/20170315190500-roles-and-teams.down.sql @@ -0,0 +1,13 @@ +drop table teammemberships; + +drop table teamorganiserships; + +drop index ix_teams_name; + +drop table teams; + +drop table rolememberships; + +drop index ix_roles_name; + +drop table roles; diff --git a/resources/migrations/20170315190500-roles-and-teams.up.sql b/resources/migrations/20170315190500-roles-and-teams.up.sql new file mode 100644 index 0000000..7ff7ffc --- /dev/null +++ b/resources/migrations/20170315190500-roles-and-teams.up.sql @@ -0,0 +1,39 @@ +create table if not exists roles ( + id serial primary key, + name varchar(64) not null +); + +create unique index ix_roles_name on roles(name); + +create table if not exists rolememberships ( + role_id integer not null references roles(id), + canvasser_id integer not null references canvassers(id) +); + +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 +); + +create unique index ix_teams_name on teams(name); + +create table if not exists teammemberships ( + team_id integer not null references teams(id), + canvasser_id integer not null references canvassers(id) +); + +create table if not exists teamorganiserships ( + team_id integer not null references teams(id), + canvasser_id integer not null references canvassers(id) +); + +alter table roles owner to youyesyet; + +alter table rolememberships owner to youyesyet; + +alter table teams owner to youyesyet; + +alter table teammemberships owner to youyesyet; diff --git a/src/clj/youyesyet/db/schema.clj b/src/clj/youyesyet/db/schema.clj index 1ff1da1..c999486 100644 --- a/src/clj/youyesyet/db/schema.clj +++ b/src/clj/youyesyet/db/schema.clj @@ -34,26 +34,6 @@ ;;; redundant, and if they are the namespace probably needs to be renamed to 'entities'. ;;; See also resources/migrations/20161014170335-basic-setup.up.sql -(defn create-districts-table! - "Create a table to hold the electoral districts in which electors are registered. - Note that, as this app is being developed for the independence referendum in which - polling is across the whole of Scotland, this part of the design isn't fully thought - through; if later adapted to general or local elections, some breakdown or hierarchy - of polling districts into constituencies will be required." - [] - (sql/db-do-commands - yyydb/*db* - (sql/create-table-ddl - :districts - ;; it may be necessary to have a serial abstract primary key but I suspect - ;; polling districts already have numbers assigned by the Electoral Commission and - ;; it would be sensible to use those. TODO: check. - [:id "integer not null primary key"] - [:name "varchar(64) not null"] - ;; TODO: it would make sense to hold polygon data for polling districts so we can reflect - ;; them on the map, but I haven't thought through how to do that yet. - ))) - (kc/defentity district (kc/pk :id) @@ -186,7 +166,7 @@ (kc/entity-fields :id :fullname :phone :email :is_admin :authorised) (kc/has-one elector) (kc/has-one address) - (kc/has-one canvasser {:fk :introduced_by}) +;; (kc/has-one canvasser {:fk :introduced_by}) (kc/has-one authority)) @@ -244,7 +224,7 @@ yyydb/*db* (sql/create-table-ddl :optionsdistricts - [:option_id"varchar(32) not null references options(option)"] + [:option_id "varchar(32) not null references options(option)"] [:district_id "integer not null references districts(id)"]))) @@ -395,6 +375,73 @@ (kc/has-one canvasser {:fk :actor})) + +(defn create-role-table! + "Create a table to record roles. I'm not even yet certain that this is strictly necessary, + but it allows us to record the fact that different users (canvassers) have different roles + in the system." + [] + (sql/db-do-commands + yyydb/*db* + (sql/create-table-ddl + :roles + [:id "serial primary key"] + [:name "varchar(64) not null"]))) + + +(defn create-role-membership-table! + "Create a link table to record membership of roles." + [] + (sql/db-do-commands + yyydb/*db* + (sql/create-table-ddl + :rolememberships + [:role_id "integer not null references role(id)"] + [:canvasser_id "integer not null references canvasser(id)"]))) + + +(kc/defentity role + (kc/table :roles) + (kc/database yyydb/*db*) + (kc/entity-fields :id :name) + (kc/many-to-many canvasser :rolememberships)) + + +(defn create-team-table! + "Create a table to record teams." + [] + (sql/db-do-commands + yyydb/*db* + (sql/create-table-ddl + :teams + [:id "serial primary key"] + [:name "varchar(64) not null"] + ;; the electoral district within which this address exists + [:district_id "integer references districts(id)"] + ;; nominal home location of this team + [:latitude :real] + [:longitude :real]))) + + +(defn create-team-membership-table! + "Create a link table to record membership of team." + [] + (sql/db-do-commands + yyydb/*db* + (sql/create-table-ddl + :teammemberships + [:team_id "integer not null references team(id)"] + [:canvasser_id "integer not null references canvasser(id)"]))) + + +(kc/defentity team + (kc/table :teams) + (kc/database yyydb/*db*) + (kc/entity-fields :id :name :latitude :longitude) + (kc/has-one district) + (kc/many-to-many canvasser :teammemberships)) + + (defn init-db! [] "Initialised the whole database." (create-districts-table!) @@ -409,4 +456,8 @@ (create-issue-expertise-table!) (create-followup-requests-table!) (create-followup-actions-table!) + (create-role-table!) + (create-role-membership-table!) + (create-team-table!) + (create-team-membership-table!) )