Update of /cvsroot/mailman/mailman3/src/mailman/categories
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv31133/src/mailman/categories

Added Files:
      Tag: 3.0
        __init__.py category.py constants.py properties.py xmlparse.py 
Log Message:
Initial checkin of Mailman3 source

--- NEW FILE: __init__.py ---
# Copyright (C) 2004 Barry A. Warsaw
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.

import os

allcats = {}
allvars = {}

specdir = os.path.join(os.path.dirname(__file__), 'specs')



def startup():
    # Define here to avoid circular imports
    from mailman.categories.xmlparse import xmlparse
    # Parse all the category .xml files
    for file in os.listdir(specdir):
        catname, ext = os.path.splitext(file)
        if ext <> '.xml':
            continue
        fp = open(os.path.join(specdir, file))
        try:
            cat = xmlparse(fp)
        finally:
            fp.close()



def shutdown():
    pass

--- NEW FILE: category.py ---
# Copyright (C) 2004 Barry A. Warsaw
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.


from mailman.categories import allcats, allvars



class Category(object):
    def __init__(self, name, heading, description, parent=None):
        self.name = name
        self.heading = heading
        self.description = description
        self.parent = parent
        # An ordered list of all attributes described in the XML file.  This
        # includes variables and section headers.
        self.attributes = []
        # A mapping from variable names to variable (i.e. Property) objects
        self.variables = {}
        # Subcategories
        self.subcategories = {}
        if parent:
            allcats[parent.name + '.' + name] = self
        else:
            allcats[name] = self

    def addSection(self, section):
        self.attributes.append(section)

    addAction = addSection

    def addVariable(self, variable):
        self.attributes.append(variable)
        self.variables[variable.name] = variable
        allvars[variable.name] = (variable, self)

    def addSubcategory(self, subcat):
        self.subcategories[subcat.name] = subcat

--- NEW FILE: constants.py ---
# Copyright (C) 2004 Barry A. Warsaw
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.

"""Enums and other constants used by the category machinery."""

from mailman.interfaces.enum import Enum



class NoYes(Enum):
    No = False
    Yes = True


class AppendReplyTo(Enum):
    No = 0
    ThisList = 1
    Explicit = 2


class Languages(Enum):
    English = 0
    Spanish = 1
    Italian = 2


class EncodePrefixes(Enum):
    Never = 0
    Always = 1
    AsNeeded = 2


class DeliveryModes(Enum):
    Regular = 0
    Digest = 1
    Either = 2


class PersonalizationChoices(Enum):
    No = 0
    Yes = 1
    Full = 2


class DigestVolumeFrequency(Enum):
    Daily = 0
    Weekly = 1
    Quarterly = 2
    Monthly = 3
    Yearly = 4

--- NEW FILE: properties.py ---
# Copyright (C) 2004 Barry A. Warsaw
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.

from email.Utils import parseaddr, formataddr

from mailman import utils
from mailman.categories import constants
from mailman.cgi.zpt import MailmanTemplate
from mailman.interfaces.enum import Enum
from mailman.profile import getOrCreateProfile

NL = '\n'

def _(s):
    return s

class RadioStyle(Enum):
    Horizontal = 1
    Vertical = 2
    Stacked = 3



class Property(object):
    isattr = False
    isheader = False
    isaction = False



class Variable(Property):
    isattr = True

    def __init__(self, name, description=u'', details=u''):
        self.name = name
        self.description = description
        self.details = details

    def widget(self):
        pt = MailmanTemplate(self._zptPath() + '.pt', here=self)
        return pt.macros['widget']

    def format(self, val):
        """Format value for display in widget."""
        return val

    def parse(self, val):
        """Parse widget text value into Python objects."""
        return unicode(val[0])

    def _zptPath(self):
        raise NotImplementedError, self

    def default(self):
        raise NotImplementedError, self



class String(Variable):
    def _zptPath(self):
        return 'macro_string'

    def default(self):
        return ''


class Email(String):
    pass


class Text(Variable):
    def __init__(self, name, description=u'', details=u'', rows=5):
        super(Text, self).__init__(name, description, details)
        self.rows = rows

    def _zptPath(self):
        return 'macro_text'

    def default(self):
        return ''



class Number(Variable):
    def _zptPath(self):
        return 'macro_string'

    def parse(self, val):
        for type in (int, long, float):
            try:
                return type(val[0])
            except ValueError:
                pass
        raise ValueError(val)

    def default(self):
        return 0



class EmailList(Text):
    def format(self, val):
        # val is a sequence of IProfiles
        addrs = []
        for profile in val:
            addrs.append(formataddr((profile.realname, profile.address)))
        return NL.join(addrs)

    def parse(self, val):
        rtn = []
        # val is a list of lines, one email address per line
        for line in val[0].splitlines():
            name, addr = parseaddr(line)
            profile, isNew = getOrCreateProfile(addr)
            if isNew:
                # Create a password for this user
                password = utils.mksyllables(8)
                profile.realname = name
                profile.password = utils.hashPassword(password)
                # XXX Sent notification to owner
                from binascii import hexlify
                print 'address:', profile.address, \
                      'realname:', profile.realname, \
                      'password:', password, \
                      'userid:', hexlify(profile.userid)
            rtn.append(profile)
        return rtn

    def default(self):
        return []



