Annotation of kupuMPIWG/plone/plonelibrarytool.py, revision 1.1.1.1

1.1       dwinter     1: ##############################################################################
                      2: #
                      3: # Copyright (c) 2003-2005 Kupu Contributors. All rights reserved.
                      4: #
                      5: # This software is distributed under the terms of the Kupu
                      6: # License. See LICENSE.txt for license text. For a list of Kupu
                      7: # Contributors see CREDITS.txt.
                      8: #
                      9: ##############################################################################
                     10: """Plone Kupu library tool
                     11: 
                     12: This module contains the Plone specific version of the Kupu library
                     13: tool.
                     14: 
                     15: $Id: plonelibrarytool.py 15693 2005-08-05 14:14:33Z duncan $
                     16: """
                     17: import os
                     18: from ZODB.PersistentList import PersistentList
                     19: from ZODB.PersistentMapping import PersistentMapping
                     20: from AccessControl import ClassSecurityInfo
                     21: from OFS.SimpleItem import SimpleItem
                     22: import Globals
                     23: from Globals import InitializeClass
                     24: 
                     25: from Products.PageTemplates.PageTemplateFile import PageTemplateFile
                     26: from Products.CMFCore.utils import UniqueObject, getToolByName
                     27: 
                     28: from Products.kupu.plone.librarytool import KupuLibraryTool
                     29: from Products.kupu.plone import permissions, scanner
                     30: from Products.kupu import kupu_globals
                     31: from Products.kupu.config import TOOLNAME, TOOLTITLE
                     32: 
                     33: _default_libraries = (
                     34:     dict(id="root",
                     35:          title="string:Home",
                     36:          uri="string:${portal_url}",
                     37:          src="string:${portal_url}/kupucollection.xml",
                     38:          icon="string:${portal_url}/misc_/CMFPlone/plone_icon"),
                     39:     dict(id="current",
                     40:          title="string:Current folder",
                     41:          uri="string:${folder_url}",
                     42:          src="string:${folder_url}/kupucollection.xml",
                     43:          icon="string:${portal_url}/folder_icon.gif"),
                     44:     dict(id="myitems",
                     45:          title="string:My recent items",
                     46:          uri="string:${portal_url}/kupumyitems.xml",
                     47:          src="string:${portal_url}/kupumyitems.xml",
                     48:          icon="string:${portal_url}/kupuimages/kupusearch_icon.gif"),
                     49:     dict(id="recentitems",
                     50:          title="string:Recent items",
                     51:          uri="string:${portal_url}/kupurecentitems.xml",
                     52:          src="string:${portal_url}/kupurecentitems.xml",
                     53:          icon="string:${portal_url}/kupuimages/kupusearch_icon.gif")
                     54:     )
                     55: 
                     56: _default_resource_types = {
                     57:     'collection': ('Plone Site', 'Folder', 'Large Plone Folder'),
                     58:     'mediaobject': ('Image',),
                     59:     'linkable': ('Document', 'Image', 'File', 'News Item', 'Event')
                     60:     }
                     61: 
                     62: # Tidy up html by exlcluding lots of things.
                     63: _excluded_html = [
                     64:   (('center', 'span', 'tt', 'big', 'small', 'u', 's', 'strike', 'basefont', 'font'), ()),
                     65:   ((), ('dir','lang','valign','halign','border','frame','rules','cellspacing','cellpadding','bgcolor')),
                     66:   (('table','th','td'),('width','height')),
                     67: ]
                     68: 
                     69: # Default should list all styles used by Kupu
                     70: _style_whitelist = ['text-align', 'list-style-type', 'float']
                     71: 
                     72: _default_paragraph_styles = (
                     73:     "Heading|h2|Heading",
                     74:     "Subheading|h3|Subheading",
                     75:     "Formatted|pre",
                     76: )
                     77: 
                     78: class PloneKupuLibraryTool(UniqueObject, SimpleItem, KupuLibraryTool):
                     79:     """Plone specific version of the kupu library tool"""
                     80: 
                     81:     id = TOOLNAME
                     82:     meta_type = "Kupu Library Tool"
                     83:     title = TOOLTITLE
                     84:     security = ClassSecurityInfo()
                     85: 
                     86:     # protect methods provided by super class KupuLibraryTool
                     87:     security.declareProtected(permissions.QueryLibraries, "getLibraries",
                     88:                               "getPortalTypesForResourceType")
                     89:     security.declareProtected(permissions.ManageLibraries, "addLibrary",
                     90:                               "deleteLibraries", "updateLibraries",
                     91:                               "moveUp", "moveDown")
                     92:     security.declareProtected(permissions.ManageLibraries, "addResourceType",
                     93:                               "updateResourceTypes", "deleteResourceTypes")
                     94: 
                     95:     def __init__(self):
                     96:         self._libraries = PersistentList()
                     97:         self._res_types = PersistentMapping()
                     98:         self.linkbyuid = True
                     99: 
                    100:     def manage_afterAdd(self, item, container):
                    101:         # We load default values here, so __init__ can still be used
                    102:         # in unit tests. Plus, it only makes sense to load these if
                    103:         # we're being added to a Plone site anyway
                    104:         for lib in _default_libraries:
                    105:             self.addLibrary(**lib)
                    106:         self._res_types.update(_default_resource_types)
                    107: 
                    108:     security.declareProtected('View', "getLinkbyuid")
                    109:     def getLinkbyuid(self):
                    110:         """Returns 'is linking by UID enabled'?"""
                    111:         try:
                    112:             return self.linkbyuid
                    113:         except AttributeError:
                    114:             return 1
                    115: 
                    116:     security.declareProtected('View', "getTableClassnames")
                    117:     def getTableClassnames(self):
                    118:         """Return a list of classnames supported in tables"""
                    119:         try:
                    120:             return self.table_classnames
                    121:         except AttributeError:
                    122:             return ('plain', 'listing', 'vertical listing', 'listing nosort')
                    123: 
                    124:     security.declareProtected('View', "getParagraphStyles")
                    125:     def getParagraphStyles(self):
                    126:         """Return a list of classnames supported in tables"""
                    127:         try:
                    128:             return self.paragraph_styles
                    129:         except AttributeError:
                    130:             return _default_paragraph_styles
                    131: 
                    132:     security.declareProtected('View', "getHtmlExclusions")
                    133:     def getHtmlExclusions(self):
                    134:         try:
                    135:             return self.html_exclusions
                    136:         except AttributeError:
                    137:             self.html_exclusions = _excluded_html
                    138:             return self.html_exclusions
                    139: 
                    140:     security.declareProtected('View', "getStyleWhitelist")
                    141:     def getStyleWhitelist(self):
                    142:         try:
                    143:             return self.style_whitelist
                    144:         except AttributeError:
                    145:             self.style_whitelist = _style_whitelist
                    146:             return self.style_whitelist
                    147: 
                    148:     security.declareProtected('View', "getClassBlacklist")
                    149:     def getClassBlacklist(self):
                    150:         return getattr(self, 'class_blacklist', [])
                    151: 
                    152:     security.declareProtected('View', "getClassBlacklist")
                    153:     def installBeforeUnload(self):
                    154:         return getattr(self, 'install_beforeunload', True)
                    155: 
                    156:     security.declareProtected('View', 'isKupuEnabled')
                    157:     def isKupuEnabled(self, useragent='', allowAnonymous=False, REQUEST=None):
                    158:         def numerics(s):
                    159:             '''Convert a string into a tuple of all digit sequences
                    160:             '''
                    161:             seq = ['']
                    162:             for c in s:
                    163:                 if c.isdigit():
                    164:                     seq[-1] = seq[-1] + c
                    165:                 elif seq[-1]:
                    166:                     seq.append('')
                    167:             return tuple([ int(val) for val in seq if val])
                    168: 
                    169:         # First check whether the user actually wants kupu
                    170:         pm = getToolByName(self, 'portal_membership')
                    171:         if pm.isAnonymousUser() and not allowAnonymous:
                    172:             return False
                    173: 
                    174:         user = pm.getAuthenticatedMember()
                    175:         if user.getProperty('wysiwyg_editor').lower() != 'kupu':
                    176:             return False
                    177: 
                    178:         # Then check whether their browser supports it.
                    179:         if not useragent:
                    180:             useragent = REQUEST['HTTP_USER_AGENT']
                    181: 
                    182:         if 'Opera' in useragent or 'BEOS' in useragent:
                    183:             return False
                    184: 
                    185:         if not useragent.startswith('Mozilla/'):
                    186:             return False
                    187: 
                    188:         try:
                    189:             mozillaver = numerics(useragent[len('Mozilla/'):].split(' ')[0])
                    190:             if mozillaver > (5,0):
                    191:                 return True
                    192:             elif mozillaver == (5,0):
                    193:                 rv = useragent.find(' rv:')
                    194:                 if rv >= 0:
                    195:                     verno = numerics(useragent[rv+4:].split(')')[0])
                    196:                     return verno >= (1,3,1)
                    197: 
                    198:             MSIE = useragent.find('MSIE')
                    199:             if MSIE >= 0:
                    200:                 verno = numerics(useragent[MSIE+4:].split(';')[0])
                    201:                 return verno >= (5,5)
                    202: 
                    203:         except:
                    204:             # In case some weird browser makes the test code blow up.
                    205:             pass
                    206:         return False
                    207: 
                    208:     # ZMI views
                    209:     manage_options = (SimpleItem.manage_options[1:] + (
                    210:          dict(label='Config', action='kupu_config'),
                    211:          dict(label='Libraries', action='zmi_libraries'),
                    212:          dict(label='Resource types', action='zmi_resource_types'),
                    213:          dict(label='Documentation', action='zmi_docs'),
                    214:          dict(label='Status', action='sanity_check'),
                    215:          ))
                    216: 
                    217: 
                    218:     security.declarePublic('scanIds')
                    219:     def scanIds(self):
                    220:         """Finds the relevant source files and the doller/Id/dollar strings they contain"""
                    221:         return scanner.scanIds()
                    222: 
                    223:     security.declarePublic('scanKWS')
                    224:     def scanKWS(self):
                    225:         """Check that kupu_wysiwyg_support is up to date"""
                    226:         return scanner.scanKWS()
                    227: 
                    228:     security.declarePublic('docs')
                    229:     def docs(self):
                    230:         """Returns Kupu docs formatted as HTML"""
                    231:         docpath = os.path.join(Globals.package_home(kupu_globals), 'doc')
                    232:         f = open(os.path.join(docpath, 'PLONE2.txt'), 'r')
                    233:         _docs = f.read()
                    234:         return _docs
                    235: 
                    236:     security.declareProtected(permissions.ManageLibraries, "zmi_docs")
                    237:     zmi_docs = PageTemplateFile("zmi_docs.pt", globals())
                    238:     zmi_docs.title = 'kupu configuration documentation'
                    239: 
                    240:     security.declareProtected(permissions.ManageLibraries, "sanity_check")
                    241:     sanity_check = PageTemplateFile("sanity_check.pt", globals())
                    242:     sanity_check.title = 'kupu status'
                    243: 
                    244:     security.declareProtected(permissions.ManageLibraries, "kupu_config")
                    245:     kupu_config = PageTemplateFile("kupu_config.pt", globals())
                    246:     kupu_config.title = 'kupu configuration'
                    247: 
                    248:     security.declareProtected(permissions.ManageLibraries, "zmi_libraries")
                    249:     zmi_libraries = PageTemplateFile("libraries.pt", globals())
                    250:     zmi_libraries.title = 'kupu configuration'
                    251: 
                    252:     security.declareProtected(permissions.ManageLibraries, "zmi_resource_types")
                    253:     zmi_resource_types = PageTemplateFile("resource_types.pt", globals())
                    254:     zmi_resource_types.title = 'kupu configuration'
                    255: 
                    256:     security.declareProtected(permissions.ManageLibraries,
                    257:                               "zmi_get_libraries")
                    258:     def zmi_get_libraries(self):
                    259:         """Return the libraries sequence for the ZMI view"""
                    260:         #return ()
                    261:         def text(value):
                    262:             return getattr(value, 'text', value)
                    263:         return [dict([(key, text(value)) for key, value in lib.items()])
                    264:                 for lib in self._libraries]
                    265: 
                    266:     security.declareProtected(permissions.ManageLibraries,
                    267:                               "zmi_add_library")
                    268:     def zmi_add_library(self, id, title, uri, src, icon, REQUEST):
                    269:         """Add a library through the ZMI"""
                    270:         self.addLibrary(id, title, uri, src, icon)
                    271:         REQUEST.RESPONSE.redirect(self.absolute_url() + '/zmi_libraries')
                    272: 
                    273:     security.declareProtected(permissions.ManageLibraries,
                    274:                               "zmi_update_libraries")
                    275:     def zmi_update_libraries(self, libraries, REQUEST):
                    276:         """Update libraries through the ZMI"""
                    277:         self.updateLibraries(libraries)
                    278:         REQUEST.RESPONSE.redirect(self.absolute_url() + '/zmi_libraries')
                    279: 
                    280:     security.declareProtected(permissions.ManageLibraries,
                    281:                               "zmi_delete_libraries")
                    282:     def zmi_delete_libraries(self, indices, REQUEST):
                    283:         """Delete libraries through the ZMI"""
                    284:         self.deleteLibraries(indices)
                    285:         REQUEST.RESPONSE.redirect(self.absolute_url() + '/zmi_libraries')
                    286: 
                    287:     security.declareProtected(permissions.ManageLibraries,
                    288:                               "zmi_move_up")
                    289:     def zmi_move_up(self, indices, REQUEST):
                    290:         """Move libraries up through the ZMI"""
                    291:         self.moveUp(indices)
                    292:         REQUEST.RESPONSE.redirect(self.absolute_url() + '/zmi_libraries')
                    293: 
                    294:     security.declareProtected(permissions.ManageLibraries,
                    295:                               "zmi_move_down")
                    296:     def zmi_move_down(self, indices, REQUEST):
                    297:         """Move libraries down through the ZMI"""
                    298:         self.moveDown(indices)
                    299:         REQUEST.RESPONSE.redirect(self.absolute_url() + '/zmi_libraries')
                    300: 
                    301:     security.declarePublic("zmi_get_default_library")
                    302:     def zmi_get_default_library(self):
                    303:         """Return the default selected library for the ZMI view"""
                    304:         return getattr(self, '_default_library', '')
                    305: 
                    306:     security.declareProtected(permissions.ManageLibraries,
                    307:                               "zmi_set_default_library")
                    308:     def zmi_set_default_library(self, defid=''):
                    309:         """Return the libraries sequence for the ZMI view"""
                    310:         self._default_library = defid
                    311: 
                    312:     security.declareProtected(permissions.ManageLibraries,
                    313:                               "zmi_get_type_mapping")
                    314:     def zmi_get_type_mapping(self):
                    315:         """Return the type mapping for the ZMI view"""
                    316:         return [(res_type, tuple(portal_type)) for res_type, portal_type
                    317:                 in self._res_types.items()]
                    318: 
                    319:     security.declareProtected(permissions.ManageLibraries,
                    320:                               "zmi_add_resource_type")
                    321:     def zmi_add_resource_type(self, resource_type, portal_types, REQUEST):
                    322:         """Add resource type through the ZMI"""
                    323:         self.addResourceType(resource_type, portal_types)
                    324:         REQUEST.RESPONSE.redirect(self.absolute_url() + '/zmi_resource_types')
                    325: 
                    326:     security.declareProtected(permissions.ManageLibraries,
                    327:                               "zmi_update_resource_types")
                    328:     def zmi_update_resource_types(self, type_info, REQUEST):
                    329:         """Update resource types through the ZMI"""
                    330:         self.updateResourceTypes(type_info)
                    331:         REQUEST.RESPONSE.redirect(self.absolute_url() + '/zmi_resource_types')
                    332: 
                    333:     security.declareProtected(permissions.ManageLibraries,
                    334:                               "zmi_delete_resource_types")
                    335:     def zmi_delete_resource_types(self, resource_types, REQUEST):
                    336:         """Delete resource types through the ZMI"""
                    337:         self.deleteResourceTypes(resource_types)
                    338:         REQUEST.RESPONSE.redirect(self.absolute_url() + '/zmi_resource_types')
                    339: 
                    340:     security.declareProtected(permissions.ManageLibraries,
                    341:                               "configure_kupu")
                    342:     def configure_kupu(self,
                    343:         linkbyuid, table_classnames, html_exclusions, style_whitelist, class_blacklist,
                    344:         installBeforeUnload=None, parastyles=None,
                    345:         REQUEST=None):
                    346:         """Delete resource types through the ZMI"""
                    347:         self.linkbyuid = int(linkbyuid)
                    348:         self.table_classnames = table_classnames
                    349:         if installBeforeUnload is not None:
                    350:             self.install_beforeunload = bool(installBeforeUnload)
                    351:         if parastyles:
                    352:             self.paragraph_styles = [ line.strip() for line in parastyles if line.strip() ]
                    353: 
                    354:         newex = html_exclusions[-1]
                    355:             
                    356:         html_exclusions = [ (tuple(h.get('tags', ())), tuple(h.get('attributes', ())))
                    357:             for h in html_exclusions[:-1] if h.get('keep')]
                    358:         
                    359:         tags, attr = newex.get('tags', ()), newex.get('attributes', ())
                    360:         if tags or attr:
                    361:             tags = tuple(tags.replace(',',' ').split())
                    362:             attr = tuple(attr.replace(',',' ').split())
                    363:             html_exclusions.append((tags, attr))
                    364: 
                    365:         self.html_exclusions = html_exclusions
                    366: 
                    367:         self.style_whitelist = list(style_whitelist)
                    368:         self.class_blacklist = list(class_blacklist)
                    369: 
                    370:         if REQUEST:
                    371:             REQUEST.RESPONSE.redirect(self.absolute_url() + '/kupu_config')
                    372: 
                    373: InitializeClass(PloneKupuLibraryTool)

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>