Update of /cvsroot/mailman/mailman/Mailman
In directory usw-pr-cvs1:/tmp/cvs-serv3633

Modified Files:
        MailList.py 
Log Message:
Add support for the list moderator role, and change of address
requests.  Specifically,

InitVars(): Add the moderator attribute, which is a list of email
addresses a la the owner attribute.

GetConfigInfo(): Added some details to the `owner' attribute
describing the different list-related roles.  Also added the
`moderator' attribute and copied the description of roles to its
details too.

ChangeMemberAddress(): Added support for change-of-address.  This
method simply pends the request and sends the confirmation email
to the new address (the old one is already verified by way of the web
authentication).

ApprovedChangeMemberAddress(): Effects the actual change-of-address by
adding the member, copying over the user options and the language
settings, and then removing the old address.  Acknowledgements are
always sent.  Handle the global change-of-address by searching for all
the matching lists (must match both host_name and have the old address
of the user as a member), and recursively calling
ApprovedChangeMemberAddress() on those lists -- with the global flag
turned off of course!

ProcessConfirmation(): Add support for CHANGE_OF_ADDRESS, which simply
unpacks the data and calls ApprovedChangeMemberAddress().

ApprovedAddMember(): Fixed a bug in the order of arguments in the call
to ApprovedAddMembers() - plural.

DeleteMember(): Fixed a bug in the i18n-marked subject text, related
to auto-interpolation.

SetPreferredLanguage(): Assert that the language we're setting to is
in the list of available languages (helped catch the
ApprovedAddMember() bug above).  Also, only add
DEFAULT_SERVER_LANGUAGE if it isn't already an item in the list.


Index: MailList.py
===================================================================
RCS file: /cvsroot/mailman/mailman/Mailman/MailList.py,v
retrieving revision 2.20
retrieving revision 2.21
diff -C2 -r2.20 -r2.21
*** MailList.py 2001/05/25 19:04:08     2.20
--- MailList.py 2001/05/31 19:52:34     2.21
***************
*** 299,302 ****
--- 299,303 ----
          self.web_page_url = mm_cfg.DEFAULT_URL   
          self.owner = [admin]
+         self.moderator = []
          self.reply_goes_to_list = mm_cfg.DEFAULT_REPLY_GOES_TO_LIST
          self.reply_to_address = ''
***************
*** 384,390 ****
  
              ('owner', mm_cfg.EmailList, (3, WIDTH), 0,
!              _("""The list admin's email address - having multiple
!              admins/addresses (on separate lines) is ok.""")),
  
              ('preferred_language', mm_cfg.Select,
               (langs, langnames, langi),
--- 385,434 ----
  
              ('owner', mm_cfg.EmailList, (3, WIDTH), 0,
!              _("""The list administrator email addresses.  Multiple
!              administrator addresses, each on separate line is okay."""),
  
+              _("""There are two ownership roles associated with each mailing
+              list.  The <em>list administrators</em> are the people who have
+              ultimate control over all parameters of this mailing list.  They
+              are able to change any list configuration variable available
+              through these administration web pages.
+ 
+              <p>The <em>list moderators</em> have more limited permissions;
+              they are not able to change any list configuration variable, but
+              they are allowed to tend to pending administration requests,
+              including approving or rejecting held subscription requests, and
+              disposing of held postings.  Of course, the <em>list
+              administrators</em> can also tend to pending requests.
+ 
+              <p>In order to split the list ownership duties into
+              administrators and moderators, you must set a separate moderator
+              password in the section below, and also provide the email
+              addresses of the list moderators in this section.  Note that the
+              field you are changing here specifies the list
+              administators.""")),
+ 
+             ('moderator', mm_cfg.EmailList, (3, WIDTH), 0,
+              _("""The list moderator email addresses.  Multiple
+              moderator addresses, each on separate line is okay."""),
+ 
+              _("""There are two ownership roles associated with each mailing
+              list.  The <em>list administrators</em> are the people who have
+              ultimate control over all parameters of this mailing list.  They
+              are able to change any list configuration variable available
+              through these administration web pages.
+ 
+              <p>The <em>list moderators</em> have more limited permissions;
+              they are not able to change any list configuration variable, but
+              they are allowed to tend to pending administration requests,
+              including approving or rejecting held subscription requests, and
+              disposing of held postings.  Of course, the <em>list
+              administrators</em> can also tend to pending requests.
+ 
+              <p>In order to split the list ownership duties into
+              administrators and moderators, you must set a separate moderator
+              password in the section below, and also provide the email
+              addresses of the list moderators in this section.  Note that the
+              field you are changing here specifies the list moderators.""")),
+ 
              ('preferred_language', mm_cfg.Select,
               (langs, langnames, langi),
***************
*** 1068,1071 ****
--- 1112,1151 ----
                  'subscriptions to %(realname)s require administrator approval')
  
+     def ChangeMemberAddress(self, oldaddr, newaddr, globally):
+         # Changing a member address consists of verifying the new address,
+         # making sure the new address isn't already a member, and optionally
+         # going through the confirmation process.
+         #
+         # Most of these checks are copied from AddMember
+         newaddr = Utils.LCDomain(newaddr)
+         Utils.ValidateEmail(newaddr)
+         if self.IsMember(newaddr):
+             raise Errors.MMAlreadyAMember
+         if newaddr == self.GetListEmail().lower():
+             raise Errors.MMBadEmailError
+         # Pend the subscription change
+         cookie = Pending.new(Pending.CHANGE_OF_ADDRESS,
+                              oldaddr, newaddr, globally)
+         confirmurl = '%s/%s' % (self.GetScriptURL('confirm', absolute=1),
+                                 cookie)
+         realname = self.real_name
+         text = Utils.maketext(
+             'verify.txt',
+             {'email'      : newaddr,
+              'listaddr'   : self.GetListEmail(),
+              'listname'   : realname,
+              'cookie'     : cookie,
+              'requestaddr': self.GetRequestEmail(),
+              'remote'     : '',
+              'listadmin'  : self.GetAdminEmail(),
+              'confirmurl' : confirmurl,
+              }, lang=self.GetPreferredLanguage(oldaddr), mlist=self)
+         msg = Message.UserNotification(
+             newaddr, self.GetRequestEmail(),
+        _('%(realname)s -- confirmation of subscription -- confirm %(cookie)s'),
+             text)
+         msg['Reply-To'] = self.GetRequestEmail()
+         msg.send(self)
+ 
      def ProcessConfirmation(self, cookie):
          data = Pending.confirm(cookie)
***************
*** 1094,1097 ****
--- 1174,1181 ----
              self.DeleteMember(addr, whence='web confirmation')
              return op, addr
+         elif op == Pending.CHANGE_OF_ADDRESS:
+             oldaddr, newaddr, globally = data
+             self.ApprovedChangeMemberAddress(oldaddr, newaddr, globally)
+             return op, newaddr
  
      def ConfirmUnsubscription(self, addr, lang=None, remote=None):
***************
*** 1129,1133 ****
                            ack=None, admin_notif=None, lang=None):
          res = self.ApprovedAddMembers([name], [password],
!                                       digest, lang, ack, admin_notif)
          # There should be exactly one (key, value) pair in the returned dict,
          # extract the possible exception value
