def test_custom_tag_1(self): # make a new tagset TagSet.objects_by_account(self.account).get_or_create(account=self.account,name="new test tagset") populate_rule_components_for_an_account(self.account) left_side = LeftSide.objects_by_account(self.account).get(display_name="have a new test tagset tag that") self.assertEqual(left_side.query_string_partial, "taggeditem__tag__in=Tag.objects_by_account(self.account).filter(tagset__name='new test tagset',name") self.assertEqualQuerySets(left_side.operators, self._tag_operators ) self.assertEqualQuerySets(left_side.right_side_types, self._text_right_side_types) self.assertEqual(left_side.add_closing_paren, True) return left_side
def test_invalid_rule_missing_operator_side(self): right_hand_term="test" # operator_name="contains" group = Factory.group(self.account) left_side = LeftSide.objects_by_account(self.account).get(display_name="have a General tag that") # icontains = Operator.objects_by_account(self.account).get(display_name=operator_name) icontains = None rst = self._text_right_side_types[0] rsv = right_hand_term GroupRule.raw_objects.create(account=self.account, group=group, left_side=left_side, operator=icontains, right_side_value=rsv, right_side_type=rst) self.assertEqual(group.has_a_valid_rule, False)
def test_populate_cleans_up_unused_rules(self): # create a custom tag from generic_tags.models import TagSet ts1 = TagSet.objects_by_account(self.account).get_or_create(account=self.account,name="new test tagset")[0] # repopulate populate_rule_components_for_an_account(self.account) # make sure it's there left_side = LeftSide.objects_by_account(self.account).get(display_name="have a new test tagset tag that") self.assertEqual(left_side.query_string_partial, "taggeditem__tag__in=Tag.objects_by_account(self.account).filter(tagset__name='new test tagset',name") self.assertEqualQuerySets(left_side.operators, self._tag_operators ) self.assertEqualQuerySets(left_side.right_side_types, self._text_right_side_types) # delete it ts1.delete() # repopulate populate_rule_components_for_an_account(self.account) # make sure it's gone self.assertEqual(LeftSide.objects_by_account(self.account).filter(display_name="have a new test tagset tag that").count(), 0)
def grouprule(cls, account, left_side_str, operator_str, right_side_str, group=None, **kwargs): if not group: group = cls.group() left_side = LeftSide.objects_by_account(account).get(display_name__iexact=left_side_str) operator = Operator.objects_by_account(account).get(display_name__iexact=operator_str) right_side_type = left_side.first_right_side_type right_side_value = right_side_str return GroupRule.raw_objects.get_or_create(account=account, left_side=left_side, operator=operator, right_side_type=right_side_type, right_side_value=right_side_value, group=group, )[0]
def test_create_new_group_rule_for_general_tag_contains(self, right_hand_term="test", operator_name="contains"): # create a new group rule group = Factory.group(self.account) left_side = LeftSide.objects_by_account(self.account).get(display_name="have a General tag that") icontains = Operator.objects_by_account(self.account).get(display_name=operator_name) rst = self._text_right_side_types[0] rsv = right_hand_term group_rule = GroupRule.raw_objects.create(account=self.account, group=group, left_side=left_side, operator=icontains, right_side_value=rsv, right_side_type=rst) new_group_rule = GroupRule.objects_by_account(self.account).get(pk=group_rule.pk) # assert the correct models exist self.assertEqual(new_group_rule.group, group) self.assertEqual(new_group_rule.left_side, left_side) self.assertEqual(new_group_rule.operator, icontains) self.assertEqual(new_group_rule.right_side_value, rsv) self.assertEqual(new_group_rule.group, group) return group, new_group_rule
def test_left_side_ordering(self): list_of_names = [l.display_name for l in LeftSide.objects_by_account(self.account).all()] target_list_of_names = [ "have any tag that", "have a General tag that", "have a Volunteer tag that", "have a Donor tag that", "volunteer status", "last donation", # "total donations in the last 12 months", "last volunteer shift", # "total volunteer hours in the last 12 months" "last conversation", "birthday", "age", "have a donation that", ] self.assertEqual(list_of_names,target_list_of_names)
def test_create_new_group_rule_for_volunteer_status_is_inactive(self, right_hand_term="inactive", operator_name="is"): # create a new group group = Factory.group(self.account) # create a new group rule left_side = LeftSide.objects_by_account(self.account).get(display_name="volunteer status") icontains = Operator.objects_by_account(self.account).get(display_name=operator_name) rst = self._choices_right_side_types[0] rsv = right_hand_term group_rule = GroupRule.raw_objects.create(account=self.account, group=group, left_side=left_side, operator=icontains, right_side_value=rsv, right_side_type=rst) new_group_rule = GroupRule.objects_by_account(self.account).get(pk=group_rule.pk) # assert the correct models exist self.assertEqual(new_group_rule.group, group) self.assertEqual(new_group_rule.left_side, left_side) self.assertEqual(new_group_rule.operator, icontains) self.assertEqual(new_group_rule.right_side_value, rsv) self.assertEqual(new_group_rule.group, group) return group, new_group_rule
def test_create_new_group_rule_for_last_donation_is_after(self, right_hand_term="2/12/2009", operator_name="is after"): # create a new group group = Factory.group(self.account) # create a new group rule left_side = LeftSide.objects_by_account(self.account).get(display_name="last donation") op = Operator.objects_by_account(self.account).get(display_name=operator_name) rst = self._date_right_side_types[0] rsv = right_hand_term group_rule = GroupRule.raw_objects.create(account=self.account, group=group, left_side=left_side, operator=op, right_side_value=rsv, right_side_type=rst) new_group_rule = GroupRule.objects_by_account(self.account).get(pk=group_rule.pk) # assert the correct models exist self.assertEqual(new_group_rule.group, group) self.assertEqual(new_group_rule.left_side, left_side) self.assertEqual(new_group_rule.operator, op) self.assertEqual(new_group_rule.right_side_value, rsv) self.assertEqual(new_group_rule.group, group) return group, new_group_rule
def test_create_new_group_rule_for_custom_tag_is_exactly(self, right_hand_term="test", operator_name="is exactly"): # create a new group group = Factory.group(self.account) # make the custom tag TagSet.raw_objects.get_or_create(account=self.account, name="new test tagset") populate_rule_components_for_an_account(self.account) # create a new group rule left_side = LeftSide.objects_by_account(self.account).get(display_name="have a new test tagset tag that") icontains = Operator.objects_by_account(self.account).get(display_name=operator_name) rst = self._text_right_side_types[0] rsv = right_hand_term group_rule = GroupRule.raw_objects.create(account=self.account, group=group, left_side=left_side, operator=icontains, right_side_value=rsv, right_side_type=rst) new_group_rule = GroupRule.objects_by_account(self.account).get(pk=group_rule.pk) # assert the correct models exist self.assertEqual(new_group_rule.group, group) self.assertEqual(new_group_rule.left_side, left_side) self.assertEqual(new_group_rule.operator, icontains) self.assertEqual(new_group_rule.right_side_value, rsv) self.assertEqual(new_group_rule.group, group) return group, new_group_rule
def delete_rule_components_for_a_tagset(sender, instance, created=None, *args, **kwargs): from rules.models import LeftSide LeftSide.objects_by_account(instance.account).using('default').filter(display_name="have a %s tag that" % (instance.name)).delete() johnny_cache.invalidate(LeftSide)
def test_last_donation(self): left_side = LeftSide.objects_by_account(self.account).get(display_name="last donation") self.assertEqual(left_side.query_string_partial, "donor__donation__date") self.assertEqualQuerySets(left_side.operators, self._date_operators ) self.assertEqualQuerySets(left_side.right_side_types, self._date_right_side_types) self.assertEqual(left_side.add_closing_paren, False)
def test_volunteer_status(self): left_side = LeftSide.objects_by_account(self.account).get(display_name="volunteer status") self.assertEqual(left_side.query_string_partial, "volunteer__status") self.assertEqualQuerySets(left_side.operators, self._choices_operators ) self.assertEqualQuerySets(left_side.right_side_types, self._choices_right_side_types) self.assertEqual(left_side.add_closing_paren, False)
def test_volunteer_tags(self): left_side = LeftSide.objects_by_account(self.account).get(display_name="have a Volunteer tag that") self.assertEqual(left_side.query_string_partial, "taggeditem__tag__in=Tag.objects_by_account(self.account).filter(tagset__name='Volunteer',name") self.assertEqualQuerySets(left_side.operators, self._tag_operators ) self.assertEqualQuerySets(left_side.right_side_types, self._text_right_side_types) self.assertEqual(left_side.add_closing_paren, True)
def test_last_volunteer_shift(self): left_side = LeftSide.objects_by_account(self.account).get(display_name="last volunteer shift") self.assertEqual(left_side.query_string_partial, "volunteer__completedshift__date") self.assertEqualQuerySets(left_side.operators, self._date_operators ) self.assertEqualQuerySets(left_side.right_side_types, self._date_right_side_types) self.assertEqual(left_side.add_closing_paren, False)
def setUp(self): self.account = Factory.account() populate_rule_components_for_an_account(self.account) self.request = Dummy() self.request.account = self.account self.left_side = LeftSide.objects_by_account(self.account).get(display_name="have a General tag that")
def populate_rule_components_for_an_account(account): try: from accounts.models import Account from rules.models import LeftSide, Operator, RightSideType from volunteers import VOLUNTEER_STATII from donors import DONATION_TYPES account = Account.objects.using("default").get(pk=account.pk) """This function performs several actions, and is idempotent. In order, it: - Sets up built-in rule options (like volunteer status) - Sets up data-driven rule options (like custom tag sets) - Cleans up unused rule options """ # print "populating for %s" % account request = Dummy() request.account = account # RightSideTypes all_right_side_types = [] right_type_text = RightSideType.raw_objects.using('default').get_or_create(account=account, name="text")[0] right_type_date = RightSideType.raw_objects.using('default').get_or_create(account=account, name="date")[0] right_type_number = RightSideType.raw_objects.using('default').get_or_create(account=account, name="number")[0] right_type_choices = RightSideType.raw_objects.using('default').get_or_create(account=account,name="choices")[0] all_right_side_types = [right_type_text, right_type_date, right_type_number, right_type_choices] # Operators all_operators = [] operator_contains = Operator.raw_objects.using('default').get_or_create(account=account, display_name="contains" , query_string_partial="__icontains=" , use_filter=True)[0] operator_contains.order = 10 operator_contains.save() operator_does_not_contain = Operator.raw_objects.using('default').get_or_create(account=account, display_name="does not contain" , query_string_partial="__icontains=" , use_filter=False)[0] operator_does_not_contain.order = 20 operator_does_not_contain.save() operator_is = Operator.raw_objects.using('default').get_or_create(account=account, display_name="is" , query_string_partial="=" , use_filter=True)[0] operator_is.order = 30 operator_is.save() operator_is_not = Operator.raw_objects.using('default').get_or_create(account=account, display_name="is not" , query_string_partial="=" , use_filter=False)[0] operator_is_not.order = 40 operator_is_not.save() operator_is_exactly = Operator.raw_objects.using('default').get_or_create(account=account, display_name="is exactly" , query_string_partial="__iexact=" , use_filter=True)[0] operator_is_exactly.order = 50 operator_is_exactly.save() operator_is_not_exactly = Operator.raw_objects.using('default').get_or_create(account=account, display_name="is not exactly" , query_string_partial="__iexact=" , use_filter=False)[0] operator_is_not_exactly.order = 60 operator_is_not_exactly.save() operator_is_on = Operator.raw_objects.using('default').get_or_create(account=account, display_name="is on" , query_string_partial="=" , use_filter=True)[0] operator_is_on.order = 70 operator_is_on.save() operator_is_before = Operator.raw_objects.using('default').get_or_create(account=account, display_name="is before" , query_string_partial="__lt=" , use_filter=True)[0] operator_is_before.order = 80 operator_is_before.save() operator_is_after = Operator.raw_objects.using('default').get_or_create(account=account, display_name="is after" , query_string_partial="__gt=" , use_filter=True)[0] operator_is_after.order = 90 operator_is_after.save() operator_is_equal = Operator.raw_objects.using('default').get_or_create(account=account, display_name="is equal to" , query_string_partial="=" , use_filter=True)[0] operator_is_equal.order = 100 operator_is_equal.save() operator_is_less_than = Operator.raw_objects.using('default').get_or_create(account=account, display_name="is less than" , query_string_partial="__lt=" , use_filter=True)[0] operator_is_less_than.order = 110 operator_is_less_than.save() operator_is_more_than = Operator.raw_objects.using('default').get_or_create(account=account, display_name="is more than" , query_string_partial="__gt=" , use_filter=True)[0] operator_is_more_than.order = 120 operator_is_more_than.save() all_operators = [ operator_is_exactly, operator_is_not_exactly, operator_contains, operator_does_not_contain, operator_is, operator_is_not, operator_is_on, operator_is_before, operator_is_after, operator_is_equal, operator_is_less_than, operator_is_more_than, ] # Helper methods all_left_sides = [] def _add_text_operators(ls): ls.allowed_operators.clear() ls.allowed_operators.add(operator_is_exactly) ls.allowed_operators.add(operator_is_not_exactly) ls.allowed_operators.add(operator_contains) ls.allowed_operators.add(operator_does_not_contain) ls.save() def _add_right_type_text(ls): ls.allowed_right_side_types.clear() ls.allowed_right_side_types.add(right_type_text) ls.save() def _add_operators_and_right_side_text(ls): _add_text_operators(ls) _add_right_type_text(ls) def _add_date_operators(ls): ls.allowed_operators.clear() ls.allowed_operators.add(operator_is_on) ls.allowed_operators.add(operator_is_before) ls.allowed_operators.add(operator_is_after) ls.save() def _add_right_type_date(ls): ls.allowed_right_side_types.clear() ls.allowed_right_side_types.add(right_type_date) ls.save() def _add_operators_and_right_side_date(ls): _add_date_operators(ls) _add_right_type_date(ls) def _add_number_operators(ls): ls.allowed_operators.clear() ls.allowed_operators.add(operator_is_equal) ls.allowed_operators.add(operator_is_less_than) ls.allowed_operators.add(operator_is_more_than) ls.save() def _add_right_type_number(ls): ls.allowed_right_side_types.clear() ls.allowed_right_side_types.add(right_type_number) ls.save() def _add_operators_and_right_side_number(ls): _add_number_operators(ls) _add_right_type_number(ls) def _add_tag_operators(ls): ls.allowed_operators.clear() ls.allowed_operators.add(operator_is_exactly) ls.allowed_operators.add(operator_contains) ls.save() def _add_operators_and_right_side_tag(ls): _add_tag_operators(ls) _add_right_type_text(ls) def _add_choices_operators(ls): ls.allowed_operators.clear() ls.allowed_operators.add(operator_is) ls.allowed_operators.add(operator_is_not) ls.save() def _add_right_type_choices(ls): ls.allowed_right_side_types.clear() ls.allowed_right_side_types.add(right_type_choices) ls.save() def _add_operators_and_right_side_choices(ls): _add_choices_operators(ls) _add_right_type_choices(ls) def _add_to_all_left_sides(ls): all_left_sides.append(ls) def left_side_for_text(**kwargs): if not "display_name" in kwargs or not "query_string_partial" in kwargs: raise Exception, "display_name and query_string_partial not passed!" ls = LeftSide.raw_objects.using('default').get_or_create(**kwargs)[0] _add_operators_and_right_side_text(ls) _add_to_all_left_sides(ls) return ls def left_side_for_date(**kwargs): if not "display_name" in kwargs or not "query_string_partial" in kwargs: raise Exception, "display_name and query_string_partial not passed!" ls = LeftSide.raw_objects.using('default').get_or_create(**kwargs)[0] _add_operators_and_right_side_date(ls) _add_to_all_left_sides(ls) return ls def left_side_for_number(**kwargs): if not "display_name" in kwargs or not "query_string_partial" in kwargs: raise Exception, "display_name and query_string_partial not passed!" ls = LeftSide.raw_objects.using('default').get_or_create(**kwargs)[0] _add_operators_and_right_side_number(ls) _add_to_all_left_sides(ls) return ls def left_side_for_tag(**kwargs): if not "display_name" in kwargs or not "query_string_partial" in kwargs: raise Exception, "display_name and query_string_partial not passed!" ls = LeftSide.raw_objects.using('default').get_or_create(**kwargs)[0] _add_operators_and_right_side_tag(ls) _add_to_all_left_sides(ls) return ls def left_side_for_choices(**kwargs): if not "display_name" in kwargs or not "query_string_partial" in kwargs: raise Exception, "display_name and query_string_partial not passed!" choices = kwargs["choices"] del kwargs["choices"] ls = LeftSide.raw_objects.using('default').get_or_create(**kwargs)[0] if not ls.choices == choices: ls.choices = choices ls.save() _add_operators_and_right_side_choices(ls) _add_to_all_left_sides(ls) return ls # Left sides - built-ins ls = left_side_for_tag (account=account, display_name="have any tag that" ,query_string_partial="taggeditem__tag__name" ) ls.order=10 ls.save() ls = left_side_for_choices(account=account, display_name="volunteer status" ,query_string_partial="volunteer__status" , choices=VOLUNTEER_STATII) ls.order=100 ls.save() ls = left_side_for_date(account=account, display_name="last donation" ,query_string_partial="donor__donation__date" ) ls.order=110 ls.save() # left_side_for_number(account=account, display_name="total donations in the last 12 months" ,query_string_partial="donor__twelvemonth_total" ) # ls.order=120 # ls.save() ls = left_side_for_date(account=account, display_name="last volunteer shift" ,query_string_partial="volunteer__completedshift__date" ) ls.order=130 ls.save() # left_side_for_number(account=account, display_name="total volunteer hours in the last 12 months" ,query_string_partial="volunteer__twelvemonth_total" ) # ls.order=140 # ls.save() ls = left_side_for_date (account=account, display_name="last conversation" ,query_string_partial="conversation__date" ) ls.order=150 ls.save() ls = left_side_for_date (account=account, display_name="birthday" ,query_string_partial="actual_birthday" ) ls.order=170 ls.save() ls = left_side_for_number (account=account, display_name="age" ,query_string_partial="age" ) ls.order=190 ls.save() ls = left_side_for_choices (account=account, display_name="have a donation that" ,query_string_partial="donor__donation__type", choices=DONATION_TYPES ) ls.order=210 ls.save() # Left sides - generateds from generic_tags.models import TagSet i = 0 for ts in TagSet.objects_by_account(account).using('default').all(): i = i+1 ls = left_side_for_tag(account=account, display_name="have a %s tag that" % (ts.name), query_string_partial="taggeditem__tag__in=Tag.objects_by_account(self.account).filter(tagset__name='%s',name" % (ts.name), add_closing_paren=True ) ls.order=20+i ls.save() # Cleanup for rs in RightSideType.objects_by_account(account).using('default').all(): if rs not in all_right_side_types: rs.delete() for o in Operator.objects_by_account(account).using('default').all(): if o not in all_operators: o.delete() for ls in LeftSide.objects_by_account(account).using('default').all(): if ls not in all_left_sides: ls.delete() johnny_cache.invalidate(RightSideType) johnny_cache.invalidate(Operator) johnny_cache.invalidate(LeftSide) except: from django.core.mail import mail_admins from qi_toolkit.helpers import exception_string mail_admins("Exception generating group rules", exception_string(), fail_silently=True)
def test_any_tags(self): left_side = LeftSide.objects_by_account(self.account).get(display_name="have any tag that") self.assertEqual(left_side.query_string_partial, "taggeditem__tag__name") self.assertEqualQuerySets(left_side.operators, self._tag_operators ) self.assertEqualQuerySets(left_side.right_side_types, self._text_right_side_types ) self.assertEqual(left_side.add_closing_paren, False)
def rules_logic_js(request): left_sides = LeftSide.objects_by_account(request.account).all() operators = Operator.objects_by_account(request.account).all() right_side_types = RightSideType.objects_by_account(request.account).all() return locals()