Repository: webkom/lego

Issue:
Admin registration to waiting list
I think we should support admin register to waiting list


Discussion:

Resolving patch:
diff --git a/lego/apps/events/models.py b/lego/apps/events/models.py
--- a/lego/apps/events/models.py
+++ b/lego/apps/events/models.py
@@ -74,7 +74,7 @@ def save(self, *args, **kwargs):
                 pool.save(update_fields=['counter'])
             return super().save(*args, **kwargs)
 
-    def admin_register(self, user, pool, admin_reason, feedback=''):
+    def admin_register(self, user, admin_reason, pool=None, feedback=''):
         """
         Used to force registration for a user, even if the event is full
         or if the user isn't allowed to register.
@@ -84,25 +84,25 @@ def admin_register(self, user, pool, admin_reason, feedback=''):
         :param feedback: Feedback to organizers
         :return: The registration
         """
-        if self.pools.filter(id=pool.id).exists():
-            with transaction.atomic():
-                reg = self.registrations.update_or_create(
-                    event=self,
-                    user=user,
-                    defaults={'pool': pool,
-                              'feedback': feedback,
-                              'registration_date': timezone.now(),
-                              'unregistration_date': None,
-                              'status': constants.SUCCESS_REGISTER,
-                              'admin_reason': admin_reason}
-                )[0]
+        if pool and not self.pools.filter(id=pool.id).exists():
+            raise NoSuchPool()
+        with transaction.atomic():
+            reg = self.registrations.update_or_create(
+                event=self,
+                user=user,
+                defaults={'pool': pool,
+                          'feedback': feedback,
+                          'registration_date': timezone.now(),
+                          'unregistration_date': None,
+                          'status': constants.SUCCESS_REGISTER,
+                          'admin_reason': admin_reason}
+            )[0]
+            if pool:
                 locked_pool = Pool.objects.select_for_update().get(pk=pool.id)
                 locked_pool.increment()
 
-                get_handler(Registration).handle_admin_registration(reg)
-                return reg
-        else:
-            raise NoSuchPool()
+            get_handler(Registration).handle_admin_registration(reg)
+            return reg
 
     def get_absolute_url(self):
         return f'{settings.FRONTEND_URL}/events/{self.id}/'
diff --git a/lego/apps/events/serializers/registrations.py b/lego/apps/events/serializers/registrations.py
--- a/lego/apps/events/serializers/registrations.py
+++ b/lego/apps/events/serializers/registrations.py
@@ -13,7 +13,7 @@
 
 class AdminRegistrationCreateAndUpdateSerializer(serializers.Serializer):
     user = PrimaryKeyRelatedFieldNoPKOpt(queryset=User.objects.all())
-    pool = PrimaryKeyRelatedFieldNoPKOpt(queryset=Pool.objects.all())
+    pool = PrimaryKeyRelatedFieldNoPKOpt(queryset=Pool.objects.all(), required=False)
     feedback = serializers.CharField(required=False)
     admin_reason = serializers.CharField(required=True)
 


Test patch:
diff --git a/lego/apps/events/tests/test_admin_registrations.py b/lego/apps/events/tests/test_admin_registrations.py
--- a/lego/apps/events/tests/test_admin_registrations.py
+++ b/lego/apps/events/tests/test_admin_registrations.py
@@ -28,7 +28,7 @@ def test_admin_registration(self):
         no_of_regs_before = event.number_of_registrations
         pool_no_of_regs_before = pool.registrations.count()
 
-        event.admin_register(user, pool, admin_reason='test')
+        event.admin_register(user, admin_reason='test', pool=pool)
         self.assertEqual(event.number_of_registrations, no_of_regs_before + 1)
         self.assertEqual(pool.registrations.count(), pool_no_of_regs_before + 1)
 
@@ -44,7 +44,7 @@ def test_ar_with_wrong_pool(self):
         pool_no_of_regs_before = wrong_pool.registrations.count()
 
         with self.assertRaises(ValueError):
-            event_one.admin_register(user, wrong_pool, admin_reason='test')
+            event_one.admin_register(user, admin_reason='test', pool=wrong_pool)
         self.assertEqual(event_one.number_of_registrations, e1_no_of_regs_before)
         self.assertEqual(event_two.number_of_registrations, e2_no_of_regs_before)
         self.assertEqual(wrong_pool.registrations.count(), pool_no_of_regs_before)
@@ -59,7 +59,7 @@ def test_ar_without_permissions_for_user(self):
         e1_no_of_regs_before = event.number_of_registrations
         pool_no_of_regs_before = pool.registrations.count()
 
