From 32ff494ddd3560e41d821426e0b58cc62b3a2470 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Barrag=C3=A1n=20Merino?= Date: Fri, 13 Feb 2015 17:59:51 +0100 Subject: [PATCH] US #55: Custom fields - :three: :weary: :tiger: --- ...0003_triggers_on_delete_customattribute.py | 87 +++++++++++++++++++ .../test_custom_attributes_issues.py | 34 ++++++++ .../test_custom_attributes_tasks.py | 34 ++++++++ .../test_custom_attributes_user_stories.py | 34 ++++++++ 4 files changed, 189 insertions(+) create mode 100644 taiga/projects/custom_attributes/migrations/0003_triggers_on_delete_customattribute.py diff --git a/taiga/projects/custom_attributes/migrations/0003_triggers_on_delete_customattribute.py b/taiga/projects/custom_attributes/migrations/0003_triggers_on_delete_customattribute.py new file mode 100644 index 00000000..a733bceb --- /dev/null +++ b/taiga/projects/custom_attributes/migrations/0003_triggers_on_delete_customattribute.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('custom_attributes', '0002_issuecustomattributesvalues_taskcustomattributesvalues_userstorycustomattributesvalues'), + ] + + operations = [ + # Function: Remove a key in a json field + migrations.RunSQL( + """ + CREATE OR REPLACE FUNCTION "json_object_delete_keys"("json" json, VARIADIC "keys_to_delete" text[]) + RETURNS json + LANGUAGE sql + IMMUTABLE + STRICT + AS $function$ + SELECT COALESCE ((SELECT ('{' || string_agg(to_json("key") || ':' || "value", ',') || '}') + FROM json_each("json") + WHERE "key" <> ALL ("keys_to_delete")), + '{}')::json $function$; + """, + reverse_sql="""DROP FUNCTION IF EXISTS "json_object_delete_keys";""" + ), + + # Function: Romeve a key in the json field of *_custom_attributes_values.values + migrations.RunSQL( + """ + CREATE OR REPLACE FUNCTION "clean_key_in_custom_attributes_values"() + RETURNS trigger + AS $clean_key_in_custom_attributes_values$ + DECLARE + key text; + tablename text; + BEGIN + key := OLD.id::text; + tablename := TG_ARGV[0]::text; + + EXECUTE 'UPDATE ' || quote_ident(tablename) || ' + SET values = json_object_delete_keys(values, ' || quote_literal(key) || ')'; + + RETURN NULL; + END; $clean_key_in_custom_attributes_values$ + LANGUAGE plpgsql; + + """, + reverse_sql="""DROP FUNCTION IF EXISTS "clean_key_in_custom_attributes_values";""" + ), + + # Trigger: Clean userstorycustomattributes values before remove a userstorycustomattribute + migrations.RunSQL( + """ + CREATE TRIGGER "update_userstorycustomvalues_afeter_remove_userstorycustomattribute" + BEFORE DELETE ON custom_attributes_userstorycustomattribute + FOR EACH ROW + EXECUTE PROCEDURE clean_key_in_custom_attributes_values('custom_attributes_userstorycustomattributesvalues'); + """, + reverse_sql="""DROP TRIGGER "update_userstorycustomvalues_afeter_remove_userstorycustomattribute";""" + ), + + # Trigger: Clean taskcustomattributes values before remove a taskcustomattribute + migrations.RunSQL( + """ + CREATE TRIGGER "update_taskcustomvalues_afeter_remove_taskcustomattribute" + BEFORE DELETE ON custom_attributes_taskcustomattribute + FOR EACH ROW + EXECUTE PROCEDURE clean_key_in_custom_attributes_values('custom_attributes_taskcustomattributesvalues'); + """, + reverse_sql="""DROP TRIGGER "update_taskcustomvalues_afeter_remove_taskcustomattribute";""" + ), + + # Trigger: Clean issuecustomattributes values before remove a issuecustomattribute + migrations.RunSQL( + """ + CREATE TRIGGER "update_issuecustomvalues_afeter_remove_issuecustomattribute" + BEFORE DELETE ON custom_attributes_issuecustomattribute + FOR EACH ROW + EXECUTE PROCEDURE clean_key_in_custom_attributes_values('custom_attributes_issuecustomattributesvalues'); + """, + reverse_sql="""DROP TRIGGER "update_issuecustomvalues_afeter_remove_issuecustomattribute";""" + ) + ] diff --git a/tests/integration/test_custom_attributes_issues.py b/tests/integration/test_custom_attributes_issues.py index 50e689c1..40f22725 100644 --- a/tests/integration/test_custom_attributes_issues.py +++ b/tests/integration/test_custom_attributes_issues.py @@ -269,3 +269,37 @@ def test_issue_custom_attributes_values_delete_us(client): assert response.status_code == 204 assert not issue.__class__.objects.filter(id=issue.id).exists() assert not custom_attrs_val.__class__.objects.filter(id=custom_attrs_val.id).exists() + + +######################################################### +# Test tristres triggers :-P +######################################################### + +def test_trigger_update_issuecustomvalues_afeter_remove_issuecustomattribute(): + issue = f.IssueFactory() + member = f.MembershipFactory(user=issue.project.owner, + project=issue.project, + is_owner=True) + + custom_attr_1 = f.IssueCustomAttributeFactory(project=issue.project) + ct1_id = "{}".format(custom_attr_1.id) + custom_attr_2 = f.IssueCustomAttributeFactory(project=issue.project) + ct2_id = "{}".format(custom_attr_2.id) + + custom_attrs_val = f.IssueCustomAttributesValuesFactory( + project=issue.project, + issue=issue, + values= { + ct1_id: "test_1", + ct2_id: "test_2" + }, + ) + + assert ct1_id in custom_attrs_val.values.keys() + assert ct2_id in custom_attrs_val.values.keys() + + custom_attr_2.delete() + custom_attrs_val = custom_attrs_val.__class__.objects.get(id=custom_attrs_val.id) + + assert ct1_id in custom_attrs_val.values.keys() + assert ct2_id not in custom_attrs_val.values.keys() diff --git a/tests/integration/test_custom_attributes_tasks.py b/tests/integration/test_custom_attributes_tasks.py index f6786737..6740427d 100644 --- a/tests/integration/test_custom_attributes_tasks.py +++ b/tests/integration/test_custom_attributes_tasks.py @@ -266,3 +266,37 @@ def test_task_custom_attributes_values_delete_us(client): assert response.status_code == 204 assert not task.__class__.objects.filter(id=task.id).exists() assert not custom_attrs_val.__class__.objects.filter(id=custom_attrs_val.id).exists() + + +######################################################### +# Test tristres triggers :-P +######################################################### + +def test_trigger_update_userstorycustomvalues_afeter_remove_userstorycustomattribute(): + user_story = f.UserStoryFactory() + member = f.MembershipFactory(user=user_story.project.owner, + project=user_story.project, + is_owner=True) + + custom_attr_1 = f.UserStoryCustomAttributeFactory(project=user_story.project) + ct1_id = "{}".format(custom_attr_1.id) + custom_attr_2 = f.UserStoryCustomAttributeFactory(project=user_story.project) + ct2_id = "{}".format(custom_attr_2.id) + + custom_attrs_val = f.UserStoryCustomAttributesValuesFactory( + project=user_story.project, + user_story=user_story, + values= { + ct1_id: "test_1", + ct2_id: "test_2" + }, + ) + + assert ct1_id in custom_attrs_val.values.keys() + assert ct2_id in custom_attrs_val.values.keys() + + custom_attr_2.delete() + custom_attrs_val = custom_attrs_val.__class__.objects.get(id=custom_attrs_val.id) + + assert ct1_id in custom_attrs_val.values.keys() + assert ct2_id not in custom_attrs_val.values.keys() diff --git a/tests/integration/test_custom_attributes_user_stories.py b/tests/integration/test_custom_attributes_user_stories.py index 8db3f395..b0ad7e9b 100644 --- a/tests/integration/test_custom_attributes_user_stories.py +++ b/tests/integration/test_custom_attributes_user_stories.py @@ -266,3 +266,37 @@ def test_userstory_custom_attributes_values_delete_us(client): assert response.status_code == 204 assert not user_story.__class__.objects.filter(id=user_story.id).exists() assert not custom_attrs_val.__class__.objects.filter(id=custom_attrs_val.id).exists() + + +######################################################### +# Test tristres triggers :-P +######################################################### + +def test_trigger_update_userstorycustomvalues_afeter_remove_userstorycustomattribute(): + user_story = f.UserStoryFactory() + member = f.MembershipFactory(user=user_story.project.owner, + project=user_story.project, + is_owner=True) + + custom_attr_1 = f.UserStoryCustomAttributeFactory(project=user_story.project) + ct1_id = "{}".format(custom_attr_1.id) + custom_attr_2 = f.UserStoryCustomAttributeFactory(project=user_story.project) + ct2_id = "{}".format(custom_attr_2.id) + + custom_attrs_val = f.UserStoryCustomAttributesValuesFactory( + project=user_story.project, + user_story=user_story, + values= { + ct1_id: "test_1", + ct2_id: "test_2" + }, + ) + + assert ct1_id in custom_attrs_val.values.keys() + assert ct2_id in custom_attrs_val.values.keys() + + custom_attr_2.delete() + custom_attrs_val = custom_attrs_val.__class__.objects.get(id=custom_attrs_val.id) + + assert ct1_id in custom_attrs_val.values.keys() + assert ct2_id not in custom_attrs_val.values.keys()