--- 1213,1217 ----
                            ack=None, admin_notif=None, lang=None):
          res = self.ApprovedAddMembers([name], [password],
!                                       digest, ack, admin_notif, lang)
          # There should be exactly one (key, value) pair in the returned dict,
          # extract the possible exception value
***************
*** 1283,1287 ****
                  admin_notif = 0
          if admin_notif:
!             subject = _('%s unsubscribe notification') % self.real_name
              text = Utils.maketext(
                  'adminunsubscribeack.txt',
--- 1367,1372 ----
                  admin_notif = 0
          if admin_notif:
!             realname = self.real_name
!             subject = _('%(realname)s unsubscribe notification')
              text = Utils.maketext(
                  'adminunsubscribeack.txt',
***************
*** 1300,1303 ****
--- 1385,1430 ----
                 (self.internal_name(), name, whence))
  
+     def ApprovedChangeMemberAddress(self, oldaddr, newaddr, globally):
+         # Get the user's current options and password.  Ugly hack: if a user's
+         # options would have been zero, then Mailman saves room by deleting
+         # the entry for the user from the user_options dictionary.  Note that
+         # /really/ it would be better if GetUserOption() and SetUserOption()
+         # supported an interface to get the entire option value.
+         flags = self.user_options.get(oldaddr, 0)
+         password = self.passwords[oldaddr]
+         digest = oldaddr in self.GetDigestMembers()
+         lang = self.GetPreferredLanguage(oldaddr)
+         self.ApprovedAddMember(newaddr, password, digest,
+                                ack=1, admin_notif=1, lang=lang)
+         # hack the account flags
+         if not flags:
+             try:
+                 del self.user_options[newaddr]
+             except KeyError:
+                 pass
+         else:
+             self.user_options[newaddr] = flags
+         # Delete the old address
+         self.DeleteMember(oldaddr, userack=1)
+         # Now, if the globally flag was set, then try to do this for every
+         # mailing list that had the oldaddr as a member.
+         if not globally:
+             return
+         for listname in Utils.list_names():
+             # Don't bother with ourselves
+             if listname == self.internal_name():
+                 continue
+             mlist = MailList(listname, lock=0)
+             if mlist.host_name <> self.host_name:
+                 continue
+             if not mlist.IsMember(oldaddr):
+                 continue
+             mlist.Lock()
+             try:
+                 mlist.ApprovedChangeMemberAddress(oldaddr, newaddr, 0)
+                 mlist.Save()
+             finally:
+                 mlist.Unlock()
+ 
      def IsMember(self, address):
          return len(Utils.FindMatchingAddresses(address, self.members,
***************
*** 1441,1444 ****
--- 1568,1572 ----
  
      def SetPreferredLanguage(self, name, lang):
+         assert lang in self.GetAvailableLanguages()
          lcname = name.lower()
          if lang <> self.preferred_language:
***************
*** 1458,1461 ****
          # blank field where the list owner is supposed to chose the list's
          # preferred language.
!         dirs.append(mm_cfg.DEFAULT_SERVER_LANGUAGE)
          return [d for d in dirs if mm_cfg.LC_DESCRIPTIONS.has_key(d)]
--- 1586,1590 ----
          # blank field where the list owner is supposed to chose the list's
          # preferred language.
!         if mm_cfg.DEFAULT_SERVER_LANGUAGE not in dirs:
!             dirs.append(mm_cfg.DEFAULT_SERVER_LANGUAGE)
          return [d for d in dirs if mm_cfg.LC_DESCRIPTIONS.has_key(d)]


_______________________________________________
Mailman-checkins mailing list
[EMAIL PROTECTED]
http://mail.python.org/mailman/listinfo/mailman-checkins

Reply via email to