-        event.admin_register(user, pool, admin_reason='test')
+        event.admin_register(user, admin_reason='test', pool=pool)
         self.assertEqual(event.number_of_registrations, e1_no_of_regs_before+1)
         self.assertEqual(pool.registrations.count(), pool_no_of_regs_before+1)
 
@@ -73,7 +73,7 @@ def test_ar_after_merge(self):
         e1_no_of_regs_before = event.number_of_registrations
         pool_no_of_regs_before = pool.registrations.count()
 
-        event.admin_register(user, pool, admin_reason='test')
+        event.admin_register(user, admin_reason='test', pool=pool)
         self.assertEqual(event.number_of_registrations, e1_no_of_regs_before+1)
         self.assertEqual(pool.registrations.count(), pool_no_of_regs_before+1)
 
@@ -91,7 +91,7 @@ def test_ar_to_full_pool(self):
         e1_no_of_regs_before = event.number_of_registrations
         pool_no_of_regs_before = pool.registrations.count()
 
-        event.admin_register(user, pool, admin_reason='test')
+        event.admin_register(user, admin_reason='test', pool=pool)
         self.assertEqual(event.number_of_registrations, e1_no_of_regs_before+1)
         self.assertEqual(pool.registrations.count(), pool_no_of_regs_before+1)
 
@@ -109,7 +109,7 @@ def test_ar_to_full_event(self):
         e1_no_of_regs_before = event.number_of_registrations
         pool_no_of_regs_before = pool.registrations.count()
 
-        event.admin_register(user, pool, admin_reason='test')
+        event.admin_register(user, admin_reason='test', pool=pool)
         self.assertEqual(event.number_of_registrations, e1_no_of_regs_before+1)
         self.assertEqual(pool.registrations.count(), pool_no_of_regs_before+1)
 
@@ -122,6 +122,17 @@ def test_ar_twice(self):
 
         e1_no_of_regs_before = event.number_of_registrations
 
-        event.admin_register(user, pool, admin_reason='test')
-        event.admin_register(user, pool, admin_reason='test')
+        event.admin_register(user, admin_reason='test', pool=pool)
+        event.admin_register(user, admin_reason='test', pool=pool)
         self.assertEqual(event.number_of_registrations, e1_no_of_regs_before+1)
+
+    def test_ar_without_pool(self):
+        """Test that admin registration without pool puts the registration in the waiting list"""
+        event = Event.objects.get(title='POOLS_NO_REGISTRATIONS')
+        user = get_dummy_users(1)[0]
+        AbakusGroup.objects.get(name='Abakus').add_user(user)
+
+        waiting_regs_before = event.waiting_registrations.count()
+
+        event.admin_register(user, admin_reason='test')
+        self.assertEqual(event.waiting_registrations.count(), waiting_regs_before+1)
diff --git a/lego/apps/events/tests/test_events_api.py b/lego/apps/events/tests/test_events_api.py
--- a/lego/apps/events/tests/test_events_api.py
+++ b/lego/apps/events/tests/test_events_api.py
@@ -654,6 +654,19 @@ def test_without_admin_reason(self):
 
         self.assertEqual(registration_response.status_code, 400)
 
+    def test_ar_to_waiting_list(self):
+        AbakusGroup.objects.get(name='Webkom').add_user(self.request_user)
+        self.client.force_authenticate(self.request_user)
+        self.assertEqual(self.event.waiting_registrations.count(), 0)
+
+        registration_response = self.client.post(
+            f'{_get_registrations_list_url(self.event.id)}admin_register/',
+            {'user': self.user.id, 'admin_reason': 'test'}
+        )
+
+        self.assertEqual(registration_response.status_code, 201)
+        self.assertEqual(self.event.waiting_registrations.count(), 1)
+
 
 @skipIf(not stripe.api_key, 'No API Key set. Set STRIPE_TEST_KEY in ENV to run test.')
 class StripePaymentTestCase(APITestCase):
diff --git a/lego/apps/events/tests/test_registrations.py b/lego/apps/events/tests/test_registrations.py
--- a/lego/apps/events/tests/test_registrations.py
+++ b/lego/apps/events/tests/test_registrations.py
@@ -473,10 +473,10 @@ def test_unregistering_and_bumping_post_merge(self):
 
         for user in abakus_users:
             AbakusGroup.objects.get(name='Abakus').add_user(user)
-            event.admin_register(user, pool_one, admin_reason='test')
+            event.admin_register(user, pool=pool_one, admin_reason='test')
         for user in webkom_users:
             AbakusGroup.objects.get(name='Webkom').add_user(user)
-            event.admin_register(user, pool_two, admin_reason='test')
+            event.admin_register(user, pool=pool_two, admin_reason='test')
 
         AbakusGroup.objects.get(name='Abakus').add_user(users[5])
         registration = Registration.objects.get_or_create(event=event, user=users[5])[0]