def installAppyTypes(self): '''We complete here the initialisation process of every Appy type of every gen-class of the application.''' appName = self.productName for klass in self.classes: # Store on wrapper class the ordered list of Appy types wrapperClass = klass.wrapperClass if not hasattr(wrapperClass, 'title'): # Special field "type" is mandatory for every class. title = gen.String(multiplicity=(1, 1), show='edit', indexed=True, searchable=True) title.init('title', None, 'appy') setattr(wrapperClass, 'title', title) # Special field "state" must be added for every class. It must be a # "select" field, because it will be necessary for displaying the # translated state name. state = gen.String(validator=gen.Selection('listStates'), show='result') state.init('state', None, 'workflow') setattr(wrapperClass, 'state', state) names = self.config.attributes[wrapperClass.__name__[:-8]] wrapperClass.__fields__ = [getattr(wrapperClass, n) for n in names] # Post-initialise every Appy type for baseClass in klass.wrapperClass.__bases__: if baseClass.__name__ == 'AbstractWrapper': continue for name, appyType in baseClass.__dict__.iteritems(): if not isinstance(appyType, gen.Field) or \ (isinstance(appyType, gen.Ref) and appyType.isBack): continue # Back refs are initialised within fw refs appyType.init(name, baseClass, appName)
class Group(ModelClass): # In a ModelClass we need to declare attributes in the following list. _appy_attributes = ['title', 'login', 'roles', 'users'] # All methods defined below are fake. Real versions are in the wrapper. m = {'group': 'main', 'width': 25, 'indexed': True} title = gen.String(multiplicity=(1, 1), **m) def showLogin(self): pass def validateLogin(self): pass login = gen.String(show=showLogin, validator=validateLogin, multiplicity=(1, 1), **m) roles = gen.String(validator=gen.Selection('getGrantableRoles'), multiplicity=(0, None), **m) users = gen.Ref(User, multiplicity=(0, None), add=False, link=True, back=gen.Ref(attribute='groups', show=True), showHeaders=True, shownInfo=('title', 'login'))
class Group(ModelClass): _appy_attributes = ['title', 'login', 'roles', 'users', 'toTool2'] # All methods defined below are fake. Real versions are in the wrapper. m = {'group': 'main', 'width': 25, 'indexed': True} title = gen.String(multiplicity=(1, 1), **m) def showLogin(self): pass def validateLogin(self): pass login = gen.String(show=showLogin, validator=validateLogin, multiplicity=(1, 1), **m) roles = gen.String(validator=gen.Selection('getGrantableRoles'), multiplicity=(0, None), **m) def getSelectableUsers(self): pass users = gen.Ref(User, multiplicity=(0, None), add=False, link=True, back=gen.Ref(attribute='groups', show=User.showRoles, multiplicity=(0, None)), select=getSelectableUsers, height=15, showHeaders=True, shownInfo=('title', 'login'))
def addMessageField(self, messageId, page, i18nFiles): '''Adds a message field corresponding to p_messageId to the Translation class, on a given p_page. We need i18n files p_i18nFiles for fine-tuning the String type to generate for this field (one-line? several lines?...)''' params = {'page': page, 'layouts': 'f', 'show': self.modelClass.show} appName = self.generator.applicationName # Scan all messages corresponding to p_messageId from all translation # files. We will define field length from the longer found message # content. maxLine = 100 # We suppose a line is 100 characters long. width = 0 height = 0 for fileName, poFile in i18nFiles.iteritems(): if not fileName.startswith('%s-' % appName) or \ not i18nFiles[fileName].messagesDict.has_key(messageId): # In this case this is not one of our Appy-managed translation # files. continue msgContent = i18nFiles[fileName].messagesDict[messageId].msg # Compute width width = max(width, len(msgContent)) # Compute height (a "\n" counts for one line) mHeight = int( len(msgContent) / maxLine) + msgContent.count('<br/>') height = max(height, mHeight) if height < 1: # This is a one-line field. params['width'] = width else: # This is a multi-line field, or a very-long-single-lined field params['format'] = gen.String.TEXT params['height'] = height self.addField(messageId, gen.String(**params))
def addSearchRelatedFields(self, classDescr): '''Adds, for class p_classDescr, attributes related to the search functionality for class p_classDescr.''' className = classDescr.name # Field that defines if advanced search is enabled for class # p_classDescr or not. fieldName = 'enableAdvancedSearchFor%s' % className fieldType = gen.Boolean(default=True, page='userInterface', group=classDescr.klass.__name__) self.addField(fieldName, fieldType) # Field that defines how many columns are shown on the custom search # screen. fieldName = 'numberOfSearchColumnsFor%s' % className fieldType = gen.Integer(default=3, page='userInterface', group=classDescr.klass.__name__) self.addField(fieldName, fieldType) # Field that allows to select, among all indexed fields, what fields # must really be used in the search screen. fieldName = 'searchFieldsFor%s' % className defaultValue = [ a[0] for a in classDescr.getOrderedAppyAttributes( condition='attrValue.indexed') ] if 'title' not in defaultValue: defaultValue.insert(0, 'title') fieldType = gen.String(multiplicity=(0, None), validator=gen.Selection( '_appy_getSearchableFields*%s' % className), default=defaultValue, page='userInterface', group=classDescr.klass.__name__) self.addField(fieldName, fieldType)
class Page(ModelClass): _appy_attributes = ['title', 'content', 'pages', 'parent', 'toTool3'] folder = True title = gen.String(show='edit', multiplicity=(1, 1), indexed=True) content = gen.String(format=gen.String.XHTML, layouts='f', richText=True) # Pages can contain other pages. def showSubPages(self): pass pages = gen.Ref(None, multiplicity=(0, None), add=True, link=False, back=gen.Ref(attribute='parent', show=False), show=showSubPages, navigable=True)
class Translation(ModelClass): _appy_attributes = ['po', 'title', 'sourceLanguage', 'trToTool'] # All methods defined below are fake. Real versions are in the wrapper. title = gen.String(show=False, indexed=True) actionsPage = gen.Page('actions') def getPoFile(self): pass po = gen.Action(action=getPoFile, page=actionsPage, result='filetmp') sourceLanguage = gen.String(page=actionsPage, width=4) def label(self): pass def show(self, name): pass
def addImportRelatedFields(self, classDescr): '''Adds, for class p_classDescr, attributes related to the import functionality for class p_classDescr.''' className = classDescr.name # Field that defines the path of the files to import. fieldName = 'importPathFor%s' % className defValue = classDescr.getCreateMean('Import').path fieldType = gen.String(page='data', multiplicity=(1,1), default=defValue,group=classDescr.klass.__name__) self.addField(fieldName, fieldType)
class User(ModelClass): # In a ModelClass we need to declare attributes in the following list. _appy_attributes = [ 'title', 'name', 'firstName', 'login', 'password1', 'password2', 'email', 'roles' ] # All methods defined below are fake. Real versions are in the wrapper. title = gen.String(show=False, indexed=True) gm = {'group': 'main', 'width': 25} def showName(self): pass name = gen.String(show=showName, **gm) firstName = gen.String(show=showName, **gm) def showEmail(self): pass email = gen.String(show=showEmail) gm['multiplicity'] = (1, 1) def showLogin(self): pass def validateLogin(self): pass login = gen.String(show=showLogin, validator=validateLogin, indexed=True, **gm) def showPassword(self): pass def validatePassword(self): pass password1 = gen.String(format=gen.String.PASSWORD, show=showPassword, validator=validatePassword, **gm) password2 = gen.String(format=gen.String.PASSWORD, show=showPassword, **gm) gm['multiplicity'] = (0, None) def showRoles(self): pass roles = gen.String(show=showRoles, indexed=True, validator=gen.Selection('getGrantableRoles'), **gm)
def addQueryResultColumns(self, classDescr): '''Adds, for class p_classDescr, the attribute in the tool that allows to select what default columns will be shown on query results.''' className = classDescr.name fieldName = 'resultColumnsFor%s' % className fieldType = gen.String(multiplicity=(0, None), validator=gen.Selection( '_appy_getAllFields*%s' % className), page='userInterface', group=classDescr.klass.__name__) self.addField(fieldName, fieldType)
class Translation(ModelClass): _appy_attributes = ['po', 'title'] # All methods defined below are fake. Real versions are in the wrapper. def getPoFile(self): pass po = gen.Action(action=getPoFile, page=gen.Page('actions', show='view'), result='filetmp') title = gen.String(show=False, indexed=True) def label(self): pass def show(self, name): pass
def addPodRelatedFields(self, fieldDescr): '''Adds the fields needed in the Tool for configuring a Pod field.''' className = fieldDescr.classDescr.name # On what page and group to display those fields ? pg = { 'page': 'documents', 'group': gen.Group(fieldDescr.classDescr.klass.__name__, ['50%'] * 2) } # Add the field that will store the pod template. fieldName = 'podTemplateFor%s_%s' % (className, fieldDescr.fieldName) fieldType = gen.File(**pg) self.addField(fieldName, fieldType) # Add the field that will store the output format(s) fieldName = 'formatsFor%s_%s' % (className, fieldDescr.fieldName) fieldType = gen.String(validator=gen.Selection('getPodOutputFormats'), multiplicity=(1, None), default=('odt', ), **pg) self.addField(fieldName, fieldType)
def installAppyTypes(self): '''We complete here the initialisation process of every Appy type of every gen-class of the application.''' appName = self.productName for klass in self.classes: # Store on wrapper class the ordered list of Appy types wrapperClass = klass.wrapperClass if not hasattr(wrapperClass, 'title'): # Special field "type" is mandatory for every class. title = gen.String(multiplicity=(1,1), show='edit',indexed=True) title.init('title', None, 'appy') setattr(wrapperClass, 'title', title) names = self.config.attributes[wrapperClass.__name__[:-8]] wrapperClass.__fields__ = [getattr(wrapperClass, n) for n in names] # Post-initialise every Appy type for baseClass in klass.wrapperClass.__bases__: if baseClass.__name__ == 'AbstractWrapper': continue for name, appyType in baseClass.__dict__.iteritems(): if not isinstance(appyType, gen.Type) or \ (isinstance(appyType, gen.Ref) and appyType.isBack): continue # Back refs are initialised within fw refs appyType.init(name, baseClass, appName)
class Tool(ModelClass): # In a ModelClass we need to declare attributes in the following list. _appy_attributes = list(defaultToolFields) # Tool attributes def validPythonWithUno(self, value): pass # Real method in the wrapper unoEnabledPython = gen.String(group="connectionToOpenOffice", validator=validPythonWithUno) openOfficePort = gen.Integer(default=2002, group="connectionToOpenOffice") numberOfResultsPerPage = gen.Integer(default=30, show=False) listBoxesMaximumWidth = gen.Integer(default=100, show=False) appyVersion = gen.String(show=False, layouts='f') def refreshSecurity(self): pass # Real method in the wrapper refreshSecurity = gen.Action(action=refreshSecurity, confirm=True) # Ref(User) will maybe be transformed into Ref(CustomUserClass). users = gen.Ref(User, multiplicity=(0, None), add=True, link=False, back=gen.Ref(attribute='toTool', show=False), page=gen.Page('users', show='view'), queryable=True, queryFields=('title', 'login'), showHeaders=True, shownInfo=('title', 'login', 'roles')) groups = gen.Ref(Group, multiplicity=(0, None), add=True, link=False, back=gen.Ref(attribute='toTool2', show=False), page=gen.Page('groups', show='view'), queryable=True, queryFields=('title', 'login'), showHeaders=True, shownInfo=('title', 'login', 'roles')) translations = gen.Ref(Translation, multiplicity=(0, None), add=False, link=False, show='view', back=gen.Ref(attribute='trToTool', show=False), page=gen.Page('translations', show='view')) enableNotifications = gen.Boolean(default=True, page=gen.Page('notifications', show=False)) @classmethod def _appy_clean(klass): toClean = [] for k, v in klass.__dict__.iteritems(): if not k.startswith('__') and (not k.startswith('_appy_')): if k not in defaultToolFields: toClean.append(k) for k in toClean: exec 'del klass.%s' % k klass._appy_attributes = list(defaultToolFields)
class Tool(ModelClass): # In a ModelClass we need to declare attributes in the following list. _appy_attributes = list(defaultToolFields) folder = True # Tool attributes def isManager(self): pass def isManagerEdit(self): pass lf = {'layouts': 'f'} title = gen.String(show=False, page=gen.Page('main', show=False), default='Configuration', **lf) mailHost = gen.String(default='localhost:25', **lf) mailEnabled = gen.Boolean(default=False, **lf) mailFrom = gen.String(default='*****@*****.**', **lf) appyVersion = gen.String(**lf) dateFormat = gen.String(default='%d/%m/%Y', **lf) hourFormat = gen.String(default='%H:%M', **lf) # Ref(User) will maybe be transformed into Ref(CustomUserClass). userPage = gen.Page('users', show=isManager) users = gen.Ref(User, multiplicity=(0, None), add=True, link=False, back=gen.Ref(attribute='toTool', show=False), page=userPage, queryable=True, queryFields=('title', 'login'), show=isManager, showHeaders=True, shownInfo=('title', 'login', 'roles')) def computeConnectedUsers(self): pass connectedUsers = gen.Computed(method=computeConnectedUsers, page=userPage, plainText=False, show=isManager) groups = gen.Ref(Group, multiplicity=(0, None), add=True, link=False, back=gen.Ref(attribute='toTool2', show=False), page=gen.Page('groups', show=isManager), show=isManager, queryable=True, queryFields=('title', 'login'), showHeaders=True, shownInfo=('title', 'login', 'roles')) pt = gen.Page('translations', show=isManager) translations = gen.Ref(Translation, multiplicity=(0, None), add=False, link=False, show='view', page=pt, back=gen.Ref(attribute='trToTool', show=False)) loadTranslationsAtStartup = gen.Boolean(default=True, show=False, page=pt, layouts='f') pages = gen.Ref(Page, multiplicity=(0, None), add=True, link=False, show='view', back=gen.Ref(attribute='toTool3', show=False), page=gen.Page('pages', show=isManager)) # Document generation page dgp = {'page': gen.Page('documents', show=isManagerEdit)} def validPythonWithUno(self, value): pass # Real method in the wrapper unoEnabledPython = gen.String(default='/usr/bin/python', show=False, validator=validPythonWithUno, **dgp) openOfficePort = gen.Integer(default=2002, show=False, **dgp) # User interface page numberOfResultsPerPage = gen.Integer(default=30, page=gen.Page('userInterface', show=False)) @classmethod def _appy_clean(klass): toClean = [] for k, v in klass.__dict__.iteritems(): if not k.startswith('__') and (not k.startswith('_appy_')): if k not in defaultToolFields: toClean.append(k) for k in toClean: exec 'del klass.%s' % k klass._appy_attributes = list(defaultToolFields) klass.folder = True
class User(ModelClass): _appy_attributes = [ 'password1', 'password2', 'title', 'name', 'firstName', 'login', 'email', 'roles', 'source', 'groups', 'toTool' ] # Passwords are on a specific page. def showPassword(self): pass def validatePassword(self): pass pp = { 'page': gen.Page('passwords', showNext=False, show=showPassword), 'width': 34, 'multiplicity': (1, 1), 'format': gen.String.PASSWORD, 'show': showPassword } password1 = gen.String(validator=validatePassword, **pp) password2 = gen.String(**pp) # All methods defined below are fake. Real versions are in the wrapper. pm = { 'page': gen.Page('main', showPrevious=False), 'group': 'main', 'width': 34 } title = gen.String(show=False, indexed=True, **pm) def showName(self): pass name = gen.String(show=showName, **pm) firstName = gen.String(show=showName, **pm) def showEmail(self): pass email = gen.String(show=showEmail, **pm) # Where is this user stored? By default, in the ZODB. But the user can be # stored in an external LDAP (source='ldap'). source = gen.String(show=False, default='zodb', layouts='f', **pm) pm['multiplicity'] = (1, 1) def showLogin(self): pass def validateLogin(self): pass login = gen.String(show=showLogin, validator=validateLogin, indexed=True, **pm) pm['multiplicity'] = (0, None) def showRoles(self): pass roles = gen.String(show=showRoles, indexed=True, validator=gen.Selection('getGrantableRoles'), **pm)