Bugfix in new.py; added new user management.
This commit is contained in:
		
							parent
							
								
									fa974239f3
								
							
						
					
					
						commit
						eb52c1bb7d
					
				
					 30 changed files with 842 additions and 397 deletions
				
			
		
							
								
								
									
										10
									
								
								bin/new.py
									
										
									
									
									
								
							
							
						
						
									
										10
									
								
								bin/new.py
									
										
									
									
									
								
							| 
						 | 
					@ -5,7 +5,7 @@
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
import os, os.path, sys, shutil
 | 
					import os, os.path, sys, shutil
 | 
				
			||||||
from optparse import OptionParser
 | 
					from optparse import OptionParser
 | 
				
			||||||
from appy.shared.utils import cleanFolder
 | 
					from appy.shared.utils import cleanFolder, copyFolder
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class NewError(Exception): pass
 | 
					class NewError(Exception): pass
 | 
				
			||||||
| 
						 | 
					@ -103,7 +103,7 @@ class NewScript:
 | 
				
			||||||
                        os.system(cmd)
 | 
					                        os.system(cmd)
 | 
				
			||||||
                    else:
 | 
					                    else:
 | 
				
			||||||
                        # Copy thre product into the instance
 | 
					                        # Copy thre product into the instance
 | 
				
			||||||
                        shutil.copytree(folderName, destFolder)
 | 
					                        copyFolder(folderName, destFolder)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    uglyChunks = ('pkg_resources', '.declare_namespace(')
 | 
					    uglyChunks = ('pkg_resources', '.declare_namespace(')
 | 
				
			||||||
    def findPythonPackageInEgg(self, currentFolder):
 | 
					    def findPythonPackageInEgg(self, currentFolder):
 | 
				
			||||||
| 
						 | 
					@ -199,7 +199,7 @@ class NewScript:
 | 
				
			||||||
                # A Zope product. Copy its content in Products.
 | 
					                # A Zope product. Copy its content in Products.
 | 
				
			||||||
                innerFolder= self.getSubFolder(self.getSubFolder(eggMainFolder))
 | 
					                innerFolder= self.getSubFolder(self.getSubFolder(eggMainFolder))
 | 
				
			||||||
                destFolder = j(productsFolder, os.path.basename(innerFolder))
 | 
					                destFolder = j(productsFolder, os.path.basename(innerFolder))
 | 
				
			||||||
                shutil.copytree(innerFolder, destFolder)
 | 
					                copyFolder(innerFolder, destFolder)
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                # A standard Python package. Copy its content in lib/python.
 | 
					                # A standard Python package. Copy its content in lib/python.
 | 
				
			||||||
                # Go into the subFolder that is not EGG-INFO.
 | 
					                # Go into the subFolder that is not EGG-INFO.
 | 
				
			||||||
| 
						 | 
					@ -218,7 +218,7 @@ class NewScript:
 | 
				
			||||||
                    # libFolder.
 | 
					                    # libFolder.
 | 
				
			||||||
                    innerFolder = self.getSubFolder(eggFolder)
 | 
					                    innerFolder = self.getSubFolder(eggFolder)
 | 
				
			||||||
                    destFolder = j(productsFolder,os.path.basename(innerFolder))
 | 
					                    destFolder = j(productsFolder,os.path.basename(innerFolder))
 | 
				
			||||||
                    shutil.copytree(innerFolder, destFolder)
 | 
					                    copyFolder(innerFolder, destFolder)
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    packageFolder = self.findPythonPackageInEgg(eggFolder)
 | 
					                    packageFolder = self.findPythonPackageInEgg(eggFolder)
 | 
				
			||||||
                    # Create the destination folder(s) in the instance,
 | 
					                    # Create the destination folder(s) in the instance,
 | 
				
			||||||
| 
						 | 
					@ -252,7 +252,7 @@ class NewScript:
 | 
				
			||||||
                    else:
 | 
					                    else:
 | 
				
			||||||
                        destFolder = libFolder
 | 
					                        destFolder = libFolder
 | 
				
			||||||
                    destFolder = j(destFolder, os.path.basename(packageFolder))
 | 
					                    destFolder = j(destFolder, os.path.basename(packageFolder))
 | 
				
			||||||
                    shutil.copytree(packageFolder, destFolder)
 | 
					                    copyFolder(packageFolder, destFolder)
 | 
				
			||||||
        self.patchPlone(productsFolder, libFolder)
 | 
					        self.patchPlone(productsFolder, libFolder)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def manageArgs(self, args):
 | 
					    def manageArgs(self, args):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										121
									
								
								gen/__init__.py
									
										
									
									
									
								
							
							
						
						
									
										121
									
								
								gen/__init__.py
									
										
									
									
									
								
							| 
						 | 
					@ -5,8 +5,8 @@ from appy.gen.layout import Table
 | 
				
			||||||
from appy.gen.layout import defaultFieldLayouts
 | 
					from appy.gen.layout import defaultFieldLayouts
 | 
				
			||||||
from appy.gen.po import PoMessage
 | 
					from appy.gen.po import PoMessage
 | 
				
			||||||
from appy.gen.utils import sequenceTypes, PageDescr, GroupDescr, Keywords, \
 | 
					from appy.gen.utils import sequenceTypes, PageDescr, GroupDescr, Keywords, \
 | 
				
			||||||
                           FileWrapper
 | 
					                           FileWrapper, getClassName
 | 
				
			||||||
from appy.shared.data import countries
 | 
					from appy.shared.data import languages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Default Appy permissions -----------------------------------------------------
 | 
					# Default Appy permissions -----------------------------------------------------
 | 
				
			||||||
r, w, d = ('read', 'write', 'delete')
 | 
					r, w, d = ('read', 'write', 'delete')
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,8 @@ digit  = re.compile('[0-9]')
 | 
				
			||||||
alpha  = re.compile('[a-zA-Z0-9]')
 | 
					alpha  = re.compile('[a-zA-Z0-9]')
 | 
				
			||||||
letter = re.compile('[a-zA-Z]')
 | 
					letter = re.compile('[a-zA-Z]')
 | 
				
			||||||
nullValues = (None, '', ' ')
 | 
					nullValues = (None, '', ' ')
 | 
				
			||||||
validatorTypes = (types.FunctionType, type(re.compile('')))
 | 
					validatorTypes = (types.FunctionType, types.UnboundMethodType,
 | 
				
			||||||
 | 
					                  type(re.compile('')))
 | 
				
			||||||
emptyTuple = ()
 | 
					emptyTuple = ()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Descriptor classes used for refining descriptions of elements in types
 | 
					# Descriptor classes used for refining descriptions of elements in types
 | 
				
			||||||
| 
						 | 
					@ -383,14 +384,7 @@ class Type:
 | 
				
			||||||
        self.name = name
 | 
					        self.name = name
 | 
				
			||||||
        # Determine ids of i18n labels for this field
 | 
					        # Determine ids of i18n labels for this field
 | 
				
			||||||
        if not klass: prefix = appName
 | 
					        if not klass: prefix = appName
 | 
				
			||||||
        elif klass.__module__.endswith('.appyWrappers'):
 | 
					        else: prefix = getClassName(klass, appName)
 | 
				
			||||||
            prefix = appName + klass.__name__
 | 
					 | 
				
			||||||
        elif Tool in klass.__bases__:
 | 
					 | 
				
			||||||
            prefix = appName + 'Tool'
 | 
					 | 
				
			||||||
        elif Flavour in klass.__bases__:
 | 
					 | 
				
			||||||
            prefix = appName + 'Flavour'
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            prefix = klass.__module__.replace('.', '_') + '_' + klass.__name__
 | 
					 | 
				
			||||||
        self.labelId = '%s_%s' % (prefix, name)
 | 
					        self.labelId = '%s_%s' % (prefix, name)
 | 
				
			||||||
        self.descrId = self.labelId + '_descr'
 | 
					        self.descrId = self.labelId + '_descr'
 | 
				
			||||||
        self.helpId  = self.labelId + '_help'
 | 
					        self.helpId  = self.labelId + '_help'
 | 
				
			||||||
| 
						 | 
					@ -583,7 +577,7 @@ class Type:
 | 
				
			||||||
        value = self.getStorableValue(value)
 | 
					        value = self.getStorableValue(value)
 | 
				
			||||||
        if self.validator and (type(self.validator) in validatorTypes):
 | 
					        if self.validator and (type(self.validator) in validatorTypes):
 | 
				
			||||||
            obj = obj.appy()
 | 
					            obj = obj.appy()
 | 
				
			||||||
            if type(self.validator) == validatorTypes[0]:
 | 
					            if type(self.validator) != validatorTypes[-1]:
 | 
				
			||||||
                # It is a custom function. Execute it.
 | 
					                # It is a custom function. Execute it.
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    validValue = self.validator(obj, value)
 | 
					                    validValue = self.validator(obj, value)
 | 
				
			||||||
| 
						 | 
					@ -598,7 +592,7 @@ class Type:
 | 
				
			||||||
                    return str(e)
 | 
					                    return str(e)
 | 
				
			||||||
                except:
 | 
					                except:
 | 
				
			||||||
                    return obj.translate('%s_valid' % self.labelId)
 | 
					                    return obj.translate('%s_valid' % self.labelId)
 | 
				
			||||||
            elif type(self.validator) == validatorTypes[1]:
 | 
					            else:
 | 
				
			||||||
                # It is a regular expression
 | 
					                # It is a regular expression
 | 
				
			||||||
                if not self.validator.match(value):
 | 
					                if not self.validator.match(value):
 | 
				
			||||||
                    # If the regular expression is among the default ones, we
 | 
					                    # If the regular expression is among the default ones, we
 | 
				
			||||||
| 
						 | 
					@ -739,7 +733,7 @@ class String(Type):
 | 
				
			||||||
        # Maximum size is 34 chars
 | 
					        # Maximum size is 34 chars
 | 
				
			||||||
        if (len(v) < 8) or (len(v) > 34): return False
 | 
					        if (len(v) < 8) or (len(v) > 34): return False
 | 
				
			||||||
        # 2 first chars must be a valid country code
 | 
					        # 2 first chars must be a valid country code
 | 
				
			||||||
        if not countries.exists(v[:2].lower()): return False
 | 
					        if not languages.exists(v[:2].lower()): return False
 | 
				
			||||||
        # 2 next chars are a control code whose value must be between 0 and 96.
 | 
					        # 2 next chars are a control code whose value must be between 0 and 96.
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            code = int(v[2:4])
 | 
					            code = int(v[2:4])
 | 
				
			||||||
| 
						 | 
					@ -768,7 +762,7 @@ class String(Type):
 | 
				
			||||||
        for c in value[:4]:
 | 
					        for c in value[:4]:
 | 
				
			||||||
            if not letter.match(c): return False
 | 
					            if not letter.match(c): return False
 | 
				
			||||||
        # 2 next chars must be a valid country code
 | 
					        # 2 next chars must be a valid country code
 | 
				
			||||||
        if not countries.exists(value[4:6].lower()): return False
 | 
					        if not languages.exists(value[4:6].lower()): return False
 | 
				
			||||||
        # Last chars represent some location within a country (a city, a
 | 
					        # Last chars represent some location within a country (a city, a
 | 
				
			||||||
        # province...). They can only be letters or figures.
 | 
					        # province...). They can only be letters or figures.
 | 
				
			||||||
        for c in value[6:]:
 | 
					        for c in value[6:]:
 | 
				
			||||||
