#! /usr/bin/python3
#
# mailman3 module to configure notification mailing lists
# Update this as needed for your application. Look for example.com
#
# This single file handles both the 2 special lists as well as the basic notification lists.
# This makes the call interface a bit confusing since dummy parameter are needed at times.
# Split into multiple files if desired.
#
# This module must be in the Python sys.path 
# sys.path = ['/opt/mailman/bin', '/usr/lib64/python39.zip', '/usr/lib64/python3.9', '/usr/lib64/python3.9/lib-dynload', '/opt/mailman/lib64/python3.9/site-packages', '/opt/mailman/lib/python3.9/site-packages']
## Example usage:
## SET UP 2 SPECIAL LISTS
# mailman create --owner siteadmin@example.com list-all@example.com
# mailman shell -l list-all@example.com --run configure_list dummy_value
# mailman create --owner siteadmin@example.com list-admin@example.com
# mailman shell -l list-admin@example.com --run configure_list dummy_value
#
## CONFIGURE A NOTIFICATION LIST
# mailman create --owner siteadmin@example.com list-0000@example.com
## ues-admin list gets copied on posts sent to every list
# echo 'list-admin@example.com' | mailman addmembers --delivery regular --no-welcome-msg - list-0000@example.com
## Configure the list options
# mailman shell -l list-0000@example.com --run configure_list "Short Description"
## The following should be run for each new notification list to allow copies to go to the admin list
# mailman shell -l list-admin@example.com --run configure_list list-0000

import datetime

# Find these module paths using mailman shell for any list (mailman shell -l test1.example.com)
# Look at __module__ attribute of the class  (e.g for SubscriptionPolicy)
# >>> SubscriptionPolicy.__module__
# 'mailman.interfaces.mailinglist'
#
from mailman.interfaces.archiver import ArchivePolicy
from mailman.interfaces.action import Action
from mailman.interfaces.mailinglist import ReplyToMunging
from mailman.interfaces.mailinglist import SubscriptionPolicy
from mailman.interfaces.member import MemberRole
from mailman.interfaces.usermanager import IUserManager
from mailman.utilities.datetime import now
from zope.component import getUtility

admin_description = 'Admins'

def get_user(display_name, email, user_manager):
  """Return an existing address record if available, otherwise make one."""
  user = user_manager.get_user(email)
  if user is not None:
      # We have a user with this email.  Return that.
      return user
  # Unknown email.  Create an address for this.
  return user_manager.create_user(email, display_name)

def add_nonmember_sender(ml, email):
  """Add nonmember to a mailing list."""
  user_manager = getUtility(IUserManager)

  display_name = email.split('@')[0]
  user = get_user(display_name, email, user_manager)
  address = list(user.addresses)[0]
  address.verified_on = now()
  user.preferred_address = address
  ml.subscribe(user, MemberRole.nonmember)
  #print(email,'subscribed as nonmember to', ml.list_name)
  # Update moderation_action after nonmember is added. Before does not work
  nonmembers = ml.get_roster(MemberRole.nonmember)
  for nonmember in nonmembers.members:
    #print('Moderation action-Checking', nonmember.address, '==', email)
    if email == nonmember.address.original_email:
      #print('Setting moderation action for', email)
      nonmember.moderation_action = Action.defer


def set_common(ml):
  """Properties common to all lists."""
  ml.admin_immed_notify = False
  ml.advertised = False
  ml.allow_list_posts = False
  ml.anonymous_list = True
  ml.archive_policy = ArchivePolicy.never
  ml.bounce_info_stale_after = datetime.timedelta(days=90)
  ml.bounce_notify_owner_on_disable = False
  ml.bounce_notify_owner_on_removal = False
  ml.bounce_score_threshold = 3
  ml.bounce_you_are_disabled_warnings = 0
  ml.default_member_action = Action.discard
  ml.default_nonmember_action = Action.discard
  ml.digests_enabled = False
  ml.filter_content = True
  ml.first_strip_reply_to = True
  ml.forward_auto_discards = False
  ml.max_days_to_hold = 1
  ml.max_message_size = 0
  ml.nntp_prefix_subject_too = False
  ml.pass_extensions = []
  ml.pass_types = ['text/plain','multipart/alternative']
  ml.reply_goes_to_list = ReplyToMunging.explicit_header
  ml.reply_to_address = "no-reply@example.com"
  ml.require_explicit_destination = False
  ml.respond_to_post_requests = False


# Description value must be passed as a parameter
def configure_notification_list(ml, description):
  """Configure general notification list."""
  set_common(ml)
  ml.description = description
  ml.subscription_policy = SubscriptionPolicy.open
  ml.unsubscription_policy = SubscriptionPolicy.open

  add_nonmember_sender(ml, 'list-all-bounces@example.com')
  add_nonmember_sender(ml, 'siteadmin@example.com')


def configure_all_list(ml):
  """Configure the send to all lists list."""
  set_common(ml)
  ml.description = "Notify_All"
  ml.subscription_policy = SubscriptionPolicy.confirm_then_moderate
  ml.unsubscription_policy = SubscriptionPolicy.confirm

  add_nonmember_sender(ml, 'siteadmin@example.com')


def configure_admin_list(ml):
  """Configure the admin list that is copied on all posts"""
  set_common(ml)
  ml.description = admin_description
  ml.subscription_policy = SubscriptionPolicy.confirm_then_moderate
  ml.unsubscription_policy = SubscriptionPolicy.confirm

  add_nonmember_sender(ml, 'list-all-bounces@example.com')
  add_nonmember_sender(ml, 'siteadmin@example.com')


# Sender list username value must be passed as a parameter (e.g. list-0000)
def update_admin_list(ml, sender):
  """Add a notification list as approved sender to the admin list."""
  add_nonmember_sender(ml, sender +'-bounces@example.com')


## Main entry point
def configure_list(ml, parameter):
  if ml.list_name == 'list-all':
    configure_all_list(ml)
  elif ml.list_name == 'list-admin':
    if ml.description == None or ml.description != admin_description:
      configure_admin_list(ml)
    else:
      update_admin_list(ml, parameter)
  else:
    configure_notification_list(ml,parameter)
