Skip to content
Open
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
37 changes: 21 additions & 16 deletions src/deploy/function_account_password_reset_request.sql
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,36 @@ CREATE FUNCTION vibetype.account_password_reset_request(
language TEXT
) RETURNS VOID AS $$
DECLARE
_notify_data RECORD;
_account vibetype_private.account%ROWTYPE;
_notify_data RECORD := NULL;
BEGIN
WITH updated AS (
UPDATE vibetype_private.account
SET password_reset_verification = gen_random_uuid()
WHERE account.email_address = account_password_reset_request.email_address
RETURNING *
) SELECT
account.username,
updated.email_address,
updated.password_reset_verification,
updated.password_reset_verification_valid_until
FROM updated, vibetype.account
WHERE updated.id = account.id
INTO _notify_data;

UPDATE vibetype_private.account
SET password_reset_verification = gen_random_uuid()
WHERE account.email_address = account_password_reset_request.email_address
RETURNING * INTO _account;

IF _account IS NOT NULL THEN
SELECT
username,
_account.email_address,
_account.password_reset_verification,
_account.password_reset_verification_valid_until
INTO _notify_data
FROM vibetype.account
WHERE id = _account.id;
END IF;

IF (_notify_data IS NULL) THEN
-- noop
ELSE
INSERT INTO vibetype_private.notification (channel, payload) VALUES (
INSERT INTO vibetype.notification (channel, payload, created_by) VALUES (
'account_password_reset_request',
jsonb_pretty(jsonb_build_object(
'account', _notify_data,
'template', jsonb_build_object('language', account_password_reset_request.language)
))
)),
_account.id
);
END IF;
END;
Expand Down
9 changes: 5 additions & 4 deletions src/deploy/function_account_registration.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ CREATE FUNCTION vibetype.account_registration(
username TEXT
) RETURNS VOID AS $$
DECLARE
_new_account_private vibetype_private.account;
_new_account_public vibetype.account;
_new_account_private vibetype_private.account%ROWTYPE;
_new_account_public vibetype.account%ROWTYPE;
_new_account_notify RECORD;
BEGIN
IF account_registration.birth_date > CURRENT_DATE - INTERVAL '18 years' THEN
Expand Down Expand Up @@ -50,12 +50,13 @@ BEGIN

INSERT INTO vibetype.contact(account_id, created_by) VALUES (_new_account_private.id, _new_account_private.id);

INSERT INTO vibetype_private.notification (channel, payload) VALUES (
INSERT INTO vibetype.notification (channel, payload, created_by) VALUES (
'account_registration',
jsonb_pretty(jsonb_build_object(
'account', row_to_json(_new_account_notify),
'template', jsonb_build_object('language', account_registration.language)
))
)),
_new_account_private.id
);

-- not possible to return data here as this would make the silent return above for email address duplicates distinguishable from a successful registration
Expand Down
8 changes: 4 additions & 4 deletions src/deploy/function_account_registration_refresh.sql
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,16 @@ BEGIN
updated.email_address,
updated.email_address_verification,
updated.email_address_verification_valid_until
FROM updated, vibetype.account
WHERE updated.id = account.id
FROM updated JOIN vibetype.account ON updated.id = account.id
INTO _new_account_notify;

INSERT INTO vibetype_private.notification (channel, payload) VALUES (
INSERT INTO vibetype.notification (channel, payload, created_by) VALUES (
'account_registration',
jsonb_pretty(jsonb_build_object(
'account', row_to_json(_new_account_notify),
'template', jsonb_build_object('language', account_registration_refresh.language)
))
)),
account_registration_refresh.account_id
);
END;
$$ LANGUAGE PLPGSQL STRICT SECURITY DEFINER;
Expand Down
40 changes: 28 additions & 12 deletions src/deploy/function_invite.sql
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,20 @@ BEGIN;
CREATE FUNCTION vibetype.invite(
guest_id UUID,
language TEXT
) RETURNS VOID AS $$
) RETURNS UUID AS $$
DECLARE
_contact RECORD;
_email_address TEXT;
_event RECORD;
_event_creator_profile_picture_upload_id UUID;
_event_creator_profile_picture_upload_storage_key TEXT;
_event_creator_username TEXT;
_guest RECORD;
_id UUID;
BEGIN
-- Guest UUID
SELECT * FROM vibetype.guest INTO _guest WHERE guest.id = invite.guest_id;
SELECT * INTO _guest
FROM vibetype.guest
WHERE guest.id = invite.guest_id;