| 
						 | 
					@ -1356,24 +1350,71 @@ class Pod(Type):
 | 
				
			||||||
        self.validable = False
 | 
					        self.validable = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Workflow-specific types ------------------------------------------------------
 | 
					# Workflow-specific types ------------------------------------------------------
 | 
				
			||||||
 | 
					class Role:
 | 
				
			||||||
 | 
					    '''Represents a role.'''
 | 
				
			||||||
 | 
					    ploneRoles = ('Manager', 'Member', 'Owner', 'Reviewer', 'Anonymous',
 | 
				
			||||||
 | 
					                  'Authenticated')
 | 
				
			||||||
 | 
					    ploneLocalRoles = ('Owner',)
 | 
				
			||||||
 | 
					    ploneUngrantableRoles = ('Anonymous', 'Authenticated')
 | 
				
			||||||
 | 
					    def __init__(self, name, local=False, grantable=True):
 | 
				
			||||||
 | 
					        self.name = name
 | 
				
			||||||
 | 
					        self.local = local # True if it can be used as local role only.
 | 
				
			||||||
 | 
					        # It is a standard Plone role or an application-specific one?
 | 
				
			||||||
 | 
					        self.plone = name in self.ploneRoles
 | 
				
			||||||
 | 
					        if self.plone and (name in self.ploneLocalRoles):
 | 
				
			||||||
 | 
					            self.local = True
 | 
				
			||||||
 | 
					        self.grantable = grantable
 | 
				
			||||||
 | 
					        if self.plone and (name in self.ploneUngrantableRoles):
 | 
				
			||||||
 | 
					            self.grantable = False
 | 
				
			||||||
 | 
					        # An ungrantable role is one that is, like the Anonymous or
 | 
				
			||||||
 | 
					        # Authenticated roles, automatically attributed to a user.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class State:
 | 
					class State:
 | 
				
			||||||
    def __init__(self, permissions, initial=False, phase='main', show=True):
 | 
					    def __init__(self, permissions, initial=False, phase='main', show=True):
 | 
				
			||||||
        self.permissions = permissions #~{s_permissionName:[s_roleName]}~ This
 | 
					        self.usedRoles = {}
 | 
				
			||||||
        # dict gives, for every permission managed by a workflow, the list of
 | 
					        # The following dict ~{s_permissionName:[s_roleName|Role_role]}~
 | 
				
			||||||
        # roles for which the permission is granted in this state.
 | 
					        # gives, for every permission managed by a workflow, the list of roles
 | 
				
			||||||
        # Standard permissions are 'read', 'write' and 'delete'.
 | 
					        # for which the permission is granted in this state. Standard
 | 
				
			||||||
 | 
					        # permissions are 'read', 'write' and 'delete'.
 | 
				
			||||||
 | 
					        self.permissions = permissions 
 | 
				
			||||||
        self.initial = initial
 | 
					        self.initial = initial
 | 
				
			||||||
        self.phase = phase
 | 
					        self.phase = phase
 | 
				
			||||||
        self.show = show
 | 
					        self.show = show
 | 
				
			||||||
    def getUsedRoles(self):
 | 
					        # Standardize the way roles are expressed within self.permissions
 | 
				
			||||||
        res = set()
 | 
					        self.standardizeRoles()
 | 
				
			||||||
        for roleValue in self.permissions.itervalues():
 | 
					
 | 
				
			||||||
            if isinstance(roleValue, basestring):
 | 
					    def getRole(self, role):
 | 
				
			||||||
                res.add(roleValue)
 | 
					        '''p_role can be the name of a role or a Role instance. If it is the
 | 
				
			||||||
            elif roleValue:
 | 
					           name of a role, this method returns self.usedRoles[role] if it
 | 
				
			||||||
                for role in roleValue:
 | 
					           exists, or creates a Role instance, puts it in self.usedRoles and
 | 
				
			||||||
                    res.add(role)
 | 
					           returns it else. If it is a Role instance, the method stores it in
 | 
				
			||||||
        return list(res)
 | 
					           self.usedRoles if it not in it yet and returns it.'''
 | 
				
			||||||
 | 
					        if isinstance(role, basestring):
 | 
				
			||||||
 | 
					            if role in self.usedRoles:
 | 
				
			||||||
 | 
					                return self.usedRoles[role]
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                theRole = Role(role)
 | 
				
			||||||
 | 
					                self.usedRoles[role] = theRole
 | 
				
			||||||
 | 
					                return theRole
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            if role.name not in self.usedRoles:
 | 
				
			||||||
 | 
					                self.usedRoles[role.name] = role
 | 
				
			||||||
 | 
					            return role
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def standardizeRoles(self):
 | 
				
			||||||
 | 
					        '''This method converts, within self.permissions, every role to a
 | 
				
			||||||
 | 
					           Role instance. Every used role is stored in self.usedRoles.'''
 | 
				
			||||||
 | 
					        for permission, roles in self.permissions.items():
 | 
				
			||||||
 | 
					            if isinstance(roles, basestring) or isinstance(roles, Role):
 | 
				
			||||||
 | 
					                self.permissions[permission] = [self.getRole(roles)]
 | 
				
			||||||
 | 
					            elif roles:
 | 
				
			||||||
 | 
					                rolesList = []
 | 
				
			||||||
 | 
					                for role in roles:
 | 
				
			||||||
 | 
					                    rolesList.append(self.getRole(role))
 | 
				
			||||||
 | 
					                self.permissions[permission] = rolesList
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getUsedRoles(self): return self.usedRoles.values()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getTransitions(self, transitions, selfIsFromState=True):
 | 
					    def getTransitions(self, transitions, selfIsFromState=True):
 | 
				
			||||||
        '''Among p_transitions, returns those whose fromState is p_self (if
 | 
					        '''Among p_transitions, returns those whose fromState is p_self (if
 | 
				
			||||||
           p_selfIsFromState is True) or those whose toState is p_self (if
 | 
					           p_selfIsFromState is True) or those whose toState is p_self (if
 | 
				
			||||||
| 
						 | 
					@ -1383,6 +1424,7 @@ class State:
 | 
				
			||||||
            if self in t.getStates(selfIsFromState):
 | 
					            if self in t.getStates(selfIsFromState):
 | 
				
			||||||
                res.append(t)
 | 
					                res.append(t)
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getPermissions(self):
 | 
					    def getPermissions(self):
 | 
				
			||||||
        '''If you get the permissions mapping through self.permissions, dict
 | 
					        '''If you get the permissions mapping through self.permissions, dict
 | 
				
			||||||
           values may be of different types (a list of roles, a single role or
 | 
					           values may be of different types (a list of roles, a single role or
 | 
				
			||||||
| 
						 | 
					@ -1407,6 +1449,9 @@ class Transition:
 | 
				
			||||||
        # transition at several places in the state-transition diagram. It may
 | 
					        # transition at several places in the state-transition diagram. It may
 | 
				
			||||||
        # be useful for "undo" transitions, for example.
 | 
					        # be useful for "undo" transitions, for example.
 | 
				
			||||||
        self.condition = condition
 | 
					        self.condition = condition
 | 
				
			||||||
 | 
					        if isinstance(condition, basestring):
 | 
				
			||||||
 | 
					            # The condition specifies the name of a role.
 | 
				
			||||||
 | 
					            self.condition = Role(condition)
 | 
				
			||||||
        self.action = action
 | 
					        self.action = action
 | 
				
			||||||
        self.notify = notify # If not None, it is a method telling who must be
 | 
					        self.notify = notify # If not None, it is a method telling who must be
 | 
				
			||||||
        # notified by email after the transition has been executed.
 | 
					        # notified by email after the transition has been executed.
 | 
				
			||||||
| 
						 | 
					@ -1414,14 +1459,14 @@ class Transition:
 | 
				
			||||||
        # the transition. It will only be possible by code.
 | 
					        # the transition. It will only be possible by code.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getUsedRoles(self):
 | 
					    def getUsedRoles(self):
 | 
				
			||||||
        '''If self.condition is specifies a role.'''
 | 
					        '''self.condition can specify a role.'''
 | 
				
			||||||
        res = []
 | 
					        res = []
 | 
				
			||||||
        if isinstance(self.condition, basestring):
 | 
					        if isinstance(self.condition, Role):
 | 
				
			||||||
            res = [self.condition]
 | 
					            res.append(self.condition)
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def isSingle(self):
 | 
					    def isSingle(self):
 | 
				
			||||||
        '''If this transitions is only define between 2 states, returns True.
 | 
					        '''If this transition is only defined between 2 states, returns True.
 | 
				
			||||||
           Else, returns False.'''
 | 
					           Else, returns False.'''
 | 
				
			||||||
        return isinstance(self.states[0], State)
 | 
					        return isinstance(self.states[0], State)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1517,13 +1562,16 @@ class Selection:
 | 
				
			||||||
        return value
 | 
					        return value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class Tool:
 | 
					class Model: pass
 | 
				
			||||||
 | 
					class Tool(Model):
 | 
				
			||||||
    '''If you want so define a custom tool class, she must inherit from this
 | 
					    '''If you want so define a custom tool class, she must inherit from this
 | 
				
			||||||
       class.'''
 | 
					       class.'''
 | 
				
			||||||
class Flavour:
 | 
					class Flavour(Model):
 | 
				
			||||||
    '''A flavour represents a given group of configuration options. If you want
 | 
					    '''A flavour represents a given group of configuration options. If you want
 | 
				
			||||||
       to define a custom flavour class, she must inherit from this class.'''
 | 
					       to define a custom flavour class, she must inherit from this class.'''
 | 
				
			||||||
    def __init__(self, name): self.name = name
 | 
					    def __init__(self, name): self.name = name
 | 
				
			||||||
 | 
					class User(Model):
 | 
				
			||||||
 | 
					    '''If you want to extend or modify the User class, subclass me.'''
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class Config:
 | 
					class Config:
 | 
				
			||||||
| 
						 | 
					@ -1544,6 +1592,11 @@ class Config:
 | 
				
			||||||
        # For every language code that you specify in this list, appy.gen will
 | 
					        # For every language code that you specify in this list, appy.gen will
 | 
				
			||||||
        # produce and maintain translation files.
 | 
					        # produce and maintain translation files.
 | 
				
			||||||
        self.languages = ['en']
 | 
					        self.languages = ['en']
 | 
				
			||||||
 | 
					        # If languageSelector is True, on every page, a language selector will
 | 
				
			||||||
 | 
					        # allow to switch between languages defined in self.languages. Else,
 | 
				
			||||||
 | 
					        # the browser-defined language will be used for choosing the language
 | 
				
			||||||
 | 
					        # of returned pages.
 | 
				
			||||||
 | 
					        self.languageSelector = False
 | 
				
			||||||
        # People having one of these roles will be able to create instances
 | 
					        # People having one of these roles will be able to create instances
 | 
				
			||||||
        # of classes defined in your application.
 | 
					        # of classes defined in your application.
 | 
				
			||||||
        self.defaultCreators = ['Manager', 'Owner']
 | 
					        self.defaultCreators = ['Manager', 'Owner']
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
import os, os.path, sys, parser, symbol, token, types
 | 
					import os, os.path, sys, parser, symbol, token, types
 | 
				
			||||||
from appy.gen import Type, State, Config, Tool, Flavour
 | 
					from appy.gen import Type, State, Config, Tool, Flavour, User
 | 
				
			||||||
from appy.gen.descriptors import *
 | 
					from appy.gen.descriptors import *
 | 
				
			||||||
from appy.gen.utils import produceNiceMessage
 | 
					from appy.gen.utils import produceNiceMessage
 | 
				
			||||||
import appy.pod, appy.pod.renderer
 | 
					import appy.pod, appy.pod.renderer
 | 
				
			||||||
| 
						 | 
					@ -133,7 +133,8 @@ class Generator:
 | 
				
			||||||
        # Default descriptor classes
 | 
					        # Default descriptor classes
 | 
				
			||||||
        self.descriptorClasses = {
 | 
					        self.descriptorClasses = {
 | 
				
			||||||
            'class': ClassDescriptor, 'tool': ClassDescriptor,
 | 
					            'class': ClassDescriptor, 'tool': ClassDescriptor,
 | 
				
			||||||
            'flavour': ClassDescriptor, 'workflow': WorkflowDescriptor}
 | 
					            'flavour': ClassDescriptor, 'user': ClassDescriptor,
 | 
				
			||||||
 | 
					            'workflow': WorkflowDescriptor}
 | 
				
			||||||
        # The following dict contains a series of replacements that need to be
 | 
					        # The following dict contains a series of replacements that need to be
 | 
				
			||||||
        # applied to file templates to generate files.
 | 
					        # applied to file templates to generate files.
 | 
				
			||||||
        self.repls = {'applicationName': self.applicationName,
 | 
					        self.repls = {'applicationName': self.applicationName,
 | 
				
			||||||
| 
						 | 
					@ -143,6 +144,7 @@ class Generator:
 | 
				
			||||||
        self.classes = []
 | 
					        self.classes = []
 | 
				
			||||||
        self.tool = None
 | 
					        self.tool = None
 | 
				
			||||||
        self.flavour = None
 | 
					        self.flavour = None
 | 
				
			||||||
 | 
					        self.user = None
 | 
				
			||||||
        self.workflows = []
 | 
					        self.workflows = []
 | 
				
			||||||
        self.initialize()
 | 
					        self.initialize()
 | 
				
			||||||
        self.config = Config.getDefault()
 | 
					        self.config = Config.getDefault()
 | 
				
			||||||
| 
						 | 
					@ -235,6 +237,12 @@ class Generator:
 | 
				
			||||||
                                self.flavour = klass(moduleElem, attrs, self)
 | 
					                                self.flavour = klass(moduleElem, attrs, self)
 | 
				
			||||||
                            else:
 | 
					                            else:
 | 
				
			||||||
                                self.flavour.update(moduleElem, attrs)
 | 
					                                self.flavour.update(moduleElem, attrs)
 | 
				
			||||||
 | 
					                        elif issubclass(moduleElem, User):
 | 
				
			||||||
 | 
					                            if not self.user:
 | 
				
			||||||
 | 
					                                klass = self.descriptorClasses['user']
 | 
				
			||||||
 | 
					                                self.user = klass(moduleElem, attrs, self)
 | 
				
			||||||
 | 
					                            else:
 | 
				
			||||||
 | 
					                                self.user.update(moduleElem, attrs)
 | 
				
			||||||
                        else:
 | 
					                        else:
 | 
				
			||||||
                            descriptorClass = self.descriptorClasses['class']
 | 
					                            descriptorClass = self.descriptorClasses['class']
 | 
				
			||||||
                            descriptor = descriptorClass(moduleElem,attrs, self)
 | 
					                            descriptor = descriptorClass(moduleElem,attrs, self)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -185,6 +185,6 @@ class Table(LayoutElement):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
defaultPageLayouts  = {
 | 
					defaultPageLayouts  = {
 | 
				
			||||||
    'view': Table('m;-s|-n!-w;-b|'), 'edit': Table('m;-s|-n!-w;-b|')}
 | 
					    'view': Table('m;-s|-n!-w|-b|'), 'edit': Table('m;-w|-b|')}
 | 
				
			||||||
defaultFieldLayouts = {'view': 'l;f!', 'edit': 'lrv;f!'}
 | 
					defaultFieldLayouts = {'view': 'l;f!', 'edit': 'lrv;f!'}
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -12,9 +12,9 @@ import appy.gen
 | 
				
			||||||
import appy.gen.descriptors
 | 
					import appy.gen.descriptors
 | 
				
			||||||
from appy.gen.po import PoMessage
 | 
					from appy.gen.po import PoMessage
 | 
				
			||||||
from appy.gen import Date, String, State, Transition, Type, Search, \
 | 
					from appy.gen import Date, String, State, Transition, Type, Search, \
 | 
				
			||||||
                     Selection, Import
 | 
					                     Selection, Import, Role
 | 
				
			||||||
from appy.gen.utils import GroupDescr, PageDescr, produceNiceMessage, \
 | 
					from appy.gen.utils import GroupDescr, PageDescr, produceNiceMessage, \
 | 
				
			||||||
     sequenceTypes
 | 
					     sequenceTypes, getClassName
 | 
				
			||||||
TABS = 4 # Number of blanks in a Python indentation.
 | 
					TABS = 4 # Number of blanks in a Python indentation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					@ -110,13 +110,7 @@ class FieldDescriptor:
 | 
				
			||||||
        # Update the list of referers
 | 
					        # Update the list of referers
 | 
				
			||||||
        self.generator.addReferer(self, relationship)
 | 
					        self.generator.addReferer(self, relationship)
 | 
				
			||||||
        # Add the widget label for the back reference
 | 
					        # Add the widget label for the back reference
 | 
				
			||||||
        refClassName = ClassDescriptor.getClassName(self.appyType.klass)
 | 
					        refClassName = getClassName(self.appyType.klass, self.applicationName)
 | 
				
			||||||
        if issubclass(self.appyType.klass, ModelClass):
 | 
					 | 
				
			||||||
            refClassName = self.applicationName + self.appyType.klass.__name__
 | 
					 | 
				
			||||||
        elif issubclass(self.appyType.klass, appy.gen.Tool):
 | 
					 | 
				
			||||||
            refClassName = '%sTool' % self.applicationName
 | 
					 | 
				
			||||||
        elif issubclass(self.appyType.klass, appy.gen.Flavour):
 | 
					 | 
				
			||||||
            refClassName = '%sFlavour' % self.applicationName
 | 
					 | 
				
			||||||
        backLabel = "%s_%s" % (refClassName, self.appyType.back.attribute)
 | 
					        backLabel = "%s_%s" % (refClassName, self.appyType.back.attribute)
 | 
				
			||||||
        poMsg = PoMessage(backLabel, '', self.appyType.back.attribute)
 | 
					        poMsg = PoMessage(backLabel, '', self.appyType.back.attribute)
 | 
				
			||||||
        poMsg.produceNiceDefault()
 | 
					        poMsg.produceNiceDefault()
 | 
				
			||||||
| 
						 | 
					@ -240,7 +234,7 @@ class ClassDescriptor(appy.gen.descriptors.ClassDescriptor):
 | 
				
			||||||
        # for child classes of this class as well, but at this time we don't
 | 
					        # for child classes of this class as well, but at this time we don't
 | 
				
			||||||
        # know yet every sub-class. So we store field definitions here; the
 | 
					        # know yet every sub-class. So we store field definitions here; the
 | 
				
			||||||
        # Generator will propagate them later.
 | 
					        # Generator will propagate them later.
 | 
				
			||||||
        self.name = self.getClassName(klass)
 | 
					        self.name = getClassName(self.klass, generator.applicationName)
 | 
				
			||||||
        self.predefined = False
 | 
					        self.predefined = False
 | 
				
			||||||
        self.customized = False
 | 
					        self.customized = False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -276,11 +270,6 @@ class ClassDescriptor(appy.gen.descriptors.ClassDescriptor):
 | 
				
			||||||
                    # Currently, we generate Archetypes fields for Refs only.
 | 
					                    # Currently, we generate Archetypes fields for Refs only.
 | 
				
			||||||
                    self.schema += '\n' + fieldDef
 | 
					                    self.schema += '\n' + fieldDef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @staticmethod
 | 
					 | 
				
			||||||
    def getClassName(klass):
 | 
					 | 
				
			||||||
        '''Generates the name of the corresponding Archetypes class.'''
 | 
					 | 
				
			||||||
        return klass.__module__.replace('.', '_') + '_' + klass.__name__
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def isAbstract(self):
 | 
					    def isAbstract(self):
 | 
				
			||||||
        '''Is self.klass abstract?'''
 | 
					        '''Is self.klass abstract?'''
 | 
				
			||||||
        res = False
 | 
					        res = False
 | 
				
			||||||
| 
						 | 
					@ -322,7 +311,14 @@ class ClassDescriptor(appy.gen.descriptors.ClassDescriptor):
 | 
				
			||||||
        '''Gets the specific creators defined for this class.'''
 | 
					        '''Gets the specific creators defined for this class.'''
 | 
				
			||||||
        res = []
 | 
					        res = []
 | 
				
			||||||
        if self.klass.__dict__.has_key('creators') and self.klass.creators:
 | 
					        if self.klass.__dict__.has_key('creators') and self.klass.creators:
 | 
				
			||||||
            res += list(self.klass.creators)
 | 
					            for creator in self.klass.creators:
 | 
				
			||||||
 | 
					                if isinstance(creator, Role):
 | 
				
			||||||
 | 
					                    if creator.local:
 | 
				
			||||||
 | 
					                        raise 'Local role "%s" cannot be used as a creator.' % \
 | 
				
			||||||
 | 
					                              creator.name
 | 
				
			||||||
 | 
					                    res.append(creator)
 | 
				
			||||||
 | 
					                else:
 | 
				
			||||||
 | 
					                    res.append(Role(creator))
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getCreateMean(self, type='Import'):
 | 
					    def getCreateMean(self, type='Import'):
 | 
				
			||||||
| 
						 | 
					@ -379,7 +375,6 @@ class ToolClassDescriptor(ClassDescriptor):
 | 
				
			||||||
    '''Represents the POD-specific fields that must be added to the tool.'''
 | 
					    '''Represents the POD-specific fields that must be added to the tool.'''
 | 
				
			||||||
    def __init__(self, klass, generator):
 | 
					    def __init__(self, klass, generator):
 | 
				
			||||||
        ClassDescriptor.__init__(self,klass,klass._appy_attributes[:],generator)
 | 
					        ClassDescriptor.__init__(self,klass,klass._appy_attributes[:],generator)
 | 
				
			||||||
        self.name = '%sTool' % generator.applicationName
 | 
					 | 
				
			||||||
        self.modelClass = self.klass
 | 
					        self.modelClass = self.klass
 | 
				
			||||||
        self.predefined = True
 | 
					        self.predefined = True
 | 
				
			||||||
        self.customized = False
 | 
					        self.customized = False
 | 
				
			||||||
| 
						 | 
					@ -405,7 +400,6 @@ class FlavourClassDescriptor(ClassDescriptor):
 | 
				
			||||||
       for the generated application.'''
 | 
					       for the generated application.'''
 | 
				
			||||||
    def __init__(self, klass, generator):
 | 
					    def __init__(self, klass, generator):
 | 
				
			||||||
        ClassDescriptor.__init__(self,klass,klass._appy_attributes[:],generator)
 | 
					        ClassDescriptor.__init__(self,klass,klass._appy_attributes[:],generator)
 | 
				
			||||||
        self.name = '%sFlavour' % generator.applicationName
 | 
					 | 
				
			||||||
        self.attributesByClass = klass._appy_classes
 | 
					        self.attributesByClass = klass._appy_classes
 | 
				
			||||||
        self.modelClass = self.klass
 | 
					        self.modelClass = self.klass
 | 
				
			||||||
        self.predefined = True
 | 
					        self.predefined = True
 | 
				
			||||||
| 
						 | 
					@ -431,13 +425,37 @@ class PodTemplateClassDescriptor(ClassDescriptor):
 | 
				
			||||||
    '''Represents a POD template.'''
 | 
					    '''Represents a POD template.'''
 | 
				
			||||||
    def __init__(self, klass, generator):
 | 
					    def __init__(self, klass, generator):
 | 
				
			||||||
        ClassDescriptor.__init__(self,klass,klass._appy_attributes[:],generator)
 | 
					        ClassDescriptor.__init__(self,klass,klass._appy_attributes[:],generator)
 | 
				
			||||||
        self.name = '%sPodTemplate' % generator.applicationName
 | 
					 | 
				
			||||||
        self.modelClass = self.klass
 | 
					        self.modelClass = self.klass
 | 
				
			||||||
        self.predefined = True
 | 
					        self.predefined = True
 | 
				
			||||||
        self.customized = False
 | 
					        self.customized = False
 | 
				
			||||||
    def getParents(self, allClasses=()): return ['PodTemplate']
 | 
					    def getParents(self, allClasses=()): return ['PodTemplate']
 | 
				
			||||||
    def isRoot(self): return False
 | 
					    def isRoot(self): return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class UserClassDescriptor(ClassDescriptor):
 | 
				
			||||||
 | 
					    '''Represents an Archetypes-compliant class that corresponds to the User
 | 
				
			||||||
 | 
					       for the generated application.'''
 | 
				
			||||||
 | 
					    def __init__(self, klass, generator):
 | 
				
			||||||
 | 
					        ClassDescriptor.__init__(self,klass,klass._appy_attributes[:],generator)
 | 
				
			||||||
 | 
					        self.modelClass = self.klass
 | 
				
			||||||
 | 
					        self.predefined = True
 | 
				
			||||||
 | 
					        self.customized = False
 | 
				
			||||||
 | 
					    def getParents(self, allClasses=()):
 | 
				
			||||||
 | 
					        res = ['User']
 | 
				
			||||||
 | 
					        if self.customized:
 | 
				
			||||||
 | 
					            res.append('%s.%s' % (self.klass.__module__, self.klass.__name__))
 | 
				
			||||||
 | 
					        return res
 | 
				
			||||||
 | 
					    def update(self, klass, attributes):
 | 
				
			||||||
 | 
					        '''This method is called by the generator when he finds a custom user
 | 
				
			||||||
 | 
					           definition. We must then add the custom user elements in this
 | 
				
			||||||
 | 
					           default User descriptor.'''
 | 
				
			||||||
 | 
					        self.orderedAttributes += attributes
 | 
				
			||||||
 | 
					        self.klass = klass
 | 
				
			||||||
 | 
					        self.customized = True
 | 
				
			||||||
 | 
					    def isFolder(self, klass=None): return True
 | 
				
			||||||
 | 
					    def isRoot(self): return False
 | 
				
			||||||
 | 
					    def generateSchema(self):
 | 
				
			||||||
 | 
					        ClassDescriptor.generateSchema(self, configClass=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class WorkflowDescriptor(appy.gen.descriptors.WorkflowDescriptor):
 | 
					class WorkflowDescriptor(appy.gen.descriptors.WorkflowDescriptor):
 | 
				
			||||||
    '''Represents a workflow.'''
 | 
					    '''Represents a workflow.'''
 | 
				
			||||||
    # How to map Appy permissions to Plone permissions ?
 | 
					    # How to map Appy permissions to Plone permissions ?
 | 
				
			||||||
| 
						 | 
					@ -497,11 +515,11 @@ class WorkflowDescriptor(appy.gen.descriptors.WorkflowDescriptor):
 | 
				
			||||||
            permissionsMapping = {}
 | 
					            permissionsMapping = {}
 | 
				
			||||||
            for permission, roles in state.getPermissions().iteritems():
 | 
					            for permission, roles in state.getPermissions().iteritems():
 | 
				
			||||||
                for plonePerm in self.getPlonePermissions(permission):
 | 
					                for plonePerm in self.getPlonePermissions(permission):
 | 
				
			||||||
                    permissionsMapping[plonePerm] = roles
 | 
					                    permissionsMapping[plonePerm] = [r.name for r in roles]
 | 
				
			||||||
            # Add 'Review portal content' to anyone; this is not a security
 | 
					            # Add 'Review portal content' to anyone; this is not a security
 | 
				
			||||||
            # problem because we limit the triggering of every transition
 | 
					            # problem because we limit the triggering of every transition
 | 
				
			||||||
            # individually.
 | 
					            # individually.
 | 
				
			||||||
            allRoles = self.generator.getAllUsedRoles()
 | 
					            allRoles = [r.name for r in self.generator.getAllUsedRoles()]
 | 
				
			||||||
            if 'Manager' not in allRoles: allRoles.append('Manager')
 | 
					            if 'Manager' not in allRoles: allRoles.append('Manager')
 | 
				
			||||||
            permissionsMapping['Review portal content'] = allRoles
 | 
					            permissionsMapping['Review portal content'] = allRoles
 | 
				
			||||||
            res[stateName] = (tNames, permissionsMapping)
 | 
					            res[stateName] = (tNames, permissionsMapping)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,10 +7,12 @@ import appy.gen
 | 
				
			||||||
from appy.gen import *
 | 
					from appy.gen import *
 | 
				
			||||||
from appy.gen.po import PoMessage, PoFile, PoParser
 | 
					from appy.gen.po import PoMessage, PoFile, PoParser
 | 
				
			||||||
from appy.gen.generator import Generator as AbstractGenerator
 | 
					from appy.gen.generator import Generator as AbstractGenerator
 | 
				
			||||||
from model import ModelClass, PodTemplate, Flavour, Tool
 | 
					from appy.gen.utils import getClassName
 | 
				
			||||||
 | 
					from model import ModelClass, PodTemplate, User, Flavour, Tool
 | 
				
			||||||
from descriptors import FieldDescriptor, ClassDescriptor, \
 | 
					from descriptors import FieldDescriptor, ClassDescriptor, \
 | 
				
			||||||
                        WorkflowDescriptor, ToolClassDescriptor, \
 | 
					                        WorkflowDescriptor, ToolClassDescriptor, \
 | 
				
			||||||
                        FlavourClassDescriptor, PodTemplateClassDescriptor
 | 
					                        FlavourClassDescriptor, PodTemplateClassDescriptor, \
 | 
				
			||||||
 | 
					                        UserClassDescriptor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Common methods that need to be defined on every Archetype class --------------
 | 
					# Common methods that need to be defined on every Archetype class --------------
 | 
				
			||||||
COMMON_METHODS = '''
 | 
					COMMON_METHODS = '''
 | 
				
			||||||
| 
						 | 
					@ -36,12 +38,14 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
        self.tool = ToolClassDescriptor(Tool, self)
 | 
					        self.tool = ToolClassDescriptor(Tool, self)
 | 
				
			||||||
        self.flavour = FlavourClassDescriptor(Flavour, self)
 | 
					        self.flavour = FlavourClassDescriptor(Flavour, self)
 | 
				
			||||||
        self.podTemplate = PodTemplateClassDescriptor(PodTemplate, self)
 | 
					        self.podTemplate = PodTemplateClassDescriptor(PodTemplate, self)
 | 
				
			||||||
 | 
					        self.user = UserClassDescriptor(User, self)
 | 
				
			||||||
        # i18n labels to generate
 | 
					        # i18n labels to generate
 | 
				
			||||||
        self.labels = [] # i18n labels
 | 
					        self.labels = [] # i18n labels
 | 
				
			||||||
        self.toolName = '%sTool' % self.applicationName
 | 
					        self.toolName = '%sTool' % self.applicationName
 | 
				
			||||||
        self.flavourName = '%sFlavour' % self.applicationName
 | 
					        self.flavourName = '%sFlavour' % self.applicationName
 | 
				
			||||||
        self.toolInstanceName = 'portal_%s' % self.applicationName.lower()
 | 
					        self.toolInstanceName = 'portal_%s' % self.applicationName.lower()
 | 
				
			||||||
        self.podTemplateName = '%sPodTemplate' % self.applicationName
 | 
					        self.podTemplateName = '%sPodTemplate' % self.applicationName
 | 
				
			||||||
 | 
					        self.userName = '%sUser' % self.applicationName
 | 
				
			||||||
        self.portletName = '%s_portlet' % self.applicationName.lower()
 | 
					        self.portletName = '%s_portlet' % self.applicationName.lower()
 | 
				
			||||||
        self.queryName = '%s_query' % self.applicationName.lower()
 | 
					        self.queryName = '%s_query' % self.applicationName.lower()
 | 
				
			||||||
        self.skinsFolder = 'skins/%s' % self.applicationName
 | 
					        self.skinsFolder = 'skins/%s' % self.applicationName
 | 
				
			||||||
| 
						 | 
					@ -54,7 +58,7 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
            {'toolName': self.toolName, 'flavourName': self.flavourName,
 | 
					            {'toolName': self.toolName, 'flavourName': self.flavourName,
 | 
				
			||||||
             'portletName': self.portletName, 'queryName': self.queryName,
 | 
					             'portletName': self.portletName, 'queryName': self.queryName,
 | 
				
			||||||
             'toolInstanceName': self.toolInstanceName,
 | 
					             'toolInstanceName': self.toolInstanceName,
 | 
				
			||||||
             'podTemplateName': self.podTemplateName,
 | 
					             'podTemplateName': self.podTemplateName, 'userName': self.userName,
 | 
				
			||||||
             'commonMethods': commonMethods})
 | 
					             'commonMethods': commonMethods})
 | 
				
			||||||
        self.referers = {}
 | 
					        self.referers = {}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -149,18 +153,19 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
            msg('image_required',       '', msg.IMAGE_REQUIRED),
 | 
					            msg('image_required',       '', msg.IMAGE_REQUIRED),
 | 
				
			||||||
        ]
 | 
					        ]
 | 
				
			||||||
        # Create a label for every role added by this application
 | 
					        # Create a label for every role added by this application
 | 
				
			||||||
        for role in self.getAllUsedRoles(appOnly=True):
 | 
					        for role in self.getAllUsedRoles():
 | 
				
			||||||
            self.labels.append(msg('role_%s' % role,'', role, niceDefault=True))
 | 
					            self.labels.append(msg('role_%s' % role.name,'', role.name,
 | 
				
			||||||
 | 
					                                   niceDefault=True))
 | 
				
			||||||
        # Create basic files (config.py, Install.py, etc)
 | 
					        # Create basic files (config.py, Install.py, etc)
 | 
				
			||||||
        self.generateTool()
 | 
					        self.generateTool()
 | 
				
			||||||
        self.generateConfig()
 | 
					        self.generateConfig()
 | 
				
			||||||
        self.generateInit()
 | 
					        self.generateInit()
 | 
				
			||||||
        self.generateInstall()
 | 
					 | 
				
			||||||
        self.generateWorkflows()
 | 
					        self.generateWorkflows()
 | 
				
			||||||
        self.generateWrappers()
 | 
					        self.generateWrappers()
 | 
				
			||||||
        self.generateTests()
 | 
					        self.generateTests()
 | 
				
			||||||
        if self.config.frontPage:
 | 
					        if self.config.frontPage:
 | 
				
			||||||
            self.generateFrontPage()
 | 
					            self.generateFrontPage()
 | 
				
			||||||
 | 
					        self.copyFile('Install.py', self.repls, destFolder='Extensions')
 | 
				
			||||||
        self.copyFile('configure.zcml', self.repls)
 | 
					        self.copyFile('configure.zcml', self.repls)
 | 
				
			||||||
        self.copyFile('import_steps.xml', self.repls,
 | 
					        self.copyFile('import_steps.xml', self.repls,
 | 
				
			||||||
                      destFolder='profiles/default')
 | 
					                      destFolder='profiles/default')
 | 
				
			||||||
| 
						 | 
					@ -227,41 +232,49 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
            if not poFile.generated:
 | 
					            if not poFile.generated:
 | 
				
			||||||
                poFile.generate()
 | 
					                poFile.generate()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    ploneRoles = ('Manager', 'Member', 'Owner', 'Reviewer', 'Anonymous')
 | 
					    def getAllUsedRoles(self, plone=None, local=None, grantable=None):
 | 
				
			||||||
    def getAllUsedRoles(self, appOnly=False):
 | 
					 | 
				
			||||||
        '''Produces a list of all the roles used within all workflows and
 | 
					        '''Produces a list of all the roles used within all workflows and
 | 
				
			||||||
           classes defined in this application. If p_appOnly is True, it
 | 
					           classes defined in this application.
 | 
				
			||||||
           returns only roles which are specific to this application (ie it
 | 
					
 | 
				
			||||||
           removes predefined Plone roles like Member, Manager, etc.'''
 | 
					           If p_plone is True, it keeps only Plone-standard roles; if p_plone
 | 
				
			||||||
        res = []
 | 
					           is False, it keeps only roles which are specific to this application;
 | 
				
			||||||
 | 
					           if p_plone is None it has no effect (so it keeps both roles).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					           If p_local is True, it keeps only local roles (ie, roles that can
 | 
				
			||||||
 | 
					           only be granted locally); if p_local is False, it keeps only "global"
 | 
				
			||||||
 | 
					           roles; if p_local is None it has no effect (so it keeps both roles).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					           If p_grantable is True, it keeps only roles that the admin can
 | 
				
			||||||
 | 
					           grant; if p_grantable is False, if keeps only ungrantable roles (ie
 | 
				
			||||||
 | 
					           those that are implicitly granted by the system like role
 | 
				
			||||||
 | 
					           "Authenticated"); if p_grantable is None it keeps both roles.'''
 | 
				
			||||||
 | 
					        allRoles = {} # ~{s_roleName:Role_role}~
 | 
				
			||||||
 | 
					        # Gather roles from workflow states and transitions
 | 
				
			||||||
        for wfDescr in self.workflows:
 | 
					        for wfDescr in self.workflows:
 | 
				
			||||||
            # Browse states and transitions
 | 
					 | 
				
			||||||
            for attr in dir(wfDescr.klass):
 | 
					            for attr in dir(wfDescr.klass):
 | 
				
			||||||
                attrValue = getattr(wfDescr.klass, attr)
 | 
					                attrValue = getattr(wfDescr.klass, attr)
 | 
				
			||||||
                if isinstance(attrValue, State) or \
 | 
					                if isinstance(attrValue, State) or \
 | 
				
			||||||
                   isinstance(attrValue, Transition):
 | 
					                   isinstance(attrValue, Transition):
 | 
				
			||||||
                    res += attrValue.getUsedRoles()
 | 
					                    for role in attrValue.getUsedRoles():
 | 
				
			||||||
 | 
					                        if role.name not in allRoles:
 | 
				
			||||||
 | 
					                            allRoles[role.name] = role
 | 
				
			||||||
 | 
					        # Gather roles from "creators" attributes from every class
 | 
				
			||||||
        for cDescr in self.getClasses(include='all'):
 | 
					        for cDescr in self.getClasses(include='all'):
 | 
				
			||||||
            res += cDescr.getCreators()
 | 
					            for role in cDescr.getCreators():
 | 
				
			||||||
        res = list(set(res))
 | 
					                if role.name not in allRoles:
 | 
				
			||||||
        if appOnly:
 | 
					                    allRoles[role.name] = role
 | 
				
			||||||
            for ploneRole in self.ploneRoles:
 | 
					        res = allRoles.values()
 | 
				
			||||||
                if ploneRole in res:
 | 
					        # Filter the result according to parameters
 | 
				
			||||||
                    res.remove(ploneRole)
 | 
					        for p in ('plone', 'local', 'grantable'):
 | 
				
			||||||
 | 
					            if eval(p) != None:
 | 
				
			||||||
 | 
					                res = [r for r in res if eval('r.%s == %s' % (p, p))]
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def addReferer(self, fieldDescr, relationship):
 | 
					    def addReferer(self, fieldDescr, relationship):
 | 
				
			||||||
        '''p_fieldDescr is a Ref type definition. We will create in config.py a
 | 
					        '''p_fieldDescr is a Ref type definition. We will create in config.py a
 | 
				
			||||||
           dict that lists all back references, by type.'''
 | 
					           dict that lists all back references, by type.'''
 | 
				
			||||||
        k = fieldDescr.appyType.klass
 | 
					        k = fieldDescr.appyType.klass
 | 
				
			||||||
        if issubclass(k, ModelClass):
 | 
					        refClassName = getClassName(k, self.applicationName)
 | 
				
			||||||
            refClassName = self.applicationName + k.__name__
 | 
					 | 
				
			||||||
        elif issubclass(k, appy.gen.Tool):
 | 
					 | 
				
			||||||
            refClassName = '%sTool' % self.applicationName
 | 
					 | 
				
			||||||
        elif issubclass(k, appy.gen.Flavour):
 | 
					 | 
				
			||||||
            refClassName = '%sFlavour' % self.applicationName
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            refClassName = ClassDescriptor.getClassName(k)
 | 
					 | 
				
			||||||
        if not self.referers.has_key(refClassName):
 | 
					        if not self.referers.has_key(refClassName):
 | 
				
			||||||
            self.referers[refClassName] = []
 | 
					            self.referers[refClassName] = []
 | 
				
			||||||
        self.referers[refClassName].append( (fieldDescr, relationship))
 | 
					        self.referers[refClassName].append( (fieldDescr, relationship))
 | 
				
			||||||
| 
						 | 
					@ -277,6 +290,59 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def generateConfig(self):
 | 
					    def generateConfig(self):
 | 
				
			||||||
 | 
					        repls = self.repls.copy()
 | 
				
			||||||
 | 
					        # Compute imports
 | 
				
			||||||
 | 
					        imports = ['import %s' % self.applicationName]
 | 
				
			||||||
 | 
					        classDescrs = self.getClasses(include='custom')
 | 
				
			||||||
 | 
					        for classDescr in (classDescrs + self.workflows):
 | 
				
			||||||
 | 
					            theImport = 'import %s' % classDescr.klass.__module__
 | 
				
			||||||
 | 
					            if theImport not in imports:
 | 
				
			||||||
 | 
					                imports.append(theImport)
 | 
				
			||||||
 | 
					        repls['imports'] = '\n'.join(imports)
 | 
				
			||||||
 | 
					        # Compute default add roles
 | 
				
			||||||
 | 
					        repls['defaultAddRoles'] = ','.join(
 | 
				
			||||||
 | 
					                              ['"%s"' % r for r in self.config.defaultCreators])
 | 
				
			||||||
 | 
					        # Compute list of add permissions
 | 
				
			||||||
 | 
					        addPermissions = ''
 | 
				
			||||||
 | 
					        for classDescr in self.getClasses(include='allButTool'):
 | 
				
			||||||
 | 
					            addPermissions += '    "%s":"%s: Add %s",\n' % (classDescr.name,
 | 
				
			||||||
 | 
					                self.applicationName, classDescr.name)
 | 
				
			||||||
 | 
					        repls['addPermissions'] = addPermissions
 | 
				
			||||||
 | 
					        # Compute root classes
 | 
				
			||||||
 | 
					        rootClasses = ''
 | 
				
			||||||
 | 
					        for classDescr in self.classes:
 | 
				
			||||||
 | 
					            if classDescr.isRoot():
 | 
				
			||||||
 | 
					                rootClasses += "'%s'," % classDescr.name
 | 
				
			||||||
 | 
					        repls['rootClasses'] = rootClasses
 | 
				
			||||||
 | 
					        # Compute list of class definitions
 | 
				
			||||||
 | 
					        appClasses = []
 | 
				
			||||||
 | 
					        for classDescr in self.classes:
 | 
				
			||||||
 | 
					            k = classDescr.klass
 | 
				
			||||||
 | 
					            appClasses.append('%s.%s' % (k.__module__, k.__name__))
 | 
				
			||||||
 | 
					        repls['appClasses'] = "[%s]" % ','.join(appClasses)
 | 
				
			||||||
 | 
					        # Compute lists of class names
 | 
				
			||||||
 | 
					        allClassNames = '"%s",' % self.flavourName
 | 
				
			||||||
 | 
					        allClassNames += '"%s",' % self.podTemplateName
 | 
				
			||||||
 | 
					        appClassNames = ','.join(['"%s"' % c.name for c in self.classes])
 | 
				
			||||||
 | 
					        allClassNames += appClassNames
 | 
				
			||||||
 | 
					        repls['allClassNames'] = allClassNames
 | 
				
			||||||
 | 
					        repls['appClassNames'] = appClassNames
 | 
				
			||||||
 | 
					        # Compute classes whose instances must not be catalogued.
 | 
				
			||||||
 | 
					        catalogMap = ''
 | 
				
			||||||
 | 
					        blackClasses = [self.toolName, self.flavourName, self.podTemplateName]
 | 
				
			||||||
 | 
					        for blackClass in blackClasses:
 | 
				
			||||||
 | 
					            catalogMap += "catalogMap['%s'] = {}\n" % blackClass
 | 
				
			||||||
 | 
					            catalogMap += "catalogMap['%s']['black'] = " \
 | 
				
			||||||
 | 
					                          "['portal_catalog']\n" % blackClass
 | 
				
			||||||
 | 
					        repls['catalogMap'] = catalogMap
 | 
				
			||||||
 | 
					        # Compute workflows
 | 
				
			||||||
 | 
					        workflows = ''
 | 
				
			||||||
 | 
					        for classDescr in self.getClasses(include='all'):
 | 
				
			||||||
 | 
					            if hasattr(classDescr.klass, 'workflow'):
 | 
				
			||||||
 | 
					                wfName = WorkflowDescriptor.getWorkflowName(
 | 
				
			||||||
 | 
					                    classDescr.klass.workflow)
 | 
				
			||||||
 | 
					                workflows += '\n    "%s":"%s",' % (classDescr.name, wfName)
 | 
				
			||||||
 | 
					        repls['workflows'] = workflows
 | 
				
			||||||
        # Compute workflow instances initialisation
 | 
					        # Compute workflow instances initialisation
 | 
				
			||||||
        wfInit = ''
 | 
					        wfInit = ''
 | 
				
			||||||
        for workflowDescr in self.workflows:
 | 
					        for workflowDescr in self.workflows:
 | 
				
			||||||
| 
						 | 
					@ -295,24 +361,7 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
            for stateName in workflowDescr.getStateNames(ordered=True):
 | 
					            for stateName in workflowDescr.getStateNames(ordered=True):
 | 
				
			||||||
                wfInit += 'wf._states.append("%s")\n' % stateName
 | 
					                wfInit += 'wf._states.append("%s")\n' % stateName
 | 
				
			||||||
            wfInit += 'workflowInstances[%s] = wf\n' % className
 | 
					            wfInit += 'workflowInstances[%s] = wf\n' % className
 | 
				
			||||||
        # Compute imports
 | 
					        repls['workflowInstancesInit'] = wfInit
 | 
				
			||||||
        imports = ['import %s' % self.applicationName]
 | 
					 | 
				
			||||||
        classDescrs = self.getClasses(include='custom')
 | 
					 | 
				
			||||||
        for classDescr in (classDescrs + self.workflows):
 | 
					 | 
				
			||||||
            theImport = 'import %s' % classDescr.klass.__module__
 | 
					 | 
				
			||||||
            if theImport not in imports:
 | 
					 | 
				
			||||||
                imports.append(theImport)
 | 
					 | 
				
			||||||
        # Compute root classes
 | 
					 | 
				
			||||||
        rootClasses = ''
 | 
					 | 
				
			||||||
        for classDescr in self.classes:
 | 
					 | 
				
			||||||
            if classDescr.isRoot():
 | 
					 | 
				
			||||||
                rootClasses += "'%s'," % classDescr.name
 | 
					 | 
				
			||||||
        # Compute list of add permissions
 | 
					 | 
				
			||||||
        addPermissions = ''
 | 
					 | 
				
			||||||
        for classDescr in self.classes:
 | 
					 | 
				
			||||||
            addPermissions += '    "%s":"%s: Add %s",\n' % (classDescr.name,
 | 
					 | 
				
			||||||
                self.applicationName, classDescr.name)
 | 
					 | 
				
			||||||
        repls = self.repls.copy()
 | 
					 | 
				
			||||||
        # Compute the list of ordered attributes (foward and backward, inherited
 | 
					        # Compute the list of ordered attributes (foward and backward, inherited
 | 
				
			||||||
        # included) for every Appy class.
 | 
					        # included) for every Appy class.
 | 
				
			||||||
        attributes = []
 | 
					        attributes = []
 | 
				
			||||||
| 
						 | 
					@ -348,17 +397,22 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
                aDict += '"%s":attributes["%s"][%d],' % \
 | 
					                aDict += '"%s":attributes["%s"][%d],' % \
 | 
				
			||||||
                         (attrNames[i], classDescr.name, i)
 | 
					                         (attrNames[i], classDescr.name, i)
 | 
				
			||||||
            attributesDict.append('"%s":{%s}' % (classDescr.name, aDict))
 | 
					            attributesDict.append('"%s":{%s}' % (classDescr.name, aDict))
 | 
				
			||||||
        # Compute list of used roles for registering them if needed
 | 
					 | 
				
			||||||
        repls['roles'] = ','.join(['"%s"' % r for r in \
 | 
					 | 
				
			||||||
                                  self.getAllUsedRoles(appOnly=True)])
 | 
					 | 
				
			||||||
        repls['rootClasses'] = rootClasses
 | 
					 | 
				
			||||||
        repls['workflowInstancesInit'] = wfInit
 | 
					 | 
				
			||||||
        repls['imports'] = '\n'.join(imports)
 | 
					 | 
				
			||||||
        repls['attributes'] = ',\n    '.join(attributes)
 | 
					        repls['attributes'] = ',\n    '.join(attributes)
 | 
				
			||||||
        repls['attributesDict'] = ',\n    '.join(attributesDict)
 | 
					        repls['attributesDict'] = ',\n    '.join(attributesDict)
 | 
				
			||||||
        repls['defaultAddRoles'] = ','.join(
 | 
					        # Compute list of used roles for registering them if needed
 | 
				
			||||||
            ['"%s"' % r for r in self.config.defaultCreators])
 | 
					        specificRoles = self.getAllUsedRoles(plone=False)
 | 
				
			||||||
        repls['addPermissions'] = addPermissions
 | 
					        repls['roles'] = ','.join(['"%s"' % r.name for r in specificRoles])
 | 
				
			||||||
 | 
					        globalRoles = self.getAllUsedRoles(plone=False, local=False)
 | 
				
			||||||
 | 
					        repls['gRoles'] = ','.join(['"%s"' % r.name for r in globalRoles])
 | 
				
			||||||
 | 
					        grantableRoles = self.getAllUsedRoles(local=False, grantable=True)
 | 
				
			||||||
 | 
					        repls['grRoles'] = ','.join(['"%s"' % r.name for r in grantableRoles])
 | 
				
			||||||
 | 
					        # Generate configuration options
 | 
				
			||||||
 | 
					        repls['showPortlet'] = self.config.showPortlet
 | 
				
			||||||
 | 
					        repls['languages'] = ','.join('"%s"' % l for l in self.config.languages)
 | 
				
			||||||
 | 
					        repls['languageSelector'] = self.config.languageSelector
 | 
				
			||||||
 | 
					        repls['minimalistPlone'] = self.config.minimalistPlone
 | 
				
			||||||
 | 
					        
 | 
				
			||||||
 | 
					        repls['appFrontPage'] = bool(self.config.frontPage)
 | 
				
			||||||
        self.copyFile('config.py', repls)
 | 
					        self.copyFile('config.py', repls)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def generateInit(self):
 | 
					    def generateInit(self):
 | 
				
			||||||
| 
						 | 
					@ -376,50 +430,6 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
        repls['totalNumberOfTests'] = self.totalNumberOfTests
 | 
					        repls['totalNumberOfTests'] = self.totalNumberOfTests
 | 
				
			||||||
        self.copyFile('__init__.py', repls)
 | 
					        self.copyFile('__init__.py', repls)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def generateInstall(self):
 | 
					 | 
				
			||||||
        # Compute lists of class names
 | 
					 | 
				
			||||||
        allClassNames = '"%s",' % self.flavourName
 | 
					 | 
				
			||||||
        allClassNames += '"%s",' % self.podTemplateName
 | 
					 | 
				
			||||||
        appClassNames = ','.join(['"%s"' % c.name for c in self.classes])
 | 
					 | 
				
			||||||
        allClassNames += appClassNames
 | 
					 | 
				
			||||||
        # Compute imports
 | 
					 | 
				
			||||||
        imports = []
 | 
					 | 
				
			||||||
        for classDescr in self.classes:
 | 
					 | 
				
			||||||
            theImport = 'import %s' % classDescr.klass.__module__
 | 
					 | 
				
			||||||
            if theImport not in imports:
 | 
					 | 
				
			||||||
                imports.append(theImport)
 | 
					 | 
				
			||||||
        # Compute list of application classes
 | 
					 | 
				
			||||||
        appClasses = []
 | 
					 | 
				
			||||||
        for classDescr in self.classes:
 | 
					 | 
				
			||||||
            k = classDescr.klass
 | 
					 | 
				
			||||||
            appClasses.append('%s.%s' % (k.__module__, k.__name__))
 | 
					 | 
				
			||||||
        # Compute classes whose instances must not be catalogued.
 | 
					 | 
				
			||||||
        catalogMap = ''
 | 
					 | 
				
			||||||
        blackClasses = [self.toolName, self.flavourName, self.podTemplateName]
 | 
					 | 
				
			||||||
        for blackClass in blackClasses:
 | 
					 | 
				
			||||||
            catalogMap += "catalogMap['%s'] = {}\n" % blackClass
 | 
					 | 
				
			||||||
            catalogMap += "catalogMap['%s']['black'] = " \
 | 
					 | 
				
			||||||
                          "['portal_catalog']\n" % blackClass
 | 
					 | 
				
			||||||
        # Compute workflows
 | 
					 | 
				
			||||||
        workflows = ''
 | 
					 | 
				
			||||||
        for classDescr in self.getClasses(include='all'):
 | 
					 | 
				
			||||||
            if hasattr(classDescr.klass, 'workflow'):
 | 
					 | 
				
			||||||
                wfName = WorkflowDescriptor.getWorkflowName(
 | 
					 | 
				
			||||||
                    classDescr.klass.workflow)
 | 
					 | 
				
			||||||
                workflows += '\n    "%s":"%s",' % (classDescr.name, wfName)
 | 
					 | 
				
			||||||
        # Generate the resulting file.
 | 
					 | 
				
			||||||
        repls = self.repls.copy()
 | 
					 | 
				
			||||||
        repls['allClassNames'] = allClassNames
 | 
					 | 
				
			||||||
        repls['appClassNames'] = appClassNames
 | 
					 | 
				
			||||||
        repls['catalogMap'] = catalogMap
 | 
					 | 
				
			||||||
        repls['imports'] = '\n'.join(imports)
 | 
					 | 
				
			||||||
        repls['appClasses'] = "[%s]" % ','.join(appClasses)
 | 
					 | 
				
			||||||
        repls['minimalistPlone'] = self.config.minimalistPlone
 | 
					 | 
				
			||||||
        repls['showPortlet'] = self.config.showPortlet
 | 
					 | 
				
			||||||
        repls['appFrontPage'] = bool(self.config.frontPage)
 | 
					 | 
				
			||||||
        repls['workflows'] = workflows
 | 
					 | 
				
			||||||
        self.copyFile('Install.py', repls, destFolder='Extensions')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def generateWorkflows(self):
 | 
					    def generateWorkflows(self):
 | 
				
			||||||
        '''Generates the file that contains one function by workflow.
 | 
					        '''Generates the file that contains one function by workflow.
 | 
				
			||||||
           Those functions are called by Plone for registering the workflows.'''
 | 
					           Those functions are called by Plone for registering the workflows.'''
 | 
				
			||||||
| 
						 | 
					@ -468,14 +478,18 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
        '''Returns the descriptors for all the classes in the generated
 | 
					        '''Returns the descriptors for all the classes in the generated
 | 
				
			||||||
           gen-application. If p_include is "all", it includes the descriptors
 | 
					           gen-application. If p_include is "all", it includes the descriptors
 | 
				
			||||||
           for the config-related classes (tool, flavour, etc); if
 | 
					           for the config-related classes (tool, flavour, etc); if
 | 
				
			||||||
           p_include is "custom", it includes descriptors for the
 | 
					           p_include is "allButTool", it includes the same descriptors, the
 | 
				
			||||||
           config-related classes for which the user has created a sub-class.'''
 | 
					           tool excepted; if p_include is "custom", it includes descriptors
 | 
				
			||||||
 | 
					           for the config-related classes for which the user has created a
 | 
				
			||||||
 | 
					           sub-class.'''
 | 
				
			||||||
        if not include: return self.classes
 | 
					        if not include: return self.classes
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            res = self.classes[:]
 | 
					            res = self.classes[:]
 | 
				
			||||||
            configClasses = [self.tool, self.flavour, self.podTemplate]
 | 
					            configClasses = [self.tool,self.flavour,self.podTemplate,self.user]
 | 
				
			||||||
            if include == 'all':
 | 
					            if include == 'all':
 | 
				
			||||||
                res += configClasses
 | 
					                res += configClasses
 | 
				
			||||||
 | 
					            elif include == 'allButTool':
 | 
				
			||||||
 | 
					                res += configClasses[1:]
 | 
				
			||||||
            elif include == 'custom':
 | 
					            elif include == 'custom':
 | 
				
			||||||
                res += [c for c in configClasses if c.customized]
 | 
					                res += [c for c in configClasses if c.customized]
 | 
				
			||||||
            return res
 | 
					            return res
 | 
				
			||||||
| 
						 | 
					@ -564,6 +578,7 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
        repls['toolBody'] = Tool._appy_getBody()
 | 
					        repls['toolBody'] = Tool._appy_getBody()
 | 
				
			||||||
        repls['flavourBody'] = Flavour._appy_getBody()
 | 
					        repls['flavourBody'] = Flavour._appy_getBody()
 | 
				
			||||||
        repls['podTemplateBody'] = PodTemplate._appy_getBody()
 | 
					        repls['podTemplateBody'] = PodTemplate._appy_getBody()
 | 
				
			||||||
 | 
					        repls['userBody'] = User._appy_getBody()
 | 
				
			||||||
        self.copyFile('appyWrappers.py', repls, destFolder='Extensions')
 | 
					        self.copyFile('appyWrappers.py', repls, destFolder='Extensions')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def generateTests(self):
 | 
					    def generateTests(self):
 | 
				
			||||||
| 
						 | 
					@ -581,7 +596,8 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
            # We need a front page, but no specific one has been given.
 | 
					            # We need a front page, but no specific one has been given.
 | 
				
			||||||
            # So we will create a basic one that will simply display
 | 
					            # So we will create a basic one that will simply display
 | 
				
			||||||
            # some translated text.
 | 
					            # some translated text.
 | 
				
			||||||
            self.labels.append(msg('front_page_text', '', msg.FRONT_PAGE_TEXT))
 | 
					            self.labels.append(PoMessage('front_page_text', '',
 | 
				
			||||||
 | 
					                                         PoMessage.FRONT_PAGE_TEXT))
 | 
				
			||||||
            repls['pageContent'] = '<span tal:replace="structure python: ' \
 | 
					            repls['pageContent'] = '<span tal:replace="structure python: ' \
 | 
				
			||||||
                'tool.translateWithMapping(\'front_page_text\')"/>'
 | 
					                'tool.translateWithMapping(\'front_page_text\')"/>'
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
| 
						 | 
					@ -605,6 +621,9 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
        Tool.flavours.klass = Flavour
 | 
					        Tool.flavours.klass = Flavour
 | 
				
			||||||
        if self.flavour.customized:
 | 
					        if self.flavour.customized:
 | 
				
			||||||
            Tool.flavours.klass = self.flavour.klass
 | 
					            Tool.flavours.klass = self.flavour.klass
 | 
				
			||||||
 | 
					        Tool.users.klass = User
 | 
				
			||||||
 | 
					        if self.user.customized:
 | 
				
			||||||
 | 
					            Tool.users.klass = self.user.klass
 | 
				
			||||||
        self.tool.generateSchema()
 | 
					        self.tool.generateSchema()
 | 
				
			||||||
        repls['fields'] = self.tool.schema
 | 
					        repls['fields'] = self.tool.schema
 | 
				
			||||||
        repls['methods'] = self.tool.methods
 | 
					        repls['methods'] = self.tool.methods
 | 
				
			||||||
| 
						 | 
					@ -659,6 +678,16 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
        repls['wrapperClass'] = '%s_Wrapper' % self.podTemplate.name
 | 
					        repls['wrapperClass'] = '%s_Wrapper' % self.podTemplate.name
 | 
				
			||||||
        self.copyFile('PodTemplate.py', repls,
 | 
					        self.copyFile('PodTemplate.py', repls,
 | 
				
			||||||
                        destName='%s.py' % self.podTemplateName)
 | 
					                        destName='%s.py' % self.podTemplateName)
 | 
				
			||||||
 | 
					        # Generate the User class
 | 
				
			||||||
 | 
					        self.user.generateSchema()
 | 
				
			||||||
 | 
					        self.labels += [ Msg(self.userName, '', Msg.USER),
 | 
				
			||||||
 | 
					                         Msg('%s_edit_descr' % self.userName, '', ' ')]
 | 
				
			||||||
 | 
					        repls = self.repls.copy()
 | 
				
			||||||
 | 
					        repls['fields'] = self.user.schema
 | 
				
			||||||
 | 
					        repls['methods'] = self.user.methods
 | 
				
			||||||
 | 
					        repls['wrapperClass'] = '%s_Wrapper' % self.user.name
 | 
				
			||||||
 | 
					        self.copyFile('UserTemplate.py', repls,
 | 
				
			||||||
 | 
					                      destName='%s.py' % self.userName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def generateClass(self, classDescr):
 | 
					    def generateClass(self, classDescr):
 | 
				
			||||||
        '''Is called each time an Appy class is found in the application, for
 | 
					        '''Is called each time an Appy class is found in the application, for
 | 
				
			||||||
| 
						 | 
					@ -681,7 +710,7 @@ class Generator(AbstractGenerator):
 | 
				
			||||||
        implements = [baseClass]
 | 
					        implements = [baseClass]
 | 
				
			||||||
        for baseClass in classDescr.klass.__bases__:
 | 
					        for baseClass in classDescr.klass.__bases__:
 | 
				
			||||||
            if self.determineAppyType(baseClass) == 'class':
 | 
					            if self.determineAppyType(baseClass) == 'class':
 | 
				
			||||||
                bcName = ClassDescriptor.getClassName(baseClass)
 | 
					                bcName = getClassName(baseClass)
 | 
				
			||||||
                parents.remove('ClassMixin')
 | 
					                parents.remove('ClassMixin')
 | 
				
			||||||
                parents.append(bcName)
 | 
					                parents.append(bcName)
 | 
				
			||||||
                implements.append(bcName)
 | 
					                implements.append(bcName)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,30 +18,27 @@ class ZCTextIndexInfo:
 | 
				
			||||||
class PloneInstaller:
 | 
					class PloneInstaller:
 | 
				
			||||||
    '''This Plone installer runs every time the generated Plone product is
 | 
					    '''This Plone installer runs every time the generated Plone product is
 | 
				
			||||||
       installed or uninstalled (in the Plone configuration interface).'''
 | 
					       installed or uninstalled (in the Plone configuration interface).'''
 | 
				
			||||||
    def __init__(self, reinstall, productName, ploneSite, minimalistPlone,
 | 
					    def __init__(self, reinstall, ploneSite, config):
 | 
				
			||||||
        appClasses, appClassNames, allClassNames, catalogMap, applicationRoles,
 | 
					        # p_cfg is the configuration module of the Plone product.
 | 
				
			||||||
        defaultAddRoles, workflows, appFrontPage, showPortlet, ploneStuff):
 | 
					 | 
				
			||||||
        self.reinstall = reinstall # Is it a fresh install or a re-install?
 | 
					        self.reinstall = reinstall # Is it a fresh install or a re-install?
 | 
				
			||||||
        self.productName = productName
 | 
					 | 
				
			||||||
        self.ploneSite = ploneSite
 | 
					        self.ploneSite = ploneSite
 | 
				
			||||||
        self.minimalistPlone = minimalistPlone # If True, lots of basic Plone
 | 
					        self.config = cfg = config
 | 
				
			||||||
                                               # stuff will be hidden.
 | 
					        # Unwrap some useful variables from config
 | 
				
			||||||
        self.appClasses = appClasses # The list of classes declared in the
 | 
					        self.productName = cfg.PROJECTNAME
 | 
				
			||||||
                                     # gen-application.
 | 
					        self.minimalistPlone = cfg.minimalistPlone
 | 
				
			||||||
        self.appClassNames = appClassNames # Names of those classes
 | 
					        self.appClasses = cfg.appClasses
 | 
				
			||||||
        self.allClassNames = allClassNames # Includes Flavour and PodTemplate
 | 
					        self.appClassNames = cfg.appClassNames
 | 
				
			||||||
        self.catalogMap = catalogMap # Indicates classes to be indexed or not
 | 
					        self.allClassNames = cfg.allClassNames
 | 
				
			||||||
        self.applicationRoles = applicationRoles # Roles defined in the app
 | 
					        self.catalogMap = cfg.catalogMap
 | 
				
			||||||
        self.defaultAddRoles = defaultAddRoles # The default roles that can add
 | 
					        self.applicationRoles = cfg.applicationRoles # Roles defined in the app
 | 
				
			||||||
                                               # content
 | 
					        self.defaultAddRoles = cfg.defaultAddRoles
 | 
				
			||||||
        self.workflows = workflows # Dict whose keys are class names and whose
 | 
					        self.workflows = cfg.workflows
 | 
				
			||||||
                                   # values are workflow names (=the workflow
 | 
					        self.appFrontPage = cfg.appFrontPage
 | 
				
			||||||
                                   # used by the content type)
 | 
					        self.showPortlet = cfg.showPortlet
 | 
				
			||||||
        self.appFrontPage = appFrontPage # Does this app define a site-wide
 | 
					        self.languages = cfg.languages
 | 
				
			||||||
                                         # front page?
 | 
					        self.languageSelector = cfg.languageSelector
 | 
				
			||||||
        self.showPortlet = showPortlet # Must we show the application portlet?
 | 
					        self.attributes = cfg.attributes
 | 
				
			||||||
        self.ploneStuff = ploneStuff # A dict of some Plone functions or vars
 | 
					        # A buffer for logging purposes
 | 
				
			||||||
        self.attributes = ploneStuff['GLOBALS']['attributes']
 | 
					 | 
				
			||||||
        self.toLog = StringIO()
 | 
					        self.toLog = StringIO()
 | 
				
			||||||
        self.typeAliases = {'sharing': '', 'gethtml': '',
 | 
					        self.typeAliases = {'sharing': '', 'gethtml': '',
 | 
				
			||||||
            '(Default)': 'skynView', 'edit': 'skyn/edit',
 | 
					            '(Default)': 'skynView', 'edit': 'skyn/edit',
 | 
				
			||||||
| 
						 | 
					@ -166,7 +163,7 @@ class PloneInstaller:
 | 
				
			||||||
            site.manage_delObjects(['skyn'])
 | 
					            site.manage_delObjects(['skyn'])
 | 
				
			||||||
        # This way, if Appy has moved from one place to the other, the
 | 
					        # This way, if Appy has moved from one place to the other, the
 | 
				
			||||||
        # directory view will always refer to the correct place.
 | 
					        # directory view will always refer to the correct place.
 | 
				
			||||||
        addDirView = self.ploneStuff['manage_addDirectoryView']
 | 
					        addDirView = self.config.manage_addDirectoryView
 | 
				
			||||||
        addDirView(site, appy.getPath() + '/gen/plone25/skin', id='skyn')
 | 
					        addDirView(site, appy.getPath() + '/gen/plone25/skin', id='skyn')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def installTypes(self):
 | 
					    def installTypes(self):
 | 
				
			||||||
| 
						 | 
					@ -174,11 +171,9 @@ class PloneInstaller:
 | 
				
			||||||
           gen-classes.'''
 | 
					           gen-classes.'''
 | 
				
			||||||
        site = self.ploneSite
 | 
					        site = self.ploneSite
 | 
				
			||||||
        # Do Plone-based type registration
 | 
					        # Do Plone-based type registration
 | 
				
			||||||
        classes = self.ploneStuff['listTypes'](self.productName)
 | 
					        classes = self.config.listTypes(self.productName)
 | 
				
			||||||
        self.ploneStuff['installTypes'](site, self.toLog, classes,
 | 
					        self.config.installTypes(site, self.toLog, classes, self.productName)
 | 
				
			||||||
            self.productName)
 | 
					        self.config.install_subskin(site, self.toLog, self.config.__dict__)
 | 
				
			||||||
        self.ploneStuff['install_subskin'](site, self.toLog,
 | 
					 | 
				
			||||||
            self.ploneStuff['GLOBALS'])
 | 
					 | 
				
			||||||
        # Set appy view/edit pages for every created type
 | 
					        # Set appy view/edit pages for every created type
 | 
				
			||||||
        for className in self.allClassNames + ['%sTool' % self.productName]:
 | 
					        for className in self.allClassNames + ['%sTool' % self.productName]:
 | 
				
			||||||
            # I did not put the app tool in self.allClassNames because it
 | 
					            # I did not put the app tool in self.allClassNames because it
 | 
				
			||||||
| 
						 | 
					@ -204,7 +199,7 @@ class PloneInstaller:
 | 
				
			||||||
        factoryTool.manage_setPortalFactoryTypes(listOfTypeIds=factoryTypes)
 | 
					        factoryTool.manage_setPortalFactoryTypes(listOfTypeIds=factoryTypes)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Configure CatalogMultiplex: tell what types will be catalogued or not.
 | 
					        # Configure CatalogMultiplex: tell what types will be catalogued or not.
 | 
				
			||||||
        atTool = getattr(site, self.ploneStuff['ARCHETYPETOOLNAME'])
 | 
					        atTool = getattr(site, self.config.ARCHETYPETOOLNAME)
 | 
				
			||||||
        for meta_type in self.catalogMap:
 | 
					        for meta_type in self.catalogMap:
 | 
				
			||||||
            submap = self.catalogMap[meta_type]
 | 
					            submap = self.catalogMap[meta_type]
 | 
				
			||||||
            current_catalogs = Set(
 | 
					            current_catalogs = Set(
 | 
				
			||||||
| 
						 | 
					@ -294,7 +289,7 @@ class PloneInstaller:
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            self.ploneSite.manage_addProduct[
 | 
					            self.ploneSite.manage_addProduct[
 | 
				
			||||||
                self.productName].manage_addTool(self.toolName)
 | 
					                self.productName].manage_addTool(self.toolName)
 | 
				
			||||||
        except self.ploneStuff['BadRequest']:
 | 
					        except self.config.BadRequest:
 | 
				
			||||||
            # If an instance with the same name already exists, this error will
 | 
					            # If an instance with the same name already exists, this error will
 | 
				
			||||||
            # be unelegantly raised by Zope.
 | 
					            # be unelegantly raised by Zope.
 | 
				
			||||||
            pass
 | 
					            pass
 | 
				
			||||||
| 
						 | 
					@ -357,7 +352,7 @@ class PloneInstaller:
 | 
				
			||||||
           groups if needed.'''
 | 
					           groups if needed.'''
 | 
				
			||||||
        site = self.ploneSite
 | 
					        site = self.ploneSite
 | 
				
			||||||
        data = list(site.__ac_roles__)
 | 
					        data = list(site.__ac_roles__)
 | 
				
			||||||
        for role in self.applicationRoles:
 | 
					        for role in self.config.applicationRoles:
 | 
				
			||||||
            if not role in data:
 | 
					            if not role in data:
 | 
				
			||||||
                data.append(role)
 | 
					                data.append(role)
 | 
				
			||||||
                # Add to portal_role_manager
 | 
					                # Add to portal_role_manager
 | 
				
			||||||
| 
						 | 
					@ -373,9 +368,11 @@ class PloneInstaller:
 | 
				
			||||||
                            pass
 | 
					                            pass
 | 
				
			||||||
                except AttributeError:
 | 
					                except AttributeError:
 | 
				
			||||||
                    pass
 | 
					                    pass
 | 
				
			||||||
            # Create a specific group and grant him this role
 | 
					            # If it is a global role, create a specific group and grant him
 | 
				
			||||||
 | 
					            # this role
 | 
				
			||||||
 | 
					            if role not in self.config.applicationGlobalRoles: continue
 | 
				
			||||||
            group = '%s_group' % role
 | 
					            group = '%s_group' % role
 | 
				
			||||||
            if not site.portal_groups.getGroupById(group):
 | 
					            if site.portal_groups.getGroupById(group): continue # Already there
 | 
				
			||||||
            site.portal_groups.addGroup(group, title=group)
 | 
					            site.portal_groups.addGroup(group, title=group)
 | 
				
			||||||
            site.portal_groups.setRolesForGroup(group, [role])
 | 
					            site.portal_groups.setRolesForGroup(group, [role])
 | 
				
			||||||
        site.__ac_roles__ = tuple(data)
 | 
					        site.__ac_roles__ = tuple(data)
 | 
				
			||||||
| 
						 | 
					@ -386,7 +383,7 @@ class PloneInstaller:
 | 
				
			||||||
        for contentType, workflowName in self.workflows.iteritems():
 | 
					        for contentType, workflowName in self.workflows.iteritems():
 | 
				
			||||||
            # Register the workflow if needed
 | 
					            # Register the workflow if needed
 | 
				
			||||||
            if workflowName not in wfTool.listWorkflows():
 | 
					            if workflowName not in wfTool.listWorkflows():
 | 
				
			||||||
                wfMethod = self.ploneStuff['ExternalMethod']('temp', 'temp',
 | 
					                wfMethod = self.config.ExternalMethod('temp', 'temp',
 | 
				
			||||||
                    self.productName + '.workflows', 'create_%s' % workflowName)
 | 
					                    self.productName + '.workflows', 'create_%s' % workflowName)
 | 
				
			||||||
                workflow = wfMethod(self, workflowName)
 | 
					                workflow = wfMethod(self, workflowName)
 | 
				
			||||||
                wfTool._setObject(workflowName, workflow)
 | 
					                wfTool._setObject(workflowName, workflow)
 | 
				
			||||||
| 
						 | 
					@ -401,7 +398,6 @@ class PloneInstaller:
 | 
				
			||||||
        cssName = self.productName + '.css'
 | 
					        cssName = self.productName + '.css'
 | 
				
			||||||
        cssTitle = self.productName + ' CSS styles'
 | 
					        cssTitle = self.productName + ' CSS styles'
 | 
				
			||||||
        cssInfo = {'id': cssName, 'title': cssTitle}
 | 
					        cssInfo = {'id': cssName, 'title': cssTitle}
 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
        portalCss = self.ploneSite.portal_css
 | 
					        portalCss = self.ploneSite.portal_css
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            portalCss.unregisterResource(cssInfo['id'])
 | 
					            portalCss.unregisterResource(cssInfo['id'])
 | 
				
			||||||
| 
						 | 
					@ -410,9 +406,6 @@ class PloneInstaller:
 | 
				
			||||||
        defaults = {'id': '', 'media': 'all', 'enabled': True}
 | 
					        defaults = {'id': '', 'media': 'all', 'enabled': True}
 | 
				
			||||||
        defaults.update(cssInfo)
 | 
					        defaults.update(cssInfo)
 | 
				
			||||||
        portalCss.registerStylesheet(**defaults)
 | 
					        portalCss.registerStylesheet(**defaults)
 | 
				
			||||||
        except:
 | 
					 | 
				
			||||||
            # No portal_css registry
 | 
					 | 
				
			||||||
            pass
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def managePortlets(self):
 | 
					    def managePortlets(self):
 | 
				
			||||||
        '''Shows or hides the application-specific portlet and configures other
 | 
					        '''Shows or hides the application-specific portlet and configures other
 | 
				
			||||||
| 
						 | 
					@ -456,6 +449,22 @@ class PloneInstaller:
 | 
				
			||||||
        if indexInfo:
 | 
					        if indexInfo:
 | 
				
			||||||
            PloneInstaller.updateIndexes(self.ploneSite, indexInfo, self)
 | 
					            PloneInstaller.updateIndexes(self.ploneSite, indexInfo, self)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def manageLanguages(self):
 | 
				
			||||||
 | 
					        '''Manages the languages supported by the application.'''
 | 
				
			||||||
 | 
					        if self.languageSelector:
 | 
				
			||||||
 | 
					            # We must install the PloneLanguageTool if not done yet
 | 
				
			||||||
 | 
					            qi = self.ploneSite.portal_quickinstaller
 | 
				
			||||||
 | 
					            if not qi.isProductInstalled('PloneLanguageTool'):
 | 
				
			||||||
 | 
					                qi.installProduct('PloneLanguageTool')
 | 
				
			||||||
 | 
					            languageTool = self.ploneSite.portal_languages
 | 
				
			||||||
 | 
					            defLanguage = self.languages[0]
 | 
				
			||||||
 | 
					            languageTool.manage_setLanguageSettings(defaultLanguage=defLanguage,
 | 
				
			||||||
 | 
					                supportedLanguages=self.languages, setContentN=None,
 | 
				
			||||||
 | 
					                setCookieN=True, setRequestN=True, setPathN=True,
 | 
				
			||||||
 | 
					                setForcelanguageUrls=True, setAllowContentLanguageFallback=None,
 | 
				
			||||||
 | 
					                setUseCombinedLanguageCodes=None, displayFlags=False,
 | 
				
			||||||
 | 
					                startNeutral=False)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def finalizeInstallation(self):
 | 
					    def finalizeInstallation(self):
 | 
				
			||||||
        '''Performs some final installation steps.'''
 | 
					        '''Performs some final installation steps.'''
 | 
				
			||||||
        site = self.ploneSite
 | 
					        site = self.ploneSite
 | 
				
			||||||
| 
						 | 
					@ -493,6 +502,7 @@ class PloneInstaller:
 | 
				
			||||||
        self.installStyleSheet()
 | 
					        self.installStyleSheet()
 | 
				
			||||||
        self.managePortlets()
 | 
					        self.managePortlets()
 | 
				
			||||||
        self.manageIndexes()
 | 
					        self.manageIndexes()
 | 
				
			||||||
 | 
					        self.manageLanguages()
 | 
				
			||||||
        self.finalizeInstallation()
 | 
					        self.finalizeInstallation()
 | 
				
			||||||
        self.log("Installation of %s done." % self.productName)
 | 
					        self.log("Installation of %s done." % self.productName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -545,17 +555,16 @@ def traverseWrapper(self, path, response=None, validated_hook=None):
 | 
				
			||||||
class ZopeInstaller:
 | 
					class ZopeInstaller:
 | 
				
			||||||
    '''This Zope installer runs every time Zope starts and encounters this
 | 
					    '''This Zope installer runs every time Zope starts and encounters this
 | 
				
			||||||
       generated Zope product.'''
 | 
					       generated Zope product.'''
 | 
				
			||||||
    def __init__(self, zopeContext, productName, toolClass,
 | 
					    def __init__(self, zopeContext, toolClass, config, classes):
 | 
				
			||||||
                 defaultAddContentPermission, addContentPermissions,
 | 
					 | 
				
			||||||
                 logger, ploneStuff, classes):
 | 
					 | 
				
			||||||
        self.zopeContext = zopeContext
 | 
					        self.zopeContext = zopeContext
 | 
				
			||||||
        self.productName = productName
 | 
					 | 
				
			||||||
        self.toolClass = toolClass
 | 
					        self.toolClass = toolClass
 | 
				
			||||||
        self.defaultAddContentPermission = defaultAddContentPermission
 | 
					        self.config = cfg = config
 | 
				
			||||||
        self.addContentPermissions = addContentPermissions
 | 
					 | 
				
			||||||
        self.logger = logger
 | 
					 | 
				
			||||||
        self.ploneStuff = ploneStuff # A dict of some Plone functions or vars
 | 
					 | 
				
			||||||
        self.classes = classes
 | 
					        self.classes = classes
 | 
				
			||||||
 | 
					        # Unwrap some useful config variables
 | 
				
			||||||
 | 
					        self.productName = cfg.PROJECTNAME
 | 
				
			||||||
 | 
					        self.logger = cfg.logger
 | 
				
			||||||
 | 
					        self.defaultAddContentPermission = cfg.DEFAULT_ADD_CONTENT_PERMISSION
 | 
				
			||||||
 | 
					        self.addContentPermissions = cfg.ADD_CONTENT_PERMISSIONS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def completeAppyTypes(self):
 | 
					    def completeAppyTypes(self):
 | 
				
			||||||
        '''We complete here the initialisation process of every Appy type of
 | 
					        '''We complete here the initialisation process of every Appy type of
 | 
				
			||||||
| 
						 | 
					@ -574,23 +583,23 @@ class ZopeInstaller:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def installApplication(self):
 | 
					    def installApplication(self):
 | 
				
			||||||
        '''Performs some application-wide installation steps.'''
 | 
					        '''Performs some application-wide installation steps.'''
 | 
				
			||||||
        register = self.ploneStuff['DirectoryView'].registerDirectory
 | 
					        register = self.config.DirectoryView.registerDirectory
 | 
				
			||||||
        register('skins', self.ploneStuff['product_globals'])
 | 
					        register('skins', self.config.__dict__)
 | 
				
			||||||
        # Register the appy skin folder among DirectoryView'able folders
 | 
					        # Register the appy skin folder among DirectoryView'able folders
 | 
				
			||||||
        register('skin', appy.getPath() + '/gen/plone25')
 | 
					        register('skin', appy.getPath() + '/gen/plone25')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def installTool(self):
 | 
					    def installTool(self):
 | 
				
			||||||
        '''Installs the tool.'''
 | 
					        '''Installs the tool.'''
 | 
				
			||||||
        self.ploneStuff['ToolInit'](self.productName + ' Tools',
 | 
					        self.config.ToolInit(self.productName + ' Tools',
 | 
				
			||||||
            tools = [self.toolClass], icon='tool.gif').initialize(
 | 
					            tools = [self.toolClass], icon='tool.gif').initialize(
 | 
				
			||||||
                self.zopeContext)
 | 
					                self.zopeContext)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def installTypes(self):
 | 
					    def installTypes(self):
 | 
				
			||||||
        '''Installs and configures the types defined in the application.'''
 | 
					        '''Installs and configures the types defined in the application.'''
 | 
				
			||||||
        contentTypes, constructors, ftis = self.ploneStuff['process_types'](
 | 
					        contentTypes, constructors, ftis = self.config.process_types(
 | 
				
			||||||
            self.ploneStuff['listTypes'](self.productName), self.productName)
 | 
					            self.config.listTypes(self.productName), self.productName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        self.ploneStuff['cmfutils'].ContentInit(self.productName + ' Content',
 | 
					        self.config.cmfutils.ContentInit(self.productName + ' Content',
 | 
				
			||||||
            content_types = contentTypes,
 | 
					            content_types = contentTypes,
 | 
				
			||||||
            permission = self.defaultAddContentPermission,
 | 
					            permission = self.defaultAddContentPermission,
 | 
				
			||||||
            extra_constructors = constructors, fti = ftis).initialize(
 | 
					            extra_constructors = constructors, fti = ftis).initialize(
 | 
				
			||||||
| 
						 | 
					@ -611,14 +620,14 @@ class ZopeInstaller:
 | 
				
			||||||
        global originalTraverse
 | 
					        global originalTraverse
 | 
				
			||||||
        if not originalTraverse:
 | 
					        if not originalTraverse:
 | 
				
			||||||
            # User tracking is not enabled yet. Do it now.
 | 
					            # User tracking is not enabled yet. Do it now.
 | 
				
			||||||
            BaseRequest = self.ploneStuff['BaseRequest']
 | 
					            BaseRequest = self.config.BaseRequest
 | 
				
			||||||
            originalTraverse = BaseRequest.traverse
 | 
					            originalTraverse = BaseRequest.traverse
 | 
				
			||||||
            BaseRequest.traverse = traverseWrapper
 | 
					            BaseRequest.traverse = traverseWrapper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def finalizeInstallation(self):
 | 
					    def finalizeInstallation(self):
 | 
				
			||||||
        '''Performs some final installation steps.'''
 | 
					        '''Performs some final installation steps.'''
 | 
				
			||||||
        # Apply customization policy if any
 | 
					        # Apply customization policy if any
 | 
				
			||||||
        cp = self.ploneStuff['CustomizationPolicy']
 | 
					        cp = self.config.CustomizationPolicy
 | 
				
			||||||
        if cp and hasattr(cp, 'register'): cp.register(context)
 | 
					        if cp and hasattr(cp, 'register'): cp.register(context)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def install(self):
 | 
					    def install(self):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -18,33 +18,10 @@ POD_ERROR = 'An error occurred while generating the document. Please ' \
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class FlavourMixin(AbstractMixin):
 | 
					class FlavourMixin(AbstractMixin):
 | 
				
			||||||
    _appy_meta_type = 'Flavour'
 | 
					    _appy_meta_type = 'Flavour'
 | 
				
			||||||
    def getPortalType(self, metaTypeOrAppyType):
 | 
					    def getPortalType(self, metaTypeOrAppyClass):
 | 
				
			||||||
        '''Returns the name of the portal_type that is based on
 | 
					        '''Returns the name of the portal_type that is based on
 | 
				
			||||||
           p_metaTypeOrAppyType in this flavour.'''
 | 
					           p_metaTypeOrAppyType in this flavour.'''
 | 
				
			||||||
        res = metaTypeOrAppyType
 | 
					        return self.getParentNode().getPortalType(metaTypeOrAppyClass)
 | 
				
			||||||
        isPredefined = False
 | 
					 | 
				
			||||||
        isAppy = False
 | 
					 | 
				
			||||||
        appName = self.getProductConfig().PROJECTNAME
 | 
					 | 
				
			||||||
        if not isinstance(res, basestring):
 | 
					 | 
				
			||||||
            res = ClassDescriptor.getClassName(res)
 | 
					 | 
				
			||||||
            isAppy = True
 | 
					 | 
				
			||||||
        if res.find('Extensions_appyWrappers') != -1:
 | 
					 | 
				
			||||||
            isPredefined = True
 | 
					 | 
				
			||||||
            elems = res.split('_')
 | 
					 | 
				
			||||||
            res = '%s%s' % (elems[1], elems[4])
 | 
					 | 
				
			||||||
        elif isAppy and issubclass(metaTypeOrAppyType, appy.gen.Tool):
 | 
					 | 
				
			||||||
            # This is the custom tool
 | 
					 | 
				
			||||||
            isPredefined = True
 | 
					 | 
				
			||||||
            res = '%sTool' % appName
 | 
					 | 
				
			||||||
        elif isAppy and issubclass(metaTypeOrAppyType, appy.gen.Flavour):
 | 
					 | 
				
			||||||
            # This is the custom Flavour
 | 
					 | 
				
			||||||
            isPredefined = True
 | 
					 | 
				
			||||||
            res = '%sFlavour' % appName
 | 
					 | 
				
			||||||
        if not isPredefined:
 | 
					 | 
				
			||||||
            number = self.appy().number
 | 
					 | 
				
			||||||
            if number != 1:
 | 
					 | 
				
			||||||
                res = '%s_%d' % (res, number)
 | 
					 | 
				
			||||||
        return res
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def registerPortalTypes(self):
 | 
					    def registerPortalTypes(self):
 | 
				
			||||||
        '''Registers, into portal_types, the portal types which are specific
 | 
					        '''Registers, into portal_types, the portal types which are specific
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,8 +1,9 @@
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
import re, os, os.path, Cookie
 | 
					import re, os, os.path, Cookie
 | 
				
			||||||
from appy.shared.utils import getOsTempFolder
 | 
					from appy.shared.utils import getOsTempFolder
 | 
				
			||||||
 | 
					import appy.gen
 | 
				
			||||||
from appy.gen import Type, Search, Selection
 | 
					from appy.gen import Type, Search, Selection
 | 
				
			||||||
from appy.gen.utils import SomeObjects, sequenceTypes
 | 
					from appy.gen.utils import SomeObjects, sequenceTypes, getClassName
 | 
				
			||||||
from appy.gen.plone25.mixins import AbstractMixin
 | 
					from appy.gen.plone25.mixins import AbstractMixin
 | 
				
			||||||
from appy.gen.plone25.mixins.FlavourMixin import FlavourMixin
 | 
					from appy.gen.plone25.mixins.FlavourMixin import FlavourMixin
 | 
				
			||||||
from appy.gen.plone25.wrappers import AbstractWrapper
 | 
					from appy.gen.plone25.wrappers import AbstractWrapper
 | 
				
			||||||
| 
						 | 
					@ -13,6 +14,17 @@ jsMessages = ('no_elem_selected', 'delete_confirm')
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class ToolMixin(AbstractMixin):
 | 
					class ToolMixin(AbstractMixin):
 | 
				
			||||||
    _appy_meta_type = 'Tool'
 | 
					    _appy_meta_type = 'Tool'
 | 
				
			||||||
 | 
					    def getPortalType(self, metaTypeOrAppyClass):
 | 
				
			||||||
 | 
					        '''Returns the name of the portal_type that is based on
 | 
				
			||||||
 | 
					           p_metaTypeOrAppyType in this flavour.'''
 | 
				
			||||||
 | 
					        appName = self.getProductConfig().PROJECTNAME
 | 
				
			||||||
 | 
					        if not isinstance(metaTypeOrAppyClass, basestring):
 | 
				
			||||||
 | 
					            res = getClassName(metaTypeOrAppyClass, appName)
 | 
				
			||||||
 | 
					        if res.find('Extensions_appyWrappers') != -1:
 | 
				
			||||||
 | 
					            elems = res.split('_')
 | 
				
			||||||
 | 
					            res = '%s%s' % (elems[1], elems[4])
 | 
				
			||||||
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getFlavour(self, contextObjOrPortalType, appy=False):
 | 
					    def getFlavour(self, contextObjOrPortalType, appy=False):
 | 
				
			||||||
        '''Gets the flavour that corresponds to p_contextObjOrPortalType.'''
 | 
					        '''Gets the flavour that corresponds to p_contextObjOrPortalType.'''
 | 
				
			||||||
        if isinstance(contextObjOrPortalType, basestring):
 | 
					        if isinstance(contextObjOrPortalType, basestring):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										7
									
								
								gen/plone25/mixins/UserMixin.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								gen/plone25/mixins/UserMixin.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,7 @@
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					from appy.gen.plone25.mixins import AbstractMixin
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					class UserMixin(AbstractMixin):
 | 
				
			||||||
 | 
					    _appy_meta_type = 'UserMixin'
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					@ -8,7 +8,7 @@
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
import os, os.path, types, mimetypes
 | 
					import os, os.path, types, mimetypes
 | 
				
			||||||
import appy.gen
 | 
					import appy.gen
 | 
				
			||||||
from appy.gen import Type, String, Selection
 | 
					from appy.gen import Type, String, Selection, Role
 | 
				
			||||||
from appy.gen.utils import *
 | 
					from appy.gen.utils import *
 | 
				
			||||||
from appy.gen.layout import Table, defaultPageLayouts
 | 
					from appy.gen.layout import Table, defaultPageLayouts
 | 
				
			||||||
from appy.gen.plone25.descriptors import ClassDescriptor
 | 
					from appy.gen.plone25.descriptors import ClassDescriptor
 | 
				
			||||||
| 
						 | 
					@ -338,14 +338,30 @@ class AbstractMixin:
 | 
				
			||||||
        i = res.startNumber
 | 
					        i = res.startNumber
 | 
				
			||||||
        # Is it possible and more efficient to perform a single query in
 | 
					        # Is it possible and more efficient to perform a single query in
 | 
				
			||||||
        # uid_catalog and get the result in the order of specified uids?
 | 
					        # uid_catalog and get the result in the order of specified uids?
 | 
				
			||||||
 | 
					        toUnlink = []
 | 
				
			||||||
        while i < (res.startNumber + res.batchSize):
 | 
					        while i < (res.startNumber + res.batchSize):
 | 
				
			||||||
            if i >= res.totalNumber: break
 | 
					            if i >= res.totalNumber: break
 | 
				
			||||||
            refUid = sortedUids[i]
 | 
					            refUid = sortedUids[i]
 | 
				
			||||||
            refObject = self.uid_catalog(UID=refUid)[0].getObject()
 | 
					            refObject = self.uid_catalog(UID=refUid)[0].getObject()
 | 
				
			||||||
 | 
					            i += 1
 | 
				
			||||||
 | 
					            tool = self.getTool()
 | 
				
			||||||
 | 
					            if refObject.meta_type != tool.getPortalType(appyType.klass):
 | 
				
			||||||
 | 
					                toUnlink.append(refObject)
 | 
				
			||||||
 | 
					                continue
 | 
				
			||||||
            if not ploneObjects:
 | 
					            if not ploneObjects:
 | 
				
			||||||
                refObject = refObject.appy()
 | 
					                refObject = refObject.appy()
 | 
				
			||||||
            res.objects.append(refObject)
 | 
					            res.objects.append(refObject)
 | 
				
			||||||
            i += 1
 | 
					        # Unlink dummy linked objects
 | 
				
			||||||
 | 
					        if toUnlink:
 | 
				
			||||||
 | 
					            suffix = '%s%s' % (fieldName[0].upper(), fieldName[1:])
 | 
				
			||||||
 | 
					            exec 'linkedObjects = self.get%s()' % suffix
 | 
				
			||||||
 | 
					            for dummyObject in toUnlink:
 | 
				
			||||||
 | 
					                linkedObjects.remove(dummyObject)
 | 
				
			||||||
 | 
					                self.getProductConfig().logger.warn('DB error: Ref %s.%s ' \
 | 
				
			||||||
 | 
					                    'contains a %s instance "%s". It was removed.' % \
 | 
				
			||||||
 | 
					                    (self.meta_type, fieldName, dummyObject.meta_type,
 | 
				
			||||||
 | 
					                     dummyObject.getId()))
 | 
				
			||||||
 | 
					            exec 'self.set%s(linkedObjects)' % suffix
 | 
				
			||||||
        if res.objects and noListIfSingleObj:
 | 
					        if res.objects and noListIfSingleObj:
 | 
				
			||||||
            if appyType.multiplicity[1] == 1:
 | 
					            if appyType.multiplicity[1] == 1:
 | 
				
			||||||
                res.objects = res.objects[0]
 | 
					                res.objects = res.objects[0]
 | 
				
			||||||
| 
						 | 
					@ -413,18 +429,6 @@ class AbstractMixin:
 | 
				
			||||||
        res = sortedObjectsUids.index(obj.UID())
 | 
					        res = sortedObjectsUids.index(obj.UID())
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def getAppyRefPortalType(self, fieldName):
 | 
					 | 
				
			||||||
        '''Gets the portal type of objects linked to me through Ref field named
 | 
					 | 
				
			||||||
           p_fieldName.'''
 | 
					 | 
				
			||||||
        appyType = self.getAppyType(fieldName)
 | 
					 | 
				
			||||||
        tool = self.getTool()
 | 
					 | 
				
			||||||
        if self._appy_meta_type == 'Flavour':
 | 
					 | 
				
			||||||
            flavour = self.appy()
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            portalTypeName = self._appy_getPortalType(self.REQUEST)
 | 
					 | 
				
			||||||
            flavour = tool.getFlavour(portalTypeName)
 | 
					 | 
				
			||||||
        return self._appy_getAtType(appyType.klass, flavour)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def getAppyType(self, name, asDict=False, className=None):
 | 
					    def getAppyType(self, name, asDict=False, className=None):
 | 
				
			||||||
        '''Returns the Appy type named p_name. If no p_className is defined, the
 | 
					        '''Returns the Appy type named p_name. If no p_className is defined, the
 | 
				
			||||||
           field is supposed to belong to self's class.'''
 | 
					           field is supposed to belong to self's class.'''
 | 
				
			||||||
| 
						 | 
					@ -696,10 +700,10 @@ class AbstractMixin:
 | 
				
			||||||
            # Get the corresponding Appy transition
 | 
					            # Get the corresponding Appy transition
 | 
				
			||||||
            transition = workflow._transitionsMapping[transitionName]
 | 
					            transition = workflow._transitionsMapping[transitionName]
 | 
				
			||||||
            user = self.portal_membership.getAuthenticatedMember()
 | 
					            user = self.portal_membership.getAuthenticatedMember()
 | 
				
			||||||
            if isinstance(transition.condition, basestring):
 | 
					            if isinstance(transition.condition, Role):
 | 
				
			||||||
                # It is a role. Transition may be triggered if the user has this
 | 
					                # It is a role. Transition may be triggered if the user has this
 | 
				
			||||||
                # role.
 | 
					                # role.
 | 
				
			||||||
                res = user.has_role(transition.condition, self)
 | 
					                res = user.has_role(transition.condition.name, self)
 | 
				
			||||||
            elif type(transition.condition) == types.FunctionType:
 | 
					            elif type(transition.condition) == types.FunctionType:
 | 
				
			||||||
                res = transition.condition(workflow, self.appy())
 | 
					                res = transition.condition(workflow, self.appy())
 | 
				
			||||||
            elif type(transition.condition) in (tuple, list):
 | 
					            elif type(transition.condition) in (tuple, list):
 | 
				
			||||||
| 
						 | 
					@ -843,28 +847,6 @@ class AbstractMixin:
 | 
				
			||||||
        rq.appyWrappers[uid] = wrapper
 | 
					        rq.appyWrappers[uid] = wrapper
 | 
				
			||||||
        return wrapper
 | 
					        return wrapper
 | 
				
			||||||
 
 | 
					 
 | 
				
			||||||
    def _appy_getAtType(self, appyClass, flavour=None):
 | 
					 | 
				
			||||||
        '''Gets the name of the Archetypes class that corresponds to
 | 
					 | 
				
			||||||
           p_appyClass (which is a Python class coming from the user
 | 
					 | 
				
			||||||
           application). If p_flavour is specified, the method returns the name
 | 
					 | 
				
			||||||
           of the specific Archetypes class in this flavour (ie suffixed with
 | 
					 | 
				
			||||||
           the flavour number).'''
 | 
					 | 
				
			||||||
        res = ClassDescriptor.getClassName(appyClass)
 | 
					 | 
				
			||||||
        appName = self.getProductConfig().PROJECTNAME
 | 
					 | 
				
			||||||
        if res.find('Extensions_appyWrappers') != -1:
 | 
					 | 
				
			||||||
            # This is not a content type defined Maybe I am a tool or flavour
 | 
					 | 
				
			||||||
            res = appName + appyClass.__name__
 | 
					 | 
				
			||||||
        elif issubclass(appyClass, appy.gen.Tool):
 | 
					 | 
				
			||||||
            # This is the custom tool
 | 
					 | 
				
			||||||
            res = '%sTool' % appName
 | 
					 | 
				
			||||||
        elif issubclass(appyClass, appy.gen.Flavour):
 | 
					 | 
				
			||||||
            # This is the custom Flavour
 | 
					 | 
				
			||||||
            res = '%sFlavour' % appName
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            if flavour and flavour.number != 1:
 | 
					 | 
				
			||||||
                res += '_%d' % flavour.number
 | 
					 | 
				
			||||||
        return res
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    def _appy_getRefsBack(self, fieldName, relName, ploneObjects=False,
 | 
					    def _appy_getRefsBack(self, fieldName, relName, ploneObjects=False,
 | 
				
			||||||
                           noListIfSingleObj=False):
 | 
					                           noListIfSingleObj=False):
 | 
				
			||||||
        '''This method returns the list of objects linked to this one
 | 
					        '''This method returns the list of objects linked to this one
 | 
				
			||||||
| 
						 | 
					@ -927,19 +909,14 @@ class AbstractMixin:
 | 
				
			||||||
            if appyType.type != 'Ref': continue
 | 
					            if appyType.type != 'Ref': continue
 | 
				
			||||||
            if appyType.isBack or appyType.link: continue
 | 
					            if appyType.isBack or appyType.link: continue
 | 
				
			||||||
            # Indeed, no possibility to create objects with such Ref
 | 
					            # Indeed, no possibility to create objects with such Ref
 | 
				
			||||||
            refContentTypeName = self.getAppyRefPortalType(appyType.name)
 | 
					            refType = self.getTool().getPortalType(appyType.klass)
 | 
				
			||||||
            refContentType = getattr(self.portal_types, refContentTypeName)
 | 
					            if refType not in addPermissions: continue
 | 
				
			||||||
            refMetaType = refContentType.content_meta_type
 | 
					 | 
				
			||||||
            if refMetaType not in addPermissions: continue
 | 
					 | 
				
			||||||
            # Indeed, there is no specific "add" permission is defined for tool
 | 
					 | 
				
			||||||
            # and flavour, for example.
 | 
					 | 
				
			||||||
            appyClass = refContentType.wrapperClass.__bases__[-1]
 | 
					 | 
				
			||||||
            # Get roles that may add this content type
 | 
					            # Get roles that may add this content type
 | 
				
			||||||
            creators = getattr(appyClass, 'creators', None)
 | 
					            creators = getattr(appyType.klass, 'creators', None)
 | 
				
			||||||
            if not creators:
 | 
					            if not creators:
 | 
				
			||||||
                creators = self.getProductConfig().defaultAddRoles
 | 
					                creators = self.getProductConfig().defaultAddRoles
 | 
				
			||||||
            # Add those creators to the list of creators for this meta_type
 | 
					            # Add those creators to the list of creators for this meta_type
 | 
				
			||||||
            addPermission = addPermissions[refMetaType]
 | 
					            addPermission = addPermissions[refType]
 | 
				
			||||||
            if addPermission in allCreators:
 | 
					            if addPermission in allCreators:
 | 
				
			||||||
                allCreators[addPermission] = allCreators[\
 | 
					                allCreators[addPermission] = allCreators[\
 | 
				
			||||||
                                             addPermission].union(creators)
 | 
					                                             addPermission].union(creators)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,7 +7,7 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
import copy, types
 | 
					import copy, types
 | 
				
			||||||
from appy.gen import Type, Integer, String, File, Ref, Boolean, Selection, Group
 | 
					from appy.gen import *
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class ModelClass:
 | 
					class ModelClass:
 | 
				
			||||||
| 
						 | 
					@ -70,6 +70,25 @@ class ModelClass:
 | 
				
			||||||
            res += '    %s=%s\n' % (attrName, klass._appy_getTypeBody(appyType))
 | 
					            res += '    %s=%s\n' % (attrName, klass._appy_getTypeBody(appyType))
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class User(ModelClass):
 | 
				
			||||||
 | 
					    # All methods defined below are fake. Real versions are in the wrapper.
 | 
				
			||||||
 | 
					    title = String(show=False)
 | 
				
			||||||
 | 
					    gm = {'group': 'main', 'multiplicity': (1,1)}
 | 
				
			||||||
 | 
					    name = String(**gm)
 | 
				
			||||||
 | 
					    firstName = String(**gm)
 | 
				
			||||||
 | 
					    def showLogin(self): pass
 | 
				
			||||||
 | 
					    def validateLogin(self): pass
 | 
				
			||||||
 | 
					    login = String(show=showLogin, validator=validateLogin, **gm)
 | 
				
			||||||
 | 
					    def showPassword(self): pass
 | 
				
			||||||
 | 
					    def validatePassword(self): pass
 | 
				
			||||||
 | 
					    password1 = String(format=String.PASSWORD, show=showPassword,
 | 
				
			||||||
 | 
					                       validator=validatePassword, **gm)
 | 
				
			||||||
 | 
					    password2 = String(format=String.PASSWORD, show=showPassword, **gm)
 | 
				
			||||||
 | 
					    gm['multiplicity'] = (0, None)
 | 
				
			||||||
 | 
					    roles = String(validator=Selection('getGrantableRoles'), **gm)
 | 
				
			||||||
 | 
					    _appy_attributes = ['title', 'name', 'firstName', 'login',
 | 
				
			||||||
 | 
					                        'password1', 'password2', 'roles']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PodTemplate(ModelClass):
 | 
					class PodTemplate(ModelClass):
 | 
				
			||||||
    description = String(format=String.TEXT)
 | 
					    description = String(format=String.TEXT)
 | 
				
			||||||
    podTemplate = File(multiplicity=(1,1))
 | 
					    podTemplate = File(multiplicity=(1,1))
 | 
				
			||||||
| 
						 | 
					@ -290,12 +309,18 @@ class Tool(ModelClass):
 | 
				
			||||||
                   # First arg is None because we don't know yet if it will link
 | 
					                   # First arg is None because we don't know yet if it will link
 | 
				
			||||||
                   # to the predefined Flavour class or a custom class defined
 | 
					                   # to the predefined Flavour class or a custom class defined
 | 
				
			||||||
                   # in the application.
 | 
					                   # in the application.
 | 
				
			||||||
    def validPythonWithUno(self, value): pass
 | 
					    users = Ref(None, multiplicity=(0,None), add=True, link=False,
 | 
				
			||||||
 | 
					                back=Ref(attribute='toTool'), page='users',
 | 
				
			||||||
 | 
					                shownInfo=('login', 'title', 'roles'), showHeaders=True)
 | 
				
			||||||
 | 
					    # First arg is None because we don't know yet if it will link to the
 | 
				
			||||||
 | 
					    # predefined User class or a custom class defined in the application.
 | 
				
			||||||
 | 
					    def validPythonWithUno(self, value): pass # Real method in the wrapper
 | 
				
			||||||
    unoEnabledPython = String(group="connectionToOpenOffice",
 | 
					    unoEnabledPython = String(group="connectionToOpenOffice",
 | 
				
			||||||
                              validator=validPythonWithUno)
 | 
					                              validator=validPythonWithUno)
 | 
				
			||||||
    openOfficePort = Integer(default=2002, group="connectionToOpenOffice")
 | 
					    openOfficePort = Integer(default=2002, group="connectionToOpenOffice")
 | 
				
			||||||
    numberOfResultsPerPage = Integer(default=30)
 | 
					    numberOfResultsPerPage = Integer(default=30)
 | 
				
			||||||
    listBoxesMaximumWidth = Integer(default=100)
 | 
					    listBoxesMaximumWidth = Integer(default=100)
 | 
				
			||||||
    _appy_attributes = ['flavours', 'unoEnabledPython', 'openOfficePort',
 | 
					    _appy_attributes = ['flavours', 'users', 'unoEnabledPython',
 | 
				
			||||||
                        'numberOfResultsPerPage', 'listBoxesMaximumWidth']
 | 
					                        'openOfficePort', 'numberOfResultsPerPage',
 | 
				
			||||||
 | 
					                        'listBoxesMaximumWidth']
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -174,7 +174,7 @@
 | 
				
			||||||
                 tal:content="structure python: tool.translate('%s_page_%s' % (contextObj.meta_type, aPage))">
 | 
					                 tal:content="structure python: tool.translate('%s_page_%s' % (contextObj.meta_type, aPage))">
 | 
				
			||||||
              </a>
 | 
					              </a>
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
            <td>
 | 
					            <td align="right">
 | 
				
			||||||
              <img tal:define="nav request/nav|nothing;
 | 
					              <img tal:define="nav request/nav|nothing;
 | 
				
			||||||
                               nav python: test(nav, '&nav=%s' % nav, '')"
 | 
					                               nav python: test(nav, '&nav=%s' % nav, '')"
 | 
				
			||||||
                   title="Edit" i18n:domain="plone" i18n:attributes="title" style="cursor:pointer"
 | 
					                   title="Edit" i18n:domain="plone" i18n:attributes="title" style="cursor:pointer"
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -104,7 +104,7 @@
 | 
				
			||||||
                 objs refObjects/objects;
 | 
					                 objs refObjects/objects;
 | 
				
			||||||
                 totalNumber refObjects/totalNumber;
 | 
					                 totalNumber refObjects/totalNumber;
 | 
				
			||||||
                 batchSize refObjects/batchSize;
 | 
					                 batchSize refObjects/batchSize;
 | 
				
			||||||
                 folder python: test(contextObj.isPrincipiaFolderish, contextObj, contextObj.getParentNode());
 | 
					                 folder python: contextObj.isPrincipiaFolderish and contextObj or contextObj.getParentNode();
 | 
				
			||||||
                 flavour python:tool.getFlavour(contextObj);
 | 
					                 flavour python:tool.getFlavour(contextObj);
 | 
				
			||||||
                 linkedPortalType python:flavour.getPortalType(appyType['klass']);
 | 
					                 linkedPortalType python:flavour.getPortalType(appyType['klass']);
 | 
				
			||||||
                 addPermission python: '%s: Add %s' % (tool.getAppName(), linkedPortalType);
 | 
					                 addPermission python: '%s: Add %s' % (tool.getAppName(), linkedPortalType);
 | 
				
			||||||
| 
						 | 
					@ -205,7 +205,7 @@
 | 
				
			||||||
            <tal:comment replace="nothing">Object title, shown here if not specified somewhere
 | 
					            <tal:comment replace="nothing">Object title, shown here if not specified somewhere
 | 
				
			||||||
              else in appyType.shownInfo.</tal:comment>
 | 
					              else in appyType.shownInfo.</tal:comment>
 | 
				
			||||||
            <td tal:condition="python: 'title' not in appyType['shownInfo']"><metal:showObjectTitle
 | 
					            <td tal:condition="python: 'title' not in appyType['shownInfo']"><metal:showObjectTitle
 | 
				
			||||||
                use-macro="portal/skyn/widgets/ref/macros/objectTitle"/> 
 | 
					                use-macro="portal/skyn/widgets/ref/macros/objectTitle"/>
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
            <tal:comment replace="nothing">Additional fields that must be shown</tal:comment>
 | 
					            <tal:comment replace="nothing">Additional fields that must be shown</tal:comment>
 | 
				
			||||||
            <td tal:repeat="widget widgets">
 | 
					            <td tal:repeat="widget widgets">
 | 
				
			||||||
| 
						 | 
					@ -217,7 +217,7 @@
 | 
				
			||||||
                                          innerRef python:True"
 | 
					                                          innerRef python:True"
 | 
				
			||||||
                                  condition="python: widget['name'] != 'title'">
 | 
					                                  condition="python: widget['name'] != 'title'">
 | 
				
			||||||
                <metal:showField use-macro="portal/skyn/widgets/show/macros/field" />
 | 
					                <metal:showField use-macro="portal/skyn/widgets/show/macros/field" />
 | 
				
			||||||
              </tal:showOtherField> 
 | 
					              </tal:showOtherField>
 | 
				
			||||||
            </td>
 | 
					            </td>
 | 
				
			||||||
            <tal:comment replace="nothing">Actions</tal:comment>
 | 
					            <tal:comment replace="nothing">Actions</tal:comment>
 | 
				
			||||||
            <td align="right">
 | 
					            <td align="right">
 | 
				
			||||||
| 
						 | 
					@ -248,7 +248,7 @@
 | 
				
			||||||
                 requestValue    python: request.get(rname, []);
 | 
					                 requestValue    python: request.get(rname, []);
 | 
				
			||||||
                 inRequest       python: request.has_key(rname);
 | 
					                 inRequest       python: request.has_key(rname);
 | 
				
			||||||
                 allObjects      python: contextObj.getSelectableAppyRefs(name);
 | 
					                 allObjects      python: contextObj.getSelectableAppyRefs(name);
 | 
				
			||||||
                 refUids         python: [o.UID() for o in here.getAppyRefs(name)['objects']];
 | 
					                 refUids         python: [o.UID() for o in contextObj.getAppyRefs(name)['objects']];
 | 
				
			||||||
                 isBeingCreated  python: contextObj.isTemporary() or ('/portal_factory/' in contextObj.absolute_url())">
 | 
					                 isBeingCreated  python: contextObj.isTemporary() or ('/portal_factory/' in contextObj.absolute_url())">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <select tal:attributes="name rname;
 | 
					  <select tal:attributes="name rname;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -26,14 +26,13 @@
 | 
				
			||||||
                        isOneLine python: fmt in (0,3)">
 | 
					                        isOneLine python: fmt in (0,3)">
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  <tal:choice condition="isSelect">
 | 
					  <tal:choice condition="isSelect">
 | 
				
			||||||
  <select tal:define="possibleValues python:contextObj.getPossibleValues(name, withTranslations=True, withBlankValue=True);
 | 
					  <select tal:define="possibleValues python:contextObj.getPossibleValues(name, withTranslations=True, withBlankValue=True)"
 | 
				
			||||||
                      multiValued python: (widget['multiplicity'][1] != 1) and True or False"
 | 
					 | 
				
			||||||
          tal:attributes="name name;
 | 
					          tal:attributes="name name;
 | 
				
			||||||
                          id name;
 | 
					                          id name;
 | 
				
			||||||
                          multiple python: multiValued and 'multiple' or '';
 | 
					                          multiple python: isMultiple and 'multiple' or '';
 | 
				
			||||||
                          onchange python: isMaster and ('javascript:updateSlaves(getMasterValue(this), \'%s\')' % widget['id']) or '';
 | 
					                          onchange python: isMaster and ('javascript:updateSlaves(getMasterValue(this), \'%s\')' % widget['id']) or '';
 | 
				
			||||||
                          class    widget/master_css;
 | 
					                          class    widget/master_css;
 | 
				
			||||||
                          size     python: multiValued and widget['height'] or 1">
 | 
					                          size     python: isMultiple and widget['height'] or 1">
 | 
				
			||||||
    <option tal:repeat="possibleValue possibleValues"
 | 
					    <option tal:repeat="possibleValue possibleValues"
 | 
				
			||||||
            tal:attributes="value python: possibleValue[0];
 | 
					            tal:attributes="value python: possibleValue[0];
 | 
				
			||||||
                            selected python:contextObj.fieldValueSelected(name, possibleValue[0], rawValue)"
 | 
					                            selected python:contextObj.fieldValueSelected(name, possibleValue[0], rawValue)"
 | 
				
			||||||
| 
						 | 
					@ -42,7 +41,8 @@
 | 
				
			||||||
  </tal:choice>
 | 
					  </tal:choice>
 | 
				
			||||||
  <tal:line condition="python: isOneLine and not isSelect">
 | 
					  <tal:line condition="python: isOneLine and not isSelect">
 | 
				
			||||||
    <input tal:attributes="id name; name name; size widget/width;
 | 
					    <input tal:attributes="id name; name name; size widget/width;
 | 
				
			||||||
                           value python: test(inRequest, requestValue, value)" type="text"/>
 | 
					                           value python: test(inRequest, requestValue, value);
 | 
				
			||||||
 | 
					                           type  python: (widget['format'] == 3) and 'password' or 'text'"/>
 | 
				
			||||||
  </tal:line>
 | 
					  </tal:line>
 | 
				
			||||||
  <tal:textarea condition="python: fmt == 1">
 | 
					  <tal:textarea condition="python: fmt == 1">
 | 
				
			||||||
    <textarea tal:attributes="id name; name name;
 | 
					    <textarea tal:attributes="id name; name name;
 | 
				
			||||||
| 
						 | 
					@ -66,8 +66,14 @@
 | 
				
			||||||
</metal:edit>
 | 
					</metal:edit>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<tal:comment replace="nothing">Cell macro for a String.</tal:comment>
 | 
					<tal:comment replace="nothing">Cell macro for a String.</tal:comment>
 | 
				
			||||||
<metal:cell define-macro="cell">
 | 
					<metal:cell define-macro="cell"
 | 
				
			||||||
 | 
					            tal:define="multipleValues python: value and isMultiple">
 | 
				
			||||||
 | 
					  <tal:multiple condition="multipleValues"
 | 
				
			||||||
 | 
					                content="python: ', '.join(value)">
 | 
				
			||||||
 | 
					  </tal:multiple>
 | 
				
			||||||
 | 
					  <tal:notMultiple condition="not: multipleValues">
 | 
				
			||||||
    <metal:call use-macro="portal/skyn/widgets/string/macros/view"/>
 | 
					    <metal:call use-macro="portal/skyn/widgets/string/macros/view"/>
 | 
				
			||||||
 | 
					  </tal:notMultiple>
 | 
				
			||||||
</metal:cell>
 | 
					</metal:cell>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
<tal:comment replace="nothing">Search macro for a String.</tal:comment>
 | 
					<tal:comment replace="nothing">Search macro for a String.</tal:comment>
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -20,7 +20,6 @@ class <!flavourName!>(OrderedBaseFolder, FlavourMixin):
 | 
				
			||||||
    allowed_content_types = []
 | 
					    allowed_content_types = []
 | 
				
			||||||
    filter_content_types = 0
 | 
					    filter_content_types = 0
 | 
				
			||||||
    global_allow = 1
 | 
					    global_allow = 1
 | 
				
			||||||
    #content_icon = '<!flavourName!>.gif'
 | 
					 | 
				
			||||||
    immediate_view = 'skyn/view'
 | 
					    immediate_view = 'skyn/view'
 | 
				
			||||||
    default_view = 'skyn/view'
 | 
					    default_view = 'skyn/view'
 | 
				
			||||||
    suppl_views = ()
 | 
					    suppl_views = ()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,38 +1,15 @@
 | 
				
			||||||
<!codeHeader!>
 | 
					<!codeHeader!>
 | 
				
			||||||
from zExceptions import BadRequest
 | 
					 | 
				
			||||||
from Products.CMFCore.DirectoryView import manage_addDirectoryView
 | 
					 | 
				
			||||||
from Products.ExternalMethod.ExternalMethod import ExternalMethod
 | 
					 | 
				
			||||||
from Products.Archetypes.Extensions.utils import installTypes
 | 
					 | 
				
			||||||
from Products.Archetypes.Extensions.utils import install_subskin
 | 
					 | 
				
			||||||
from Products.Archetypes.config import TOOL_NAME as ARCHETYPETOOLNAME
 | 
					 | 
				
			||||||
from Products.Archetypes.atapi import listTypes
 | 
					 | 
				
			||||||
from Products.<!applicationName!>.config import applicationRoles,defaultAddRoles
 | 
					 | 
				
			||||||
from Products.<!applicationName!>.config import product_globals as GLOBALS
 | 
					 | 
				
			||||||
import appy.gen
 | 
					import appy.gen
 | 
				
			||||||
from appy.gen.plone25.installer import PloneInstaller
 | 
					from appy.gen.plone25.installer import PloneInstaller
 | 
				
			||||||
<!imports!>
 | 
					import Products.<!applicationName!>.config as config
 | 
				
			||||||
catalogMap = {}
 | 
					
 | 
				
			||||||
<!catalogMap!>
 | 
					 | 
				
			||||||
appClasses = <!appClasses!>
 | 
					 | 
				
			||||||
appClassNames = [<!appClassNames!>]
 | 
					 | 
				
			||||||
allClassNames = [<!allClassNames!>]
 | 
					 | 
				
			||||||
workflows = {<!workflows!>}
 | 
					 | 
				
			||||||
showPortlet = <!showPortlet!>
 | 
					 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
def install(self, reinstall=False):
 | 
					def install(self, reinstall=False):
 | 
				
			||||||
    '''Installation of product "<!applicationName!>"'''
 | 
					    '''Installation procedure.'''
 | 
				
			||||||
    ploneInstaller = PloneInstaller(reinstall, "<!applicationName!>", self,
 | 
					    return PloneInstaller(reinstall, self, config).install()
 | 
				
			||||||
        <!minimalistPlone!>, appClasses, appClassNames, allClassNames,
 | 
					 | 
				
			||||||
        catalogMap, applicationRoles, defaultAddRoles, workflows,
 | 
					 | 
				
			||||||
        <!appFrontPage!>, showPortlet, globals())
 | 
					 | 
				
			||||||
    return ploneInstaller.install()
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
def uninstall(self, reinstall=False):
 | 
					def uninstall(self, reinstall=False):
 | 
				
			||||||
    '''Uninstallation of product "<!applicationName!>"'''
 | 
					    '''Uninstallation procedure.'''
 | 
				
			||||||
    ploneInstaller = PloneInstaller(reinstall, "<!applicationName!>", self,
 | 
					    return PloneInstaller(reinstall, self, config).uninstall()
 | 
				
			||||||
        <!minimalistPlone!>, appClasses, appClassNames, allClassNames,
 | 
					 | 
				
			||||||
        catalogMap, applicationRoles, defaultAddRoles, workflows,
 | 
					 | 
				
			||||||
        <!appFrontPage!>, showPortlet, globals())
 | 
					 | 
				
			||||||
    return ploneInstaller.uninstall()
 | 
					 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,19 +14,17 @@ class <!applicationName!>PodTemplate(BaseContent, PodTemplateMixin):
 | 
				
			||||||
    '''POD template.'''
 | 
					    '''POD template.'''
 | 
				
			||||||
    security = ClassSecurityInfo()
 | 
					    security = ClassSecurityInfo()
 | 
				
			||||||
    __implements__ = (getattr(BaseContent,'__implements__',()),)
 | 
					    __implements__ = (getattr(BaseContent,'__implements__',()),)
 | 
				
			||||||
 | 
					 | 
				
			||||||
    archetype_name = '<!applicationName!>PodTemplate'
 | 
					    archetype_name = '<!applicationName!>PodTemplate'
 | 
				
			||||||
    meta_type = '<!applicationName!>PodTemplate'
 | 
					    meta_type = '<!applicationName!>PodTemplate'
 | 
				
			||||||
    portal_type = '<!applicationName!>PodTemplate'
 | 
					    portal_type = '<!applicationName!>PodTemplate'
 | 
				
			||||||
    allowed_content_types = []
 | 
					    allowed_content_types = []
 | 
				
			||||||
    filter_content_types = 0
 | 
					    filter_content_types = 0
 | 
				
			||||||
    global_allow = 1
 | 
					    global_allow = 1
 | 
				
			||||||
    #content_icon = '<!applicationName!>PodTemplate.gif'
 | 
					 | 
				
			||||||
    immediate_view = 'skyn/view'
 | 
					    immediate_view = 'skyn/view'
 | 
				
			||||||
    default_view = 'skyn/view'
 | 
					    default_view = 'skyn/view'
 | 
				
			||||||
    suppl_views = ()
 | 
					    suppl_views = ()
 | 
				
			||||||
    typeDescription = "<!applicationName!>PodTemplate"
 | 
					    typeDescription = "<!applicationName!>PodTemplate"
 | 
				
			||||||
    typeDescMsgId = '<!applicationName!>_edit_descr'
 | 
					    typeDescMsgId = '<!applicationName!>PodTemplate_edit_descr'
 | 
				
			||||||
    wrapperClass = <!wrapperClass!>
 | 
					    wrapperClass = <!wrapperClass!>
 | 
				
			||||||
    schema = fullSchema
 | 
					    schema = fullSchema
 | 
				
			||||||
    for elem in dir(PodTemplateMixin):
 | 
					    for elem in dir(PodTemplateMixin):
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -170,21 +170,13 @@ th {
 | 
				
			||||||
  /* overflow: visible; IE produces ugly results with this */
 | 
					  /* overflow: visible; IE produces ugly results with this */
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.listing {
 | 
					.listing { margin: 0em 0em; }
 | 
				
			||||||
  margin: 0em 0em;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.listing td, .stx table td {
 | 
					.listing td, .stx table td {
 | 
				
			||||||
  padding-right: 0.1em;
 | 
					  padding : 0.1em 0.3em 0.1em 0.3em;
 | 
				
			||||||
  padding-left: 0.3em;
 | 
					 | 
				
			||||||
  padding-top: 0.3em;
 | 
					 | 
				
			||||||
  padding-bottom: 0em;
 | 
					 | 
				
			||||||
  border-top : 1px solid #8CACBB;
 | 
					  border-top : 1px solid #8CACBB;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					.listing th, .stx table th { padding: 0.25em 0.3em; }
 | 
				
			||||||
.vertical td {
 | 
					.vertical td { padding-left: 0.3em; }
 | 
				
			||||||
  padding-left: 0.3em;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
.innerAppyTable {
 | 
					.innerAppyTable {
 | 
				
			||||||
  border-width: 0px;
 | 
					  border-width: 0px;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										34
									
								
								gen/plone25/templates/UserTemplate.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								gen/plone25/templates/UserTemplate.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,34 @@
 | 
				
			||||||
 | 
					<!codeHeader!>
 | 
				
			||||||
 | 
					from AccessControl import ClassSecurityInfo
 | 
				
			||||||
 | 
					from Products.Archetypes.atapi import *
 | 
				
			||||||
 | 
					import Products.<!applicationName!>.config
 | 
				
			||||||
 | 
					from appy.gen.plone25.mixins.UserMixin import UserMixin
 | 
				
			||||||
 | 
					from Extensions.appyWrappers import <!wrapperClass!>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					schema = Schema((<!fields!>
 | 
				
			||||||
 | 
					),)
 | 
				
			||||||
 | 
					fullSchema = BaseSchema.copy() + schema.copy()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class <!applicationName!>User(BaseContent, UserMixin):
 | 
				
			||||||
 | 
					    '''Configuration flavour class for <!applicationName!>.'''
 | 
				
			||||||
 | 
					    security = ClassSecurityInfo()
 | 
				
			||||||
 | 
					    __implements__ = (getattr(BaseContent,'__implements__',()),)
 | 
				
			||||||
 | 
					    archetype_name = '<!applicationName!>User'
 | 
				
			||||||
 | 
					    meta_type = '<!applicationName!>User'
 | 
				
			||||||
 | 
					    portal_type = '<!applicationName!>User'
 | 
				
			||||||
 | 
					    allowed_content_types = []
 | 
				
			||||||
 | 
					    filter_content_types = 0
 | 
				
			||||||
 | 
					    global_allow = 1
 | 
				
			||||||
 | 
					    immediate_view = 'skyn/view'
 | 
				
			||||||
 | 
					    default_view = 'skyn/view'
 | 
				
			||||||
 | 
					    suppl_views = ()
 | 
				
			||||||
 | 
					    typeDescription = "<!applicationName!>User"
 | 
				
			||||||
 | 
					    typeDescMsgId = '<!applicationName!>User_edit_descr'
 | 
				
			||||||
 | 
					    i18nDomain = '<!applicationName!>'
 | 
				
			||||||
 | 
					    schema = fullSchema
 | 
				
			||||||
 | 
					    wrapperClass = <!wrapperClass!>
 | 
				
			||||||
 | 
					    for elem in dir(UserMixin):
 | 
				
			||||||
 | 
					        if not elem.startswith('__'): security.declarePublic(elem)
 | 
				
			||||||
 | 
					<!commonMethods!>
 | 
				
			||||||
 | 
					<!methods!>
 | 
				
			||||||
 | 
					registerType(<!applicationName!>User, '<!applicationName!>')
 | 
				
			||||||
| 
						 | 
					@ -25,20 +25,8 @@ def countTest():
 | 
				
			||||||
    numberOfExecutedTests += 1
 | 
					    numberOfExecutedTests += 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
from config import *
 | 
					import config
 | 
				
			||||||
from ZPublisher.HTTPRequest import BaseRequest
 | 
					 | 
				
			||||||
import logging
 | 
					 | 
				
			||||||
try:
 | 
					 | 
				
			||||||
    import CustomizationPolicy
 | 
					 | 
				
			||||||
except ImportError:
 | 
					 | 
				
			||||||
    CustomizationPolicy = None
 | 
					 | 
				
			||||||
from Products.CMFCore import utils as cmfutils
 | 
					 | 
				
			||||||
from Products.CMFCore import DirectoryView
 | 
					 | 
				
			||||||
from Products.CMFPlone.utils import ToolInit
 | 
					 | 
				
			||||||
from Products.Archetypes.atapi import *
 | 
					 | 
				
			||||||
from Products.Archetypes import listTypes
 | 
					 | 
				
			||||||
from appy.gen.plone25.installer import ZopeInstaller
 | 
					from appy.gen.plone25.installer import ZopeInstaller
 | 
				
			||||||
logger = logging.getLogger(PROJECTNAME)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
# Zope-level installation of the generated product. ----------------------------
 | 
					# Zope-level installation of the generated product. ----------------------------
 | 
				
			||||||
def initialize(context):
 | 
					def initialize(context):
 | 
				
			||||||
| 
						 | 
					@ -46,8 +34,6 @@ def initialize(context):
 | 
				
			||||||
    # I need to do those imports here; else, types and add permissions will not
 | 
					    # I need to do those imports here; else, types and add permissions will not
 | 
				
			||||||
    # be registered.
 | 
					    # be registered.
 | 
				
			||||||
    classes = [<!classes!>]
 | 
					    classes = [<!classes!>]
 | 
				
			||||||
    ZopeInstaller(context, PROJECTNAME,
 | 
					    ZopeInstaller(context, <!applicationName!>Tool.<!applicationName!>Tool,
 | 
				
			||||||
        <!applicationName!>Tool.<!applicationName!>Tool,
 | 
					        config, classes).install()
 | 
				
			||||||
        DEFAULT_ADD_CONTENT_PERMISSION, ADD_CONTENT_PERMISSIONS,
 | 
					 | 
				
			||||||
        logger, globals(), classes).install()
 | 
					 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -4,6 +4,7 @@ from appy.gen.plone25.wrappers import AbstractWrapper
 | 
				
			||||||
from appy.gen.plone25.wrappers.ToolWrapper import ToolWrapper
 | 
					from appy.gen.plone25.wrappers.ToolWrapper import ToolWrapper
 | 
				
			||||||
from appy.gen.plone25.wrappers.FlavourWrapper import FlavourWrapper
 | 
					from appy.gen.plone25.wrappers.FlavourWrapper import FlavourWrapper
 | 
				
			||||||
from appy.gen.plone25.wrappers.PodTemplateWrapper import PodTemplateWrapper
 | 
					from appy.gen.plone25.wrappers.PodTemplateWrapper import PodTemplateWrapper
 | 
				
			||||||
 | 
					from appy.gen.plone25.wrappers.UserWrapper import UserWrapper
 | 
				
			||||||
from Globals import InitializeClass
 | 
					from Globals import InitializeClass
 | 
				
			||||||
from AccessControl import ClassSecurityInfo
 | 
					from AccessControl import ClassSecurityInfo
 | 
				
			||||||
<!imports!>
 | 
					<!imports!>
 | 
				
			||||||
| 
						 | 
					@ -11,6 +12,9 @@ from AccessControl import ClassSecurityInfo
 | 
				
			||||||
class PodTemplate(PodTemplateWrapper):
 | 
					class PodTemplate(PodTemplateWrapper):
 | 
				
			||||||
    '''This class represents a POD template for this application.'''
 | 
					    '''This class represents a POD template for this application.'''
 | 
				
			||||||
<!podTemplateBody!>
 | 
					<!podTemplateBody!>
 | 
				
			||||||
 | 
					class User(UserWrapper):
 | 
				
			||||||
 | 
					    '''This class represents a user.'''
 | 
				
			||||||
 | 
					<!userBody!>
 | 
				
			||||||
class Flavour(FlavourWrapper):
 | 
					class Flavour(FlavourWrapper):
 | 
				
			||||||
    '''This class represents the Appy class used for defining a flavour.'''
 | 
					    '''This class represents the Appy class used for defining a flavour.'''
 | 
				
			||||||
    folder=True
 | 
					    folder=True
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,10 +10,26 @@ import Extensions.appyWrappers as wraps
 | 
				
			||||||
# every Archetype instance has a method "getProductConfig" that returns this
 | 
					# every Archetype instance has a method "getProductConfig" that returns this
 | 
				
			||||||
# module.
 | 
					# module.
 | 
				
			||||||
from persistent.list import PersistentList
 | 
					from persistent.list import PersistentList
 | 
				
			||||||
 | 
					from zExceptions import BadRequest
 | 
				
			||||||
 | 
					from ZPublisher.HTTPRequest import BaseRequest
 | 
				
			||||||
 | 
					try:
 | 
				
			||||||
 | 
					    import CustomizationPolicy
 | 
				
			||||||
 | 
					except ImportError:
 | 
				
			||||||
 | 
					    CustomizationPolicy = None
 | 
				
			||||||
from OFS.Image import File
 | 
					from OFS.Image import File
 | 
				
			||||||
from DateTime import DateTime
 | 
					from DateTime import DateTime
 | 
				
			||||||
 | 
					from Products.CMFCore import utils as cmfutils
 | 
				
			||||||
from Products.CMFCore.utils import getToolByName
 | 
					from Products.CMFCore.utils import getToolByName
 | 
				
			||||||
from Products.CMFPlone.PloneBatch import Batch
 | 
					from Products.CMFPlone.PloneBatch import Batch
 | 
				
			||||||
 | 
					from Products.CMFPlone.utils import ToolInit
 | 
				
			||||||
 | 
					from Products.CMFCore import DirectoryView
 | 
				
			||||||
 | 
					from Products.CMFCore.DirectoryView import manage_addDirectoryView
 | 
				
			||||||
 | 
					from Products.ExternalMethod.ExternalMethod import ExternalMethod
 | 
				
			||||||
 | 
					from Products.Archetypes.Extensions.utils import installTypes
 | 
				
			||||||
 | 
					from Products.Archetypes.Extensions.utils import install_subskin
 | 
				
			||||||
 | 
					from Products.Archetypes.config import TOOL_NAME as ARCHETYPETOOLNAME
 | 
				
			||||||
 | 
					from Products.Archetypes import listTypes, process_types
 | 
				
			||||||
 | 
					import appy.gen
 | 
				
			||||||
import logging
 | 
					import logging
 | 
				
			||||||
logger = logging.getLogger('<!applicationName!>')
 | 
					logger = logging.getLogger('<!applicationName!>')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -25,10 +41,19 @@ DEFAULT_ADD_CONTENT_PERMISSION = "Add portal content"
 | 
				
			||||||
ADD_CONTENT_PERMISSIONS = {
 | 
					ADD_CONTENT_PERMISSIONS = {
 | 
				
			||||||
<!addPermissions!>}
 | 
					<!addPermissions!>}
 | 
				
			||||||
setDefaultRoles(DEFAULT_ADD_CONTENT_PERMISSION, tuple(defaultAddRoles))
 | 
					setDefaultRoles(DEFAULT_ADD_CONTENT_PERMISSION, tuple(defaultAddRoles))
 | 
				
			||||||
product_globals = globals()
 | 
					 | 
				
			||||||
applicationRoles = [<!roles!>]
 | 
					 | 
				
			||||||
rootClasses = [<!rootClasses!>]
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Applications classes, in various formats and flavours
 | 
				
			||||||
 | 
					rootClasses = [<!rootClasses!>]
 | 
				
			||||||
 | 
					appClasses = <!appClasses!>
 | 
				
			||||||
 | 
					appClassNames = [<!appClassNames!>]
 | 
				
			||||||
 | 
					allClassNames = [<!allClassNames!>]
 | 
				
			||||||
 | 
					# List of classes that must be hidden from the catalog
 | 
				
			||||||
 | 
					catalogMap = {}
 | 
				
			||||||
 | 
					<!catalogMap!>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Dict whose keys are class names and whose values are workflow names (=the
 | 
				
			||||||
 | 
					# workflow used by the content type)
 | 
				
			||||||
 | 
					workflows = {<!workflows!>}
 | 
				
			||||||
# In the following dict, we keep one instance for every Appy workflow defined
 | 
					# In the following dict, we keep one instance for every Appy workflow defined
 | 
				
			||||||
# in the application. Those prototypical instances will be used for executing
 | 
					# in the application. Those prototypical instances will be used for executing
 | 
				
			||||||
# user-defined actions and transitions. For each instance, we add a special
 | 
					# user-defined actions and transitions. For each instance, we add a special
 | 
				
			||||||
| 
						 | 
					@ -43,4 +68,16 @@ attributes = {<!attributes!>}
 | 
				
			||||||
# In the followinf dict, we store, for every Appy class, a dict of appy types
 | 
					# In the followinf dict, we store, for every Appy class, a dict of appy types
 | 
				
			||||||
# keyed by their names.
 | 
					# keyed by their names.
 | 
				
			||||||
attributesDict = {<!attributesDict!>}
 | 
					attributesDict = {<!attributesDict!>}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Application roles
 | 
				
			||||||
 | 
					applicationRoles = [<!roles!>]
 | 
				
			||||||
 | 
					applicationGlobalRoles = [<!gRoles!>]
 | 
				
			||||||
 | 
					grantableRoles = [<!grRoles!>]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Configuration options
 | 
				
			||||||
 | 
					showPortlet = <!showPortlet!>
 | 
				
			||||||
 | 
					languages = [<!languages!>]
 | 
				
			||||||
 | 
					languageSelector = <!languageSelector!>
 | 
				
			||||||
 | 
					minimalistPlone = <!minimalistPlone!>
 | 
				
			||||||
 | 
					appFrontPage = <!appFrontPage!>
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										93
									
								
								gen/plone25/wrappers/UserWrapper.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								gen/plone25/wrappers/UserWrapper.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,93 @@
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					from appy.gen.plone25.wrappers import AbstractWrapper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					class UserWrapper(AbstractWrapper):
 | 
				
			||||||
 | 
					    def showLogin(self):
 | 
				
			||||||
 | 
					        '''When must we show the login field?'''
 | 
				
			||||||
 | 
					        if self.o.isTemporary(): return 'edit'
 | 
				
			||||||
 | 
					        return 'view'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def validateLogin(self, login):
 | 
				
			||||||
 | 
					        '''Is this p_login valid?'''
 | 
				
			||||||
 | 
					        # The login can't be the id of the whole site or "admin"
 | 
				
			||||||
 | 
					        if (login == self.o.portal_url.getPortalObject().getId()) or \
 | 
				
			||||||
 | 
					           (login == 'admin'):
 | 
				
			||||||
 | 
					            return self.translate(u'This username is reserved. Please choose ' \
 | 
				
			||||||
 | 
					                                   'a different name.', domain='plone')
 | 
				
			||||||
 | 
					        # Check that the login does not already exist and check some
 | 
				
			||||||
 | 
					        # Plone-specific rules.
 | 
				
			||||||
 | 
					        pr = self.o.portal_registration
 | 
				
			||||||
 | 
					        if not pr.isMemberIdAllowed(login):
 | 
				
			||||||
 | 
					            return self.translate(u'The login name you selected is already ' \
 | 
				
			||||||
 | 
					               'in use or is not valid. Please choose another.', domain='plone')
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def validatePassword(self, password):
 | 
				
			||||||
 | 
					        '''Is this p_password valid?'''
 | 
				
			||||||
 | 
					        # Password must be at least 5 chars length
 | 
				
			||||||
 | 
					        if len(password) < 5:
 | 
				
			||||||
 | 
					            return self.translate(u'Passwords must contain at least 5 letters.',
 | 
				
			||||||
 | 
					                                  domain='plone')
 | 
				
			||||||
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def showPassword(self):
 | 
				
			||||||
 | 
					        '''When must we show the 2 fields for entering a password ?'''
 | 
				
			||||||
 | 
					        if self.o.isTemporary(): return 'edit'
 | 
				
			||||||
 | 
					        return False
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def getGrantableRoles(self):
 | 
				
			||||||
 | 
					        '''Returns the list of roles that the admin can grant to a user.'''
 | 
				
			||||||
 | 
					        res = []
 | 
				
			||||||
 | 
					        for role in self.o.getProductConfig().grantableRoles:
 | 
				
			||||||
 | 
					            res.append( (role, self.translate('role_%s' % role)) )
 | 
				
			||||||
 | 
					        return res
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def validate(self, new, errors):
 | 
				
			||||||
 | 
					        '''Inter-field validation.'''
 | 
				
			||||||
 | 
					        page = self.request.get('page', 'main')
 | 
				
			||||||
 | 
					        if page == 'main':
 | 
				
			||||||
 | 
					            if hasattr(new, 'password1') and (new.password1 != new.password2):
 | 
				
			||||||
 | 
					                msg = self.translate(u'Passwords do not match.', domain='plone')
 | 
				
			||||||
 | 
					                errors.password1 = msg
 | 
				
			||||||
 | 
					                errors.password2 = msg
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def onEdit(self, created):
 | 
				
			||||||
 | 
					        self.title = self.firstName + ' ' + self.name
 | 
				
			||||||
 | 
					        pm = self.o.portal_membership
 | 
				
			||||||
 | 
					        if created:
 | 
				
			||||||
 | 
					            # Create the corresponding Plone user
 | 
				
			||||||
 | 
					            pm.addMember(self.login, self.password1, ('Member',), None)
 | 
				
			||||||
 | 
					            # Remove our own password copies
 | 
				
			||||||
 | 
					            self.password1 = self.password2 = ''
 | 
				
			||||||
 | 
					        # Perform updates on the corresponding Plone user
 | 
				
			||||||
 | 
					        ploneUser = self.o.portal_membership.getMemberById(self.login)
 | 
				
			||||||
 | 
					        ploneUser.setMemberProperties({'fullname': self.title})
 | 
				
			||||||
 | 
					        # Change group membership according to self.roles. Indeed, instead of
 | 
				
			||||||
 | 
					        # granting roles directly to the user, we will add the user to a
 | 
				
			||||||
 | 
					        # Appy-created group having this role.
 | 
				
			||||||
 | 
					        userRoles = self.roles
 | 
				
			||||||
 | 
					        userGroups = ploneUser.getGroups()
 | 
				
			||||||
 | 
					        for role in self.o.getProductConfig().grantableRoles:
 | 
				
			||||||
 | 
					            # Retrieve the group corresponding to this role
 | 
				
			||||||
 | 
					            groupName = '%s_group' % role
 | 
				
			||||||
 | 
					            if role == 'Manager':    groupName = 'Administrators'
 | 
				
			||||||
 | 
					            elif role == 'Reviewer': groupName = 'Reviewers'
 | 
				
			||||||
 | 
					            group = self.o.portal_groups.getGroupById(groupName)
 | 
				
			||||||
 | 
					            # Add or remove the user from this group according to its role(s).
 | 
				
			||||||
 | 
					            if role in userRoles:
 | 
				
			||||||
 | 
					                # Add the user if not already present in the group
 | 
				
			||||||
 | 
					                if groupName not in userGroups:
 | 
				
			||||||
 | 
					                    group.addMember(self.login)
 | 
				
			||||||
 | 
					            else:
 | 
				
			||||||
 | 
					                # Remove the user if it was in the corresponding group
 | 
				
			||||||
 | 
					                if groupName in userGroups:
 | 
				
			||||||
 | 
					                    group.removeMember(self.login)
 | 
				
			||||||
 | 
					        # Call the custom user "onEdit" method if it exists
 | 
				
			||||||
 | 
					        # XXX This code does not work.
 | 
				
			||||||
 | 
					        if len(self.__class__.__bases__) > 1:
 | 
				
			||||||
 | 
					            customUser = self.__class__.__bases__[-1]
 | 
				
			||||||
 | 
					            # There is a custom user class
 | 
				
			||||||
 | 
					            if customUser.__dict__.has_key('onEdit'):
 | 
				
			||||||
 | 
					                customUser.__dict__['onEdit'](self, created)
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					@ -151,13 +151,13 @@ class AbstractWrapper:
 | 
				
			||||||
        isField = isinstance(fieldNameOrClass, basestring)
 | 
					        isField = isinstance(fieldNameOrClass, basestring)
 | 
				
			||||||
        # Determine the portal type of the object to create
 | 
					        # Determine the portal type of the object to create
 | 
				
			||||||
        if isField:
 | 
					        if isField:
 | 
				
			||||||
            fieldName = fieldNameOrClass
 | 
					            fieldName = idPrefix = fieldNameOrClass
 | 
				
			||||||
            idPrefix = fieldName
 | 
					            appyType = self.o.getAppyType(fieldName)
 | 
				
			||||||
            portalType = self.o.getAppyRefPortalType(fieldName)
 | 
					            portalType = self.tool.o.getPortalType(appyType.klass)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            theClass = fieldNameOrClass
 | 
					            klass = fieldNameOrClass
 | 
				
			||||||
            idPrefix = theClass.__name__
 | 
					            idPrefix = klass.__name__
 | 
				
			||||||
            portalType = self.o._appy_getAtType(theClass, self.flavour.o)
 | 
					            portalType = self.tool.o.getPortalType(klass)
 | 
				
			||||||
        # Determine object id
 | 
					        # Determine object id
 | 
				
			||||||
        if kwargs.has_key('id'):
 | 
					        if kwargs.has_key('id'):
 | 
				
			||||||
            objId = kwargs['id']
 | 
					            objId = kwargs['id']
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -40,6 +40,7 @@ class PoMessage:
 | 
				
			||||||
        'comment every time a transition is triggered'
 | 
					        'comment every time a transition is triggered'
 | 
				
			||||||
    MSG_showAllStatesInPhaseFor = 'Show all states in phase'
 | 
					    MSG_showAllStatesInPhaseFor = 'Show all states in phase'
 | 
				
			||||||
    POD_TEMPLATE = 'POD template'
 | 
					    POD_TEMPLATE = 'POD template'
 | 
				
			||||||
 | 
					    USER = 'User'
 | 
				
			||||||
    POD_ASKACTION = 'Trigger related action'
 | 
					    POD_ASKACTION = 'Trigger related action'
 | 
				
			||||||
    DEFAULT_VALID_ERROR = 'Please fill or correct this.'
 | 
					    DEFAULT_VALID_ERROR = 'Please fill or correct this.'
 | 
				
			||||||
    REF_NO = 'No object.'
 | 
					    REF_NO = 'No object.'
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										17
									
								
								gen/utils.py
									
										
									
									
									
								
							
							
						
						
									
										17
									
								
								gen/utils.py
									
										
									
									
									
								
							| 
						 | 
					@ -308,4 +308,21 @@ class FileWrapper:
 | 
				
			||||||
                tool.log(CONVERSION_ERROR % (cmd, errorMessage), type='error')
 | 
					                tool.log(CONVERSION_ERROR % (cmd, errorMessage), type='error')
 | 
				
			||||||
                return
 | 
					                return
 | 
				
			||||||
        return filePath
 | 
					        return filePath
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
 | 
					def getClassName(klass, appName=None):
 | 
				
			||||||
 | 
					    '''Generates, from appy-class p_klass, the name of the corresponding
 | 
				
			||||||
 | 
					       Archetypes class. For some classes, name p_appName is required: it is
 | 
				
			||||||
 | 
					       part of the class name.'''
 | 
				
			||||||
 | 
					    moduleName = klass.__module__
 | 
				
			||||||
 | 
					    if (moduleName == 'appy.gen.plone25.model') or \
 | 
				
			||||||
 | 
					       moduleName.endswith('.appyWrappers'):
 | 
				
			||||||
 | 
					        # This is a model (generation time or run time)
 | 
				
			||||||
 | 
					        res = appName + klass.__name__
 | 
				
			||||||
 | 
					    elif klass.__bases__ and (klass.__bases__[-1].__module__ == 'appy.gen'):
 | 
				
			||||||
 | 
					        # This is a customized class (inherits from appy.gen.Tool, User,...)
 | 
				
			||||||
 | 
					        res = appName + klass.__bases__[-1].__name__
 | 
				
			||||||
 | 
					    else: # This is a standard class
 | 
				
			||||||
 | 
					        res = klass.__module__.replace('.', '_') + '_' + klass.__name__
 | 
				
			||||||
 | 
					    return res
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,20 +5,178 @@
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
import os, os.path
 | 
					import os, os.path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# List of names of language in their own language ------------------------------
 | 
				
			||||||
 | 
					# It was copied from Plone 2.5.5 (PloneLanguageTool), don't know any "authentic
 | 
				
			||||||
 | 
					# source" for that.
 | 
				
			||||||
 | 
					nativeNames = {
 | 
				
			||||||
 | 
					  'aa' : 'магIарул мацI',
 | 
				
			||||||
 | 
					  'ab' : 'бызшәа',
 | 
				
			||||||
 | 
					  'af' : 'Afrikaans',
 | 
				
			||||||
 | 
					  'am' : 'አማርኛ',
 | 
				
			||||||
 | 
					  'ar' : 'العربية',
 | 
				
			||||||
 | 
					  'as' : 'অসমিয়া',
 | 
				
			||||||
 | 
					  'ay' : 'Aymara',
 | 
				
			||||||
 | 
					  'az' : 'Azəri Türkçəsi',
 | 
				
			||||||
 | 
					  'ba' : 'Bashkir',
 | 
				
			||||||
 | 
					  'be' : 'Беларускі',
 | 
				
			||||||
 | 
					  'bg' : 'Български',
 | 
				
			||||||
 | 
					  'bh' : 'Bihari',
 | 
				
			||||||
 | 
					  'bi' : 'Bislama',
 | 
				
			||||||
 | 
					  'bn' : 'বাংলা',
 | 
				
			||||||
 | 
					  'bo' : 'བོད་སྐད་',
 | 
				
			||||||
 | 
					  'bs' : 'Bosanski',
 | 
				
			||||||
 | 
					  'br' : 'Brezhoneg',
 | 
				
			||||||
 | 
					  'ca' : 'Català',
 | 
				
			||||||
 | 
					  'ch' : 'Chamoru',
 | 
				
			||||||
 | 
					  'co' : 'Corsu',
 | 
				
			||||||
 | 
					  'cs' : 'Čeština',
 | 
				
			||||||
 | 
					  'cy' : 'Cymraeg',
 | 
				
			||||||
 | 
					  'da' : 'Dansk',
 | 
				
			||||||
 | 
					  'de' : 'Deutsch',
 | 
				
			||||||
 | 
					  'dz' : 'རྫོང་ཁ',
 | 
				
			||||||
 | 
					  'el' : 'Ελληνικά',
 | 
				
			||||||
 | 
					  'en' : 'English',
 | 
				
			||||||
 | 
					  'eo' : 'Esperanto',
 | 
				
			||||||
 | 
					  'es' : 'Español',
 | 
				
			||||||
 | 
					  'et' : 'Eesti',
 | 
				
			||||||
 | 
					  'eu' : 'Euskara',
 | 
				
			||||||
 | 
					  'fa' : 'فارسی',
 | 
				
			||||||
 | 
					  'fi' : 'Suomi',
 | 
				
			||||||
 | 
					  'fj' : 'Fiji',
 | 
				
			||||||
 | 
					  'fo' : 'Føroyska',
 | 
				
			||||||
 | 
					  'fr' : 'Français',
 | 
				
			||||||
 | 
					  'fy' : 'Frysk',
 | 
				
			||||||
 | 
					  'ga' : 'Gaeilge',
 | 
				
			||||||
 | 
					  'gd' : 'Gàidhlig',
 | 
				
			||||||
 | 
					  'gl' : 'Galego',
 | 
				
			||||||
 | 
					  'gn' : 'Guarani',
 | 
				
			||||||
 | 
					  'gu' : 'ગુજરાતી',
 | 
				
			||||||
 | 
					  'gv' : 'Gaelg',
 | 
				
			||||||
 | 
					  'ha' : 'هَوُس',
 | 
				
			||||||
 | 
					  'he' : 'עברית',
 | 
				
			||||||
 | 
					  'hi' : 'हिंदी',
 | 
				
			||||||
 | 
					  'hr' : 'Hrvatski',
 | 
				
			||||||
 | 
					  'hu' : 'Magyar',
 | 
				
			||||||
 | 
					  'hy' : 'Հայերէն',
 | 
				
			||||||
 | 
					  'ia' : 'Interlingua',
 | 
				
			||||||
 | 
					  'id' : 'Bahasa Indonesia',
 | 
				
			||||||
 | 
					  'ie' : 'Interlingue',
 | 
				
			||||||
 | 
					  'ik' : 'Inupiak',
 | 
				
			||||||
 | 
					  'is' : 'Íslenska',
 | 
				
			||||||
 | 
					  'it' : 'Italiano',
 | 
				
			||||||
 | 
					  'iu' : 'ᐃᓄᒃᑎᑐᑦ',
 | 
				
			||||||
 | 
					  'ja' : '日本語',
 | 
				
			||||||
 | 
					  'jbo': 'lojban',
 | 
				
			||||||
 | 
					  'jw' : 'Basa Jawi',
 | 
				
			||||||
 | 
					  'ka' : 'ქართული',
 | 
				
			||||||
 | 
					  'kk' : 'ﻗﺎﺯﺍﻗﺸﺎ',
 | 
				
			||||||
 | 
					  'kl' : 'Greenlandic',
 | 
				
			||||||
 | 
					  'km' : 'ខ្មែរ',
 | 
				
			||||||
 | 
					  'kn' : 'ಕನ್ನಡ',
 | 
				
			||||||
 | 
					  'ko' : '한국어',
 | 
				
			||||||
 | 
					  'ks' : 'काऽशुर',
 | 
				
			||||||
 | 
					  'ku' : 'Kurdí',
 | 
				
			||||||
 | 
					  'kw' : 'Kernewek',
 | 
				
			||||||
 | 
					  'ky' : 'Кыргыз',
 | 
				
			||||||
 | 
					  'la' : 'Latin',
 | 
				
			||||||
 | 
					  'lb' : 'Lëtzebuergesch',
 | 
				
			||||||
 | 
					  'li' : 'Limburgs',
 | 
				
			||||||
 | 
					  'ln' : 'Lingala',
 | 
				
			||||||
 | 
					  'lo' : 'ພາສາລາວ',
 | 
				
			||||||
 | 
					  'lt' : 'Lietuviskai',
 | 
				
			||||||
 | 
					  'lv' : 'Latviešu',
 | 
				
			||||||
 | 
					  'mg' : 'Malagasy',
 | 
				
			||||||
 | 
					  'mi' : 'Maori',
 | 
				
			||||||
 | 
					  'mk' : 'Македонски',
 | 
				
			||||||
 | 
					  'ml' : 'മലയാളം',
 | 
				
			||||||
 | 
					  'mn' : 'Монгол',
 | 
				
			||||||
 | 
					  'mo' : 'Moldavian',
 | 
				
			||||||
 | 
					  'mr' : 'मराठी',
 | 
				
			||||||
 | 
					  'ms' : 'Bahasa Melayu',
 | 
				
			||||||
 | 
					  'mt' : 'Malti',
 | 
				
			||||||
 | 
					  'my' : 'Burmese',
 | 
				
			||||||
 | 
					  'na' : 'Nauru',
 | 
				
			||||||
 | 
					  'ne' : 'नेपाली',
 | 
				
			||||||
 | 
					  'nl' : 'Nederlands',
 | 
				
			||||||
 | 
					  'no' : 'Norsk',
 | 
				
			||||||
 | 
					  'nn' : 'Nynorsk',
 | 
				
			||||||
 | 
					  'oc' : 'Languedoc',
 | 
				
			||||||
 | 
					  'om' : 'Oromo',
 | 
				
			||||||
 | 
					  'or' : 'ଓଡ଼ିଆ',
 | 
				
			||||||
 | 
					  'pa' : 'ਪੰਜਾਬੀ',
 | 
				
			||||||
 | 
					  'pl' : 'Polski',
 | 
				
			||||||
 | 
					  'ps' : 'پښتو',
 | 
				
			||||||
 | 
					  'pt' : 'Português',
 | 
				
			||||||
 | 
					  'qu' : 'Quechua',
 | 
				
			||||||
 | 
					  'rm' : 'Rumantsch',
 | 
				
			||||||
 | 
					  'rn' : 'Kirundi',
 | 
				
			||||||
 | 
					  'ro' : 'Română',
 | 
				
			||||||
 | 
					  'ru' : 'Русский',
 | 
				
			||||||
 | 
					  'rw' : 'Kiyarwanda',
 | 
				
			||||||
 | 
					  'sa' : 'संस्कृत',
 | 
				
			||||||
 | 
					  'sd' : 'Sindhi',
 | 
				
			||||||
 | 
					  'se' : 'Northern Sámi',
 | 
				
			||||||
 | 
					  'sg' : 'Sangho',
 | 
				
			||||||
 | 
					  'sh' : 'Serbo-Croatian',
 | 
				
			||||||
 | 
					  'si' : 'Singhalese',
 | 
				
			||||||
 | 
					  'sk' : 'Slovenčina',
 | 
				
			||||||
 | 
					  'sl' : 'Slovenščina',
 | 
				
			||||||
 | 
					  'sm' : 'Samoan',
 | 
				
			||||||
 | 
					  'sn' : 'Shona',
 | 
				
			||||||
 | 
					  'so' : 'Somali',
 | 
				
			||||||
 | 
					  'sq' : 'Shqip',
 | 
				
			||||||
 | 
					  'sr' : 'српски',
 | 
				
			||||||
 | 
					  'ss' : 'Siswati',
 | 
				
			||||||
 | 
					  'st' : 'Sesotho',
 | 
				
			||||||
 | 
					  'su' : 'Sudanese',
 | 
				
			||||||
 | 
					  'sv' : 'Svenska',
 | 
				
			||||||
 | 
					  'sw' : 'Kiswahili',
 | 
				
			||||||
 | 
					  'ta' : 'தமிழ',
 | 
				
			||||||
 | 
					  'te' : 'తెలుగు',
 | 
				
			||||||
 | 
					  'tg' : 'Тоҷики',
 | 
				
			||||||
 | 
					  'th' : 'ไทย',
 | 
				
			||||||
 | 
					  'ti' : 'ትግርኛ',
 | 
				
			||||||
 | 
					  'tk' : 'түркmенче',
 | 
				
			||||||
 | 
					  'tl' : 'Tagalog',
 | 
				
			||||||
 | 
					  'tn' : 'Setswana',
 | 
				
			||||||
 | 
					  'to' : 'Lea faka-Tonga',
 | 
				
			||||||
 | 
					  'tr' : 'Türkçe',
 | 
				
			||||||
 | 
					  'ts' : 'Tsonga',
 | 
				
			||||||
 | 
					  'tt' : 'татарча',
 | 
				
			||||||
 | 
					  'tw' : 'Twi',
 | 
				
			||||||
 | 
					  'ug' : 'Uigur',
 | 
				
			||||||
 | 
					  'uk' : 'Українська',
 | 
				
			||||||
 | 
					  'ur' : 'اردو',
 | 
				
			||||||
 | 
					  'uz' : 'Ўзбекча',
 | 
				
			||||||
 | 
					  'vi' : 'Tiếng Việt',
 | 
				
			||||||
 | 
					  'vo' : 'Volapük',
 | 
				
			||||||
 | 
					  'wa' : 'Walon',
 | 
				
			||||||
 | 
					  'wo' : 'Wolof',
 | 
				
			||||||
 | 
					  'xh' : 'isiXhosa',
 | 
				
			||||||
 | 
					  'yi' : 'ײִדיש',
 | 
				
			||||||
 | 
					  'yo' : 'Yorùbá',
 | 
				
			||||||
 | 
					  'za' : 'Zhuang',
 | 
				
			||||||
 | 
					  'zh' : '中文',
 | 
				
			||||||
 | 
					  'zu' : 'isiZulu'
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class Countries:
 | 
					class Languages:
 | 
				
			||||||
    '''This class gives access to the country codes as standardized by
 | 
					    '''This class gives access to the language codes as standardized by
 | 
				
			||||||
       ISO-639. The file has been downloaded in July 2009 from
 | 
					       ISO-639. The file has been downloaded in July 2009 from
 | 
				
			||||||
       http://www.loc.gov/standards/iso639-2/ascii_8bits.html (UTF-8 version)'''
 | 
					       http://www.loc.gov/standards/iso639-2/ascii_8bits.html (UTF-8 version)'''
 | 
				
			||||||
    def __init__(self):
 | 
					    def __init__(self):
 | 
				
			||||||
        self.fileName = os.path.dirname(__file__) + '/CountryCodesIso639.2.txt'
 | 
					        self.fileName = os.path.dirname(__file__) + '/LanguageCodesIso639.2.txt'
 | 
				
			||||||
        self.languageCodes = []
 | 
					        self.languageCodes = []
 | 
				
			||||||
 | 
					        # Names of languages in English
 | 
				
			||||||
        self.languageNames = []
 | 
					        self.languageNames = []
 | 
				
			||||||
 | 
					        # Names of languages in their language. It is not part of ISO 639.2 and
 | 
				
			||||||
 | 
					        # is taken from dict languageNames above.
 | 
				
			||||||
 | 
					        self.nativeNames = []
 | 
				
			||||||
        self.parseFile()
 | 
					        self.parseFile()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def parseFile(self):
 | 
					    def parseFile(self):
 | 
				
			||||||
        '''Parses the language codes and names in the ISO file and puts them in
 | 
					        '''Parses the language codes and names in the ISO file and puts them in
 | 
				
			||||||
           self.languageCodes and self.languageNames.'''
 | 
					           self.languageCodes, self.languageNames and self.nativeNames.'''
 | 
				
			||||||
        f = file(self.fileName)
 | 
					        f = file(self.fileName)
 | 
				
			||||||
        for line in f:
 | 
					        for line in f:
 | 
				
			||||||
            if line.strip():
 | 
					            if line.strip():
 | 
				
			||||||
| 
						 | 
					@ -27,11 +185,16 @@ class Countries:
 | 
				
			||||||
                    # I take only those that have a 2-chars ISO-639-1 code.
 | 
					                    # I take only those that have a 2-chars ISO-639-1 code.
 | 
				
			||||||
                    self.languageCodes.append(lineElems[2])
 | 
					                    self.languageCodes.append(lineElems[2])
 | 
				
			||||||
                    self.languageNames.append(lineElems[3])
 | 
					                    self.languageNames.append(lineElems[3])
 | 
				
			||||||
 | 
					                    if lineElems[2] in nativeNames:
 | 
				
			||||||
 | 
					                        self.nativeNames.append(nativeNames[lineElems[2]])
 | 
				
			||||||
 | 
					                    else:
 | 
				
			||||||
 | 
					                        # Put the english name nevertheless.
 | 
				
			||||||
 | 
					                        self.nativeNames.append(lineElems[3])
 | 
				
			||||||
        f.close()
 | 
					        f.close()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def exists(self, countryCode):
 | 
					    def exists(self, code):
 | 
				
			||||||
        '''Is p_countryCode a valid 2-digits country code?'''
 | 
					        '''Is p_code a valid 2-digits language/country code?'''
 | 
				
			||||||
        return countryCode in self.languageCodes
 | 
					        return code in self.languageCodes
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __repr__(self):
 | 
					    def __repr__(self):
 | 
				
			||||||
        i = -1
 | 
					        i = -1
 | 
				
			||||||
| 
						 | 
					@ -41,7 +204,7 @@ class Countries:
 | 
				
			||||||
            res += 'Language: ' + languageCode + ' - ' + self.languageNames[i]
 | 
					            res += 'Language: ' + languageCode + ' - ' + self.languageNames[i]
 | 
				
			||||||
            res += '\n'
 | 
					            res += '\n'
 | 
				
			||||||
        return res
 | 
					        return res
 | 
				
			||||||
countries = Countries() # As this is international, I instantiate it.
 | 
					languages = Languages() # As this is international, I instantiate it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class BelgianCities:
 | 
					class BelgianCities:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -17,7 +17,7 @@
 | 
				
			||||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,USA.
 | 
					# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,USA.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
import os, os.path, sys, traceback, unicodedata
 | 
					import os, os.path, sys, traceback, unicodedata, shutil
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class FolderDeleter:
 | 
					class FolderDeleter:
 | 
				
			||||||
| 
						 | 
					@ -47,6 +47,29 @@ def cleanFolder(folder, exts=extsToClean, verbose=False):
 | 
				
			||||||
                if verbose: print 'Removing %s...' % fileToRemove
 | 
					                if verbose: print 'Removing %s...' % fileToRemove
 | 
				
			||||||
                os.remove(fileToRemove)
 | 
					                os.remove(fileToRemove)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def copyFolder(source, dest, cleanDest=False):
 | 
				
			||||||
 | 
					    '''Copies the content of folder p_source to folder p_dest. p_dest is
 | 
				
			||||||
 | 
					       created, with intermediary subfolders if required. If p_cleanDest is
 | 
				
			||||||
 | 
					       True, it removes completely p_dest if it existed.'''
 | 
				
			||||||
 | 
					    dest = os.path.abspath(dest)
 | 
				
			||||||
 | 
					    # Delete the dest folder if required
 | 
				
			||||||
 | 
					    if os.path.exists(dest) and cleanDest:
 | 
				
			||||||
 | 
					        FolderDeleter.delete(dest)
 | 
				
			||||||
 | 
					    # Create the dest folder if it does not exist
 | 
				
			||||||
 | 
					    if not os.path.exists(dest):
 | 
				
			||||||
 | 
					        os.makedirs(dest)
 | 
				
			||||||
 | 
					    # Copy the content of p_source to p_dest.
 | 
				
			||||||
 | 
					    for name in os.listdir(source):
 | 
				
			||||||
 | 
					        sourceName = os.path.join(source, name)
 | 
				
			||||||
 | 
					        destName = os.path.join(dest, name)
 | 
				
			||||||
 | 
					        if os.path.isfile(sourceName):
 | 
				
			||||||
 | 
					            # Copy a single file
 | 
				
			||||||
 | 
					            shutil.copy(sourceName, destName)
 | 
				
			||||||
 | 
					        elif os.path.isdir(sourceName):
 | 
				
			||||||
 | 
					            # Copy a subfolder (recursively)
 | 
				
			||||||
 | 
					            copyFolder(sourceName, destName)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
# ------------------------------------------------------------------------------
 | 
					# ------------------------------------------------------------------------------
 | 
				
			||||||
class Traceback:
 | 
					class Traceback:
 | 
				
			||||||
    '''Dumps the last traceback into a string.'''
 | 
					    '''Dumps the last traceback into a string.'''
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue