1 # -*- coding: utf-8 -*-
3 ## Copyright (C)2006 Ingeniweb
5 ## This program is free software; you can redistribute it and/or modify
6 ## it under the terms of the GNU General Public License as published by
7 ## the Free Software Foundation; either version 2 of the License, or
8 ## (at your option) any later version.
10 ## This program is distributed in the hope that it will be useful,
11 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 ## GNU General Public License for more details.
15 ## You should have received a copy of the GNU General Public License
16 ## along with this program; see the file COPYING. If not, write to the
17 ## Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 __version__
= "$Revision: $"
23 # $Id: Installation.py 30098 2006-09-08 12:35:01Z encolpe $
24 __docformat__
= 'restructuredtext'
27 from cStringIO
import StringIO
29 from Products
.CMFCore
.utils
import getToolByName
30 from Products
.CMFCore
.TypesTool
import ContentFactoryMetadata
31 from Products
.CMFCore
.DirectoryView
import addDirectoryViews
32 from Products
.CMFPlone
.migrations
.migration_util
import safeEditProperty
35 def __init__(self
, root
):
38 self
.typesTool
= getToolByName(self
.root
, 'portal_types')
39 self
.skinsTool
= getToolByName(self
.root
, 'portal_skins')
40 self
.portal_properties
= getToolByName(self
.root
, 'portal_properties')
41 self
.navigation_properties
= self
.portal_properties
.navigation_properties
42 self
.form_properties
= self
.portal_properties
.form_properties
45 self
.out
.write('Installation completed.\n')
46 return self
.out
.getvalue()
48 def setupTools(self
, product_name
, tools
):
49 addTool
= self
.root
.manage_addProduct
[product_name
].manage_addTool
50 for tool
, title
in tools
:
52 for obj
in self
.root
.objectValues():
53 if obj
.meta_type
== tool
:
60 for obj
in root
.objectValues():
61 if obj
.meta_type
== tool
:
63 self
.out
.write("Added '%s' tool.\n" % (tool
,))
66 self
.out
.write("Couldn't add '%s' tool.\n" % (tool
,))
68 def installSubSkin(self
, skinFolder
):
69 """ Install a subskin, i.e. a folder/directoryview.
71 for skin
in self
.skinsTool
.getSkinSelections():
72 path
= self
.skinsTool
.getSkinPath(skin
)
73 path
= map( string
.strip
, string
.split( path
,',' ) )
74 if not skinFolder
in path
:
76 path
.insert( path
.index( 'custom')+1, skinFolder
)
78 path
.append(skinFolder
)
79 path
= string
.join( path
, ', ' )
80 self
.skinsTool
.addSkinSelection( skin
, path
)
81 self
.out
.write('Subskin successfully installed into %s.\n' % skin
)
83 self
.out
.write('*** Subskin was already installed into %s.\n' % skin
)
85 def setupCustomModelsSkin(self
, skin_name
):
86 """ Install custom skin folder
89 self
.skinsTool
.manage_addProduct
['OFSP'].manage_addFolder(skin_name
+ 'CustomModels')
91 self
.out
.write('*** Skin %sCustomModels already existed in portal_skins.\n' % skin_name
)
92 self
.installSubSkin('%sCustomModels' % skin_name
)
94 def setupTypesandSkins(self
, fti_list
, skin_name
, install_globals
):
96 setup of types and skins
99 # Former types deletion (added by PJG)
101 if f
['id'] in self
.typesTool
.objectIds():
102 self
.out
.write('*** Object "%s" already existed in the types tool => deleting\n' % (f
['id']))
103 self
.typesTool
._delObject
(f
['id'])
107 # Plone1 : if cmfformcontroller is not available and plone1_action key is defined,
108 # use this key instead of the regular 'action' key.
109 if (not self
.hasFormController()) and f
.has_key('plone1_action'):
110 f
['action'] = f
['plone1_action']
112 # Regular FTI processing
113 cfm
= apply(ContentFactoryMetadata
, (), f
)
114 self
.typesTool
._setObject
(f
['id'], cfm
)
115 self
.out
.write('Type "%s" registered with the types tool\n' % (f
['id']))
117 # Install de chaque nouvelle subskin/layer
119 addDirectoryViews(self
.skinsTool
, 'skins', install_globals
)
120 self
.out
.write( "Added directory views to portal_skins.\n" )
122 self
.out
.write( '*** Unable to add directory views to portal_skins.\n')
124 # Param de chaque nouvelle subskin/layer
125 self
.installSubSkin(skin_name
)
129 isPlone2(self,) => return true if we're using Plone2 ! :-)
131 return self
.hasFormController()
133 def hasFormController(self
,):
135 hasFormController(self,) => Return 1 if CMFFC is available
137 if 'portal_form_controller' in self
.root
.objectIds():
142 def addFormValidators(self
, mapping
):
144 Adds the form validators.
145 DON'T ADD ANYTHING IF CMFFORMCONTROLLER IS INSTALLED
148 if self
.hasFormController():
150 for (key
, value
) in mapping
:
151 safeEditProperty(self
.form_properties
, key
, value
)
153 def addNavigationTransitions(self
, transitions
):
155 Adds Navigation Transitions in portal properties
158 if self
.hasFormController():
160 for (key
, value
) in transitions
:
161 safeEditProperty(self
.navigation_properties
, key
, value
)
163 def setPermissions(self
, perms_list
):
165 setPermissions(self) => Set standard permissions / roles
167 # As a default behavior, newly-created permissions are granted to owner and manager.
168 # To change this, just comment this code and grab back the code commented below to
169 # make it suit your needs.
170 for perm
in perms_list
:
171 self
.root
.manage_permission(
173 ('Manager', 'Owner'),
176 self
.out
.write("Reseted default permissions\n")
178 def installMessageCatalog(self
, plone
, prodglobals
, domain
, poPrefix
):
179 """Sets up the a message catalog for this product
180 according to the available languages in both:
181 - .pot files in the "i18n" folder of this product
182 - MessageCatalog available for this domain
183 Typical use, create below this function:
184 def installCatalog(self):
185 installMessageCatalog(self, Products.MyProduct, 'mydomain', 'potfile_')
187 This assumes that you set the domain 'mydomain' in 'translation_service'
188 and the .../Products/YourProduct/i18n/potfile_en.po (...) contain your messages.
190 @param plone: the plone site
191 @type plone: a 'Plone site' object
192 @param prodglobals: see PloneSkinRegistrar.__init__
193 @param domain: the domain nick in Plone 'translation_service'
194 @type domain: string or None for the default domain
195 (you shouldn't use the default domain)
196 @param poPrefix: .po files to use start with that prefix.
197 i.e. use 'foo_' to install words from 'foo_fr.po', 'foo_en.po' (...)
198 @type poPrefix: string
202 "!! I18N INSTALLATION CANCELED !!\n"
203 "It seems that your Plone instance does not have the i18n features installed correctly.\n"
204 "You should have a 'translation_service' object in your Plone root.\n"
205 "This object should have the '%(domain)s' domain registered and associated\n"
206 "with an **existing** MessageCatalog object.\n"
207 "Fix all this first and come back here." % locals())
209 # Find Plone i18n resources
212 ts
= getattr(plone
, 'translation_service')
213 except AttributeError, e
:
216 for nick
, path
in ts
.getDomainInfo():
223 mc
= ts
.restrictedTraverse(path
)
224 except (AttributeError, KeyError), e
:
226 self
.out
.write("Installing I18N messages into '%s'\n" % '/'.join(mc
.getPhysicalPath()))
227 enabledLangs
= [nick
for nick
, lang
in mc
.get_languages_tuple()]
228 self
.out
.write("This MessageCatalog has %s languages enabled.\n" % ", ".join(enabledLangs
))
232 i18nPath
= os
.path
.join(prodglobals
['__path__'][0], 'i18n')
233 poPtn
= os
.path
.join(i18nPath
, poPrefix
+ '*.po')
234 poFiles
= glob
.glob(poPtn
)
235 rxFindLanguage
= re
.compile(poPrefix
+r
'(.*)\.po')
238 k
= rxFindLanguage
.findall(file)[0]
240 self
.out
.write("This Product provides messages for %s languages.\n" % ", ".join(poRsrc
.keys()))
241 for lang
in enabledLangs
:
242 if poRsrc
.has_key(lang
):
243 self
.out
.write("Adding support for language %s.\n" % lang
)
244 fh
= open(poRsrc
[lang
])
245 mc
.manage_import(lang
, fh
.read())
247 self
.out
.write("Done !")