commit
						27d0e1c6be
					
				
					 5 changed files with 188 additions and 13 deletions
				
			
		|  | @ -97,6 +97,19 @@ class SpeakerDiscountAdmin(admin.ModelAdmin, EffectsDisplayMixin): | |||
|     ] | ||||
| 
 | ||||
| 
 | ||||
| @admin.register(conditions.GroupMemberDiscount) | ||||
| class GroupMemberDiscountAdmin(admin.ModelAdmin, EffectsDisplayMixin): | ||||
| 
 | ||||
|     fields = ("description", "group") | ||||
| 
 | ||||
|     list_display = ("description", "effects") | ||||
| 
 | ||||
|     inlines = [ | ||||
|         DiscountForProductInline, | ||||
|         DiscountForCategoryInline, | ||||
|     ] | ||||
| 
 | ||||
| 
 | ||||
| # Vouchers | ||||
| 
 | ||||
| class VoucherDiscountInline(nested_admin.NestedStackedInline): | ||||
|  | @ -194,3 +207,11 @@ class SpeakerFlagAdmin(nested_admin.NestedAdmin, EffectsDisplayMixin): | |||
|     list_display = ("description", "is_presenter", "is_copresenter", "effects") | ||||
| 
 | ||||
|     ordering = ("-is_presenter", "-is_copresenter") | ||||
| 
 | ||||
| 
 | ||||
| @admin.register(conditions.GroupMemberFlag) | ||||
| class GroupMemberFlagAdmin(admin.ModelAdmin, EffectsDisplayMixin): | ||||
| 
 | ||||
|     fields = ("description", "group") | ||||
| 
 | ||||
