diff options
4 files changed, 74 insertions, 2 deletions
| diff --git a/pydis_site/apps/api/migrations/0051_offtopicchannelname_used.py b/pydis_site/apps/api/migrations/0051_offtopicchannelname_used.py new file mode 100644 index 00000000..1b838aec --- /dev/null +++ b/pydis_site/apps/api/migrations/0051_offtopicchannelname_used.py @@ -0,0 +1,18 @@ +# Generated by Django 2.2.11 on 2020-03-30 10:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + +    dependencies = [ +        ('api', '0050_remove_infractions_active_default_value'), +    ] + +    operations = [ +        migrations.AddField( +            model_name='offtopicchannelname', +            name='used', +            field=models.BooleanField(default=False, help_text='Whether or not this name has already been used during this rotation'), +        ), +    ] diff --git a/pydis_site/apps/api/models/bot/off_topic_channel_name.py b/pydis_site/apps/api/models/bot/off_topic_channel_name.py index 29280c27..413cbfae 100644 --- a/pydis_site/apps/api/models/bot/off_topic_channel_name.py +++ b/pydis_site/apps/api/models/bot/off_topic_channel_name.py @@ -16,6 +16,11 @@ class OffTopicChannelName(ModelReprMixin, models.Model):          help_text="The actual channel name that will be used on our Discord server."      ) +    used = models.BooleanField( +        default=False, +        help_text="Whether or not this name has already been used during this rotation", +    ) +      def __str__(self):          """Returns the current off-topic name, for display purposes."""          return self.name diff --git a/pydis_site/apps/api/tests/test_off_topic_channel_names.py b/pydis_site/apps/api/tests/test_off_topic_channel_names.py index bd42cd81..06624d89 100644 --- a/pydis_site/apps/api/tests/test_off_topic_channel_names.py +++ b/pydis_site/apps/api/tests/test_off_topic_channel_names.py @@ -21,6 +21,12 @@ class UnauthenticatedTests(APISubdomainTestCase):          self.assertEqual(response.status_code, 401) +    def test_cannot_read_off_topic_channel_name_list_with_random_item_and_mark_used_param(self): +        url = reverse('bot:offtopicchannelname-list', host='api') +        response = self.client.get(f'{url}?random_items=no&mark_used=true') + +        self.assertEqual(response.status_code, 401) +  class EmptyDatabaseTests(APISubdomainTestCase):      def test_returns_empty_object(self): @@ -59,8 +65,8 @@ class EmptyDatabaseTests(APISubdomainTestCase):  class ListTests(APISubdomainTestCase):      @classmethod      def setUpTestData(cls): -        cls.test_name = OffTopicChannelName.objects.create(name='lemons-lemonade-stand') -        cls.test_name_2 = OffTopicChannelName.objects.create(name='bbq-with-bisk') +        cls.test_name = OffTopicChannelName.objects.create(name='lemons-lemonade-stand', used=False) +        cls.test_name_2 = OffTopicChannelName.objects.create(name='bbq-with-bisk', used=True)      def test_returns_name_in_list(self):          url = reverse('bot:offtopicchannelname-list', host='api') @@ -82,6 +88,20 @@ class ListTests(APISubdomainTestCase):          self.assertEqual(response.status_code, 200)          self.assertEqual(len(response.json()), 1) +    def test_returns_single_correct_item_with_mark_used_parameter_true_and_random_items_1(self): +        url = reverse('bot:offtopicchannelname-list', host='api') +        response = self.client.get(f'{url}?random_items=1&mark_used=true') + +        self.assertEqual(response.status_code, 200) +        self.assertEqual(response.json(), [self.test_name.name]) + +    def test_running_out_of_names_with_mark_used_parameter(self): +        url = reverse('bot:offtopicchannelname-list', host='api') +        response = self.client.get(f'{url}?random_items=2&mark_used=true') + +        self.assertEqual(response.status_code, 200) +        self.assertEqual(response.json(), [self.test_name.name, self.test_name_2.name]) +  class CreationTests(APISubdomainTestCase):      def setUp(self): diff --git a/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py b/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py index d6da2399..4328c894 100644 --- a/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py +++ b/pydis_site/apps/api/viewsets/bot/off_topic_channel_name.py @@ -21,6 +21,10 @@ class OffTopicChannelNameViewSet(DestroyModelMixin, ViewSet):      If the `random_items` query parameter is given, for example using...          $ curl api.pythondiscord.local:8000/bot/off-topic-channel-names?random_items=5      ... then the API will return `5` random items from the database. +    If the `mark_used` query parameter is given like... +        $ curl api.pydis.local:8000/bot/off-topic-channel-names?random_items=5&mark_used=true +    ... then the API will mark returned `5` items `used`. +    When running out of names, API will mark all names to not used and start new round.      #### Response format      Return a list of off-topic-channel names: @@ -106,6 +110,31 @@ class OffTopicChannelNameViewSet(DestroyModelMixin, ViewSet):                      'random_items': ["Must be a positive integer."]                  }) +            if 'mark_used' in request.query_params and request.query_params['mark_used']: +                queryset = self.get_queryset().order_by('?').exclude(used=True)[:random_count] +                self.get_queryset().filter( +                    name__in=(query.name for query in queryset) +                ).update(used=True) + +                # When client request more channel names than non-used names is available, start +                # new round of names. +                if len(queryset) < random_count: +                    # Get how much names still missing and don't fetch duplicate names. +                    need_more = random_count - len(queryset) +                    ext = self.get_queryset().order_by('?').exclude( +                        name__in=(query.name for query in queryset) +                    )[:need_more] + +                    # Set all names `used` field to False except these that we just used. +                    self.get_queryset().exclude(name__in=( +                        query.name for query in ext) +                    ).update(used=False) +                    # Join original queryset (that had missing names) +                    # and extension with these missing names. +                    queryset = list(queryset) + list(ext) +                serialized = self.serializer_class(queryset, many=True) +                return Response(serialized.data) +              queryset = self.get_queryset().order_by('?')[:random_count]              serialized = self.serializer_class(queryset, many=True)              return Response(serialized.data) | 
