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
This commit is contained in:
parent
b4cf04a09d
commit
efdaee3bb3
|
@ -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()
|
|
@ -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"
|
||||
|
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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))
|
||||
|
||||
|
||||
|
|
|
@ -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)
|
628
ietf/mailinglists/migrations/0002_nonwgmailinglist.py
Normal file
628
ietf/mailinglists/migrations/0002_nonwgmailinglist.py
Normal file
|
@ -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),
|
||||
]
|
|
@ -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",
|
||||
),
|
||||
]
|
|
@ -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 "<List: %s>" % self.name
|
||||
return "<NonWgMailingList: %s>" % 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 "<Subscribed: %s at %s>" % (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])
|
||||
|
|
|
@ -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())
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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<name>[^/]*)/?$', 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})
|
||||
|
|
Loading…
Reference in a new issue