# Copyright (C) 2021 by David Bremner # Licensed under the LGPL v3 https://www.gnu.org/licenses/lgpl-3.0.html import os import cmd2 import configparser from pathlib import PurePath from mailmanclient.client import Client from mailmanclient import Member class ModShell(cmd2.Cmd): intro = 'Type help or ? for a list of commands' def __init__(self, client, mlist): super().__init__() self.client = client; self.mlist = mlist; self.prompt = '({:s}) '.format(mlist.list_name) for command in ['shell', 'load', 'pyscript', 'shortcuts', 'alias', 'edit', 'history', 'py', 'set', 'unalias']: method='do_{:s}'.format(command) delattr(cmd2.Cmd,method) def print_held(self): self.held_messages = self.mlist.get_held_page (50,1) print () for msg in self.held_messages: print(msg.request_id, msg.subject, msg.sender) print () def matching_request_ids(self,text): candidates = [] prefix_len = len(text) for msg in self.held_messages: string = str(msg.request_id) if string.startswith(text): candidates.append(string) return candidates def complete_accept(self, text, line, begidx, endidx): return self.matching_request_ids(text) def do_accept(self, arg): ''' accept Post held message to mailing list. ''' try: n = int(arg) self.mlist.get_held_message (n).accept() except ValueError: print('Illegal request_id: {:s}'.format(arg)) return False def complete_verify(self, text, line, begidx, endidx): return self.matching_request_ids(text) def do_verify(self, arg): ''' Post held message, and accept further messages from the same sender. ''' try: n = int(arg) msg=self.mlist.get_held_message (n) member=get_nonmember(self.mlist, msg.sender) member.moderation_action = 'accept' member.save() msg.accept() except ValueError: print('Illegal request_id: {:s}'.format(arg)) return False def complete_discard(self, text, line, begidx, endidx): candidates = self.matching_request_ids(text) if "page".startswith(text): candidates.append('page') return candidates def do_discard(self, arg): ''' discard | page Discard held message(s) as spam. ''' try: if arg == 'page': for msg in self.held_messages: msg.discard() else: n = int(arg) self.mlist.get_held_message (n).discard() except ValueError: print('Illegal request_id: {:s}'.format(arg)) return False def preloop(self): self.print_held() def postcmd(self, stop, line): if (not stop): self.print_held() return stop # in later versions, this exists as a method of MailingList, but not in # version 3.2.1 def get_nonmember(mlist, email): """Get a nonmember. :param address: The email address of the member for this list. :return: A member proxy object. """ # In order to get the member object we query the REST API for # the member. Incase there is no matching subscription, an # HTTPError is returned instead. try: path = 'lists/{0}/nonmember/{1}'.format(mlist.list_id, email) response, content = mlist._connection.call(path) return Member(mlist._connection, content['self_link'], content) except HTTPError: raise ValueError('%s is not a known nonmember address of %s' % (email, mlist.fqdn_listname)) def main (): home = os.environ.get('HOME') xdg_config_home = os.environ.get('XDG_CONFIG_HOME') or \ os.path.join(home, '.config') config_path = PurePath (xdg_config_home, 'mm3mod', 'config.ini') config = configparser.ConfigParser () with open(config_path) as f: config.read_file (f) baseurl = config.get('rest', 'baseurl', fallback="http://localhost:8001/3.1/") user = config.get('rest', 'user', fallback='restadmin') password = config.get('rest', 'password') client = Client (baseurl, name=user, password=password); list_name = config.get('list','name') mlist = client.get_list (list_name) ModShell(client, mlist).cmdloop() if __name__ == "__main__": main()