from Globals import get_request import re import os import sys try: from App.config import getConfiguration except ImportError: getConfiguration = None if getConfiguration is None: data_dir = '/var/lib/zope/data' else: data_dir = getConfiguration().instancehome + '/data' fs_skin_spec = ('ERP5 Filesystem Formulator Form', 'ERP5 Filesystem PDF Template', 'Filesystem Formulator Form', 'Filesystem Page Template', 'Filesystem Script (Python)', 'Filesystem Z SQL Method') zodb_skin_spec = ('ERP5 Form', 'ERP5 PDF Template', 'Page Template', 'Script', 'Script (Python)','Z SQL Method') def getSkinPathList(self, spec=fs_skin_spec+zodb_skin_spec): path_list = self.portal_skins.getSkinPath(self.portal_skins.getDefaultSkin()) path_list = path_list.split(',') skin_list = [] for path in path_list: if path in ('content', 'content18', 'control', 'generic', 'mailin', 'pro', 'topic', 'zpt_content', 'zpt_control', 'zpt_generic', 'zpt_reporttool', 'zpt_topic'): continue for id in self.portal_skins[path].objectIds(spec): skin_list.append(path + '/' + id) return skin_list def split(name): """ Split the name using an underscore as a separator and using the change from lower case to upper case as a separator. Example: foo_barBaz -> foo, bar, Baz """ part_list = [] part = '' pc = None for c in name: if c == '_': if len(part) > 0: part_list.append(part) part = '' pc = None elif pc is not None and pc.islower() and c.isupper(): if len(part) > 0: part_list.append(part) part = c pc = None else: pc = c part += c if pc is not None: part_list.append(part) return part_list def suggestName(name, meta_type): """ Suggest a good name for a given name. """ # Determine the prefix. The default is "Base_". i = name.find('_') if i < 1: prefix = 'Base' else: # Special treatment for view, print, create and list, because they are used very often. # packing list is an exception, because it is confusing (i.e. sale_packing_list_list). view_index = name.find('_view') print_index = name.find('_print') create_index = name.find('_create') list_index = name.find('_list') packing_list_index = name.find('packing_list_') if view_index > 0: i = view_index elif print_index > 0: i = print_index elif create_index > 0: i = create_index elif list_index > 0: if packing_list_index > 0: i = packing_list_index + 12 else: i = list_index part_list = split(name[:i]) prefix = '' for part in part_list: prefix += part.capitalize() name = name[i+1:] if meta_type in ('Filesystem Z SQL Method', 'Z SQL Method'): new_name = 'z' if name[0] == 'z': name = name[1:] part_list = split(name) for part in part_list: new_name += part.capitalize() else: part_list = split(name) new_name = part_list[0].lower() for part in part_list[1:]: new_name += part.capitalize() return prefix + '_' + new_name def checkSkinNames(self, REQUEST=None, csv=0, all=0): """ Check if the name of each skin follows the naming convention. """ if csv: msg = 'Folder,Name,New Name,Meta Type\n' else: msg = '<html><body>' rexp = re.compile('^[A-Z][a-zA-Z0-9]*_[a-z][a-zA-Z0-9]*$') rexp_zsql = re.compile('^[A-Z][a-zA-Z0-9]*_z[A-Z][a-zA-Z0-9]*$') path_list = getSkinPathList(self) bad_list = [] for path in path_list: name = path.split('/')[-1] skin = self.portal_skins.restrictedTraverse(path) if skin.meta_type in ('Filesystem Z SQL Method', 'Z SQL Method'): r = rexp_zsql else: r = rexp if all or r.search(name) is None: bad_list.append((path, skin.meta_type)) if len(bad_list) == 0: if not csv: msg += '<p>Everything is fine.</p>\n' else: bad_list.sort() if not csv: msg += '<p>These %d skins do not follow the naming convention:</p><table width="100%%">\n' % len(bad_list) msg += '<tr><td>Folder</td><td>Skin Name</td><td>Meta Type</td></tr>\n' i = 0 for path,meta_type in bad_list: name = path.split('/')[-1] suggested_name = suggestName(name, meta_type) folder = path[:-len(name)-1] if (i % 2) == 0: c = '#88dddd' else: c = '#dddd88' i += 1 if csv: msg += '%s,%s,%s,%s\n' % (folder, name, suggested_name, meta_type) else: msg += '<tr bgcolor="%s"><td>%s</td><td>%s</td><td>%s</td></tr>\n' % (c, folder, name, meta_type) if not csv: msg += '</table>\n' if not csv: msg += '</body></html>' return msg def fixSkinNames(self, REQUEST=None, file=None, dry_run=1): """ Fix bad skin names. This method does: - Check all the contents of all skins. - Check immediate_view, constructor_path and actions in all portal types. - Check skins of all business templates. - Check actbox_url in transitions and worklists and scripts of all workflows. - Rename skins. """ if REQUEST is None: REQUEST = get_request() if file is None: msg = 'You must put a CSV file inside the data directory, and specify %s/ERP5Site_fixSkinNames?file=NAME \n\n' % self.absolute_url() msg += 'The template of a CSV file is available via %s/ERP5Site_checkSkinNames?csv=1 \n\n' % self.absolute_url() msg += 'This does not modify anything by default. If you really want to fix skin names, specify %s/ERP5Site_fixSkinNames?file=NAME&dry_run=0 \n\n' % self.absolute_url() return msg file = os.path.join(data_dir, file) file = open(file, 'r') class NamingInformation: pass info_list = [] try: for line in file: folder, name, new_name, meta_type = line.strip().split(',') if meta_type == 'Meta Type': continue if name == new_name: continue # Check the existence of the skin and the meta type. Paranoid? #if self.portal_skins[folder][name].meta_type != meta_type: # raise RuntimeError, '%s/%s has a different meta type' % (folder, name) info = NamingInformation() info.folder = folder info.name = name info.new_name = new_name info.regexp = re.compile('\\b' + re.escape(name) + '\\b') # This is used to search the name info_list.append(info) finally: file.close() # Now we have information enough. Check the skins. msg = '' path_list = getSkinPathList(self) for path in path_list: skin = self.portal_skins.restrictedTraverse(path) try: text = skin.manage_FTPget() except: type, value, traceback = sys.exc_info() msg += 'WARNING: the skin %s could not be retrieved because of the exception %s: %s\n' % (path, str(type), str(value)) else: name_list = [] for info in info_list: if info.regexp.search(text) is not None: text = info.regexp.sub(info.new_name, text) name_list.append(info.name) if len(name_list) > 0: msg += '%s is modified for %s\n' % ('portal_skins/' + path, ', '.join(name_list)) if not dry_run: REQUEST['BODY'] = text skin.manage_FTPput(REQUEST, REQUEST.RESPONSE) # Check the portal types. for t in self.portal_types.objectValues(): # Initial view name. text = t.immediate_view for info in info_list: if info.name == text: msg += 'Initial view name of %s is modified for %s\n' % ('portal_types/' + t.id, text) if not dry_run: t.immediate_view = info.new_name break # Constructor path. text = getattr(t, 'constructor_path', None) if text is not None: for info in info_list: if info.name == text: msg += 'Constructor path of %s is modified for %s\n' % ('portal_types/' + t.id, text) if not dry_run: t.constructor_path = info.new_name break # Actions. for action in t.listActions(): text = action.action.text for info in info_list: if info.regexp.search(text) is not None: text = info.regexp.sub(info.new_name, text) msg += 'Action %s of %s is modified for %s\n' % (action.getId(), 'portal_types/' + t.id, info.name) if not dry_run: action.action.text = text break # Check the portal templates. template_tool = getattr(self, 'portal_templates', None) # Check the existence of template tool, because an older version of ERP5 does not have it. if template_tool is not None: for template in template_tool.contentValues(filter={'portal_type':'Business Template'}): # Skins. skin_id_list = [] name_list = [] for skin_id in template.getTemplateSkinIdList(): for info in info_list: if info.name == skin_id: name_list.append(skin_id) skin_id = info.new_name break skin_id_list.append(skin_id) if len(name_list) > 0: msg += 'Skins of %s is modified for %s\n' % ('portal_templates/' + template.getId(), ', '.join(name_list)) if not dry_run: template.setTemplateSkinIdList(skin_id_list) # Paths. path_list = [] name_list = [] for path in template.getTemplatePathList(): for info in info_list: if info.regexp.search(path): name_list.append(skin_id) path = info.regexp.sub(info.new_name, path) break path_list.append(path) if len(name_list) > 0: msg += 'Paths of %s is modified for %s\n' % ('portal_templates/' + template.getId(), ', '.join(name_list)) if not dry_run: template.setTemplatePathList(path_list) # Workflows. for wf in self.portal_workflow.objectValues(): # Transitions. for id in wf.transitions.objectIds(): transition = wf.transitions._getOb(id) text = transition.actbox_url for info in info_list: if info.regexp.search(text) is not None: text = info.regexp.sub(info.new_name, text) msg += 'Transition %s of %s is modified for %s\n' % (id, 'portal_workflow/' + wf.id, info.name) if not dry_run: transition.actbox_url = text break # Worklists. for id in wf.worklists.objectIds(): worklist = wf.worklists._getOb(id) text = worklist.actbox_url for info in info_list: if info.regexp.search(text) is not None: text = info.regexp.sub(info.new_name, text) msg += 'Worklist %s of %s is modified for %s\n' % (id, 'portal_workflow/' + wf.id, info.name) if not dry_run: worklist.actbox_url = text break # Scripts. for id in wf.scripts.objectIds(): script = wf.scripts._getOb(id) text = script.manage_FTPget() name_list = [] for info in info_list: if info.regexp.search(text) is not None: text = info.regexp.sub(info.new_name, text) name_list.append(info.name) if len(name_list) > 0: msg += 'Script %s of %s is modified for %s\n' % (id, 'portal_workflow/' + wf.id, ', '.join(name_list)) if not dry_run: REQUEST['BODY'] = text script.manage_FTPput(REQUEST, REQUEST.RESPONSE) # Rename the skins. if not dry_run: for info in info_list: try: folder = self.portal_skins[info.folder] folder.manage_renameObjects([info.name], [info.new_name]) except: type, value, traceback = sys.exc_info() msg += 'WARNING: the skin %s could not be renamed to %s because of the exception %s: %s\n' % (info.name, info.new_name, str(type), str(value)) return msg