-
-
Notifications
You must be signed in to change notification settings - Fork 3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(account): add possibility to block #73
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -4,32 +4,43 @@ | |||||||
-- requires: schema_public | ||||||||
-- requires: table_invitation | ||||||||
-- requires: table_contact | ||||||||
-- requires: table_account_block | ||||||||
-- requires: role_account | ||||||||
-- requires: role_anonymous | ||||||||
|
||||||||
BEGIN; | ||||||||
|
||||||||
CREATE FUNCTION maevsi_private.events_invited() | ||||||||
RETURNS TABLE (event_id UUID) AS $$ | ||||||||
CREATE OR REPLACE FUNCTION maevsi_private.events_invited() | ||||||||
RETURNS TABLE(event_id uuid) | ||||||||
AS $$ | ||||||||
DECLARE | ||||||||
jwt_account_id UUID; | ||||||||
BEGIN | ||||||||
jwt_account_id := NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID; | ||||||||
|
||||||||
RETURN QUERY | ||||||||
SELECT invitation.event_id FROM maevsi.invitation | ||||||||
SELECT event_id FROM maevsi.invitation | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In a few places it's necessary to keep this prefix or the column name would be ambiguous, but maybe this is not necessary here any more if you've checked it and it works without. If this function is confirmed to still be working, you can resolve this comment. |
||||||||
WHERE | ||||||||
invitation.contact_id IN ( | ||||||||
( | ||||||||
contact_id IN ( | ||||||||
SELECT id | ||||||||
FROM maevsi.contact | ||||||||
WHERE | ||||||||
jwt_account_id IS NOT NULL | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why is the
|
||||||||
AND | ||||||||
contact.account_id = jwt_account_id | ||||||||
) -- The contact selection does not return rows where account_id "IS" null due to the equality comparison. | ||||||||
OR invitation.id = ANY (maevsi.invitation_claim_array()); | ||||||||
account_id = jwt_account_id | ||||||||
-- The contact selection does not return rows where account_id "IS" null due to the equality comparison. | ||||||||
AND | ||||||||
-- contact not created by a blocked account | ||||||||
author_account_id NOT IN ( | ||||||||
SELECT account_block_id | ||||||||
FROM maevsi.account_block | ||||||||
WHERE b.author_account_id = jwt_account_id | ||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where is |
||||||||
) | ||||||||
) | ||||||||
) | ||||||||
OR id = ANY (maevsi.invitation_claim_array()); | ||||||||
END | ||||||||
$$ LANGUAGE PLPGSQL STRICT STABLE SECURITY DEFINER; | ||||||||
$$ LANGUAGE plpgsql STABLE STRICT SECURITY DEFINER | ||||||||
; | ||||||||
Comment on lines
+42
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Let's keep the formatting as is and change it only in a separate PR if wanted. |
||||||||
|
||||||||
COMMENT ON FUNCTION maevsi_private.events_invited() IS 'Add a function that returns all event ids for which the invoker is invited.'; | ||||||||
|
||||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -1,20 +1,40 @@ | ||||||||||||||
-- Deploy maevsi:function_invitation_claim_array to pg | ||||||||||||||
-- requires: privilege_execute_revoke | ||||||||||||||
-- requires: schema_public | ||||||||||||||
-- requires: table_invitation | ||||||||||||||
-- requires: table_contact | ||||||||||||||
-- requires: table_account_block | ||||||||||||||
-- requires: role_account | ||||||||||||||
-- requires: role_anonymous | ||||||||||||||
|
||||||||||||||
BEGIN; | ||||||||||||||
|
||||||||||||||
CREATE FUNCTION maevsi.invitation_claim_array() | ||||||||||||||
CREATE OR REPLACE FUNCTION maevsi.invitation_claim_array() | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we actually want to remove invitation ids that a user has collected when the event, an invitation was created for, is already made inaccessible for the user? In case a user is unblocked, this user would need to reclaim all invitation codes. If we just leave this method as is, the user would still be unable to access events by the user who blocked but would also be able to access the events again when unblocked. This is a highly theoretical question though, as this function is used for users without accounts primarily as far as I know. |
||||||||||||||
RETURNS UUID[] AS $$ | ||||||||||||||
DECLARE | ||||||||||||||
_arr UUID[]; | ||||||||||||||
_result_arr UUID[] := ARRAY[]::UUID[]; | ||||||||||||||
_id UUID; | ||||||||||||||
Comment on lines
+15
to
+17
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Let's continue using names here that immediately make clear how the variables are used 👍
Suggested change
|
||||||||||||||
BEGIN | ||||||||||||||
RETURN string_to_array(replace(btrim(current_setting('jwt.claims.invitations', true), '[]'), '"', ''), ',')::UUID[]; | ||||||||||||||
_arr := string_to_array(replace(btrim(current_setting('jwt.claims.invitations', true), '[]'), '"', ''), ',')::UUID[]; | ||||||||||||||
FOREACH _id IN ARRAY arr | ||||||||||||||
LOOP | ||||||||||||||
-- omit invitations authored by a blocked account | ||||||||||||||
IF NOT EXISTS( | ||||||||||||||
SELECT 1 | ||||||||||||||
FROM maevsi.invitation i | ||||||||||||||
JOIN maevsi.contact c ON i.contact_id = c.contact_id | ||||||||||||||
JOIN maevsi.account_block b ON c.author_account_id = b.blocked_account_id | ||||||||||||||
WHERE i.id = _id and b.author_account_id = current_setting('jwt.claims.account_id', true) | ||||||||||||||
) THEN | ||||||||||||||
_result_arr := append_array(result_arr, _id); | ||||||||||||||
END IF; | ||||||||||||||
END LOOP; | ||||||||||||||
|
||||||||||||||
RETURN _result_arr; | ||||||||||||||
END | ||||||||||||||
$$ LANGUAGE PLPGSQL STRICT STABLE SECURITY INVOKER; | ||||||||||||||
|
||||||||||||||
COMMENT ON FUNCTION maevsi.invitation_claim_array() IS 'Returns the current invitation claims as UUID array.'; | ||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Where did this comment go? |
||||||||||||||
|
||||||||||||||
GRANT EXECUTE ON FUNCTION maevsi.invitation_claim_array() TO maevsi_account, maevsi_anonymous; | ||||||||||||||
|
||||||||||||||
COMMIT; |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,20 +2,32 @@ | |
-- requires: privilege_execute_revoke | ||
-- requires: schema_public | ||
-- requires: table_invitation | ||
-- requires: table_contact | ||
-- requires: table_account_block | ||
-- requires: function_invitation_claim_array | ||
-- requires: function_events_organized | ||
-- requires: role_account | ||
-- requires: role_anonymous | ||
|
||
BEGIN; | ||
|
||
CREATE FUNCTION maevsi.invitation_contact_ids() | ||
CREATE OR REPLACE FUNCTION maevsi.invitation_contact_ids() | ||
RETURNS TABLE (contact_id UUID) AS $$ | ||
BEGIN | ||
RETURN QUERY | ||
SELECT invitation.contact_id FROM maevsi.invitation | ||
WHERE id = ANY (maevsi.invitation_claim_array()) | ||
OR event_id IN (SELECT maevsi.events_organized()); | ||
OR ( | ||
event_id IN (SELECT maevsi.events_organized()) | ||
AND | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shouldn't this |
||
-- omit contacts authored by a blocked account or referring to a blocked account | ||
contact_id NOT IN ( | ||
SELECT c.id | ||
FROM maevsi.contact c | ||
JOIN maevsi.account_block b ON c.author_account_id = b.blocked_account_id OR c.account_id = b.blocked_account_id | ||
WHERE b.author_account_id = NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID | ||
) | ||
); | ||
END; | ||
$$ LANGUAGE PLPGSQL STRICT STABLE SECURITY DEFINER; | ||
|
||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,22 @@ | ||||||
-- Deploy maevsi:table_account_block to pg | ||||||
-- requires: schema_public | ||||||
-- requires: table_account_public | ||||||
|
||||||
BEGIN; | ||||||
|
||||||
CREATE TABLE maevsi.account_block ( | ||||||
id UUID PRIMARY KEY DEFAULT gen_random_uuid(), | ||||||
author_account_id UUID NOT NULL REFERENCES maevsi.account(id), | ||||||
blocked_account_id UUID NOT NULL REFERENCES maevsi.account(id), | ||||||
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, | ||||||
UNIQUE (author_account_id, blocked_account_id), | ||||||
CHECK (author_account_id != blocked_account_id) | ||||||
); | ||||||
|
||||||
COMMENT ON TABLE maevsi.account_block IS E'@omit update,delete\nBlocking of an account by another account.'; | ||||||
COMMENT ON COLUMN maevsi.account_block.id IS '@omit create\nThe blocking''s internal id.'; | ||||||
COMMENT ON COLUMN maevsi.account_block.author_account_id IS 'The id of the user who created the blocking.'; | ||||||
COMMENT ON COLUMN maevsi.account_block.blocked_account_id IS 'The id of the account to be blocked.'; | ||||||
COMMENT ON COLUMN maevsi.account_block.created_at IS E'@omit update,delete\nThe timestamp when the blocking was created.'; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
The |
||||||
|
||||||
COMMIT; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
-- Deploy maevsi:table_account_block_policy to pg | ||
-- requires: schema_public | ||
-- requires: table_account_block | ||
-- requires: role_account | ||
|
||
BEGIN; | ||
|
||
GRANT INSERT, SELECT ON TABLE maevsi.account_block TO maevsi_account; | ||
|
||
ALTER TABLE maevsi.account_block ENABLE ROW LEVEL SECURITY; | ||
|
||
-- Only allow inserts for blocked accounts authored by the current user. | ||
CREATE POLICY account_block_insert ON maevsi.account_block FOR INSERT WITH CHECK ( | ||
NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID IS NOT NULL | ||
AND | ||
author_account_id = NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID | ||
); | ||
|
||
-- Only allow selects for blocked accounts authored by the current user. | ||
CREATE POLICY account_block_select ON maevsi.account_block FOR SELECT USING ( | ||
NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID IS NOT NULL | ||
AND | ||
author_account_id = NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID | ||
); | ||
|
||
COMMIT; |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,5 +1,6 @@ | ||||||
-- Deploy maevsi:table_contact_policy to pg | ||||||
-- requires: schema_public | ||||||
-- requires: table_account_block | ||||||
-- requires: table_contact | ||||||
-- requires: role_account | ||||||
-- requires: role_anonymous | ||||||
|
@@ -12,34 +13,52 @@ GRANT INSERT, UPDATE, DELETE ON TABLE maevsi.contact TO maevsi_account; | |||||
|
||||||
ALTER TABLE maevsi.contact ENABLE ROW LEVEL SECURITY; | ||||||
|
||||||
-- Only display contacts referencing the invoker's account. | ||||||
-- Only display contacts authored by the invoker's account. | ||||||
-- Only display contacts for which an accessible invitation exists. | ||||||
-- Only display contacts referencing the invoker's account, omit contacts authored by a blocked account. | ||||||
-- Only display contacts authored by the invoker's account, omit contacts referring to a blocked account. | ||||||
-- Only display contacts for which an accessible invitation exists, omit contacts auhored by a blocked account or referring to a blocked account. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
The last case is not covered here, it's implicitly covered by the word |
||||||
CREATE POLICY contact_select ON maevsi.contact FOR SELECT USING ( | ||||||
( | ||||||
NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID IS NOT NULL | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think removing this |
||||||
AND ( | ||||||
account_id = NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID | ||||||
OR | ||||||
account_id = NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID | ||||||
AND | ||||||
author_account_id NOT IN ( | ||||||
SELECT blocked_account_id | ||||||
FROM maevsi.account_block | ||||||
WHERE author_account_id = NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID | ||||||
) | ||||||
) | ||||||
OR | ||||||
( | ||||||
author_account_id = NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID | ||||||
) | ||||||
) | ||||||
OR | ||||||
id IN (SELECT maevsi.invitation_contact_ids()) | ||||||
AND | ||||||
account_id NOT IN ( | ||||||
SELECT blocked_account_id | ||||||
FROM maevsi.account_block | ||||||
WHERE author_account_id = NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID | ||||||
) | ||||||
) | ||||||
OR id IN (SELECT maevsi.invitation_contact_ids()) | ||||||
); | ||||||
|
||||||
-- Only allow inserts for contacts authored by the invoker's account. | ||||||
-- Only allow inserts for contacts authored by the invoker's account | ||||||
-- No blocked account can be invited | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
CREATE POLICY contact_insert ON maevsi.contact FOR INSERT WITH CHECK ( | ||||||
NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID IS NOT NULL | ||||||
AND | ||||||
author_account_id = NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID | ||||||
AND account_id NOT IN ( | ||||||
SELECT blocked_account_id | ||||||
FROM maevsi.account_block | ||||||
WHERE author_account_id = NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID | ||||||
) | ||||||
); | ||||||
|
||||||
-- Only allow updates for contacts authored by the invoker's account. | ||||||
-- No contact referring to a blocked account can be updated | ||||||
CREATE POLICY contact_update ON maevsi.contact FOR UPDATE USING ( | ||||||
NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID IS NOT NULL | ||||||
AND | ||||||
author_account_id = NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID | ||||||
AND account_id NOT IN ( | ||||||
SELECT blocked_account_id | ||||||
FROM maevsi.account_block | ||||||
WHERE author_account_id = NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID | ||||||
) | ||||||
); | ||||||
|
||||||
-- Only allow deletes for contacts authored by the invoker's account except for the own account's contact. | ||||||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -1,6 +1,7 @@ | ||||||
-- Deploy maevsi:table_event_policy to pg | ||||||
-- requires: schema_public | ||||||
-- requires: table_event | ||||||
-- requires: table_account_block | ||||||
-- requires: role_account | ||||||
-- requires: role_anonymous | ||||||
-- requires: schema_private | ||||||
|
@@ -13,26 +14,31 @@ GRANT INSERT, UPDATE, DELETE ON TABLE maevsi.event TO maevsi_account; | |||||
|
||||||
ALTER TABLE maevsi.event ENABLE ROW LEVEL SECURITY; | ||||||
|
||||||
-- Only display events that are public and not full. | ||||||
-- Only display events that are public and not full and not organized by a blocked account | ||||||
-- Only display events that are organized by oneself. | ||||||
-- Only display events to which oneself is invited. | ||||||
-- Only display events to which oneself is invited, but not by an invitation authored by a blocked account | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Let's not start changing the format of comments (same for the line above). |
||||||
CREATE POLICY event_select ON maevsi.event FOR SELECT USING ( | ||||||
-- Below copied to function `maevsi.event_invitee_count_maximum`. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this comment still true now? |
||||||
( | ||||||
visibility = 'public' | ||||||
AND | ||||||
( | ||||||
invitee_count_maximum IS NULL | ||||||
OR | ||||||
invitee_count_maximum > (maevsi.invitee_count(id)) -- Using the function here is required as there would otherwise be infinite recursion. | ||||||
) | ||||||
) | ||||||
OR ( | ||||||
NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID IS NOT NULL | ||||||
( | ||||||
visibility = 'public' | ||||||
AND | ||||||
author_account_id = NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID | ||||||
( | ||||||
invitee_count_maximum IS NULL | ||||||
OR | ||||||
invitee_count_maximum > (maevsi.invitee_count(id)) -- Using the function here is required as there would otherwise be infinite recursion. | ||||||
) | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just fyi: changing the indentation while also having changes to the code makes it hard to read the difference for reviewers as you can see in above. The code stays mostly the same here, but there are way more green and red lines than necessary for an addition. Therefore, it's better to change formatting in a separate PR. You can resolve this comment once understood. |
||||||
AND author_account_id NOT IN ( | ||||||
SELECT blocked_account_id | ||||||
FROM maevsi.account_block | ||||||
WHERE author_account_id = NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID | ||||||
) | ||||||
) | ||||||
OR id IN (SELECT maevsi_private.events_invited()) | ||||||
OR ( | ||||||
author_account_id = NULLIF(current_setting('jwt.claims.account_id', true), '')::UUID | ||||||
) | ||||||
OR ( | ||||||
id IN (SELECT maevsi_private.events_invited()) | ||||||
) | ||||||
); | ||||||
|
||||||
-- Only allow inserts for events authored by the current user. | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why
OR REPLACE
? The way migrations are applied or reverted currently does not allow for any case where this function could be replaced, I think.