IF (
_guest IS NULL
Expand All @@ -41,14 +43,17 @@ BEGIN
visibility,
created_at,
created_by
FROM vibetype.event INTO _event WHERE "event".id = _guest.event_id;
INTO _event
FROM vibetype.event WHERE id = _guest.event_id;

IF (_event IS NULL) THEN
RAISE 'Event not accessible!' USING ERRCODE = 'no_data_found';
END IF;

-- Contact
SELECT account_id, email_address FROM vibetype.contact INTO _contact WHERE contact.id = _guest.contact_id;
SELECT account_id, email_address INTO _contact
FROM vibetype.contact
WHERE id = _guest.contact_id;

IF (_contact IS NULL) THEN
RAISE 'Contact not accessible!' USING ERRCODE = 'no_data_found';
Expand All @@ -62,22 +67,29 @@ BEGIN
END IF;
ELSE
-- Account
SELECT email_address FROM vibetype_private.account INTO _email_address WHERE account.id = _contact.account_id;
SELECT email_address INTO _email_address
FROM vibetype_private.account
WHERE id = _contact.account_id;

IF (_email_address IS NULL) THEN
RAISE 'Account email address not accessible!' USING ERRCODE = 'no_data_found';
END IF;
END IF;

-- Event creator username
SELECT username FROM vibetype.account INTO _event_creator_username WHERE account.id = _event.created_by;
SELECT username INTO _event_creator_username
FROM vibetype.account
WHERE id = _event.created_by;

-- Event creator profile picture storage key
SELECT upload_id FROM vibetype.profile_picture INTO _event_creator_profile_picture_upload_id WHERE profile_picture.account_id = _event.created_by;
SELECT storage_key FROM vibetype.upload INTO _event_creator_profile_picture_upload_storage_key WHERE upload.id = _event_creator_profile_picture_upload_id;
SELECT u.storage_key INTO _event_creator_profile_picture_upload_storage_key
FROM vibetype.profile_picture p
JOIN vibetype.upload u ON p.upload_id = u.id
WHERE p.account_id = _event.created_by;

INSERT INTO vibetype_private.notification (channel, payload)
INSERT INTO vibetype.notification_invitation (guest_id, channel, payload, created_by)
VALUES (
invite.guest_id,
'event_invitation',
jsonb_pretty(jsonb_build_object(
'data', jsonb_build_object(
Expand All @@ -88,8 +100,12 @@ BEGIN
'guestId', _guest.id
),
'template', jsonb_build_object('language', invite.language)
))
);
)),
vibetype.invoker_account_id()
)
RETURNING id INTO _id;

RETURN _id;
END;
$$ LANGUAGE PLPGSQL STRICT SECURITY DEFINER;

Expand Down
11 changes: 8 additions & 3 deletions src/deploy/function_notification_acknowledge.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,15 @@ CREATE FUNCTION vibetype.notification_acknowledge(
id UUID,
is_acknowledged BOOLEAN
) RETURNS VOID AS $$
DECLARE
update_count INTEGER;
BEGIN
IF (EXISTS (SELECT 1 FROM vibetype_private.notification WHERE "notification".id = notification_acknowledge.id)) THEN
UPDATE vibetype_private.notification SET is_acknowledged = notification_acknowledge.is_acknowledged WHERE "notification".id = notification_acknowledge.id;
ELSE
UPDATE vibetype.notification SET
is_acknowledged = notification_acknowledge.is_acknowledged
WHERE id = notification_acknowledge.id;

GET DIAGNOSTICS update_count = ROW_COUNT;
IF update_count = 0 THEN
RAISE 'Notification with given id not found!' USING ERRCODE = 'no_data_found';
END IF;
END;
Expand Down
31 changes: 22 additions & 9 deletions src/deploy/table_notification.sql
Original file line number Diff line number Diff line change
@@ -1,23 +1,36 @@
BEGIN;

CREATE TABLE vibetype_private.notification (
CREATE TABLE vibetype.notification (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),

channel TEXT NOT NULL,
is_acknowledged BOOLEAN,
payload TEXT NOT NULL CHECK (octet_length(payload) <= 8000),

created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP
created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT CURRENT_TIMESTAMP,
created_by UUID NOT NULL REFERENCES vibetype.account(id) ON DELETE CASCADE
);

COMMENT ON TABLE vibetype_private.notification IS 'A notification.';
COMMENT ON COLUMN vibetype_private.notification.id IS 'The notification''s internal id.';
COMMENT ON COLUMN vibetype_private.notification.channel IS 'The notification''s channel.';
COMMENT ON COLUMN vibetype_private.notification.is_acknowledged IS 'Whether the notification was acknowledged.';
COMMENT ON COLUMN vibetype_private.notification.payload IS 'The notification''s payload.';
COMMENT ON COLUMN vibetype_private.notification.created_at IS 'The timestamp of the notification''s creation.';
CREATE INDEX idx_notification_created_by ON vibetype.notification USING btree (created_by);

COMMENT ON TABLE vibetype.notification IS 'A notification.';
COMMENT ON COLUMN vibetype.notification.id IS 'The notification''s internal id.';
COMMENT ON COLUMN vibetype.notification.channel IS 'The notification''s channel.';
COMMENT ON COLUMN vibetype.notification.is_acknowledged IS 'Whether the notification was acknowledged.';
COMMENT ON COLUMN vibetype.notification.payload IS 'The notification''s payload.';
COMMENT ON COLUMN vibetype.notification.created_at IS 'The timestamp of the notification''s creation.';
COMMENT ON COLUMN vibetype.notification.created_by IS 'Reference to the account that created the notification.';

GRANT SELECT ON vibetype.notification TO vibetype_account;

ALTER TABLE vibetype.notification ENABLE ROW LEVEL SECURITY;

CREATE POLICY notification_all ON vibetype.notification FOR ALL
USING (
created_by = vibetype.invoker_account_id()
);

\set role_service_grafana_username `cat /run/secrets/postgres_role_service_grafana_username`
GRANT SELECT ON TABLE vibetype_private.notification TO :role_service_grafana_username;
GRANT SELECT ON TABLE vibetype.notification TO :role_service_grafana_username;

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

CREATE TABLE vibetype.notification_invitation (
guest_id UUID NOT NULL REFERENCES vibetype.guest(id)
)
INHERITS (vibetype.notification);

CREATE INDEX idx_invitation_guest_id ON vibetype.notification_invitation USING btree (guest_id);

COMMENT ON TABLE vibetype.notification_invitation IS '@omit update,delete\nStores invitations and their statuses.';
COMMENT ON COLUMN vibetype.notification_invitation.guest_id IS 'The ID of the guest associated with this invitation.';

GRANT SELECT ON vibetype.notification_invitation TO vibetype_account;

ALTER TABLE vibetype.notification_invitation ENABLE ROW LEVEL SECURITY;

COMMIT;
4 changes: 3 additions & 1 deletion src/revert/table_notification.sql
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
BEGIN;

DROP TABLE vibetype_private.notification;
DROP POLICY notification_all ON vibetype.notification;

DROP TABLE vibetype.notification;

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

DROP TABLE vibetype.notification_invitation;

