source: trunk/ConfigurationMethods.py @ 1319

Revision 1319, 22.4 KB checked in by vahur, 13 years ago (diff)

adding cz key

  • 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    # Replace front-page with a PythonScript that does a redirection to
117    # the content section.
118    try:
119        portal._delObject('front-page')
120    except AttributeError:
121        pass
122    id = portal._setObject('front-page',PythonScript('front-page'))
123    getattr(portal,id).write(
124"""request = container.REQUEST
125RESPONSE =  request.RESPONSE
126RESPONSE.redirect(container.absolute_url()+'/content/') """)
127                 
128def setupFolders(self,portal):
129    """Setup the basic structure of the site."""
130    atool = getToolByName(portal, 'portal_actions')
131    acts = atool._cloneActions()
132
133    # Loop through all main sections
134    for item in SECTIONS:
135        # Create folder
136         
137        if item in SECTION_FOLDER_TYPES:
138            if not hasattr(portal, item.lower()):
139                addObject(portal,item.lower(),SECTION_FOLDER_TYPES[item],item)
140            folder = getattr(portal,item.lower())
141            folder.manage_permission(ADD_CONTENT_PERMISSION, ('Member',), acquire=1)
142            folder.manage_permission(LIST_FOLDER_CONTENTS, ('Member',), acquire=1)
143            folder.manage_permission(ADD_TOPICS, ('Member',), acquire=1)
144           
145        # Set up properties for folder
146        if SECTION_PROPERTIES[item]:
147            for property in SECTION_PROPERTIES[item].keys():
148                value=SECTION_PROPERTIES[item][property]
149                if type(value) == type(True):
150                    dtype='boolean'
151                else:
152                    dtype='lines'
153                safeEditProperty(obj=getattr(portal,item.lower()),
154                    key=property,
155                    value=value,
156                    data_type=dtype)
157        # Set up tab actions
158        flag = False
159        for action in acts:
160            if action.category == 'portal_tabs' and action.title == item:
161                flag = True
162        if not flag:
163            # Add action for portal tab
164            acts.append(ActionInformation(id=item.lower(),
165                                      title=item,
166                                      description=item,
167                                      category='portal_tabs',
168                                      permissions=('View',),
169                                      visible=True,
170                                      action='string:$portal_url/%s' % item.lower()))
171    atool._actions=acts
172
173def setupGroups(self, portal):
174    """Set groups to use Blogs as workspaces"""
175    grouptool=getToolByName(portal, "portal_groups")
176
177    if not grouptool.getGroupWorkspacesCreationFlag():
178        grouptool.toggleGroupWorkspacesCreation()
179    grouptool.setGroupWorkspacesFolder(id=MEMBERS_FOLDER.lower(), title=MEMBERS_FOLDER)
180    grouptool.setGroupWorkspaceType('GroupBlog')
181    grouptool.manage_permission('Add Groups', ('Manager','Member'), acquire=1)
182    grouptool.manage_permission('Delete Groups', ('Manager','Owner'), acquire=1)
183    grouptool.manage_permission('Manage Groups', ('Manager','Owner','Member'), acquire=1)
184
185
186def setupMembersFolder(self,portal):
187    """Set members folder to something else (MEMBERS_FOLDER= 'community')""" 
188    membertool=getToolByName(portal,"portal_membership")
189    membertool.setMembersFolderById(id=MEMBERS_FOLDER.lower())
190    membertool.setMemberAreaType('MemberFolder')
191
192def setupToptabs(self,portal):
193    # Disable automatic tabs for top level folders
194    stp = getToolByName(portal,'portal_properties').site_properties
195    safeEditProperty(stp,'disable_folder_sections',True)
196
197    # Hide all tabs that aren't what we want
198    atool = getToolByName(portal, 'portal_actions')
199    # Hide all tabs that aren't needed
200    for a in atool._actions:
201        if a.getCategory() in ('portal_tabs',):
202            # Don't hide the tabs that we've created (specified in "SECTIONS")
203            if a.Title() not in SECTIONS:
204                a.visible=0
205
206
207def setupJavascripts(self, portal):
208    """Install new scripts"""
209    jsreg = getToolByName(portal, 'portal_javascripts', None)
210    script = 'js_helpers.js'
211    if jsreg is not None:
212        script_ids = jsreg.getResourceIds()
213        # Failsafe: first make sure the stylesheet doesn't exist in the list
214        if script not in script_ids:
215            jsreg.registerScript(script)
216            # put it at the bottom of the stack
217            jsreg.moveResourceToBottom(script)   
218#        script = 'js_helpers.js'
219#        if script not in script_ids:
220#            jsreg.registerScript(script)
221#            jsreg.moveResourceToBottom(script)   
222
223
224def setupPortlets(self,portal):
225    """Sets up the basic portlet layout."""
226
227    # Use safeEditProperty always to edit properties of the portal or any tools
228    safeEditProperty(portal,'left_slots',('here/portlet_empty/macros/portlet',))
229    safeEditProperty(portal,'right_slots',('',))
230
231def setupSiteSyndication(self, portal):
232    # Enable syndication
233    syn_tool = getToolByName(portal, 'portal_syndication')
234    syn_tool.editProperties(isAllowed=True)
235    #safeEditProperty(syn_tool,'isAllowed',True)
236
237
238def setupUsers(self,portal):
239    mdat_tool = getToolByName(portal, 'portal_memberdata')
240    mship_tool = getToolByName(portal, 'portal_membership')
241    for prop in MEMBER_PROPERTIES:
242        if not hasattr(mdat_tool, prop[0]):
243            mdat_tool.manage_addProperty(prop[0],'',prop[1])
244    # default_portrait seems to be in two places. Hope some of these get the work done.
245    portal.manage_changeProperties(default_portrait=DEFAULT_PORTRAIT)
246    portal.default_portrait=DEFAULT_PORTRAIT
247    mship_tool.manage_changeProperties(default_portrait=DEFAULT_PORTRAIT)
248    mship_tool.default_portrait=DEFAULT_PORTRAIT
249   
250def setupCatalog(self,portal):
251    # put 'language' and 'subject' in catalog index and retrieved metadata
252    # from http://plone.org/documentation/how-to/adding-new-fields-to-smart-folders-search
253    # these are metadata fields from basic plone objects.
254    class args:
255            def __init__(self, **kw):
256                self.__dict__.update(kw)
257            def keys(self):
258                return self.__dict__.keys()
259
260
261    catalog_tool = getToolByName(portal, 'portal_catalog')
262    try:
263        catalog_tool._removeIndex("Language")
264    except:
265        pass
266    try:
267        catalog_tool.delColumn("Language")
268    except:
269        pass
270
271    extra = args(doc_attr='Language',
272                 lexicon_id='plone_lexicon',
273                 index_type='Okapi BM25 Rank')
274    catalog_tool.manage_addIndex("Language", "FieldIndex", extra)
275    catalog_tool.manage_addColumn("Language")
276    try:
277        catalog_tool.delColumn("sortable_title")
278    except:
279        pass
280    catalog_tool.manage_addColumn("sortable_title")   
281
282
283def setup002Workflows(self, portal):
284    """Setup custom workflows."""
285    wtool = getToolByName(portal, 'portal_workflow')
286    for workflow in ['lemill_workflow','group_workflow','wikish_workflow','personal_workflow']:
287        try:
288            wtool.manage_delObjects(workflow)
289        except:
290            pass
291    wtool.manage_addWorkflow('group_workflow (LeMill group workflow)', 'group_workflow')
292    wtool.manage_addWorkflow('wikish_workflow (LeMill wiki-like workflow)', 'wikish_workflow')
293    wtool.manage_addWorkflow('personal_workflow (LeMill personal workflow)', 'personal_workflow')
294    wtool.setChainForPortalTypes(MATERIAL_TYPES+('GroupBlog',), 'group_workflow') # here LeMillReferences get wrong workflow
295    wtool.setChainForPortalTypes(('Activity', 'Tool','Piece','LeMillReference'), 'wikish_workflow') # here they get fixed
296    wtool.setChainForPortalTypes(('Story', 'MemberFolder', 'BlogPost',), 'personal_workflow')
297    # Update all resources to have permissions that match the current workflow spec
298    wtool.updateRoleMappings()
299    portal.manage_permission('Review portal content', ('Manager','Owner','Reviewer'), acquire=1)
300
301
302def setupTopics(self, portal):
303    """Setup pre-defined searches inside SECTIONS to provide a browsable lists of contents."""
304
305    portal_types=getToolByName(portal, 'portal_types')
306    if hasattr(portal_types, 'Topic'):
307        methodlist=portal_types.Topic.getAvailableViewMethods(None)
308        if DEFAULT_TOPIC_VIEW not in methodlist:
309            methodlist=methodlist+(DEFAULT_TOPIC_VIEW,)
310        portal_types.Topic.manage_changeProperties(view_methods=methodlist)
311        portal_types.Topic.manage_changeProperties(default_view=DEFAULT_TOPIC_VIEW)
312    # Loop through all main sections
313
314    for foldername in SECTIONS:
315        if SECTION_TOPICS.has_key(foldername):
316            # additional loop for having several kinds of type restrictions
317            for topic_type in SECTION_TOPICS[foldername]:
318                generated_topics = topic_type[1]
319                allowed_types = topic_type[0]
320                # Loop through topics inside folders
321                if SECTION_TOPICS[foldername]:
322                    folder = getattr(portal, foldername.lower())
323                    for topic_conf in generated_topics:
324                        # Create topics with specific queries
325                        if hasattr(folder.aq_base, topic_conf['id']):
326                            folder._delObject(topic_conf['id'])
327                        addObject(folder, topic_conf['id'], 'Topic', topic_conf['title'])
328                        # Set up properties for topics
329                        topic = getattr(folder, topic_conf['id'])
330                        topic.manage_permission(ADD_CONTENT_PERMISSION, ('Member',), acquire=1)
331                        topic.manage_permission(LIST_FOLDER_CONTENTS, ('Member',), acquire=1)
332                        if topic_conf.has_key('getmethod'):
333                            rev = False
334                            if topic_conf.has_key('reversed'):
335                                rev=topic_conf['reversed']
336                            topic.setSortCriterion(topic_conf['getmethod'], reversed=rev)
337                        criterion = topic.addCriterion('Type', 'ATPortalTypeCriterion' )
338                        criterion.setValue(allowed_types)
339                        # Set additional criterions for drafts and publisheds
340                        if topic_conf.has_key('criterions'):
341                            for crit,crittype,value in topic_conf['criterions']:
342                                criterion = topic.addCriterion(crittype, crit)
343                                if not value=='':
344                                    criterion.setValue(value)
345                        else:
346                            criterion = topic.addCriterion('review_state','ATSelectionCriterion')
347                            criterion.setValue(('public','draft'))   
348                        if topic_conf['id'] == 'recent':
349                            crit = topic.addCriterion('modified', 'ATFriendlyDateCriteria')
350                            crit.setOperation('less')
351                            crit.setDateRange('-')
352                            crit.setValue('3')
353                        if topic_conf['id'] == 'portfolio':
354                            if not hasattr(topic.aq_base, 'left_slots'):
355                                topic._setProperty('left_slots', ['here/portlet_member/macros/memberportrait',], 'lines')
356
357
358def setupRemoteLeMilles(self, portal):
359    #If variable set, tries to add REMOTE_SERVERS to be included in LeMill searches
360    search_tool=getToolByName(portal, 'lemill_search')
361    remote_boxes=search_tool.get_remote_lemilles()
362    for box in REMOTE_SERVERS:
363        add = 1
364        for r in remote_boxes.values():
365            if box == r['URL']:
366                add = 0
367        if add:
368            search_tool.setNewLocation(box)
369
370
371def setupCleanDuplicateActions(self, portal):
372    # Migrating Plone or LeMill causes duplication of certain actions. This is Plone's fault.
373    # addNewActions in Plone's ConfigurationMethods creates these actions without checking if they already exist.
374    atool=getToolByName(portal, 'portal_actions')
375    acts = atool._cloneActions()
376    clean_acts=[]
377    home_check = ownership_check = rename_check = paste_check = delete_check = 0
378    # Go through actions and add only first instances of the following actions to the new actions list:
379    for a in acts:
380        if a.getId()=='index_html': #'Home'
381            if home_check==0:
382                home_check=1
383                clean_acts.append(a)
384        elif a.getId()=='change_ownership':
385            if ownership_check==0:
386                ownership_check=1
387                clean_acts.append(a)
388        elif a.getId()=='rename':
389            if rename_check==0:
390                rename_check=1
391                clean_acts.append(a)
392        elif a.getId()=='paste':
393            if paste_check==0:
394                paste_check=1
395                clean_acts.append(a)
396        elif a.getId()=='delete':
397            if delete_check==0:
398                delete_check=1
399                clean_acts.append(a)
400        else:
401            clean_acts.append(a)
402    atool._actions = tuple( clean_acts )
403
404def setupFactoryTypes(self, portal):
405    """ set types that should use portal_factory """
406    ft = getToolByName(portal, 'portal_factory')
407    types_list = ft.getFactoryTypes()
408    for t in ALL_CONTENT_TYPES:
409        types_list[t] = 1
410    ft.manage_setPortalFactoryTypes(None, types_list)
411
412def setupConfigureKupu(self, portal):
413    """ configure kupu """
414    k = getToolByName(portal, 'kupu_library_tool')
415    k.configure_kupu(1, '',  #linkbyuid, table_classnames
416            [   # html exclusion. list tags you don't want to be in HTML code
417                {'tags':['center', 'span', 'tt', 'big', 'small', 'u', 's', 'strike', 'basefont', 'font', 'table', 'th', 'td', 'tbody', 'thead', 'tr', 'div', 'img'],
418                 'attributes':'',
419                 'keep':1,
420                }, # list attributes you don't want in HTML code
421                {'tags':'',
422                 'attributes':'dir,lang,valign,halign,border,frame,rules,cellspacing,cellpadding,bgcolor',
423                 'keep':1,
424                },
425            ],
426            ['text-align', 'list-style-type'],   # style whitelist
427            [],  # class_blacklist
428            1,  # install before unload
429            ['Heading|h2', 'Code|pre'])   # Kupu can't handle 'code'
430
431language_list = ['cz','et','en','es','fi','ru']
432
433def setupLanguageTool(self, portal):
434    """ configure plone language tool to use browser language request negotation """
435    lt = getToolByName(portal, 'portal_languages')
436    if lt is None:
437        return
438    lt.addLanguage('cz', 'Czech')
439    lt.manage_setLanguageSettings('en', #default language
440            language_list, # supported languages (needs to be a list, not a tuple)
441            1, # use cookie negotiation
442            1, # use request negotiation
443            0, # use path negotiation
444            0, # force language URLs (content)
445            1, # allow fallback (content)
446            1, # use combined languages
447            0, # display flags
448            0, # start neutral (content)
449            )
450
451def setupProperties(self, portal):
452    lt = getToolByName(portal, 'lemill_tool')
453    safeEditProperty(lt, 'portal_integration', value=False, data_type="boolean")
454    safeEditProperty(lt, 'portal_search_link', value="TODO", data_type="string")
455    safeEditProperty(lt, 'primary_languages', value=language_list, data_type="tokens")
456    safeEditProperty(lt, 'allow_banning', value=False, data_type="boolean")
457    lt.language_dict=dict(portal.availableLanguages())
458   
459def setupRoles(self, portal):
460    portal._addRole('CoAuthor')
461
462def toolboxSetupCustomization(self, portal):
463    # Do necessary additional customization steps
464
465    # Use EUN skin
466    skinsTool = getToolByName(portal,"portal_skins")
467    skinsTool.default_skin="LeMill EUN"
468   
469    # Setup basic properties
470    lt = getToolByName(portal, 'lemill_tool')
471    safeEditProperty(lt, 'portal_integration', value=True)
472    safeEditProperty(lt, 'portal_search_link', value="http://calibrate.eun.org/merlin/index.cfm?fuseaction=resources.dsp_search")
473    language_list = ['cz','de','en','et','hu','lt','nl','pl','sl']
474    safeEditProperty(lt, 'primary_languages', value=language_list, data_type="tokens")
475
476    lt = getToolByName(portal, 'portal_languages')
477    lt.addLanguage('cz', 'Czech')
478    lt.manage_setLanguageSettings('en', #default language
479            language_list,
480            1, # use cookie negotiation
481            1, # use request negotiation
482            0, # use path negotiation
483            0, # force language URLs (content)
484            1, # allow fallback (content)
485            1, # use combined languages
486            0, # display flags
487            0, # start neutral (content)
488            )
489    # Disable Join functionality
490    portal.manage_permission('Add portal member',('Manager',))
491
492#########
493# Collect all setup functions into a setup widget
494
495afunctions = {}
496for f in dir():
497    if f.startswith('setup'):
498        func = eval("%s" % f)
499        if type(func) == types.FunctionType:
500            afunctions[f] = func
501
502toolbox_functions = {}
503for f in dir():
504    if f.startswith('toolboxSetup'):
505        func = eval("%s" % f)
506        if type(func) == types.FunctionType:
507            toolbox_functions[f] = func
508
509
510class LeMillSetup(SetupWidget):
511    type = 'LeMill Setup'
512
513    description = """Customization methods needed by the LeMill Plone portal"""
514
515    functions = afunctions
516
517    def setup(self):
518        pass
519
520    def delItems(self, fns):
521        out = []
522        out.append(('Currently there is no way to remove a function', INFO))
523        return out
524
525    def addItems(self, fns):
526        """This method is called when configuration methods need to be applied.
527        fns is the list of function names that need to be executed in order."""
528        out = []
529        for fn in fns:
530            # All functions are executed with the portal as the first actual parameter
531            self.functions[fn](self, self.portal)
532            out.append(('Function %s has been applied' % fn, INFO))
533        return out
534
535    def installed(self):
536        return []
537
538    def available(self):
539        """Get a list of availabel functions."""
540        funcs = self.functions.keys()
541        # Sort, so we get a pre-determined order.
542        # The functions need to be named properly
543        funcs.sort()
544        return funcs
545
546
547class ToolboxSetup(LeMillSetup):
548    type = 'Toolbox Setup'
549
550    description = """Customization methods needed by the Toolbox"""
551
552    functions = {}
553    functions.update(afunctions)
554    functions.update(toolbox_functions)
555
Note: See TracBrowser for help on using the repository browser.