source: trunk/ConfigurationMethods.py @ 1388

Revision 1388, 22.7 KB checked in by tarmo, 12 years ago (diff)

Added 'hu' into our list of UI languages.

  • Property svn:eol-style set to native
Line 
1# Copyright 2006 by the LeMill Team (see AUTHORS)
2#
3# This file is part of LeMill.
4#
5# LeMill 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# LeMill 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 LeMill; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
18
19# -*- coding: iso-8859-1 -*-
20
21from Acquisition import aq_get
22from AccessControl import Permissions, getSecurityManager
23from zExceptions import BadRequest
24from OFS.PropertyManager import PropertyManager
25from zLOG import INFO, ERROR
26
27from Products.CMFCore.utils import getToolByName
28from Products.CMFCore.DirectoryView import registerDirectory, addDirectoryViews
29from Products.CMFCore.ActionInformation import ActionInformation
30from Products.CMFPlone.migrations.migration_util import safeEditProperty
31from Products.CMFPlone.PloneFolder import addPloneFolder
32from Products.CMFPlone.setup.SetupBase import SetupWidget
33from Products.SiteErrorLog.SiteErrorLog import manage_addErrorLog
34from Products.Archetypes.public import listTypes, registerType
35from Products.Archetypes.Extensions.utils \
36     import installTypes, install_subskin
37from Products.PythonScripts.PythonScript import PythonScript
38
39from DateTime import DateTime
40import string, types
41from cStringIO import StringIO
42
43from config import *
44
45
46# All methods starting with "setup" will be used in the customization policy
47# The methods will be sorted by ascii value, so if something  needs to happen before
48# something else, make it so (see method setup001Dependencies).
49
50# Note that all methods need to be repeatable - they should not fail
51# if they are run again when all that they do has already been done.
52# Also, the methods should be able to upgrade, meaning that older customizations
53# should be changed to match the newest specifications.
54
55def setup001Dependencies(self, portal):
56    """Install all necessary products into the plone instance."""
57    qi=getToolByName(portal, 'portal_quickinstaller')
58    # We need ourselves installed into the plone instance,
59    # since we provide portal tools and content
60    qi.installProduct('LeMill')
61    # LanguageTool is also necessary
62    qi.installProduct('PloneLanguageTool')
63
64def setupSkin(self,portal):
65    """Create new custom skin."""
66    skinsTool = getToolByName(portal,"portal_skins")
67
68    # Register our own skin folder as a viewable folder
69    try:
70        addDirectoryViews(skinsTool,SKINS_DIR,GLOBALS)
71    except:
72        # If the directory is already registered, we just continue
73        pass
74
75    # Create our new skin, making it a copy of BASE_SKIN and adding
76    # our skin layer just after "custom".
77    for SKIN_NAME in SKIN_NAMES:
78        if SKIN_NAME not in skinsTool.getSkinSelections():
79            path = skinsTool.getSkinPath(BASE_SKIN)
80            path = map(string.strip,string.split(path,','))
81            for skinFolder in SKIN_COMMON_FOLDERS + [SKIN_NAME.lower().replace(' ','_'),]:
82                if skinFolder not in path:
83                    try:
84                        path.insert(path.index('custom')+1,skinFolder)
85                    except ValueError:
86                        path.append(skinFolder)
87            path=string.join(path,',')
88            skinsTool.addSkinSelection(SKIN_NAME,path)
89
90    # Select our first skin as default
91    skinsTool.default_skin=SKIN_NAMES[0]
92
93def addObject(portal,id,type,title,desc=None):
94    """Convenience method for creating new content items."""
95    try:
96        portal.invokeFactory(id=id,type_name=type)
97    except BadRequest:
98        # If the id already existed, we'll just quietly be happy about it.
99        pass
100    finalizeObject(portal,id,title,desc)
101
102def finalizeObject(portal,id,title,desc=None):
103    """Set content object properties in place."""
104    ob=getattr(portal,id)
105   
106    # Set basic properties of object
107    ob.setTitle(to_unicode(title))
108    if desc:
109        ob.setDescription(to_unicode(desc))
110       
111    # Publish content
112    ob.content_status_modify(workflow_action='publish')
113
114def setupFrontPage(self,portal):
115    """Setup the front page."""
116    # Make sure that old PythonScript for redirecting isn't there anymore
117    # the content section.
118    try:
119        portal._delObject('front-page')
120    except AttributeError:
121        pass
122                 
123def setupFolders(self,portal):
124    """Setup the basic structure of the site."""
125    atool = getToolByName(portal, 'portal_actions')
126    acts = atool._cloneActions()
127    # Clean up any portal_tabs from actions
128    new_acts=[]
129    for action in acts:
130        if action.category == 'portal_tabs':
131            pass
132        else:
133            new_acts.append(action)
134
135    # Loop through all main sections
136    for item in SECTIONS:
137        # Create folder
138         
139        if item in SECTION_FOLDER_TYPES:
140            if not hasattr(portal, item.lower()):
141                addObject(portal,item.lower(),SECTION_FOLDER_TYPES[item],item)
142            folder = getattr(portal,item.lower())
143            folder.manage_permission(ADD_CONTENT_PERMISSION, ('Member',), acquire=1)
144            folder.manage_permission(LIST_FOLDER_CONTENTS, ('Member',), acquire=1)
145            folder.manage_permission(ADD_TOPICS, ('Member',), acquire=1)
146           
147        # Set up properties for folder
148        if SECTION_PROPERTIES[item]:
149            for property in SECTION_PROPERTIES[item].keys():
150                value=SECTION_PROPERTIES[item][property]
151                if type(value) == type(True):
152                    dtype='boolean'
153                else:
154                    dtype='lines'
155                safeEditProperty(obj=getattr(portal,item.lower()),
156                    key=property,
157                    value=value,
158                    data_type=dtype)
159               
160        # Add action for portal tab
161        new_acts.append(ActionInformation(id=item.lower(),
162                                          title=item,
163                                          description=item,
164                                          category='portal_tabs',
165                                          permissions=('View',),
166                                          visible=True,
167                                          action='string:$portal_url/%s' % item.lower()))
168    atool._actions=new_acts
169
170def setupGroups(self, portal):
171    """Set groups to use Blogs as workspaces"""
172    grouptool=getToolByName(portal, "portal_groups")
173
174    if not grouptool.getGroupWorkspacesCreationFlag():
175        grouptool.toggleGroupWorkspacesCreation()
176    grouptool.setGroupWorkspacesFolder(id=MEMBERS_FOLDER.lower(), title=MEMBERS_FOLDER)
177    grouptool.setGroupWorkspaceType('GroupBlog')
178    grouptool.manage_permission('Add Groups', ('Manager','Member'), acquire=1)
179    grouptool.manage_permission('Delete Groups', ('Manager','Owner'), acquire=1)
180    grouptool.manage_permission('Manage Groups', ('Manager','Owner','Member'), acquire=1)
181
182
183def setupMembersFolder(self,portal):
184    """Set members folder to something else (MEMBERS_FOLDER= 'community')""" 
185    membertool=getToolByName(portal,"portal_membership")
186    membertool.setMembersFolderById(id=MEMBERS_FOLDER.lower())
187    membertool.setMemberAreaType('MemberFolder')
188
189def setupToptabs(self,portal):
190    # Disable automatic tabs for top level folders
191    stp = getToolByName(portal,'portal_properties').site_properties
192    safeEditProperty(stp,'disable_folder_sections',True)
193
194    # Hide all tabs that aren't what we want
195    atool = getToolByName(portal, 'portal_actions')
196    # Hide all tabs that aren't needed
197    for a in atool._actions:
198        if a.getCategory() in ('portal_tabs',):
199            # Don't hide the tabs that we've created (specified in "SECTIONS")
200            if a.Title() not in SECTIONS:
201                a.visible=0
202
203
204def setupJavascripts(self, portal):
205    """Install new scripts"""
206    jsreg = getToolByName(portal, 'portal_javascripts', None)
207    script = 'js_helpers.js'
208    if jsreg is not None:
209        script_ids = jsreg.getResourceIds()
210        # Failsafe: first make sure the stylesheet doesn't exist in the list
211        if script not in script_ids:
212            jsreg.registerScript(script)
213            # put it at the bottom of the stack
214            jsreg.moveResourceToBottom(script)   
215#        script = 'js_helpers.js'
216#        if script not in script_ids:
217#            jsreg.registerScript(script)
218#            jsreg.moveResourceToBottom(script)   
219
220
221def setupPortlets(self,portal):
222    """Sets up the basic portlet layout."""
223
224    # Use safeEditProperty always to edit properties of the portal or any tools
225    safeEditProperty(portal,'left_slots',('here/portlet_empty/macros/portlet',))
226    safeEditProperty(portal,'right_slots',('',))
227
228def setupSiteSyndication(self, portal):
229    # Enable syndication
230    syn_tool = getToolByName(portal, 'portal_syndication')
231    syn_tool.editProperties(isAllowed=True)
232    #safeEditProperty(syn_tool,'isAllowed',True)
233
234
235def setupUsers(self,portal):
236    mdat_tool = getToolByName(portal, 'portal_memberdata')
237    mship_tool = getToolByName(portal, 'portal_membership')
238    for prop in MEMBER_PROPERTIES:
239        if not hasattr(mdat_tool, prop[0]):
240            mdat_tool.manage_addProperty(prop[0],'',prop[1])
241    # default_portrait seems to be in two places. Hope some of these get the work done.
242    portal.manage_changeProperties(default_portrait=DEFAULT_PORTRAIT)
243    portal.default_portrait=DEFAULT_PORTRAIT
244    mship_tool.manage_changeProperties(default_portrait=DEFAULT_PORTRAIT)
245    mship_tool.default_portrait=DEFAULT_PORTRAIT
246   
247def setupCatalog(self,portal):
248    # put 'language' and 'subject' in catalog index and retrieved metadata
249    # from http://plone.org/documentation/how-to/adding-new-fields-to-smart-folders-search
250    # these are metadata fields from basic plone objects.
251    class args:
252            def __init__(self, **kw):
253                self.__dict__.update(kw)
254            def keys(self):
255                return self.__dict__.keys()
256
257
258    catalog_tool = getToolByName(portal, 'portal_catalog')
259    try:
260        catalog_tool._removeIndex("Language")
261    except:
262        pass
263    try:
264        catalog_tool.delColumn("Language")
265    except:
266        pass
267
268    extra = args(doc_attr='Language',
269                 lexicon_id='plone_lexicon',
270                 index_type='Okapi BM25 Rank')
271    catalog_tool.manage_addIndex("Language", "FieldIndex", extra)
272    catalog_tool.manage_addColumn("Language")
273    try:
274        catalog_tool.delColumn("sortable_title")
275    except:
276        pass
277    catalog_tool.manage_addColumn("sortable_title")   
278    try:
279        catalog_tool.delColumn("UID")
280    except:
281        pass
282    catalog_tool.manage_addColumn("UID")   
283
284
285def setup002Workflows(self, portal):
286    """Setup custom workflows."""
287    wtool = getToolByName(portal, 'portal_workflow')
288    for workflow in ['lemill_workflow','group_workflow','wikish_workflow','personal_workflow']:
289        try:
290            wtool.manage_delObjects(workflow)
291        except:
292            pass
293    wtool.manage_addWorkflow('group_workflow (LeMill group workflow)', 'group_workflow')
294    wtool.manage_addWorkflow('wikish_workflow (LeMill wiki-like workflow)', 'wikish_workflow')
295    wtool.manage_addWorkflow('personal_workflow (LeMill personal workflow)', 'personal_workflow')
296    wtool.setChainForPortalTypes(MATERIAL_TYPES+('GroupBlog',), 'group_workflow') # here LeMillReferences get wrong workflow
297    wtool.setChainForPortalTypes(('Activity', 'Tool','Piece','LeMillReference'), 'wikish_workflow') # here they get fixed
298    wtool.setChainForPortalTypes(('Story', 'MemberFolder', 'BlogPost',), 'personal_workflow')
299    # Update all resources to have permissions that match the current workflow spec
300    wtool.updateRoleMappings()
301    portal.manage_permission('Review portal content', ('Manager','Owner','Reviewer'), acquire=1)
302
303
304def setupTopics(self, portal):
305    """Setup pre-defined searches inside SECTIONS to provide a browsable lists of contents."""
306
307    portal_types=getToolByName(portal, 'portal_types')
308    if hasattr(portal_types, 'Topic'):
309        methodlist=portal_types.Topic.getAvailableViewMethods(None)
310        if DEFAULT_TOPIC_VIEW not in methodlist:
311            methodlist=methodlist+(DEFAULT_TOPIC_VIEW,)
312        portal_types.Topic.manage_changeProperties(view_methods=methodlist)
313        portal_types.Topic.manage_changeProperties(default_view=DEFAULT_TOPIC_VIEW)
314    # Loop through all main sections
315
316    for foldername in SECTIONS:
317        if SECTION_TOPICS.has_key(foldername):
318            # additional loop for having several kinds of type restrictions
319            for topic_type in SECTION_TOPICS[foldername]:
320                generated_topics = topic_type[1]
321                allowed_types = topic_type[0]
322                # Loop through topics inside folders
323                if SECTION_TOPICS[foldername]:
324                    folder = getattr(portal, foldername.lower())
325                    for topic_conf in generated_topics:
326                        # Create topics with specific queries
327                        if hasattr(folder.aq_base, topic_conf['id']):
328                            folder._delObject(topic_conf['id'])
329                        addObject(folder, topic_conf['id'], 'Topic', topic_conf['title'])
330                        # Set up properties for topics
331                        topic = getattr(folder, topic_conf['id'])
332                        topic.manage_permission(ADD_CONTENT_PERMISSION, ('Member',), acquire=1)
333                        topic.manage_permission(LIST_FOLDER_CONTENTS, ('Member',), acquire=1)
334                        if topic_conf.has_key('getmethod'):
335                            rev = False
336                            if topic_conf.has_key('reversed'):
337                                rev=topic_conf['reversed']
338                            topic.setSortCriterion(topic_conf['getmethod'], reversed=rev)
339                        criterion = topic.addCriterion('Type', 'ATPortalTypeCriterion' )
340                        criterion.setValue(allowed_types)
341                        # Set additional criterions for drafts and publisheds
342                        if topic_conf.has_key('criterions'):
343                            for crit,crittype,value in topic_conf['criterions']:
344                                criterion = topic.addCriterion(crittype, crit)
345                                if not value=='':
346                                    criterion.setValue(value)
347                        else:
348                            criterion = topic.addCriterion('review_state','ATSelectionCriterion')
349                            criterion.setValue(('public','draft'))   
350                        if topic_conf['id'] == 'recent':
351                            crit = topic.addCriterion('modified', 'ATFriendlyDateCriteria')
352                            crit.setOperation('less')
353                            crit.setDateRange('-')
354                            crit.setValue('3')
355                        if topic_conf['id'] == 'portfolio':
356                            if not hasattr(topic.aq_base, 'left_slots'):
357                                topic._setProperty('left_slots', ['here/portlet_member/macros/memberportrait',], 'lines')
358
359
360def setupRemoteLeMilles(self, portal):
361    #If variable set, tries to add REMOTE_SERVERS to be included in LeMill searches
362    search_tool=getToolByName(portal, 'lemill_search')
363    remote_boxes=search_tool.get_remote_lemilles()
364    for box in REMOTE_SERVERS:
365        add = 1
366        for r in remote_boxes.values():
367            if box == r['URL']:
368                add = 0
369        if add:
370            search_tool.setNewLocation(box)
371
372
373def setupCleanDuplicateActions(self, portal):
374    # Migrating Plone or LeMill causes duplication of certain actions. This is Plone's fault.
375    # addNewActions in Plone's ConfigurationMethods creates these actions without checking if they already exist.
376    atool=getToolByName(portal, 'portal_actions')
377    acts = atool._cloneActions()
378    clean_acts=[]
379    home_check = ownership_check = rename_check = paste_check = delete_check = 0
380    # Go through actions and add only first instances of the following actions to the new actions list:
381    for a in acts:
382        if a.getId()=='index_html': #'Home'
383            if home_check==0:
384                home_check=1
385                clean_acts.append(a)
386        elif a.getId()=='change_ownership':
387            if ownership_check==0:
388                ownership_check=1
389                clean_acts.append(a)
390        elif a.getId()=='rename':
391            if rename_check==0:
392                rename_check=1
393                clean_acts.append(a)
394        elif a.getId()=='paste':
395            if paste_check==0:
396                paste_check=1
397                clean_acts.append(a)
398        elif a.getId()=='delete':
399            if delete_check==0:
400                delete_check=1
401                clean_acts.append(a)
402        else:
403            clean_acts.append(a)
404    atool._actions = tuple( clean_acts )
405
406def setupFactoryTypes(self, portal):
407    """ set types that should use portal_factory """
408    ft = getToolByName(portal, 'portal_factory')
409    types_list = ft.getFactoryTypes()
410    for t in ALL_CONTENT_TYPES:
411        types_list[t] = 1
412    ft.manage_setPortalFactoryTypes(None, types_list)
413
414def setupConfigureKupu(self, portal):
415    """ configure kupu """
416    k = getToolByName(portal, 'kupu_library_tool')
417    k.configure_kupu(1, '',  #linkbyuid, table_classnames
418            [   # html exclusion. list tags you don't want to be in HTML code
419                {'tags':TAGS_BLACKLIST,
420                 'attributes':'',
421                 'keep':1,
422                }, # list attributes you don't want in HTML code
423                {'tags':'',
424                 'attributes':'dir,lang,valign,halign,border,frame,rules,cellspacing,cellpadding,bgcolor',
425                 'keep':1,
426                },
427            ],
428            ['text-align', 'list-style-type'],   # style whitelist
429            [],  # class_blacklist
430            1,  # install before unload
431            ['Heading|h2', 'Code|pre'])   # Kupu can't handle 'code'
432
433language_list = ['cz','et','en','es','fi','hu','ru']
434
435def setupLanguageTool(self, portal):
436    """ configure plone language tool to use browser language request negotation """
437    lt = getToolByName(portal, 'portal_languages')
438    if lt is None:
439        return
440    lt.addLanguage('cz', 'Czech')
441    lt.manage_setLanguageSettings('en', #default language
442            language_list, # supported languages (needs to be a list, not a tuple)
443            1, # use cookie negotiation
444            1, # use request negotiation
445            0, # use path negotiation
446            0, # force language URLs (content)
447            1, # allow fallback (content)
448            1, # use combined languages
449            0, # display flags
450            0, # start neutral (content)
451            )
452
453def setupProperties(self, portal):
454    lt = getToolByName(portal, 'lemill_tool')
455    safeEditProperty(lt, 'portal_integration', value=False, data_type="boolean")
456    safeEditProperty(lt, 'portal_search_link', value="TODO", data_type="string")
457    safeEditProperty(lt, 'primary_languages', value=language_list, data_type="tokens")
458    safeEditProperty(lt, 'allow_banning', value=False, data_type="boolean")
459    safeEditProperty(lt, 'irc_link', value='http://lemill.net/irc/irc.cgi', data_type="string")
460    lt.language_dict=dict(portal.availableLanguages())
461   
462def setupRoles(self, portal):
463    portal._addRole('CoAuthor')
464
465def toolboxSetupCustomization(self, portal):
466    # Do necessary additional customization steps
467
468    # Use EUN skin
469    skinsTool = getToolByName(portal,"portal_skins")
470    skinsTool.default_skin="LeMill EUN"
471   
472    # Setup basic properties
473    lt = getToolByName(portal, 'lemill_tool')
474    safeEditProperty(lt, 'portal_integration', value=True)
475    safeEditProperty(lt, 'portal_search_link', value="http://calibrate.eun.org/merlin/index.cfm?fuseaction=resources.dsp_search")
476    language_list = ['cz','de','en','et','hu','lt','nl','pl','sl']
477    safeEditProperty(lt, 'primary_languages', value=language_list, data_type="tokens")
478
479    lt = getToolByName(portal, 'portal_languages')
480    lt.addLanguage('cz', 'Czech')
481    lt.manage_setLanguageSettings('en', #default language
482            language_list,
483            1, # use cookie negotiation
484            1, # use request negotiation
485            0, # use path negotiation
486            0, # force language URLs (content)
487            1, # allow fallback (content)
488            1, # use combined languages
489            0, # display flags
490            0, # start neutral (content)
491            )
492    # Disable Join functionality
493    portal.manage_permission('Add portal member',('Manager',))
494
495    # Replace front-page with a PythonScript that does a redirection to
496    # the content section.
497    try:
498        portal._delObject('front-page')
499    except AttributeError:
500        pass
501    id = portal._setObject('front-page',PythonScript('front-page'))
502    getattr(portal,id).write(
503    """request = container.REQUEST
504    RESPONSE =  request.RESPONSE
505    RESPONSE.redirect(container.absolute_url()+'/content/') """)
506
507#########
508# Collect all setup functions into a setup widget
509
510afunctions = {}
511for f in dir():
512    if f.startswith('setup'):
513        func = eval("%s" % f)
514        if type(func) == types.FunctionType:
515            afunctions[f] = func
516
517toolbox_functions = {}
518for f in dir():
519    if f.startswith('toolboxSetup'):
520        func = eval("%s" % f)
521        if type(func) == types.FunctionType:
522            toolbox_functions[f] = func
523
524
525class LeMillSetup(SetupWidget):
526    type = 'LeMill Setup'
527
528    description = """Customization methods needed by the LeMill Plone portal"""
529
530    functions = afunctions
531
532    def setup(self):
533        pass
534
535    def delItems(self, fns):
536        out = []
537        out.append(('Currently there is no way to remove a function', INFO))
538        return out
539
540    def addItems(self, fns):
541        """This method is called when configuration methods need to be applied.
542        fns is the list of function names that need to be executed in order."""
543        out = []
544        for fn in fns:
545            # All functions are executed with the portal as the first actual parameter
546            self.functions[fn](self, self.portal)
547            out.append(('Function %s has been applied' % fn, INFO))
548        return out
549
550    def installed(self):
551        return []
552
553    def available(self):
554        """Get a list of availabel functions."""
555        funcs = self.functions.keys()
556        # Sort, so we get a pre-determined order.
557        # The functions need to be named properly
558        funcs.sort()
559        return funcs
560
561
562class ToolboxSetup(LeMillSetup):
563    type = 'Toolbox Setup'
564
565    description = """Customization methods needed by the Toolbox"""
566
567    functions = {}
568    functions.update(afunctions)
569    functions.update(toolbox_functions)
570
Note: See TracBrowser for help on using the repository browser.