source: trunk/ConfigurationMethods.py @ 495

Revision 495, 18.5 KB checked in by vahur, 13 years ago (diff)

made a list of content types. Also made config.py accessible from python scripts and page templates.

  • 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        if item in SECTION_FOLDER_TYPES:
137            addObject(portal,item.lower(),SECTION_FOLDER_TYPES[item],item)
138            folder = getattr(portal,item.lower())
139            folder.manage_permission(ADD_CONTENT_PERMISSION, ('Member',), acquire=1)
140            folder.manage_permission(LIST_FOLDER_CONTENTS, ('Member',), acquire=1)
141           
142        # Set up properties for folder
143        if SECTION_PROPERTIES[item]:
144            for property in SECTION_PROPERTIES[item].keys():
145                value=SECTION_PROPERTIES[item][property]
146                if type(value) == type(True):
147                    dtype='boolean'
148                else:
149                    dtype='lines'
150                safeEditProperty(obj=getattr(portal,item.lower()),
151                    key=property,
152                    value=value,
153                    data_type=dtype)
154        # Set up tab actions
155        flag = False
156        for action in acts:
157            if action.category == 'portal_tabs' and action.title == item:
158                flag = True
159        if not flag:
160            # Add action for portal tab
161            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=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
182def setupLanguageTool(self, portal):
183    """Add tool portal_language and set it to ignore browser's default language"""
184    languagetool=getToolByName(portal,"portal_languages")
185    languagetool.manage_changeProperties(use_request_negotiation=0)
186    languagetool.use_request_negotiation=0
187    languagetool.setLanguageBindings()   
188    #safeEditProperty(languagetool,'use_request_negotiation',0)
189
190def setupMembersFolder(self,portal):
191    """Set members folder to something else (MEMBERS_FOLDER= 'community')""" 
192    membertool=getToolByName(portal,"portal_membership")
193    membertool.setMembersFolderById(id=MEMBERS_FOLDER.lower())
194    membertool.setMemberAreaType('MemberFolder')
195
196def setupToptabs(self,portal):
197    # Disable automatic tabs for top level folders
198    stp = getToolByName(portal,'portal_properties').site_properties
199    safeEditProperty(stp,'disable_folder_sections',True)
200
201    # Hide all tabs that aren't what we want
202    atool = getToolByName(portal, 'portal_actions')
203    # Hide all tabs that aren't needed
204    for a in atool._actions:
205        if a.getCategory() in ('portal_tabs',):
206            # Don't hide the tabs that we've created (specified in "SECTIONS")
207            if a.Title() not in SECTIONS:
208                a.visible=0
209
210
211def setupPortlets(self,portal):
212    """Sets up the basic portlet layout."""
213
214    # Use safeEditProperty always to edit properties of the portal or any tools
215    safeEditProperty(portal,'left_slots',('here/portlet_login/macros/portlet',
216                                          'here/portlet_related/macros/portlet'))
217    safeEditProperty(portal,'right_slots',('here/portlet_review/macros/portlet',
218                                           'here/portlet_news/macros/portlet',
219                                           'here/portlet_events/macros/portlet'))
220
221def setupSiteSyndication(self, portal):
222    # Enable syndication
223    syn_tool = getToolByName(portal, 'portal_syndication')
224    syn_tool.editProperties(isAllowed=True)
225    #safeEditProperty(syn_tool,'isAllowed',True)
226
227
228def setupUsers(self,portal):
229    mdat_tool = getToolByName(portal, 'portal_memberdata')
230    mship_tool = getToolByName(portal, 'portal_membership')
231    for prop in MEMBER_PROPERTIES:
232        if not hasattr(mdat_tool, prop[0]):
233            mdat_tool.manage_addProperty(prop[0],'',prop[1])
234    # default_portrait seems to be in two places. Hope some of these get the work done.
235    portal.manage_changeProperties(default_portrait=DEFAULT_PORTRAIT)
236    portal.default_portrait=DEFAULT_PORTRAIT
237    mship_tool.manage_changeProperties(default_portrait=DEFAULT_PORTRAIT)
238    mship_tool.default_portrait=DEFAULT_PORTRAIT
239   
240def setupCatalog(self,portal):
241    # put 'language' and 'subject' in catalog index and retrieved metadata
242    # from http://plone.org/documentation/how-to/adding-new-fields-to-smart-folders-search
243    # these are metadata fields from basic plone objects.
244    class args:
245            def __init__(self, **kw):
246                self.__dict__.update(kw)
247            def keys(self):
248                return self.__dict__.keys()
249
250
251    catalog_tool = getToolByName(portal, 'portal_catalog')
252    try:
253        catalog_tool._removeIndex("Language")
254    except:
255        pass
256    try:
257        catalog_tool.delColumn("Language")
258    except:
259        pass
260
261    extra = args(doc_attr='Language',
262                 lexicon_id='plone_lexicon',
263                 index_type='Okapi BM25 Rank')
264    catalog_tool.manage_addIndex("Language", "FieldIndex", extra)
265    catalog_tool.manage_addColumn("Language")
266
267
268def setupXternals_Fle3(self,portal):
269    if not FLE3_AVAILABLE:
270        return
271    # FIXME: Doesn't work right now, plus needs to be done differently
272    return
273   
274    user = getSecurityManager().getUser()
275    uname = user.getUserName()
276    # Install Fle3
277    Products.FLE.FLE.manage_addFLE(portal,'fle3','LeMill Knowledge Building',
278                                   uname,'','','','',
279                                   'LeMill',
280                                   '','')
281    # Customize Fle3
282    portal.fle3.courses.manage_permission('Add FLE LO',('User',),0)
283
284    # Add resource objects
285    addObject(portal.activities,'kb','KB',
286              'Knowledge Building',
287              'This is a description of knowledge building')
288   
289    addObject(portal.tools,'fle3','Tool',
290              'Fle3',
291              'Collaborative learning environment for progressive inquiry and <a href="../activities/kb">knowledge building</a>.')
292
293def setup002Workflows(self, portal):
294    """Setup custom workflows."""
295    wtool = getToolByName(portal, 'portal_workflow')
296    for workflow in ['lemill_workflow','group_workflow','wikish_workflow','personal_workflow']:
297        try:
298            wtool.manage_delObjects(workflow)
299        except:
300            pass
301    wtool.manage_addWorkflow('group_workflow (LeMill group workflow)', 'group_workflow')
302    wtool.manage_addWorkflow('wikish_workflow (LeMill wiki-like workflow)', 'wikish_workflow')
303    wtool.manage_addWorkflow('personal_workflow (LeMill personal workflow)', 'personal_workflow')
304    wtool.setChainForPortalTypes(('PresentationMaterial', 'Material', 'GroupBlog'), 'group_workflow')
305    wtool.setChainForPortalTypes(('Activity', 'Tool','Piece'), 'wikish_workflow')
306    wtool.setChainForPortalTypes(('Story', 'MemberFolder', 'BlogPost',), 'personal_workflow')
307    # Update all resources to have permissions that match the current workflow spec
308    wtool.updateRoleMappings()
309
310def setupTopics(self, portal):
311    """Setup pre-defined searches inside SECTIONS to provide a browsable lists of contents."""
312
313    portal_types=getToolByName(portal, 'portal_types')
314    if hasattr(portal_types, 'Topic'):
315        methodlist=portal_types.Topic.getAvailableViewMethods(None)
316        if DEFAULT_TOPIC_VIEW not in methodlist:
317            methodlist=methodlist+(DEFAULT_TOPIC_VIEW,)
318        portal_types.Topic.manage_changeProperties(view_methods=methodlist)
319        portal_types.Topic.manage_changeProperties(default_view=DEFAULT_TOPIC_VIEW)
320    # Loop through all main sections
321
322    for foldername in SECTIONS:
323        if SECTION_TOPICS.has_key(foldername):
324            # additional loop for having several kinds of type restrictions
325            for topic_type in SECTION_TOPICS[foldername]:
326                generated_topics = topic_type[1]
327                allowed_types = topic_type[0]
328                # Loop through topics inside folders
329                if SECTION_TOPICS[foldername]:
330                    folder = getattr(portal, foldername.lower())
331                    for topic_conf in generated_topics:
332                        # Create topics
333                        if hasattr(folder.aq_base, topic_conf['id']):
334                            folder._delObject(topic_conf['id'])
335                            #print "deleted %s" % topic_conf['id']
336                        addObject(folder, topic_conf['id'], 'Topic', topic_conf['title'])
337                        #print 'Created topic '+topic_conf['id']+' in '+str(folder)
338                        # Set up properties for topics
339                        topic = getattr(folder, topic_conf['id'])
340                        topic.manage_permission(ADD_CONTENT_PERMISSION, ('Member',), acquire=1)
341                        topic.manage_permission(LIST_FOLDER_CONTENTS, ('Member',), acquire=1)
342                        if topic_conf.has_key('orderby') and topic_conf.has_key('reversed'):
343                            topic.setSortCriterion(topic_conf['orderby'], reversed=topic_conf['reversed'])
344                        criterion = topic.addCriterion('Type', 'ATPortalTypeCriterion' )
345                        criterion.setValue(allowed_types)
346                        # Set additional criterions for drafts and publisheds
347                        if topic_conf.has_key('criterions'):
348                            for crit,crittype,value in topic_conf['criterions']:
349                                criterion = topic.addCriterion(crittype, crit)
350                                if not value=='':
351                                    criterion.setValue(value)
352                        else:
353                            criterion = topic.addCriterion('review_state','ATSelectionCriterion')
354                            criterion.setValue(('public','draft'))   
355
356def setupRemoteLeMilles(self, portal):
357    #If variable set, tries to add REMOTE_SERVERS to be included in LeMill searches
358    search_tool=getToolByName(portal, 'lemill_search')
359    remote_boxes=search_tool.get_remote_lemilles()
360    for box in REMOTE_SERVERS:
361        if not box in remote_boxes.values():
362            search_tool.setNewLocation(box)
363
364
365def setupCleanDuplicateActions(self, portal):
366    # Migrating Plone or LeMill causes duplication of certain actions. This is Plone's fault.
367    # addNewActions in Plone's ConfigurationMethods creates these actions without checking if they already exist.
368    atool=getToolByName(portal, 'portal_actions')
369    acts = atool._cloneActions()
370    clean_acts=[]
371    home_check = ownership_check = rename_check = paste_check = delete_check = 0
372    # Go through actions and add only first instances of the following actions to the new actions list:
373    for a in acts:
374        if a.getId()=='index_html': #'Home'
375            if home_check==0:
376                home_check=1
377                clean_acts.append(a)
378        elif a.getId()=='change_ownership':
379            if ownership_check==0:
380                ownership_check=1
381                clean_acts.append(a)
382        elif a.getId()=='rename':
383            if rename_check==0:
384                rename_check=1
385                clean_acts.append(a)
386        elif a.getId()=='paste':
387            if paste_check==0:
388                paste_check=1
389                clean_acts.append(a)
390        elif a.getId()=='delete':
391            if delete_check==0:
392                delete_check=1
393                clean_acts.append(a)
394        else:
395            clean_acts.append(a)
396    atool._actions = tuple( clean_acts )
397
398def setupFactoryTypes(self, portal):
399    """ set types that should use portal_factory """
400    ft = getToolByName(portal, 'portal_factory')
401    types_list = ft.getFactoryTypes()
402    for t in ALL_CONTENT_TYPES:
403        types_list[t] = 1
404    ft.manage_setPortalFactoryTypes(None, types_list)
405
406
407#########
408# Collect all setup functions into a setup widget
409
410afunctions = {}
411
412for f in dir():
413    if f.startswith('setup'):
414        func = eval("%s" % f)
415        if type(func) == types.FunctionType:
416            afunctions[f] = func
417
418class LeMillSetup(SetupWidget):
419    type = 'LeMill Setup'
420
421    description = """Customization methods needed by the LeMill Plone portal"""
422
423    functions = afunctions
424
425    def setup(self):
426        pass
427
428    def delItems(self, fns):
429        out = []
430        out.append(('Currently there is no way to remove a function', INFO))
431        return out
432
433    def addItems(self, fns):
434        """This method is called when configuration methods need to be applied.
435        fns is the list of function names that need to be executed in order."""
436        out = []
437        for fn in fns:
438            # All functions are executed with the portal as the first actual parameter
439            self.functions[fn](self, self.portal)
440            out.append(('Function %s has been applied' % fn, INFO))
441        return out
442
443    def installed(self):
444        return []
445
446    def available(self):
447        """Get a list of availabel functions."""
448        funcs = self.functions.keys()
449        # Sort, so we get a pre-determined order.
450        # The functions need to be named properly
451        funcs.sort()
452        return funcs
453
Note: See TracBrowser for help on using the repository browser.