diff --git a/.env b/.env index 08ee2fd..b97af71 100644 --- a/.env +++ b/.env @@ -1,7 +1,7 @@ COMPOSE_FILE=docker-compose.dev.yml -COMPOSE_PROJECT_NAME=candymat +COMPOSE_PROJECT_NAME=kandimat # Backend vars POSTGRES_PASSWORD=postgres!dev -DATABASE_URL=postgres://candymat_postgraphile:postgres!dev@postgres:5432/candymat_db +DATABASE_URL=postgres://kandimat_postgraphile:postgres!dev@postgres:5432/kandimat_db JWT_SECRET=asdfasdfasdf diff --git a/.gitmodules b/.gitmodules index cd396e7..1f23435 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "candymat-user-app"] - path = candymat-user-app - url = git@git.verdigado.com:Netzbegruenung/candymat-user-app.git - branch = develop-candymat + path = kandimat-user-app + url = git@git.verdigado.com:NB-Public/kandimat-user-app.git + branch = main diff --git a/README.md b/README.md index 7677200..4c55f32 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# Candymat - Wahl-o-Mat fuer Personalwahlen +# Kandimat - Wahl-o-Mat fuer Personalwahlen ## Introduction -The candymat is a Wahl-o-Mat for elections of candidates. +The kandimat is a Wahl-o-Mat for elections of candidates. ## Services @@ -27,7 +27,7 @@ and is used to find the perfect candidate for everyone who is allowed to vote. It is written in vue.js. -See also: [Service Readme](https://git.verdigado.com/Netzbegruenung/candymat-user-app/src/README.md) +See also: [Service Readme](https://git.verdigado.com/Netzbegruenung/kandimat-user-app/src/README.md) ### Postgraphile (Backend) @@ -39,7 +39,7 @@ For more on this (e.g. how to use the graphQl api by yourself) see [backend read ### Check-out repository * [Install git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) -* `git clone https://git.verdigado.com/Netzbegruenung/candymat.git` +* `git clone https://git.verdigado.com/Netzbegruenung/kandimat.git` * To get the (external) user-app source: ``` git submodule update --init @@ -65,8 +65,8 @@ docker-compose up To start with a clean database, either delete the volume from the postgres configuration in the compose file or run ``` -docker container rm candymat_postgres_1 -docker volume rm candymat_db-data +docker container rm kandimat_postgres_1 +docker volume rm kandimat_db-data ``` before starting docker-compose. diff --git a/backend/README.md b/backend/README.md index 0d320c4..691be8f 100644 --- a/backend/README.md +++ b/backend/README.md @@ -1,6 +1,6 @@ -# Candymat Backend +# Kandimat Backend -The candymat backend consists of a postgres database and a [postgraphile](https://www.graphile.org/postgraphile/introduction/) instance. +The kandimat backend consists of a postgres database and a [postgraphile](https://www.graphile.org/postgraphile/introduction/) instance. Postgraphile generates a Graphql backend based on the underlying postgres schema. ## Introduction @@ -29,7 +29,7 @@ in setups where there is no public access to the data. #### Authentication Authentication is handled via jwt. -The candymat setup roughly follows the instructions in the [postgraphile docu](https://www.graphile.org/postgraphile/postgresql-schema-design/#authentication-and-authorization). +The kandimat setup roughly follows the instructions in the [postgraphile docu](https://www.graphile.org/postgraphile/postgresql-schema-design/#authentication-and-authorization). ## Manually test the backend diff --git a/backend/backend.env b/backend/backend.env index d9d28b4..d08e902 100644 --- a/backend/backend.env +++ b/backend/backend.env @@ -1,5 +1,5 @@ # Postgres database setup -POSTGRES_USER=candymat_postgraphile +POSTGRES_USER=kandimat_postgraphile # Password is handled by docker-compose -POSTGRES_DB=candymat_db -POSTGRES_SCHEMA=candymat_data +POSTGRES_DB=kandimat_db +POSTGRES_SCHEMA=kandimat_data diff --git a/backend/deep_reset_db.sh b/backend/deep_reset_db.sh index a9d72a2..74b7301 100755 --- a/backend/deep_reset_db.sh +++ b/backend/deep_reset_db.sh @@ -1,10 +1,10 @@ #!/bin/bash docker-compose stop postgres -CONTAINER=$(docker image rm candymat-postgres:11.5 2> >(grep -P '[a-f0-9]{12}' -o) | head -1) +CONTAINER=$(docker image rm kandimat-postgres:11.5 2> >(grep -P '[a-f0-9]{12}' -o) | head -1) echo "Going to remove container: $CONTAINER" docker container rm $CONTAINER -docker image rm candymat-postgres:11.5 +docker image rm kandimat-postgres:11.5 echo "Deleting db-data docker volumes ..." VOLUMES=$(docker volume ls -q | grep "db-data") for volume in ${VOLUMES[@]}; do diff --git a/backend/sql/01_create_basic_structure.sql b/backend/sql/01_create_basic_structure.sql index 00de479..230a1d1 100644 --- a/backend/sql/01_create_basic_structure.sql +++ b/backend/sql/01_create_basic_structure.sql @@ -1,28 +1,28 @@ -\connect candymat_db +\connect kandimat_db --- Create schema for candymat_data -create SCHEMA candymat_data; -create SCHEMA candymat_data_privat; +-- Create schema for kandimat_data +create SCHEMA kandimat_data; +create SCHEMA kandimat_data_privat; -- create roles -create role candymat_person; -create role candymat_anonymous; -create role candymat_editor; -create role candymat_candidate; +create role kandimat_person; +create role kandimat_anonymous; +create role kandimat_editor; +create role kandimat_candidate; -grant candymat_editor to candymat_postgraphile; -grant candymat_candidate to candymat_postgraphile; -grant candymat_person to candymat_postgraphile, candymat_candidate, candymat_editor; -grant candymat_anonymous to candymat_postgraphile; +grant kandimat_editor to kandimat_postgraphile; +grant kandimat_candidate to kandimat_postgraphile; +grant kandimat_person to kandimat_postgraphile, kandimat_candidate, kandimat_editor; +grant kandimat_anonymous to kandimat_postgraphile; -create type candymat_data.role as enum ( - 'candymat_editor', - 'candymat_candidate', - 'candymat_person' +create type kandimat_data.role as enum ( + 'kandimat_editor', + 'kandimat_candidate', + 'kandimat_person' ); -- set table wide permissions -grant usage on schema candymat_data to candymat_anonymous, candymat_person; +grant usage on schema kandimat_data to kandimat_anonymous, kandimat_person; -- make functions non executeable w/o further checks alter default privileges revoke execute on functions from public; diff --git a/backend/sql/02_create-user_tables.sql b/backend/sql/02_create-user_tables.sql index 8e75a40..15f12b7 100644 --- a/backend/sql/02_create-user_tables.sql +++ b/backend/sql/02_create-user_tables.sql @@ -1,43 +1,43 @@ -- create table for users -create table candymat_data.person +create table kandimat_data.person ( row_id serial primary key, first_name character varying(200) check (first_name <> ''), last_name character varying(200) check (last_name <> ''), about character varying(2000), created_at timestamp default now(), - role candymat_data.role not null default 'candymat_person' + role kandimat_data.role not null default 'kandimat_person' ); -grant select, update, delete on table candymat_data.person to candymat_person; +grant select, update, delete on table kandimat_data.person to kandimat_person; -- the following is only necessary as long as anonymous should be able to view candidates and editors -grant select on table candymat_data.person to candymat_anonymous; +grant select on table kandimat_data.person to kandimat_anonymous; -- create table for accounts -create table candymat_data_privat.person_account +create table kandimat_data_privat.person_account ( - person_row_id integer primary key references candymat_data.person (row_id) on delete cascade, + person_row_id integer primary key references kandimat_data.person (row_id) on delete cascade, email character varying(320) not null unique check (email ~* '^.+@.+\..+$'), password_hash character varying(256) not null ); -alter table candymat_data.person +alter table kandimat_data.person enable row level security; -create policy update_person on candymat_data.person for update to candymat_person +create policy update_person on kandimat_data.person for update to kandimat_person with check (row_id = nullif(current_setting('jwt.claims.person_row_id', true), '')::integer); -create policy delete_person on candymat_data.person for delete to candymat_person +create policy delete_person on kandimat_data.person for delete to kandimat_person using (row_id = nullif(current_setting('jwt.claims.person_row_id', true), '')::integer); -- The following enables viewing candidates and editors information for every person. -- This may be changed to only enable registered (and verified) persons. create policy select_person_public - on candymat_data.person + on kandimat_data.person for select - to candymat_anonymous, candymat_person -- maybe change to candymat_person only in the future - using (role in ('candymat_editor', 'candymat_candidate')); + to kandimat_anonymous, kandimat_person -- maybe change to kandimat_person only in the future + using (role in ('kandimat_editor', 'kandimat_candidate')); -- Editors can see all registered persons in order to elevate their privileges create policy select_person_editor - on candymat_data.person + on kandimat_data.person for select - to candymat_editor + to kandimat_editor using (true); diff --git a/backend/sql/03_create_content_tables.sql b/backend/sql/03_create_content_tables.sql index 1de8fa1..3022560 100644 --- a/backend/sql/03_create_content_tables.sql +++ b/backend/sql/03_create_content_tables.sql @@ -1,51 +1,51 @@ -- create table for categories -create table candymat_data.category +create table kandimat_data.category ( row_id serial primary key, title character varying(300) UNIQUE NOT NULL check ( title <> '' ), description character varying(15000) ); -grant select on table candymat_data.category to candymat_person; --- the following line is only necessary as long as the candymat should be publicly accessible -grant select on table candymat_data.category to candymat_anonymous; -grant insert, update, delete on table candymat_data.category to candymat_editor; -grant usage on sequence candymat_data.category_row_id_seq to candymat_editor; +grant select on table kandimat_data.category to kandimat_person; +-- the following line is only necessary as long as the kandimat should be publicly accessible +grant select on table kandimat_data.category to kandimat_anonymous; +grant insert, update, delete on table kandimat_data.category to kandimat_editor; +grant usage on sequence kandimat_data.category_row_id_seq to kandimat_editor; -- create table for questions -create table candymat_data.question +create table kandimat_data.question ( row_id serial primary key, - category_row_id integer REFERENCES candymat_data.category (row_id) ON UPDATE CASCADE ON DELETE SET NULL, + category_row_id integer REFERENCES kandimat_data.category (row_id) ON UPDATE CASCADE ON DELETE SET NULL, title character varying(3000) UNIQUE NOT NULL check ( title <> '' ), description character varying(15000) ); -grant select on table candymat_data.question to candymat_person; --- the following line is only necessary as long as the candymat should be publicly accessible -grant select on table candymat_data.question to candymat_anonymous; -grant insert, update, delete on table candymat_data.question to candymat_editor; -grant usage on sequence candymat_data.question_row_id_seq to candymat_editor; +grant select on table kandimat_data.question to kandimat_person; +-- the following line is only necessary as long as the kandimat should be publicly accessible +grant select on table kandimat_data.question to kandimat_anonymous; +grant insert, update, delete on table kandimat_data.question to kandimat_editor; +grant usage on sequence kandimat_data.question_row_id_seq to kandimat_editor; -- create table for answers -create table candymat_data.answer +create table kandimat_data.answer ( - question_row_id integer REFERENCES candymat_data.question (row_id) ON UPDATE CASCADE ON DELETE CASCADE, - person_row_id integer REFERENCES candymat_data.person (row_id) ON UPDATE CASCADE ON DELETE CASCADE, + question_row_id integer REFERENCES kandimat_data.question (row_id) ON UPDATE CASCADE ON DELETE CASCADE, + person_row_id integer REFERENCES kandimat_data.person (row_id) ON UPDATE CASCADE ON DELETE CASCADE, position integer NOT NULL check (position between 0 and 3), text character varying(15000), created_at timestamp default now(), primary key (question_row_id, person_row_id) ); -grant select on table candymat_data.answer to candymat_person; --- the following line is only necessary as long as the candymat should be publicly accessible -grant select on table candymat_data.answer to candymat_anonymous; -grant insert, update, delete on table candymat_data.answer to candymat_candidate; +grant select on table kandimat_data.answer to kandimat_person; +-- the following line is only necessary as long as the kandimat should be publicly accessible +grant select on table kandimat_data.answer to kandimat_anonymous; +grant insert, update, delete on table kandimat_data.answer to kandimat_candidate; -alter table candymat_data.answer +alter table kandimat_data.answer enable row level security; -create policy change_answer on candymat_data.answer to candymat_candidate +create policy change_answer on kandimat_data.answer to kandimat_candidate using (person_row_id = nullif(current_setting('jwt.claims.person_row_id', true), '')::integer); create policy select_answer - on candymat_data.answer + on kandimat_data.answer for select - to candymat_anonymous, candymat_person -- maybe change to candymat_person only in the future + to kandimat_anonymous, kandimat_person -- maybe change to kandimat_person only in the future using (true); diff --git a/backend/sql/04_setup_authentication.sql b/backend/sql/04_setup_authentication.sql index 892a924..8018470 100644 --- a/backend/sql/04_setup_authentication.sql +++ b/backend/sql/04_setup_authentication.sql @@ -2,8 +2,8 @@ create extension if not exists "pgcrypto"; -- Define JWT claim structure -drop type if exists candymat_data.jwt_token cascade; -create type candymat_data.jwt_token as +drop type if exists kandimat_data.jwt_token cascade; +create type kandimat_data.jwt_token as ( role text, person_row_id integer, @@ -12,28 +12,28 @@ create type candymat_data.jwt_token as -- Function to get the currently logged-in person -drop function if exists candymat_data.current_person; -create function candymat_data.current_person( -) returns candymat_data.person as +drop function if exists kandimat_data.current_person; +create function kandimat_data.current_person( +) returns kandimat_data.person as $$ select * -from candymat_data.person +from kandimat_data.person where row_id = nullif(current_setting('jwt.claims.person_row_id', true), '')::integer $$ language sql stable; -grant execute on function candymat_data.current_person() to candymat_person; +grant execute on function kandimat_data.current_person() to kandimat_person; -- Function to register a new user -drop function if exists candymat_data.register_person; -create function candymat_data.register_person( +drop function if exists kandimat_data.register_person; +create function kandimat_data.register_person( first_name text, last_name text, email text, password text -) returns candymat_data.person as +) returns kandimat_data.person as $$ declare - person candymat_data.person; + person kandimat_data.person; begin if (trim(register_person.first_name) <> '') is not true then raise 'Invalid first name: ''%''', register_person.first_name; @@ -44,70 +44,70 @@ begin if (trim(register_person.password) <> '') is not true then raise 'Invalid password.'; end if; - insert into candymat_data.person (first_name, last_name) + insert into kandimat_data.person (first_name, last_name) values ($1, $2) returning * into person; - insert into candymat_data_privat.person_account (person_row_id, email, password_hash) + insert into kandimat_data_privat.person_account (person_row_id, email, password_hash) values (person.row_id, $3, crypt($4, gen_salt('bf'))); return person; end ; $$ language plpgsql strict security definer; -grant execute on function candymat_data.register_person(text, text, text, text) to candymat_anonymous; +grant execute on function kandimat_data.register_person(text, text, text, text) to kandimat_anonymous; -- Authenticate: Login for user -drop function if exists candymat_data.authenticate; -create function candymat_data.authenticate( +drop function if exists kandimat_data.authenticate; +create function kandimat_data.authenticate( email text, password text -) returns candymat_data.jwt_token as +) returns kandimat_data.jwt_token as $$ declare - account candymat_data_privat.person_account; - declare person candymat_data.person; + account kandimat_data_privat.person_account; + declare person kandimat_data.person; begin select a.* into account - from candymat_data_privat.person_account as a + from kandimat_data_privat.person_account as a where a.email = $1; select p.* into person - from candymat_data.person as p + from kandimat_data.person as p where p.row_id = account.person_row_id; if account.password_hash = crypt(password, account.password_hash) then return (person.role, account.person_row_id, - extract(epoch from (now() + interval '2 days')))::candymat_data.jwt_token; + extract(epoch from (now() + interval '2 days')))::kandimat_data.jwt_token; else return null; end if; end; $$ language plpgsql strict security definer; -grant execute on function candymat_data.authenticate(text, text) to candymat_anonymous, candymat_person; +grant execute on function kandimat_data.authenticate(text, text) to kandimat_anonymous, kandimat_person; -- Change role: Changes role for a given user. Only editors are allowed to use it. -drop function if exists candymat_data.change_role; -create function candymat_data.change_role( +drop function if exists kandimat_data.change_role; +create function kandimat_data.change_role( person_row_id integer, - new_role candymat_data.role + new_role kandimat_data.role ) - returns candymat_data.person as + returns kandimat_data.person as $$ declare - person candymat_data.person; + person kandimat_data.person; begin - update candymat_data.person + update kandimat_data.person set role = new_role - where candymat_data.person.row_id = $1 + where kandimat_data.person.row_id = $1 returning * into person; return person; end; $$ language plpgsql strict security definer; -grant execute on function candymat_data.change_role(integer, candymat_data.role) to candymat_editor; +grant execute on function kandimat_data.change_role(integer, kandimat_data.role) to kandimat_editor; diff --git a/backend/sql/test_01_add_users.sql b/backend/sql/test_01_add_users.sql index 9200f6c..9ecce2b 100644 --- a/backend/sql/test_01_add_users.sql +++ b/backend/sql/test_01_add_users.sql @@ -1,40 +1,40 @@ -select candymat_data.register_person( +select kandimat_data.register_person( 'Erika', 'Mustermann', 'erika@mustermann.de', 'password' ); -select candymat_data.change_role( +select kandimat_data.change_role( 1, - 'candymat_editor' + 'kandimat_editor' ); -select candymat_data.register_person( +select kandimat_data.register_person( 'Max', 'Mustermann', 'max@mustermann.de', 'password' ); -select candymat_data.change_role( +select kandimat_data.change_role( 2, - 'candymat_candidate' + 'kandimat_candidate' ); -select candymat_data.register_person( +select kandimat_data.register_person( 'Tricia', 'McMillan', 'trillian@universe.com', 'password' ); -select candymat_data.change_role( +select kandimat_data.change_role( 3, - 'candymat_candidate' + 'kandimat_candidate' ); -select candymat_data.register_person( +select kandimat_data.register_person( 'Happy', 'User', 'happy@user.de', 'password' ); -select candymat_data.change_role( +select kandimat_data.change_role( 4, - 'candymat_person' + 'kandimat_person' ); diff --git a/backend/sql/test_02_add_questions.sql b/backend/sql/test_02_add_questions.sql index 283952d..a992a74 100644 --- a/backend/sql/test_02_add_questions.sql +++ b/backend/sql/test_02_add_questions.sql @@ -1,9 +1,9 @@ -insert into candymat_data.category (title, description) values +insert into kandimat_data.category (title, description) values ('Umwelt', 'Themen rund um Naturschutz usw.'); -insert into candymat_data.category (title, description) values +insert into kandimat_data.category (title, description) values ('Sonstiges', ''); -insert into candymat_data.question (category_row_id, title, description) values +insert into kandimat_data.question (category_row_id, title, description) values (1, 'Was sagen Sie zur 10H Regel?', 'In Bayern dürfen Windräder nur ...'); -insert into candymat_data.question (category_row_id, title, description) values +insert into kandimat_data.question (category_row_id, title, description) values (2, 'Umgehungsstraße XY?', 'Zur Entlastung der Hauptstraße ...'); diff --git a/backend/sql/test_03_add_answers.sql b/backend/sql/test_03_add_answers.sql index 1162a32..eb4f2ca 100644 --- a/backend/sql/test_03_add_answers.sql +++ b/backend/sql/test_03_add_answers.sql @@ -1,9 +1,9 @@ -insert into candymat_data.answer (question_row_id, person_row_id, position, text) +insert into kandimat_data.answer (question_row_id, person_row_id, position, text) values (1, 2, 2, 'bin dagegen'); -insert into candymat_data.answer (question_row_id, person_row_id, position, text) +insert into kandimat_data.answer (question_row_id, person_row_id, position, text) values (2, 2, 0, 'bin dafür'); -insert into candymat_data.answer (question_row_id, person_row_id, position, text) +insert into kandimat_data.answer (question_row_id, person_row_id, position, text) values (1, 3, 1, 'mir egal'); -insert into candymat_data.answer (question_row_id, person_row_id, position, text) +insert into kandimat_data.answer (question_row_id, person_row_id, position, text) values (2, 3, 3, 'keine lust mehr'); diff --git a/candymat-user-app b/candymat-user-app deleted file mode 160000 index d7f669b..0000000 --- a/candymat-user-app +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d7f669bc9978b0f0284bfc6d17552a75fbc13a7c diff --git a/docker-compose.dev.yml b/docker-compose.dev.yml index 075fe9f..3cff80b 100644 --- a/docker-compose.dev.yml +++ b/docker-compose.dev.yml @@ -15,7 +15,7 @@ services: user-app: build: - context: ./candymat-user-app/ + context: kandimat-user-app/ dockerfile: ./dev.Dockerfile depends_on: - graphql @@ -25,7 +25,7 @@ services: - frontend postgres: - image: candymat-postgres:11.5 + image: kandimat-postgres:11.5 build: dockerfile: ./Dockerfile context: ./backend/ @@ -53,9 +53,9 @@ services: "--host", "0.0.0.0", "--port", "5000", "--cors", - "--schema", "candymat_data", - "--default-role", "candymat_anonymous", - "--jwt-token-identifier", "candymat_data.jwt_token", + "--schema", "kandimat_data", + "--default-role", "kandimat_anonymous", + "--jwt-token-identifier", "kandimat_data.jwt_token", "--jwt-secret", $JWT_SECRET, "--watch", "--retry-on-init-fail", diff --git a/kandimat-user-app b/kandimat-user-app new file mode 160000 index 0000000..dc1602b --- /dev/null +++ b/kandimat-user-app @@ -0,0 +1 @@ +Subproject commit dc1602b6e87c80d3c37f92bc87f02c98865895d3 diff --git a/redaktions-app/public/index.html b/redaktions-app/public/index.html index 5e23519..9c3ad90 100644 --- a/redaktions-app/public/index.html +++ b/redaktions-app/public/index.html @@ -7,7 +7,7 @@ -