Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions src/deploy/extension_postgis.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,15 @@ CREATE EXTENSION postgis WITH SCHEMA public;

COMMENT ON EXTENSION postgis IS 'Functions to work with geospatial data.';

GRANT EXECUTE ON FUNCTION
geography(geometry),
geometry(text),
geometrytype(geography),
postgis_type_name(character varying, integer, boolean),
st_asgeojson(geography, integer, integer),
st_coorddim(geometry),
st_geomfromgeojson(text),
st_srid(geography)
TO maevsi_anonymous, maevsi_account;

COMMIT;
7 changes: 7 additions & 0 deletions src/deploy/index_account_private_location.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
BEGIN;

CREATE INDEX idx_account_private_location ON maevsi_private.account USING GIST (location);

COMMENT ON INDEX maevsi_private.idx_account_private_location IS 'Spatial index on column location in maevsi_private.account.';

COMMIT;
7 changes: 7 additions & 0 deletions src/deploy/index_event_location.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
BEGIN;

CREATE INDEX idx_event_location ON maevsi.event USING GIST (location_geography);

COMMENT ON INDEX maevsi.idx_event_location IS 'Spatial index on column location in maevsi.event.';

COMMIT;
2 changes: 2 additions & 0 deletions src/deploy/table_account_private.sql
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ CREATE TABLE maevsi_private.account (
email_address TEXT NOT NULL CHECK (char_length(email_address) < 255) UNIQUE, -- no regex check as "a valid email address is one that you can send emails to" (http://www.dominicsayers.com/isemail/)
email_address_verification UUID DEFAULT gen_random_uuid(),
email_address_verification_valid_until TIMESTAMP WITH TIME ZONE,
location GEOGRAPHY(Point, 4326),
password_hash TEXT NOT NULL,
password_reset_verification UUID,
password_reset_verification_valid_until TIMESTAMP WITH TIME ZONE,
Expand All @@ -22,6 +23,7 @@ COMMENT ON COLUMN maevsi_private.account.birth_date IS 'The account owner''s dat
COMMENT ON COLUMN maevsi_private.account.email_address IS 'The account''s email address for account related information.';
COMMENT ON COLUMN maevsi_private.account.email_address_verification IS 'The UUID used to verify an email address, or null if already verified.';
COMMENT ON COLUMN maevsi_private.account.email_address_verification_valid_until IS 'The timestamp until which an email address verification is valid.';
COMMENT ON COLUMN maevsi_private.account.location IS 'The account''s geometric location.';
COMMENT ON COLUMN maevsi_private.account.password_hash IS 'The account''s password, hashed and salted.';
COMMENT ON COLUMN maevsi_private.account.password_reset_verification IS 'The UUID used to reset a password, or null if there is no pending reset request.';
COMMENT ON COLUMN maevsi_private.account.password_reset_verification_valid_until IS 'The timestamp until which a password reset is valid.';
Expand Down
2 changes: 2 additions & 0 deletions src/deploy/table_event.sql
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ CREATE TABLE maevsi.event (
is_remote BOOLEAN,
language maevsi.language,
location TEXT CHECK (char_length("location") > 0 AND char_length("location") < 300),
location_geography GEOGRAPHY(Point, 4326),
name TEXT NOT NULL CHECK (char_length("name") > 0 AND char_length("name") < 100),
slug TEXT NOT NULL CHECK (char_length(slug) < 100 AND slug ~ '^[-A-Za-z0-9]+$'),
start TIMESTAMP WITH TIME ZONE NOT NULL,
Expand All @@ -34,6 +35,7 @@ COMMENT ON COLUMN maevsi.event.is_archived IS 'Indicates whether the event is ar
COMMENT ON COLUMN maevsi.event.is_in_person IS 'Indicates whether the event takes place in person.';
COMMENT ON COLUMN maevsi.event.is_remote IS 'Indicates whether the event takes place remotely.';
COMMENT ON COLUMN maevsi.event.location IS 'The event''s location as it can be shown on a map.';
COMMENT ON COLUMN maevsi.event.location_geography IS 'The event''s geographic location.';
COMMENT ON COLUMN maevsi.event.name IS 'The event''s name.';
COMMENT ON COLUMN maevsi.event.slug IS 'The event''s name, slugified.';
COMMENT ON COLUMN maevsi.event.start IS 'The event''s start date and time, with timezone.';
Expand Down
162 changes: 162 additions & 0 deletions src/deploy/test_location.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
BEGIN;


CREATE FUNCTION maevsi.account_filter_radius_event(
_event_id UUID,
_distance_max DOUBLE PRECISION
)
RETURNS TABLE (
account_id UUID,
distance DOUBLE PRECISION
) AS $$
BEGIN
RETURN QUERY
WITH event AS (
SELECT location_geography
FROM maevsi.event
WHERE id = _event_id
)
SELECT
a.id AS account_id,
ST_Distance(e.location_geography, a.location) AS distance
FROM
event e,
maevsi_private.account a
WHERE
ST_DWithin(e.location_geography, a.location, _distance_max * 1000);
END;
$$ LANGUAGE PLPGSQL STRICT STABLE SECURITY DEFINER;

COMMENT ON FUNCTION maevsi.account_filter_radius_event(UUID, DOUBLE PRECISION) IS 'Returns account locations within a given radius around the location of an event.';

GRANT EXECUTE ON FUNCTION maevsi.account_filter_radius_event(UUID, DOUBLE PRECISION) TO maevsi_account;


CREATE FUNCTION maevsi.event_filter_radius_account(
_account_id UUID,
_distance_max DOUBLE PRECISION
)
RETURNS TABLE (
event_id UUID,
distance DOUBLE PRECISION
) AS $$
BEGIN
RETURN QUERY
WITH account AS (
SELECT location
FROM maevsi_private.account
WHERE id = _account_id
)
SELECT
e.id AS event_id,
ST_Distance(a.location, e.location_geography) AS distance
FROM
account a,
maevsi.event e
WHERE
ST_DWithin(a.location, e.location_geography, _distance_max * 1000);
END;
$$ LANGUAGE PLPGSQL STRICT STABLE SECURITY DEFINER;

COMMENT ON FUNCTION maevsi.event_filter_radius_account(UUID, DOUBLE PRECISION) IS 'Returns event locations within a given radius around the location of an account.';

GRANT EXECUTE ON FUNCTION maevsi.event_filter_radius_account(UUID, DOUBLE PRECISION) TO maevsi_account;


CREATE FUNCTION maevsi.account_location_update(
_account_id UUID,
_latitude DOUBLE PRECISION,
_longitude DOUBLE PRECISION
)
RETURNS VOID AS $$
BEGIN
UPDATE maevsi_private.account
SET
location = ST_Point(_longitude, _latitude, 4326)
WHERE
id = _account_id;
END;
$$ LANGUAGE PLPGSQL STRICT SECURITY DEFINER;

COMMENT ON FUNCTION maevsi.account_location_update(UUID, DOUBLE PRECISION, DOUBLE PRECISION) IS 'Updates an account''s location based on latitude and longitude (GPS coordinates).';

GRANT EXECUTE ON FUNCTION maevsi.account_location_update(UUID, DOUBLE PRECISION, DOUBLE PRECISION) TO maevsi_account;


CREATE FUNCTION maevsi.event_location_update(
_event_id UUID,
_latitude DOUBLE PRECISION,
_longitude DOUBLE PRECISION
)
RETURNS VOID AS $$
BEGIN
UPDATE maevsi.event
SET
location_geography = ST_Point(_longitude, _latitude, 4326)
WHERE
id = _event_id;
END;
$$ LANGUAGE PLPGSQL STRICT SECURITY DEFINER;

COMMENT ON FUNCTION maevsi.event_location_update(UUID, DOUBLE PRECISION, DOUBLE PRECISION) IS 'Updates an event''s location based on latitude and longitude (GPS coordinates).';

GRANT EXECUTE ON FUNCTION maevsi.event_location_update(UUID, DOUBLE PRECISION, DOUBLE PRECISION) TO maevsi_account;


CREATE FUNCTION maevsi.account_location_coordinates(
_account_id UUID
)
RETURNS DOUBLE PRECISION[] AS $$
DECLARE
_latitude DOUBLE PRECISION;
_longitude DOUBLE PRECISION;
BEGIN
SELECT
ST_Y(location::geometry),
ST_X(location::geometry)
INTO
_latitude,
_longitude
FROM
maevsi_private.account
WHERE
id = _account_id;

RETURN ARRAY[_latitude, _longitude];
END;
$$ LANGUAGE PLPGSQL STRICT STABLE SECURITY DEFINER;

COMMENT ON FUNCTION maevsi.account_location_coordinates(UUID) IS 'Returns an array with latitude and longitude of the account''s current location data';

GRANT EXECUTE ON FUNCTION maevsi.account_location_coordinates(UUID) TO maevsi_account;


CREATE FUNCTION maevsi.event_location_coordinates(
_event_id UUID
)
RETURNS DOUBLE PRECISION[] AS $$
DECLARE
_latitude DOUBLE PRECISION;
_longitude DOUBLE PRECISION;
BEGIN
SELECT
ST_Y(location_geography::geometry),
ST_X(location_geography::geometry)
INTO
_latitude,
_longitude
FROM
maevsi.event
WHERE
id = _event_id;

RETURN ARRAY[_latitude, _longitude];
END;
$$ LANGUAGE PLPGSQL STRICT STABLE SECURITY DEFINER;

COMMENT ON FUNCTION maevsi.event_location_coordinates(UUID) IS 'Returns an array with latitude and longitude of the event''s current location data.';

GRANT EXECUTE ON FUNCTION maevsi.event_location_coordinates(UUID) TO maevsi_account;


COMMIT;
11 changes: 11 additions & 0 deletions src/revert/extension_postgis.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
BEGIN;

REVOKE EXECUTE ON FUNCTION
st_srid(geography),
st_geomfromgeojson(text),
st_coorddim(geometry),
st_asgeojson(geography, integer, integer),
postgis_type_name(character varying, integer, boolean),
geometrytype(geography),
geometry(text),
geography(geometry)
FROM maevsi_anonymous, maevsi_account;

DROP EXTENSION postgis;

COMMIT;
5 changes: 5 additions & 0 deletions src/revert/index_account_private_location.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
BEGIN;

DROP INDEX maevsi_private.idx_account_private_location;

COMMIT;
5 changes: 5 additions & 0 deletions src/revert/index_event_location.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
BEGIN;

DROP INDEX maevsi.idx_event_location;

COMMIT;
12 changes: 12 additions & 0 deletions src/revert/test_location.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
BEGIN;

DROP FUNCTION maevsi.account_filter_radius_event(UUID, DOUBLE PRECISION);
DROP FUNCTION maevsi.event_filter_radius_account(UUID, DOUBLE PRECISION);

DROP FUNCTION maevsi.account_location_update(UUID, DOUBLE PRECISION, DOUBLE PRECISION);
DROP FUNCTION maevsi.event_location_update(UUID, DOUBLE PRECISION, DOUBLE PRECISION);

DROP FUNCTION maevsi.account_location_coordinates(UUID);
DROP FUNCTION maevsi.event_location_coordinates(UUID);

COMMIT;
9 changes: 6 additions & 3 deletions src/sqitch.plan
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@ function_invoker_account_id [privilege_execute_revoke schema_public role_account
enum_invitation_feedback [schema_public] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Possible answers to an invitation: accepted, canceled.
enum_event_visibility [schema_public] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Possible visibilities of events and event groups: public, private.
table_notification [schema_private] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Notifications that are sent via pg_notify.
table_account_private [schema_private schema_public] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Add private table account.
extension_postgis [schema_public] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Add functions to work with geospatial data.
table_account_private [schema_private extension_postgis] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Add private table account.
table_account_public [schema_public schema_private table_account_private] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Add public table account.
table_account_block [schema_public table_account_public] 1970-01-01T00:00:00Z Sven Thelemann <sven.thelemann@t-online.de> # Blocking of an account by another account.
table_account_block_policy [schema_public table_account_block role_account role_anonymous function_invoker_account_id] 1970-01-01T00:00:00Z Sven Thelemann <sven.thelemann@t-online.de> # Policy for table account block.
table_event_group [schema_public role_account role_anonymous table_account_public enum_event_visibility] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Add table event_group.
index_event_group_author_username [table_event_group] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Add an index to the event group table's author_username field.
enum_language [schema_public] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Supported ISO 639 language codes.
function_language_iso_full_text_search [privilege_execute_revoke schema_public enum_language] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # ISO language code to full text search language conversion.
table_event [schema_public table_account_public enum_language enum_event_visibility function_language_iso_full_text_search role_account role_anonymous] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Add table event.
table_event [schema_public table_account_public enum_language extension_postgis enum_event_visibility function_language_iso_full_text_search role_account role_anonymous] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Add table event.
function_events_organized [privilege_execute_revoke schema_public function_invoker_account_id table_event role_account role_anonymous] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Add a function that returns all event ids for which the invoker is the author.
index_event_author_username [table_event] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Add an index to the event table's username field.
enum_invitation_feedback_paper 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Possible choices on how to receive a paper invitation: paper, digital.
Expand Down Expand Up @@ -93,5 +94,7 @@ table_event_recommendation_policy [schema_public table_event_recommendation role
table_event_favourite [schema_public table_account_public table_event] 1970-01-01T00:00:00Z Sven Thelemann <sven.thelemann@t-online.de> # A table for the user accounts' favourite events.
table_event_favourite_policy [schema_public table_account_public table_event role_account] 1970-01-01T00:00:00Z Sven Thelemann <sven.thelemann@t-online.de> # Policy for table event_favourite.
test_account_blocking [schema_test] 1970-01-01T00:00:00Z Sven Thelemann <sven.thelemann@t-online.de> # Test cases for account blocking.
extension_postgis [schema_public] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Add functions to work with geospatial data.
function_event_search [privilege_execute_revoke schema_public enum_language schema_private function_language_iso_full_text_search table_event role_account role_anonymous] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+maevsi/sqitch@jonas-thelemann.de> # Full-text search on events.
index_account_private_location [schema_private table_account_private] 1970-01-01T00:00:00Z Sven Thelemann <sven.thelemann@t-online.de> # Spacial index on location column in table maevsi_private.account.
index_event_location [schema_public table_event] 1970-01-01T00:00:00Z Sven Thelemann <sven.thelemann@t-online.de> # Spacial index on location_geography column in table maevsi.event.
test_location [schema_public schema_private extension_postgis table_account_private table_event role_anonymous role_account] 1970-01-01T00:00:00Z Sven Thelemann <sven.thelemann@t-online.de> # A collection of location related functions.
29 changes: 28 additions & 1 deletion src/verify/extension_postgis.sql
Original file line number Diff line number Diff line change
@@ -1,6 +1,33 @@
BEGIN;

SELECT 1/count(*) FROM pg_extension WHERE extname = 'postgis';
SELECT has_function_privilege('public.ST_DWithin(public.geometry, public.geometry, double precision)', 'EXECUTE');
SELECT has_function_privilege('ST_DWithin(geometry, geometry, double precision)', 'EXECUTE');

SAVEPOINT function_privileges_for_roles;
DO $$
DECLARE
functions TEXT[] := ARRAY[
'geography(geometry)',
'geometry(TEXT)',
'geometrytype(GEOGRAPHY)',
'postgis_type_name(CHARACTER VARYING, INTEGER, BOOLEAN)',
'st_asgeojson(GEOGRAPHY, INTEGER, INTEGER)',
'st_coorddim(GEOMETRY)',
'st_geomfromgeojson(TEXT)',
'st_srid(GEOGRAPHY)'
];
roles TEXT[] := ARRAY['maevsi_account', 'maevsi_anonymous'];
function TEXT;
role TEXT;
BEGIN
FOREACH role IN ARRAY roles LOOP
FOREACH function IN ARRAY functions LOOP
IF NOT (SELECT pg_catalog.has_function_privilege(role, function, 'EXECUTE')) THEN
RAISE EXCEPTION 'Test function_privileges_for_roles failed: % does not have EXECUTE privilege on function %', role, function;
END IF;
END LOOP;
END LOOP;
END $$;
ROLLBACK TO SAVEPOINT function_privileges_for_roles;

ROLLBACK;
9 changes: 9 additions & 0 deletions src/verify/index_account_private_location.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
BEGIN;

SELECT 1/COUNT(*)
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = 'idx_account_private_location'
AND n.nspname = 'maevsi_private';

ROLLBACK;
9 changes: 9 additions & 0 deletions src/verify/index_event_location.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
BEGIN;

SELECT 1/COUNT(*)
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relname = 'idx_event_location'
AND n.nspname = 'maevsi';

ROLLBACK;
1 change: 1 addition & 0 deletions src/verify/table_account_private.sql
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ SELECT id,
email_address_verification,
email_address_verification_valid_until,
last_activity,
location,
password_hash,
password_reset_verification,
password_reset_verification_valid_until,
Expand Down
1 change: 1 addition & 0 deletions src/verify/table_event.sql
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ SELECT id,
is_in_person,
is_remote,
location,
location_geography,
name,
slug,
start,
Expand Down
Loading