Unsubscribe/resubscribe members when they're expired and renewed (#53)
continuous-integration/drone/push Build is passing Details

Co-authored-by: Rio Liu <rio.liu@r26.me>
Co-authored-by: Rio6 <rio.liu@r26.me>
Co-authored-by: Max Erenberg <merenber@csclub.uwaterloo.ca>
Reviewed-on: #53
Co-authored-by: Rio <r345liu@localhost>
Co-committed-by: Rio <r345liu@localhost>
This commit is contained in:
Rio Liu 2022-06-02 02:06:49 -04:00 committed by Max Erenberg
parent 87470e1f3b
commit 55c4b2151d
2 changed files with 64 additions and 4 deletions

View File

@ -4,8 +4,8 @@ from zope import component
from .utils import authz_restrict_to_staff, authz_restrict_to_syscom, \
user_is_in_group, requires_authentication_no_realm, \
create_streaming_response, development_only, is_truthy
from ceo_common.errors import BadRequest
from ceo_common.interfaces import ILDAPService
from ceo_common.errors import BadRequest, UserAlreadySubscribedError, UserNotSubscribedError
from ceo_common.interfaces import ILDAPService, IConfig
from ceod.transactions.members import (
AddMemberTransaction,
ModifyMemberTransaction,
@ -92,14 +92,25 @@ def renew_user(username: str):
g.need_admin_creds = True
ldap_srv = component.getUtility(ILDAPService)
cfg = component.getUtility(IConfig)
user = ldap_srv.get_user(username)
member_list = cfg.get('mailman3_new_member_list')
def unexpire(user):
if user.shadowExpire:
user.set_expired(False)
try:
user.subscribe_to_mailing_list(member_list)
except UserAlreadySubscribedError:
pass
if body.get('terms'):
user.add_terms(body['terms'])
user.set_expired(False)
unexpire(user)
return {'terms_added': body['terms']}
elif body.get('non_member_terms'):
user.add_non_member_terms(body['non_member_terms'])
user.set_expired(False)
unexpire(user)
return {'non_member_terms_added': body['non_member_terms']}
else:
raise BadRequest('Must specify either terms or non-member terms')
@ -129,10 +140,16 @@ def expire_users():
dry_run = is_truthy(request.args.get('dry_run', 'false'))
ldap_srv = component.getUtility(ILDAPService)
cfg = component.getUtility(IConfig)
members = ldap_srv.get_expiring_users()
member_list = cfg.get('mailman3_new_member_list')
if not dry_run:
for member in members:
member.set_expired(True)
try:
member.unsubscribe_from_mailing_list(member_list)
except UserNotSubscribedError:
pass
return json.jsonify([member.uid for member in members])

View File

@ -0,0 +1,43 @@
#!/usr/bin/env python3
"""
This is a script which unsubscribes expired members from csc-general.
GSSAPI is used for SPNEGO authentication, so make sure to run `kinit` first.
Also, make sure to run this script from the top-level of the git directory
(see the sys.path hack below).
"""
import os
import sys
import ldap3
from zope import component
sys.path.append(os.getcwd())
from ceo_common.errors import UserNotSubscribedError
from ceo_common.interfaces import IConfig, IHTTPClient
from ceo_common.model import Config, HTTPClient, RemoteMailmanService
# modify as necessary
CONFIG_FILE = '/etc/csc/ceod.ini'
NEW_MEMBER_LIST = 'csc-general'
cfg = Config(CONFIG_FILE)
component.provideUtility(cfg, IConfig)
http_client = HTTPClient()
component.provideUtility(http_client, IHTTPClient)
mailman_srv = RemoteMailmanService()
LDAP_URI = cfg.get('ldap_server_url')
LDAP_MEMBERS_BASE = cfg.get('ldap_users_base')
conn = ldap3.Connection(LDAP_URI, auto_bind=True, raise_exceptions=True)
conn.search(LDAP_MEMBERS_BASE, '(shadowExpire=1)', attributes=['uid'])
total_unsubscribed = 0
for entry in conn.entries:
uid = entry.uid.value
try:
mailman_srv.unsubscribe(uid, NEW_MEMBER_LIST)
print(f'Unsubscribed {uid}')
total_unsubscribed += 1
except UserNotSubscribedError:
print(f'{uid} is already unsubscribed')
print(f'Total unsubscribed: {total_unsubscribed}')