COMMIT;
3 changes: 2 additions & 1 deletion src/sqitch.plan
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ 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+vibetype/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+vibetype/sqitch@jonas-thelemann.de> # Possible visibilities of events and event groups: public, private and unlisted.
function_trigger_metadata_update [privilege_execute_revoke schema_public function_invoker_account_id role_account] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+vibetype/sqitch@jonas-thelemann.de> # Trigger function to automatically update metadata fields `updated_at` and `updated_by` when a row is modified. Sets `updated_at` to the current timestamp and `updated_by` to the account ID of the invoker.
table_notification [schema_private] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+vibetype/sqitch@jonas-thelemann.de> # Notifications that are sent via pg_notify.
table_account_private [schema_private] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+vibetype/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+vibetype/sqitch@jonas-thelemann.de> # Add public table account.
table_notification [schema_private table_account_public] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+vibetype/sqitch@jonas-thelemann.de> # Notifications that are sent via pg_notify.
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.
function_account_block_ids [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> # Function returning all account id's involved in blocking.
enum_language [schema_public] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+vibetype/sqitch@jonas-thelemann.de> # Supported ISO 639 language codes.
Expand Down Expand Up @@ -87,6 +87,7 @@ table_event_format_mapping [schema_public table_event table_event_format role_an
table_audit_log [schema_private] 1970-01-01T00:00:00Z Sven Thelemann <sven.thelemann@t-online.de> # Table for storing audit log records.
view_audit_log_trigger [schema_private] 1970-01-01T00:00:00Z Sven Thelemann <sven.thelemann@t-online.de> # View showing all audit log triggers.
function_audit_log [schema_private table_audit_log view_audit_log_trigger] 1970-01-01T00:00:00Z Sven Thelemann <sven.thelemann@t-online.de> # Utility functions for managing audit log triggers.
table_notification_invitation [schema_public table_guest] 1970-01-01T00:00:00Z Sven Thelemann <sven.thelemann@t-online.de> # A table for tracking actions around invitations.
table_preference_event_format [schema_public table_account_public table_event_category] 1970-01-01T00:00:00Z Sven Thelemann <sven.thelemann@t-online.de> # Event formats a user account is interested in (M:N relationship).
function_account_location_update [privilege_execute_revoke schema_public table_account_private function_invoker_account_id role_account] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+vibetype/sqitch@jonas-thelemann.de> # Sets the location for the invoker's account.
table_preference_event_location [schema_public table_account_public role_account function_invoker_account_id] 1970-01-01T00:00:00Z Jonas Thelemann <e-mail+vibetype/sqitch@jonas-thelemann.de> # Stores preferred event locations for user accounts, including coordinates and search radius.
Expand Down
15 changes: 14 additions & 1 deletion src/verify/table_notification.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,20 @@ SELECT id,
channel,
is_acknowledged,
payload,
created_by,
created_at
FROM vibetype_private.notification WHERE FALSE;
FROM vibetype.notification WHERE FALSE;

DO $$
BEGIN
ASSERT (SELECT pg_catalog.has_table_privilege('vibetype_account', 'vibetype.notification', 'SELECT'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_account', 'vibetype.notification', 'INSERT'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_account', 'vibetype.notification', 'UPDATE'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_account', 'vibetype.notification', 'DELETE'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_anonymous', 'vibetype.notification', 'SELECT'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_anonymous', 'vibetype.notification', 'INSERT'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_anonymous', 'vibetype.notification', 'UPDATE'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_anonymous', 'vibetype.notification', 'DELETE'));
END $$;

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

SELECT
-- inherited from vibetype.notification
id,
channel,
is_acknowledged,
payload,
created_by,
created_at,
-- columns specific for vibetype.notification_invitation
guest_id
FROM vibetype.notification_invitation
WHERE FALSE;

DO $$
BEGIN
ASSERT (SELECT pg_catalog.has_table_privilege('vibetype_account', 'vibetype.notification_invitation', 'SELECT'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_account', 'vibetype.notification_invitation', 'INSERT'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_account', 'vibetype.notification_invitation', 'UPDATE'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_account', 'vibetype.notification_invitation', 'DELETE'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_anonymous', 'vibetype.notification_invitation', 'SELECT'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_anonymous', 'vibetype.notification_invitation', 'INSERT'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_anonymous', 'vibetype.notification_invitation', 'UPDATE'));
ASSERT NOT (SELECT pg_catalog.has_table_privilege('vibetype_anonymous', 'vibetype.notification_invitation', 'DELETE'));
END $$;

ROLLBACK;
Loading
Loading