From efdaee3bb3d12d0f9dafa404058b458f0c1cd455 Mon Sep 17 00:00:00 2001 From: Robert Sparks Date: Mon, 5 Feb 2024 09:28:23 -0600 Subject: [PATCH] feat: decouple from mailman2 - explicitly model nonwg mailing lists (#7013) * fix: remove synchronization with mailman2 * feat: manage non wg mailing lists explicitly * chore: black * fix: update tests for new nonwg view * feat: drop unused models --- ietf/bin/mailman_listinfo.py | 50 -- ietf/ietfauth/tests.py | 13 - ietf/ietfauth/views.py | 10 - ietf/mailinglists/admin.py | 17 +- ietf/mailinglists/factories.py | 8 +- .../commands/import_mailman_listinfo.py | 130 ---- .../migrations/0002_nonwgmailinglist.py | 628 ++++++++++++++++++ ...e_subscribed_lists_delete_list_and_more.py | 23 + ietf/mailinglists/models.py | 17 +- ietf/mailinglists/resources.py | 27 +- ietf/mailinglists/tests.py | 16 +- ietf/mailinglists/views.py | 36 +- 12 files changed, 688 insertions(+), 287 deletions(-) delete mode 100755 ietf/bin/mailman_listinfo.py delete mode 100644 ietf/mailinglists/management/commands/import_mailman_listinfo.py create mode 100644 ietf/mailinglists/migrations/0002_nonwgmailinglist.py create mode 100644 ietf/mailinglists/migrations/0003_remove_subscribed_lists_delete_list_and_more.py diff --git a/ietf/bin/mailman_listinfo.py b/ietf/bin/mailman_listinfo.py deleted file mode 100755 index f7e4cfe4c..000000000 --- a/ietf/bin/mailman_listinfo.py +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/python2.7 -# Copyright The IETF Trust 2022, All Rights Reserved -# Note the shebang. This specifically targets deployment on IETFA and intends to use its system python2.7. - -# This is an adaptor to pull information out of Mailman2 using its python libraries (which are only available for python2). -# It is NOT django code, and does not have access to django.conf.settings. - -import json -import sys - -from collections import defaultdict - -def main(): - - sys.path.append('/usr/lib/mailman') - - have_mailman = False - try: - from Mailman import Utils - from Mailman import MailList - from Mailman import MemberAdaptor - have_mailman = True - except ImportError: - pass - - - if not have_mailman: - sys.stderr.write("Could not import mailman modules -- skipping import of mailman list info") - sys.exit() - - names = list(Utils.list_names()) - - # need to emit dict of names, each name has an mlist, and each mlist has description, advertised, and members (calculated as below) - result = defaultdict(dict) - for name in names: - mlist = MailList.MailList(name, lock=False) - result[name] = dict() - result[name]['internal_name'] = mlist.internal_name() - result[name]['real_name'] = mlist.real_name - result[name]['description'] = mlist.description # Not attempting to change encoding - result[name]['advertised'] = mlist.advertised - result[name]['members'] = list() - if mlist.advertised: - members = mlist.getRegularMemberKeys() + mlist.getDigestMemberKeys() - members = set([ m for m in members if mlist.getDeliveryStatus(m) == MemberAdaptor.ENABLED ]) - result[name]['members'] = list(members) - json.dump(result, sys.stdout) - -if __name__ == "__main__": - main() diff --git a/ietf/ietfauth/tests.py b/ietf/ietfauth/tests.py index ec085ed81..e9c521d08 100644 --- a/ietf/ietfauth/tests.py +++ b/ietf/ietfauth/tests.py @@ -37,7 +37,6 @@ from ietf.group.factories import GroupFactory, RoleFactory from ietf.group.models import Group, Role, RoleName from ietf.ietfauth.htpasswd import update_htpasswd_file from ietf.ietfauth.utils import has_role -from ietf.mailinglists.models import Subscribed from ietf.meeting.factories import MeetingFactory from ietf.nomcom.factories import NomComFactory from ietf.person.factories import PersonFactory, EmailFactory, UserFactory, PersonalApiKeyFactory @@ -250,18 +249,6 @@ class IetfAuthTests(TestCase): # register and verify allowlisted email self.register_and_verify(email) - - def test_create_subscribed_account(self): - # verify creation with email in subscribed list - saved_delay = settings.LIST_ACCOUNT_DELAY - settings.LIST_ACCOUNT_DELAY = 1 - email = "subscribed@example.com" - s = Subscribed(email=email) - s.save() - time.sleep(1.1) - self.register_and_verify(email) - settings.LIST_ACCOUNT_DELAY = saved_delay - def test_create_existing_account(self): # create account once email = "new-account@example.com" diff --git a/ietf/ietfauth/views.py b/ietf/ietfauth/views.py index ac4763449..53c28b589 100644 --- a/ietf/ietfauth/views.py +++ b/ietf/ietfauth/views.py @@ -160,18 +160,8 @@ def create_account(request): ) new_account_email = None # Indicate to the template that we failed to create the requested account else: - # For the IETF 113 Registration period (at least) we are lowering the - # barriers for account creation to the simple email round-trip check send_account_creation_email(request, new_account_email) - # The following is what to revert to should that lowered barrier prove problematic - # existing = Subscribed.objects.filter(email__iexact=new_account_email).first() - # ok_to_create = ( Allowlisted.objects.filter(email__iexact=new_account_email).exists() - # or existing and (existing.time + TimeDelta(seconds=settings.LIST_ACCOUNT_DELAY)) < DateTime.now() ) - # if ok_to_create: - # send_account_creation_email(request, new_account_email) - # else: - # return render(request, 'registration/manual.html', { 'account_request_email': settings.ACCOUNT_REQUEST_EMAIL }) else: form = RegistrationForm() diff --git a/ietf/mailinglists/admin.py b/ietf/mailinglists/admin.py index 90efaf9c9..51b906053 100644 --- a/ietf/mailinglists/admin.py +++ b/ietf/mailinglists/admin.py @@ -2,20 +2,15 @@ from django.contrib import admin -from ietf.mailinglists.models import List, Subscribed, Allowlisted +from ietf.mailinglists.models import NonWgMailingList, Allowlisted -class ListAdmin(admin.ModelAdmin): - list_display = ('id', 'name', 'description', 'advertised') + + +class NonWgMailingListAdmin(admin.ModelAdmin): + list_display = ('id', 'name', 'description') search_fields = ('name',) -admin.site.register(List, ListAdmin) - - -class SubscribedAdmin(admin.ModelAdmin): - list_display = ('id', 'time', 'email') - raw_id_fields = ('lists',) - search_fields = ('email',) -admin.site.register(Subscribed, SubscribedAdmin) +admin.site.register(NonWgMailingList, NonWgMailingListAdmin) class AllowlistedAdmin(admin.ModelAdmin): diff --git a/ietf/mailinglists/factories.py b/ietf/mailinglists/factories.py index bc6b2b820..1a3b0ffa1 100644 --- a/ietf/mailinglists/factories.py +++ b/ietf/mailinglists/factories.py @@ -3,16 +3,14 @@ import factory -import random -from ietf.mailinglists.models import List +from ietf.mailinglists.models import NonWgMailingList -class ListFactory(factory.django.DjangoModelFactory): +class NonWgMailingListFactory(factory.django.DjangoModelFactory): class Meta: - model = List + model = NonWgMailingList name = factory.Sequence(lambda n: "list-name-%s" % n) description = factory.Faker('sentence', nb_words=10) - advertised = factory.LazyAttribute(lambda obj: random.randint(0, 1)) diff --git a/ietf/mailinglists/management/commands/import_mailman_listinfo.py b/ietf/mailinglists/management/commands/import_mailman_listinfo.py deleted file mode 100644 index 8d2396411..000000000 --- a/ietf/mailinglists/management/commands/import_mailman_listinfo.py +++ /dev/null @@ -1,130 +0,0 @@ -# Copyright The IETF Trust 2016-2019, All Rights Reserved - -import json -import sys -import subprocess -import time -from textwrap import dedent - -import debug # pyflakes:ignore - -from pathlib import Path - -from django.conf import settings -from django.core.management.base import BaseCommand -from django.core.exceptions import MultipleObjectsReturned - - -from ietf.mailinglists.models import List, Subscribed -from ietf.utils.log import log - -mark = time.time() - -def import_mailman_listinfo(verbosity=0): - def note(msg): - if verbosity > 2: - sys.stdout.write(msg) - sys.stdout.write('\n') - def log_time(msg): - global mark - if verbosity > 1: - t = time.time() - log(msg+' (%.1fs)'% (t-mark)) - mark = t - - cmd = str(Path(settings.BASE_DIR) / "bin" / "mailman_listinfo.py") - result = subprocess.run([cmd], capture_output=True) - if result.stderr: - log("Error exporting information from mailmain") - log(result.stderr) - return - mailman_export = json.loads(result.stdout) - - names = sorted(mailman_export.keys()) - addr_max_length = Subscribed._meta.get_field('email').max_length - - subscribed = { l.name: set(l.subscribed_set.values_list('email', flat=True)) for l in List.objects.all().prefetch_related('subscribed_set') } - - for name in names: - note("List: %s" % mailman_export[name]['internal_name']) - - lists = List.objects.filter(name=mailman_export[name]['real_name']) - if lists.count() > 1: - # Arbitrary choice; we'll update the remaining item next - for item in lists[1:]: - item.delete() - mmlist, created = List.objects.get_or_create(name=mailman_export[name]['real_name']) - dirty = False - desc = mailman_export[name]['description'][:256] - if mmlist.description != desc: - mmlist.description = desc - dirty = True - if mmlist.advertised != mailman_export[name]['advertised']: - mmlist.advertised = mailman_export[name]['advertised'] - dirty = True - if dirty: - mmlist.save() - # The following calls return lowercased addresses - if mailman_export[name]['advertised']: - members = set(mailman_export[name]['members']) - if not mailman_export[name]['real_name'] in subscribed: - # 2022-7-29: lots of these going into the logs but being ignored... - # log("Note: didn't find '%s' in the dictionary of subscriptions" % mailman_export[name]['real_name']) - continue - known = subscribed[mailman_export[name]['real_name']] - log_time(" Fetched known list members from database") - to_remove = known - members - to_add = members - known - for addr in to_remove: - note(" Removing subscription: %s" % (addr)) - old = Subscribed.objects.get(email=addr) # Intentionally leaving this as case-sensitive in postgres - old.lists.remove(mmlist) - if old.lists.count() == 0: - note(" Removing address with no subscriptions: %s" % (addr)) - old.delete() - if to_remove: - log(" Removed %s addresses from %s" % (len(to_remove), name)) - for addr in to_add: - if len(addr) > addr_max_length: - sys.stderr.write(" ** Email address subscribed to '%s' too long for table: <%s>\n" % (name, addr)) - continue - note(" Adding subscription: %s" % (addr)) - try: - new, created = Subscribed.objects.get_or_create(email=addr) # Intentionally leaving this as case-sensitive in postgres - except MultipleObjectsReturned as e: - sys.stderr.write(" ** Error handling %s in %s: %s\n" % (addr, name, e)) - continue - new.lists.add(mmlist) - if to_add: - log(" Added %s addresses to %s" % (len(to_add), name)) - log("Completed import of list info from Mailman") - -class Command(BaseCommand): - """ - Import list information from Mailman. - - Import announced list names, descriptions, and subscribers, by calling the - appropriate Mailman functions and adding entries to the database. - - Run this from cron regularly, with sufficient permissions to access the - mailman database files. - - """ - - help = dedent(__doc__).strip() - - #option_list = BaseCommand.option_list + ( ) - - - def handle(self, *filenames, **options): - """ - - * Import announced lists, with appropriate meta-information. - - * For each list, import the members. - - """ - - verbosity = int(options.get('verbosity')) - - import_mailman_listinfo(verbosity) diff --git a/ietf/mailinglists/migrations/0002_nonwgmailinglist.py b/ietf/mailinglists/migrations/0002_nonwgmailinglist.py new file mode 100644 index 000000000..dfc941db9 --- /dev/null +++ b/ietf/mailinglists/migrations/0002_nonwgmailinglist.py @@ -0,0 +1,628 @@ +# Copyright The IETF Trust 2024, All Rights Reserved + +from django.db import migrations, models + + +def forward(apps, schema_editor): + NonWgMailingList = apps.get_model("mailinglists", "NonWgMailingList") + List = apps.get_model("mailinglists", "List") + + for l in List.objects.filter( + pk__in=[ + 10754, + 10769, + 10770, + 10768, + 10787, + 10785, + 10791, + 10786, + 10816, + 10817, + 10819, + 10818, + 10922, + 10923, + 10921, + 10940, + 10941, + 10942, + 572, + 10297, + 182, + 43, + 10704, + 10314, + 201, + 419, + 282, + 149, + 223, + 10874, + 10598, + 10639, + 10875, + 10737, + 105, + 65, + 10781, + 10771, + 10946, + 518, + 421, + 214, + 285, + 393, + 445, + 553, + 183, + 10725, + 33, + 10766, + 114, + 417, + 10789, + 10876, + 4244, + 10705, + 10706, + 10878, + 10324, + 10879, + 10642, + 10821, + 547, + 532, + 10636, + 10592, + 327, + 248, + 10697, + 288, + 346, + 10731, + 10955, + 10857, + 446, + 55, + 10799, + 10800, + 10801, + 10612, + 73, + 3, + 358, + 9640, + 10868, + 378, + 462, + 6595, + 10914, + 10915, + 197, + 63, + 558, + 10824, + 124, + 10881, + 177, + 312, + 252, + 185, + 523, + 4572, + 10618, + 206, + 68, + 10859, + 560, + 513, + 246, + 7817, + 148, + 10864, + 10589, + 10773, + 10748, + 364, + 311, + 10302, + 10272, + 10929, + 171, + 10865, + 10919, + 377, + 469, + 467, + 411, + 505, + 6318, + 10811, + 10304, + 10882, + 10845, + 568, + 10883, + 4774, + 264, + 10779, + 10884, + 10303, + 409, + 10590, + 451, + 10749, + 10765, + 486, + 519, + 10593, + 10313, + 550, + 10707, + 307, + 10861, + 10654, + 10708, + 10275, + 134, + 460, + 10911, + 10574, + 10885, + 10814, + 10676, + 10747, + 10305, + 10688, + 36, + 10844, + 10620, + 458, + 10282, + 10594, + 10752, + 389, + 296, + 10684, + 48, + 533, + 443, + 10739, + 491, + 139, + 461, + 10690, + 424, + 290, + 336, + 31, + 10709, + 382, + 10866, + 10724, + 539, + 10710, + 559, + 10609, + 74, + 10582, + 133, + 10621, + 34, + 10596, + 442, + 13, + 56, + 128, + 323, + 10285, + 80, + 315, + 3520, + 10949, + 10950, + 189, + 2599, + 10822, + 164, + 10267, + 10286, + 464, + 440, + 254, + 262, + 10943, + 465, + 75, + 179, + 162, + 457, + 10572, + 372, + 452, + 10273, + 88, + 366, + 331, + 140, + 407, + 416, + 91, + 10632, + 542, + 151, + 117, + 431, + 10628, + 10271, + 14, + 540, + 278, + 352, + 159, + 10851, + 9981, + 10694, + 10619, + 10732, + 320, + 348, + 338, + 349, + 10678, + 468, + 293, + 350, + 402, + 57, + 524, + 141, + 71, + 67, + 508, + 7828, + 10268, + 10631, + 10713, + 10889, + 345, + 78, + 342, + 190, + 10869, + 46, + 334, + 255, + 5823, + 400, + 10867, + 23, + 10666, + 10685, + 405, + 2801, + 92, + 137, + 10640, + 10656, + 104, + 123, + 10643, + 10891, + 466, + 10567, + 10318, + 526, + 30, + 222, + 194, + 10735, + 10714, + 247, + 493, + 1162, + 414, + 10648, + 10677, + 126, + 16, + 422, + 271, + 295, + 81, + 10634, + 544, + 10850, + 426, + 573, + 353, + 10829, + 538, + 10913, + 10566, + 167, + 10675, + 272, + 10673, + 10767, + 528, + 284, + 564, + 268, + 10825, + 231, + 520, + 10645, + 10872, + 515, + 10956, + 10947, + 569, + 233, + 10952, + 195, + 10938, + 2809, + 10591, + 10665, + 9639, + 10775, + 10760, + 10715, + 10716, + 10667, + 361, + 184, + 10935, + 10957, + 10944, + 94, + 449, + 525, + 1962, + 10300, + 10894, + 9156, + 10774, + 256, + 289, + 218, + 187, + 40, + 10777, + 10761, + 10670, + 249, + 10764, + 420, + 548, + 232, + 410, + 196, + 72, + 335, + 70, + 146, + 10287, + 10299, + 10311, + 10895, + 10617, + 531, + 343, + 10934, + 10933, + 10597, + 158, + 10600, + 10692, + 8630, + 556, + 324, + 11, + 10784, + 498, + 10772, + 478, + 10833, + 10691, + 391, + 10565, + 10669, + 113, + 110, + 7831, + 10855, + 10312, + 10315, + 10896, + 10672, + 10306, + 438, + 395, + 82, + 10599, + 10953, + 10858, + 10807, + 10717, + 310, + 10808, + 119, + 10595, + 10718, + 10317, + 10898, + 454, + 427, + 10583, + 10916, + 403, + 10843, + 10899, + 291, + 10812, + 10900, + 10794, + 341, + 121, + 230, + 136, + 166, + 394, + 234, + 10901, + 2466, + 10573, + 10939, + 221, + 490, + 10820, + 10873, + 10792, + 10870, + 10793, + 10904, + 181, + 10693, + 482, + 10611, + 125, + 10568, + 10788, + 211, + 10756, + 10719, + 100, + 228, + 5833, + 251, + 122, + 39, + 534, + 437, + 504, + 10613, + 439, + 306, + 10863, + 10823, + 10926, + 76, + 227, + 59, + 42, + 455, + 10927, + 10928, + 204, + 430, + 10720, + 267, + 396, + 10849, + 10308, + 281, + 10905, + 10736, + 168, + 153, + 385, + 89, + 529, + 412, + 215, + 484, + 10951, + 66, + 173, + 10633, + 10681, + 3613, + 10274, + 10750, + 367, + 387, + 10832, + 35, + 147, + 10325, + 10671, + 565, + 313, + 10871, + 10751, + 37, + 10936, + 10937, + 287, + 496, + 244, + 10841, + 10683, + 10906, + 10584, + 479, + 10856, + 163, + 10910, + 257, + 276, + 10840, + 10689, + 365, + 10847, + 99, + 77, + 435, + 213, + 15, + 10932, + 58, + 10722, + 131, + 363, + 10674, + 322, + 180, + 10917, + 10918, + 10738, + 10954, + 10581, + 208, + 337, + 4, + 571, + 10668, + 10291, + ] + ): + NonWgMailingList.objects.create(name=l.name, description=l.description) + +class Migration(migrations.Migration): + + dependencies = [ + ("mailinglists", "0001_initial"), + ] + + operations = [ + migrations.CreateModel( + name="NonWgMailingList", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("name", models.CharField(max_length=32)), + ("description", models.CharField(max_length=256)), + ], + ), + migrations.RunPython(forward), + ] diff --git a/ietf/mailinglists/migrations/0003_remove_subscribed_lists_delete_list_and_more.py b/ietf/mailinglists/migrations/0003_remove_subscribed_lists_delete_list_and_more.py new file mode 100644 index 000000000..6171136b2 --- /dev/null +++ b/ietf/mailinglists/migrations/0003_remove_subscribed_lists_delete_list_and_more.py @@ -0,0 +1,23 @@ +# Generated by Django 4.2.9 on 2024-02-02 23:04 + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ("mailinglists", "0002_nonwgmailinglist"), + ] + + operations = [ + migrations.RemoveField( + model_name="subscribed", + name="lists", + ), + migrations.DeleteModel( + name="List", + ), + migrations.DeleteModel( + name="Subscribed", + ), + ] diff --git a/ietf/mailinglists/models.py b/ietf/mailinglists/models.py index 21f3a7671..1e56c43d9 100644 --- a/ietf/mailinglists/models.py +++ b/ietf/mailinglists/models.py @@ -9,25 +9,18 @@ from django.db import models from ietf.person.models import Person from ietf.utils.models import ForeignKey -class List(models.Model): + +# NonWgMailingList is a temporary bridging class to hold information known about mailman2 +# while decoupling from mailman2 until we integrate with mailman3 +class NonWgMailingList(models.Model): name = models.CharField(max_length=32) description = models.CharField(max_length=256) - advertised = models.BooleanField(default=True) def __str__(self): - return "" % self.name + return "" % self.name def info_url(self): return settings.MAILING_LIST_INFO_URL % {'list_addr': self.name } -class Subscribed(models.Model): - time = models.DateTimeField(auto_now_add=True) - email = models.CharField(max_length=128, validators=[validate_email]) - lists = models.ManyToManyField(List) - def __str__(self): - return "" % (self.email, self.time) - class Meta: - verbose_name_plural = "Subscribed" - class Allowlisted(models.Model): time = models.DateTimeField(auto_now_add=True) email = models.CharField("Email address", max_length=64, validators=[validate_email]) diff --git a/ietf/mailinglists/resources.py b/ietf/mailinglists/resources.py index 018a8327b..b075d1807 100644 --- a/ietf/mailinglists/resources.py +++ b/ietf/mailinglists/resources.py @@ -11,7 +11,7 @@ from tastypie.cache import SimpleCache from ietf import api from ietf.api import ToOneField # pyflakes:ignore -from ietf.mailinglists.models import Allowlisted, List, Subscribed +from ietf.mailinglists.models import Allowlisted, NonWgMailingList from ietf.person.resources import PersonResource @@ -31,34 +31,19 @@ class AllowlistedResource(ModelResource): } api.mailinglists.register(AllowlistedResource()) -class ListResource(ModelResource): +class NonWgMailingListResource(ModelResource): class Meta: - queryset = List.objects.all() + queryset = NonWgMailingList.objects.all() serializer = api.Serializer() cache = SimpleCache() - #resource_name = 'list' + #resource_name = 'nonwgmailinglist' ordering = ['id', ] filtering = { "id": ALL, "name": ALL, "description": ALL, - "advertised": ALL, } -api.mailinglists.register(ListResource()) +api.mailinglists.register(NonWgMailingListResource()) + -class SubscribedResource(ModelResource): - lists = ToManyField(ListResource, 'lists', null=True) - class Meta: - queryset = Subscribed.objects.all() - serializer = api.Serializer() - cache = SimpleCache() - #resource_name = 'subscribed' - ordering = ['id', ] - filtering = { - "id": ALL, - "time": ALL, - "email": ALL, - "lists": ALL_WITH_RELATIONS, - } -api.mailinglists.register(SubscribedResource()) diff --git a/ietf/mailinglists/tests.py b/ietf/mailinglists/tests.py index 0c983da80..0b44d28c7 100644 --- a/ietf/mailinglists/tests.py +++ b/ietf/mailinglists/tests.py @@ -9,7 +9,7 @@ from django.urls import reverse as urlreverse import debug # pyflakes:ignore from ietf.group.factories import GroupFactory -from ietf.mailinglists.factories import ListFactory +from ietf.mailinglists.factories import NonWgMailingListFactory from ietf.utils.test_utils import TestCase @@ -32,23 +32,13 @@ class MailingListTests(TestCase): def test_nonwg(self): - groups = list() - groups.append(GroupFactory(type_id='wg', acronym='mars', list_archive='https://ietf.org/mars')) - groups.append(GroupFactory(type_id='wg', acronym='ames', state_id='conclude', list_archive='https://ietf.org/ames')) - groups.append(GroupFactory(type_id='wg', acronym='newstuff', state_id='bof', list_archive='https://ietf.org/newstuff')) - groups.append(GroupFactory(type_id='rg', acronym='research', list_archive='https://irtf.org/research')) - lists = ListFactory.create_batch(7) + + lists = NonWgMailingListFactory.create_batch(7) url = urlreverse("ietf.mailinglists.views.nonwg") r = self.client.get(url) for l in lists: - if l.advertised: self.assertContains(r, l.name) self.assertContains(r, l.description) - else: - self.assertNotContains(r, l.name, html=True) - self.assertNotContains(r, l.description, html=True) - for g in groups: - self.assertNotContains(r, g.acronym, html=True) diff --git a/ietf/mailinglists/views.py b/ietf/mailinglists/views.py index 51c31c546..460f30e16 100644 --- a/ietf/mailinglists/views.py +++ b/ietf/mailinglists/views.py @@ -1,33 +1,25 @@ # Copyright The IETF Trust 2007-2022, All Rights Reserved -import re - from django.shortcuts import render -import debug # pyflakes:ignore +import debug # pyflakes:ignore from ietf.group.models import Group -from ietf.mailinglists.models import List +from ietf.mailinglists.models import NonWgMailingList + def groups(request): - groups = Group.objects.filter(type__features__acts_like_wg=True, list_archive__startswith='http').exclude(state__in=('bof', 'conclude')).order_by("acronym") + groups = ( + Group.objects.filter( + type__features__acts_like_wg=True, list_archive__startswith="http" + ) + .exclude(state__in=("bof", "conclude")) + .order_by("acronym") + ) + + return render(request, "mailinglists/group_archives.html", {"groups": groups}) - return render(request, "mailinglists/group_archives.html", { "groups": groups } ) def nonwg(request): - groups = Group.objects.filter(type__features__acts_like_wg=True).exclude(state__in=['bof']).order_by("acronym") - - #urls = [ g.list_archive for g in groups if '.ietf.org' in g.list_archive ] - - wg_lists = set() - for g in groups: - wg_lists.add(g.acronym) - match = re.search(r'^(https?://mailarchive.ietf.org/arch/(browse/|search/\?email-list=))(?P[^/]*)/?$', g.list_archive) - if match: - wg_lists.add(match.group('name').lower()) - - lists = List.objects.filter(advertised=True) - #debug.show('lists.count()') - lists = lists.exclude(name__in=wg_lists).order_by('name') - #debug.show('lists.count()') - return render(request, "mailinglists/nonwg.html", { "lists": lists } ) + lists = NonWgMailingList.objects.order_by("name") + return render(request, "mailinglists/nonwg.html", {"lists": lists})