|     list_display = ("description", "effects") | ||||
|  |  | |||
|  | @ -23,6 +23,8 @@ class ConditionController(object): | |||
|     def _controllers(): | ||||
|         return { | ||||
|             conditions.CategoryFlag: CategoryConditionController, | ||||
|             conditions.GroupMemberDiscount: GroupMemberConditionController, | ||||
|             conditions.GroupMemberFlag: GroupMemberConditionController, | ||||
|             conditions.IncludedProductDiscount: ProductConditionController, | ||||
|             conditions.ProductFlag: ProductConditionController, | ||||
|             conditions.SpeakerFlag: SpeakerConditionController, | ||||
|  | @ -319,7 +321,19 @@ class SpeakerConditionController(IsMetByFilter, ConditionController): | |||
|         # User is a copresenter | ||||
|         user_is_copresenter = Q( | ||||
|             is_copresenter=True, | ||||
|             proposal_kind__proposalbase__presentation__additional_speakers__user=u, | ||||
|             proposal_kind__proposalbase__presentation__additional_speakers__user=u,  # NOQA | ||||
|         ) | ||||
| 
 | ||||
|         return queryset.filter(user_is_presenter | user_is_copresenter) | ||||
| 
 | ||||
| 
 | ||||
| class GroupMemberConditionController(IsMetByFilter, ConditionController): | ||||
| 
 | ||||
|     @classmethod | ||||
|     def pre_filter(self, conditions, user): | ||||
|         ''' Returns all of the items from conditions which are enabled by a | ||||
|         user being member of a Django Auth Group. ''' | ||||
| 
 | ||||
|         return conditions.filter( | ||||
|             group=user.groups.all(), | ||||
|         ) | ||||
|  |  | |||
|  | @ -0,0 +1,41 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| # Generated by Django 1.9.2 on 2016-09-04 23:59 | ||||
| from __future__ import unicode_literals | ||||
| 
 | ||||
| from django.db import migrations, models | ||||
| import django.db.models.deletion | ||||
| 
 | ||||
| 
 | ||||
| class Migration(migrations.Migration): | ||||
| 
 | ||||
|     dependencies = [ | ||||
|         ('auth', '0007_alter_validators_add_error_messages'), | ||||
|         ('registrasion', '0003_auto_20160904_0235'), | ||||
|     ] | ||||
| 
 | ||||
|     operations = [ | ||||
|         migrations.CreateModel( | ||||
|             name='GroupMemberDiscount', | ||||
|             fields=[ | ||||
|                 ('discountbase_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='registrasion.DiscountBase')), | ||||
|                 ('group', models.ManyToManyField(help_text='The groups a user needs to be a member of for thiscondition to be met.', to='auth.Group')), | ||||
|             ], | ||||
|             options={ | ||||
|                 'verbose_name': 'discount (group member)', | ||||
|                 'verbose_name_plural': 'discounts (group member)', | ||||
|             }, | ||||
|             bases=('registrasion.discountbase', models.Model), | ||||
|         ), | ||||
|         migrations.CreateModel( | ||||
|             name='GroupMemberFlag', | ||||
|             fields=[ | ||||
|                 ('flagbase_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='registrasion.FlagBase')), | ||||
|                 ('group', models.ManyToManyField(help_text='The groups a user needs to be a member of for thiscondition to be met.', to='auth.Group')), | ||||
|             ], | ||||
|             options={ | ||||
|                 'verbose_name': 'flag (group member)', | ||||
|                 'verbose_name_plural': 'flags (group member)', | ||||
|             }, | ||||
|             bases=('registrasion.flagbase', models.Model), | ||||
|         ), | ||||
|     ] | ||||
|  | @ -2,6 +2,7 @@ import itertools | |||
| 
 | ||||
| from . import inventory | ||||
| 
 | ||||
| from django.contrib.auth.models import Group | ||||
| from django.core.exceptions import ValidationError | ||||
| from django.db import models | ||||
| from django.utils.encoding import python_2_unicode_compatible | ||||
|  | @ -81,7 +82,7 @@ class IncludedProductCondition(models.Model): | |||
| 
 | ||||
| class SpeakerCondition(models.Model): | ||||
|     ''' Conditions that are met if a user is a presenter, or copresenter, | ||||
|     of a specific of presentation. ''' | ||||
|     of a specific kind of presentation. ''' | ||||
| 
 | ||||
|     class Meta: | ||||
|         abstract = True | ||||
|  | @ -103,6 +104,20 @@ class SpeakerCondition(models.Model): | |||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| class GroupMemberCondition(models.Model): | ||||
|     ''' Conditions that are met if a user is a member (not declined or | ||||
|     rejected) of a specific django auth group. ''' | ||||
| 
 | ||||
|     class Meta: | ||||
|         abstract = True | ||||
| 
 | ||||
|     group = models.ManyToManyField( | ||||
|         Group, | ||||
|         help_text=_("The groups a user needs to be a member of for this" | ||||
|                     "condition to be met."), | ||||
|     ) | ||||
| 
 | ||||
| 
 | ||||
| # Discounts | ||||
| 
 | ||||
| @python_2_unicode_compatible | ||||
|  | @ -325,12 +340,23 @@ class SpeakerDiscount(SpeakerCondition, DiscountBase): | |||
|         verbose_name_plural = _("discounts (speaker)") | ||||
| 
 | ||||
| 
 | ||||
| class RoleDiscount(object): | ||||
|     ''' Discounts that are enabled because the active user has a specific | ||||
|     role. This is for e.g. volunteers who can get a discount ticket. ''' | ||||
|     # TODO: implement RoleDiscount | ||||
|     pass | ||||
| class GroupMemberDiscount(GroupMemberCondition, DiscountBase): | ||||
|     ''' Discounts that are enabled because the user is a member of a specific | ||||
|     django auth Group. | ||||
| 
 | ||||
|     Attributes: | ||||
|         group ([Group, ...]): The condition should be met if the user is a | ||||
|             member of one of these groups. | ||||
| 
 | ||||
|     ''' | ||||
| 
 | ||||
|     class Meta: | ||||
|         app_label = "registrasion" | ||||
|         verbose_name = _("discount (group member)") | ||||
|         verbose_name_plural = _("discounts (group member)") | ||||
| 
 | ||||
| 
 | ||||
| # Flags | ||||
| 
 | ||||
| @python_2_unicode_compatible | ||||
| class FlagBase(models.Model): | ||||
|  | @ -517,9 +543,17 @@ class SpeakerFlag(SpeakerCondition, FlagBase): | |||
|         verbose_name_plural = _("flags (speaker)") | ||||
| 
 | ||||
| 
 | ||||
| # @python_2_unicode_compatible | ||||
| class RoleFlag(object): | ||||
|     ''' The condition is met because the active user has a particular Role. | ||||
|     This is for e.g. enabling Team tickets. ''' | ||||
|     # TODO: implement RoleFlag | ||||
|     pass | ||||
| class GroupMemberFlag(GroupMemberCondition, FlagBase): | ||||
|     ''' Flag whose conditions are metbecause the user is a member of a specific | ||||
|     django auth Group. | ||||
| 
 | ||||
|     Attributes: | ||||
|         group ([Group, ...]): The condition should be met if the user is a | ||||
|             member of one of these groups. | ||||
| 
 | ||||
|     ''' | ||||
| 
 | ||||
|     class Meta: | ||||
|         app_label = "registrasion" | ||||
|         verbose_name = _("flag (group member)") | ||||
|         verbose_name_plural = _("flags (group member)") | ||||
|  |  | |||
							
								
								
									
										65
									
								
								registrasion/tests/test_group_member.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								registrasion/tests/test_group_member.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,65 @@ | |||
| import pytz | ||||
| 
 | ||||
| from django.contrib.auth.models import Group | ||||
| from django.core.exceptions import ValidationError | ||||
| 
 | ||||
| from registrasion.models import commerce | ||||
| from registrasion.models import conditions | ||||
| from registrasion.controllers.category import CategoryController | ||||
| from controller_helpers import TestingCartController | ||||
| from controller_helpers import TestingInvoiceController | ||||
| from registrasion.controllers.product import ProductController | ||||
| 
 | ||||
| from test_cart import RegistrationCartTestCase | ||||
| 
 | ||||
| UTC = pytz.timezone('UTC') | ||||
| 
 | ||||
| 
 | ||||
| class GroupMemberTestCase(RegistrationCartTestCase): | ||||
| 
 | ||||
|     @classmethod | ||||
|     def _create_group_and_flag(cls): | ||||
|         ''' Creates cls.GROUP, and restricts cls.PROD_1 only to users who are | ||||
|         members of the group. ''' | ||||
| 
 | ||||
|         group = Group.objects.create( | ||||
|             name="TEST GROUP", | ||||
|         ) | ||||
| 
 | ||||
|         flag = conditions.GroupMemberFlag.objects.create( | ||||
|             description="Group member flag", | ||||
|             condition=conditions.FlagBase.ENABLE_IF_TRUE, | ||||
|         ) | ||||
|         flag.group.add(group) | ||||
|         flag.products.add(cls.PROD_1) | ||||
| 
 | ||||
|         cls.GROUP = group | ||||
| 
 | ||||
|     def test_product_not_enabled_until_user_joins_group(self): | ||||
|         ''' Tests that GroupMemberFlag disables a product for a user until | ||||
|         they are a member of a specific group. ''' | ||||
| 
 | ||||
|         self._create_group_and_flag() | ||||
| 
 | ||||
|         # USER_1 cannot see PROD_1 until they're in GROUP. | ||||
|         available = ProductController.available_products( | ||||
|             self.USER_1, | ||||
|             products=[self.PROD_1], | ||||
|         ) | ||||
|         self.assertNotIn(self.PROD_1, available) | ||||
| 
 | ||||
|         self.USER_1.groups.add(self.GROUP) | ||||
| 
 | ||||
|         # USER_1 cannot see PROD_1 until they're in GROUP. | ||||
|         available = ProductController.available_products( | ||||
|             self.USER_1, | ||||
|             products=[self.PROD_1], | ||||
|         ) | ||||
|         self.assertIn(self.PROD_1, available) | ||||
| 
 | ||||
|         # USER_2 is still locked out | ||||
|         available = ProductController.available_products( | ||||
|             self.USER_2, | ||||
|             products=[self.PROD_1], | ||||
|         ) | ||||
|         self.assertNotIn(self.PROD_1, available) | ||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Christopher Neugebauer
						Christopher Neugebauer