eggification
[GroupUserFolder.git] / Products / GroupUserFolder / Installation.py
1 # -*- coding: utf-8 -*-
2 ## GroupUserFolder
3 ## Copyright (C)2006 Ingeniweb
4
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.
9
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.
14
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.
18 """
19
20 """
21 __version__ = "$Revision: $"
22 # $Source: $
23 # $Id: Installation.py 30098 2006-09-08 12:35:01Z encolpe $
24 __docformat__ = 'restructuredtext'
25
26
27 from cStringIO import StringIO
28 import string
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
33
34 class Installation:
35 def __init__(self, root):
36 self.root=root
37 self.out=StringIO()
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
43
44 def report(self):
45 self.out.write('Installation completed.\n')
46 return self.out.getvalue()
47
48 def setupTools(self, product_name, tools):
49 addTool = self.root.manage_addProduct[product_name].manage_addTool
50 for tool, title in tools:
51 found = 0
52 for obj in self.root.objectValues():
53 if obj.meta_type == tool:
54 found = 1
55 if not found:
56 addTool(tool, None)
57
58 found = 0
59 root=self.root
60 for obj in root.objectValues():
61 if obj.meta_type == tool:
62 obj.title=title
63 self.out.write("Added '%s' tool.\n" % (tool,))
64 found = 1
65 if not found:
66 self.out.write("Couldn't add '%s' tool.\n" % (tool,))
67
68 def installSubSkin(self, skinFolder):
69 """ Install a subskin, i.e. a folder/directoryview.
70 """
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:
75 try:
76 path.insert( path.index( 'custom')+1, skinFolder )
77 except ValueError:
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)
82 else:
83 self.out.write('*** Subskin was already installed into %s.\n' % skin)
84
85 def setupCustomModelsSkin(self, skin_name):
86 """ Install custom skin folder
87 """
88 try:
89 self.skinsTool.manage_addProduct['OFSP'].manage_addFolder(skin_name + 'CustomModels')
90 except:
91 self.out.write('*** Skin %sCustomModels already existed in portal_skins.\n' % skin_name)
92 self.installSubSkin('%sCustomModels' % skin_name)
93
94 def setupTypesandSkins(self, fti_list, skin_name, install_globals):
95 """
96 setup of types and skins
97 """
98
99 # Former types deletion (added by PJG)
100 for f in fti_list:
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'])
104
105 # Type re-creation
106 for f in fti_list:
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']
111
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']))
116
117 # Install de chaque nouvelle subskin/layer
118 try:
119 addDirectoryViews(self.skinsTool, 'skins', install_globals)
120 self.out.write( "Added directory views to portal_skins.\n" )
121 except:
122 self.out.write( '*** Unable to add directory views to portal_skins.\n')
123
124 # Param de chaque nouvelle subskin/layer
125 self.installSubSkin(skin_name)
126
127 def isPlone2(self,):
128 """
129 isPlone2(self,) => return true if we're using Plone2 ! :-)
130 """
131 return self.hasFormController()
132
133 def hasFormController(self,):
134 """
135 hasFormController(self,) => Return 1 if CMFFC is available
136 """
137 if 'portal_form_controller' in self.root.objectIds():
138 return 1
139 else:
140 return None
141
142 def addFormValidators(self, mapping):
143 """
144 Adds the form validators.
145 DON'T ADD ANYTHING IF CMFFORMCONTROLLER IS INSTALLED
146 """
147 # Plone2 management
148 if self.hasFormController():
149 return
150 for (key, value) in mapping:
151 safeEditProperty(self.form_properties, key, value)
152
153 def addNavigationTransitions(self, transitions):
154 """
155 Adds Navigation Transitions in portal properties
156 """
157 # Plone2 management
158 if self.hasFormController():
159 return
160 for (key, value) in transitions:
161 safeEditProperty(self.navigation_properties, key, value)
162
163 def setPermissions(self, perms_list):
164 """
165 setPermissions(self) => Set standard permissions / roles
166 """
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(
172 perm,
173 ('Manager', 'Owner'),
174 acquire = 1
175 )
176 self.out.write("Reseted default permissions\n")
177
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_')
186 return
187 This assumes that you set the domain 'mydomain' in 'translation_service'
188 and the .../Products/YourProduct/i18n/potfile_en.po (...) contain your messages.
189
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
199 """
200
201 installInfo = (
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())
208 #
209 # Find Plone i18n resources
210 #
211 try:
212 ts = getattr(plone, 'translation_service')
213 except AttributeError, e:
214 return installInfo
215 found = 0
216 for nick, path in ts.getDomainInfo():
217 if nick == domain:
218 found = 1
219 break
220 if not found:
221 return installInfo
222 try:
223 mc = ts.restrictedTraverse(path)
224 except (AttributeError, KeyError), e:
225 return installInfo
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))
229 #
230 # Find .po files
231 #
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')
236 poRsrc = {}
237 for file in poFiles:
238 k = rxFindLanguage.findall(file)[0]
239 poRsrc[k] = file
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())
246 fh.close()
247 self.out.write("Done !")