# Container class for path expressions in choices
class _Bag:
    def __init__(self, label, enum):
        self.label = label
        self.value = enum


class Choices(Variable):
    def __init__(self, name, description=u'', details=u'',
                 enum='NoYes', labels=None, style='Horizontal'):
        super(Choices, self).__init__(name, description, details)
        # Some of the configuration information is in the node attributes.
        self.enum = getattr(constants, enum)
        if labels is not None:
            self.labels = labels.split(';')
        else:
            self.labels = [str(x) for x in self.enum]
        self.style = getattr(RadioStyle, style)

    def format(self, val):
        # Return the integer value of the EnumInstance
        return int(val)

    def parse(self, val):
        return self.enum[int(val[0])]

    def choices(self):
        for item in self.enum:
            intval = int(item)
            yield _Bag(self.labels[intval], intval)

    def default(self):
        return int(self.enum[0])



class Radio(Choices):
    def _zptPath(self):
        if self.style == RadioStyle.Horizontal:
            return 'macro_radiohoriz'
        elif self.style == RadioStyle.Vertical:
            return 'macro_radiovert'
        elif self.style == RadioStyle.Stacked:
            return 'macro_radiostacked'
        else:
            raise ValueError('bad style: %s' % self.style)



class Toggle(Radio):
    pass


class Pulldown(Choices):
    def _zptPath(self):
        return 'macro_pulldown'


class Select(Radio):
    def _zptPath(self):
        return 'macro_checkboxes'

    def format(self, val):
        return [int(x) for x in val]

    def parse(self, val):
        return [self.enum[int(x)] for x in val]

    def default(self):
        return []



class SectionHeader(Property):
    isheader = True

    def __init__(self, s):
        self.heading = s



class Action(Property):
    isaction = True

    def __init__(self, name, label, description):
        self.name = name
        self.label = label
        self.description = description

--- NEW FILE: xmlparse.py ---
# Copyright (C) 2004 Barry A. Warsaw
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the Free
# Software Foundation; either version 2 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
# more details.
#
# You should have received a copy of the GNU General Public License along with
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
# Place - Suite 330, Boston, MA 02111-1307, USA.

import re
import logging
from xml.dom import minidom
from xml.parsers.expat import ExpatError

from mailman.categories import properties
from mailman.categories.category import Category
from mailman.text.strings import dstring

SPACE = ' '
EMPTYSTRING = ''
RETMPL = '^<%s[^>]*?>(.*)</%s>$'

log = logging.getLogger('mailman.error')



def xmlstring(s):
    # Convert all whitespace to a single space, strip whitespace off the front
    # and end and turn the string into a $-substitutable string.
    return SPACE.join(s.strip().split())



def visit(node, kws):
    # Find the subnode values
    for child in node.childNodes:
        if child.nodeType == minidom.Node.ELEMENT_NODE:
            name = child.tagName
            text = xmlstring(child.toxml())
            # We have to strip off the start and end tags.
            mo = re.match(RETMPL % (name, name), text)
            # name is going to be a unicode, but Python doesn't allow
            # unicode objects as keywords to function calls.  Since
            # they must be ascii strings, we just coerce them here.
            kws[str(name)] = mo.group(1)



def makecategory(node, parent=None):
    name = xmlstring(node.getAttribute('name'))
    heading = xmlstring(node.getAttribute('heading'))
    descrip = xmlstring(node.getAttribute('description'))
    category = Category(name, heading, descrip, parent)
    # Now parse the subnodes, populating the category
    for node in node.childNodes:
        if node.nodeType <> minidom.Node.ELEMENT_NODE:
            continue
        if node.tagName == 'section':
            text = xmlstring(node.childNodes[0].data)
            header = properties.SectionHeader(text)
            category.addSection(header)
        elif node.tagName == 'variable':
            classname = xmlstring(node.getAttribute('type'))
            cls = getattr(properties, xmlstring(classname))
            # Initialize the constructor keywords, from the attributes in the
            # variable tag.  But remove the type attribute, which instead
            # describes class to use.
            kws = dict([(str(k), node.getAttribute(k))
                        for k in node.attributes.keys()])
            del kws['type']
            visit(node, kws)
            variable = cls(**kws)
            category.addVariable(variable)
        elif node.tagName == 'action':
            kws = {}
            visit(node, kws)
            action = properties.Action(**kws)
            category.addAction(action)
        elif node.tagName == 'category':
            subcat = makecategory(node, category)
            category.addSubcategory(subcat)
    return category



def xmlparse(fp):
    category = None
    # Parse the XML document and pull out the top-level category node.
    try:
        doc = minidom.parse(fp)
    except ExpatError:
        log.error('minidom parse error on file: %s', fp.name)
        raise
    doc.normalize()
    # Find the category node
    for node in doc.childNodes:
        if node.nodeType <> minidom.Node.ELEMENT_NODE:
            continue
        if node.tagName == 'category':
            category = makecategory(node)
            break
    assert category
    return category


_______________________________________________
Mailman-checkins mailing list
[EMAIL PROTECTED]
Unsubscribe: http://mail.python.org/mailman/options/mailman-checkins/archive%40jab.org

Reply via email to