Back to index

plone3  3.1.7
Installation.py
Go to the documentation of this file.
00001 # -*- coding: utf-8 -*-
00002 ## GroupUserFolder
00003 ## Copyright (C)2006 Ingeniweb
00004 
00005 ## This program is free software; you can redistribute it and/or modify
00006 ## it under the terms of the GNU General Public License as published by
00007 ## the Free Software Foundation; either version 2 of the License, or
00008 ## (at your option) any later version.
00009 
00010 ## This program is distributed in the hope that it will be useful,
00011 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 ## GNU General Public License for more details.
00014 
00015 ## You should have received a copy of the GNU General Public License
00016 ## along with this program; see the file COPYING. If not, write to the
00017 ## Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00018 """
00019 
00020 """
00021 __version__ = "$Revision:  $"
00022 # $Source:  $
00023 # $Id: Installation.py 30098 2006-09-08 12:35:01Z encolpe $
00024 __docformat__ = 'restructuredtext'
00025 
00026 
00027 from cStringIO import StringIO
00028 import string
00029 from Products.CMFCore.utils import getToolByName
00030 from Products.CMFCore.TypesTool import ContentFactoryMetadata
00031 from Products.CMFCore.DirectoryView import addDirectoryViews
00032 from Products.CMFPlone.migrations.migration_util import safeEditProperty
00033 
00034 class Installation:
00035     def __init__(self, root):
00036         self.root=root
00037         self.out=StringIO()
00038         self.typesTool = getToolByName(self.root, 'portal_types')
00039         self.skinsTool = getToolByName(self.root, 'portal_skins')
00040         self.portal_properties = getToolByName(self.root, 'portal_properties')
00041         self.navigation_properties = self.portal_properties.navigation_properties
00042         self.form_properties = self.portal_properties.form_properties
00043 
00044     def report(self):
00045         self.out.write('Installation completed.\n')
00046         return self.out.getvalue()
00047 
00048     def setupTools(self, product_name, tools):
00049         addTool = self.root.manage_addProduct[product_name].manage_addTool
00050         for tool, title in tools:
00051             found = 0
00052             for obj in self.root.objectValues():
00053                 if obj.meta_type == tool:
00054                     found = 1
00055             if not found:
00056                 addTool(tool, None)
00057 
00058             found = 0
00059             root=self.root
00060             for obj in root.objectValues():
00061                 if obj.meta_type == tool:
00062                     obj.title=title
00063                     self.out.write("Added '%s' tool.\n" % (tool,))
00064                     found = 1
00065             if not found:
00066                 self.out.write("Couldn't add '%s' tool.\n" % (tool,))
00067 
00068     def installSubSkin(self, skinFolder):
00069         """ Install a subskin, i.e. a folder/directoryview.
00070         """
00071         for skin in self.skinsTool.getSkinSelections():
00072             path = self.skinsTool.getSkinPath(skin)
00073             path = map( string.strip, string.split( path,',' ) )
00074             if not skinFolder in path:
00075                 try:
00076                     path.insert( path.index( 'custom')+1, skinFolder )
00077                 except ValueError:
00078                     path.append(skinFolder)
00079                 path = string.join( path, ', ' )
00080                 self.skinsTool.addSkinSelection( skin, path )
00081                 self.out.write('Subskin successfully installed into %s.\n' % skin)
00082             else:
00083                 self.out.write('*** Subskin was already installed into %s.\n' % skin)
00084 
00085     def setupCustomModelsSkin(self, skin_name):
00086         """ Install custom skin folder
00087         """
00088         try:
00089             self.skinsTool.manage_addProduct['OFSP'].manage_addFolder(skin_name + 'CustomModels')
00090         except:
00091             self.out.write('*** Skin %sCustomModels already existed in portal_skins.\n' % skin_name)
00092         self.installSubSkin('%sCustomModels' % skin_name)
00093 
00094     def setupTypesandSkins(self, fti_list, skin_name, install_globals):
00095         """
00096         setup of types and skins
00097         """
00098 
00099         # Former types deletion (added by PJG)
00100         for f in fti_list:
00101             if f['id'] in self.typesTool.objectIds():
00102                 self.out.write('*** Object "%s" already existed in the types tool => deleting\n' % (f['id']))
00103                 self.typesTool._delObject(f['id'])
00104 
00105         # Type re-creation
00106         for f in fti_list:
00107             # Plone1 : if cmfformcontroller is not available and plone1_action key is defined,
00108             # use this key instead of the regular 'action' key.
00109             if (not self.hasFormController()) and f.has_key('plone1_action'):
00110                 f['action'] = f['plone1_action']
00111 
00112             # Regular FTI processing
00113             cfm = apply(ContentFactoryMetadata, (), f)
00114             self.typesTool._setObject(f['id'], cfm)
00115             self.out.write('Type "%s" registered with the types tool\n' % (f['id']))
00116 
00117         # Install de chaque nouvelle subskin/layer
00118         try:
00119             addDirectoryViews(self.skinsTool, 'skins', install_globals)
00120             self.out.write( "Added directory views to portal_skins.\n" )
00121         except:
00122             self.out.write( '*** Unable to add directory views to portal_skins.\n')
00123 
00124         # Param de chaque nouvelle subskin/layer
00125         self.installSubSkin(skin_name)
00126 
00127     def isPlone2(self,):
00128         """
00129         isPlone2(self,) => return true if we're using Plone2 ! :-)
00130         """
00131         return self.hasFormController()
00132 
00133     def hasFormController(self,):
00134         """
00135         hasFormController(self,) => Return 1 if CMFFC is available
00136         """
00137         if 'portal_form_controller' in self.root.objectIds():
00138             return 1
00139         else:
00140             return None
00141 
00142     def addFormValidators(self, mapping):
00143         """
00144         Adds the form validators.
00145         DON'T ADD ANYTHING IF CMFFORMCONTROLLER IS INSTALLED
00146         """
00147         # Plone2 management
00148         if self.hasFormController():
00149             return
00150         for (key, value) in mapping:
00151             safeEditProperty(self.form_properties, key, value)
00152 
00153     def addNavigationTransitions(self, transitions):
00154         """
00155         Adds Navigation Transitions in portal properties
00156         """
00157         # Plone2 management
00158         if self.hasFormController():
00159             return
00160         for (key, value) in transitions:
00161             safeEditProperty(self.navigation_properties, key, value)
00162 
00163     def setPermissions(self, perms_list):
00164         """
00165         setPermissions(self) => Set standard permissions / roles
00166         """
00167         # As a default behavior, newly-created permissions are granted to owner and manager.
00168         # To change this, just comment this code and grab back the code commented below to
00169         # make it suit your needs.
00170         for perm in perms_list:
00171             self.root.manage_permission(
00172                 perm,
00173                 ('Manager', 'Owner'),
00174                 acquire = 1
00175                 )
00176         self.out.write("Reseted default permissions\n")
00177 
00178     def installMessageCatalog(self, plone, prodglobals, domain, poPrefix):
00179         """Sets up the a message catalog for this product
00180         according to the available languages in both:
00181         - .pot files in the "i18n" folder of this product
00182         - MessageCatalog available for this domain
00183         Typical use, create below this function:
00184         def installCatalog(self):
00185             installMessageCatalog(self, Products.MyProduct, 'mydomain', 'potfile_')
00186             return
00187         This assumes that you set the domain 'mydomain' in 'translation_service'
00188         and the .../Products/YourProduct/i18n/potfile_en.po (...) contain your messages.
00189 
00190         @param plone: the plone site
00191         @type plone: a 'Plone site' object
00192         @param prodglobals: see PloneSkinRegistrar.__init__
00193         @param domain: the domain nick in Plone 'translation_service'
00194         @type domain: string or None for the default domain
00195             (you shouldn't use the default domain)
00196         @param poPrefix: .po files to use start with that prefix.
00197             i.e. use 'foo_' to install words from 'foo_fr.po', 'foo_en.po' (...)
00198         @type poPrefix: string
00199         """
00200 
00201         installInfo = (
00202             "!! I18N INSTALLATION CANCELED !!\n"
00203             "It seems that your Plone instance does not have the i18n features installed correctly.\n"
00204             "You should have a 'translation_service' object in your Plone root.\n"
00205             "This object should have the '%(domain)s' domain registered and associated\n"
00206             "with an **existing** MessageCatalog object.\n"
00207             "Fix all this first and come back here." % locals())
00208         #
00209         # Find Plone i18n resources
00210         #
00211         try:
00212             ts = getattr(plone, 'translation_service')
00213         except AttributeError, e:
00214             return installInfo
00215         found = 0
00216         for nick, path in ts.getDomainInfo():
00217             if nick == domain:
00218                 found = 1
00219                 break
00220         if not found:
00221             return installInfo
00222         try:
00223             mc = ts.restrictedTraverse(path)
00224         except (AttributeError, KeyError), e:
00225             return installInfo
00226         self.out.write("Installing I18N messages into '%s'\n" % '/'.join(mc.getPhysicalPath()))
00227         enabledLangs = [nick for nick, lang in mc.get_languages_tuple()]
00228         self.out.write("This MessageCatalog has %s languages enabled.\n" %  ", ".join(enabledLangs))
00229         #
00230         # Find .po files
00231         #
00232         i18nPath = os.path.join(prodglobals['__path__'][0], 'i18n')
00233         poPtn = os.path.join(i18nPath, poPrefix + '*.po')
00234         poFiles = glob.glob(poPtn)
00235         rxFindLanguage = re.compile(poPrefix +r'(.*)\.po')
00236         poRsrc = {}
00237         for file in poFiles:
00238             k = rxFindLanguage.findall(file)[0]
00239             poRsrc[k] = file
00240         self.out.write("This Product provides messages for %s languages.\n" % ", ".join(poRsrc.keys()))
00241         for lang in enabledLangs:
00242             if poRsrc.has_key(lang):
00243                 self.out.write("Adding support for language %s.\n" % lang)
00244                 fh = open(poRsrc[lang])
00245                 mc.manage_import(lang, fh.read())
00246                 fh.close()
00247         self.out.write("Done !")