Package Products :: Package ZenModel :: Module ZenModelBase
[hide private]
[frames] | no frames]

Source Code for Module Products.ZenModel.ZenModelBase

  1  ########################################################################### 
  2  # 
  3  # This program is part of Zenoss Core, an open source monitoring platform. 
  4  # Copyright (C) 2007, Zenoss Inc. 
  5  # 
  6  # This program is free software; you can redistribute it and/or modify it 
  7  # under the terms of the GNU General Public License version 2 as published by 
  8  # the Free Software Foundation. 
  9  # 
 10  # For complete information please visit: http://www.zenoss.com/oss/ 
 11  # 
 12  ########################################################################### 
 13   
 14  __doc__="""ZenModelBase 
 15   
 16  $Id: ZenModelBase.py,v 1.17 2004/04/23 19:11:58 edahl Exp $""" 
 17   
 18  __version__ = "$Revision: 1.17 $"[11:-2] 
 19   
 20  import re 
 21  import time 
 22  import types 
 23  import sys 
 24   
 25  from xml.sax import saxutils 
 26  from urllib import unquote 
 27  from cgi import escape 
 28  import zope.component 
 29  import zope.interface 
 30   
 31  from OFS.ObjectManager import checkValidId as globalCheckValidId 
 32   
 33  from AccessControl import ClassSecurityInfo, getSecurityManager, Unauthorized 
 34  from Globals import InitializeClass 
 35  from Acquisition import aq_base, aq_chain 
 36   
 37  from Products.ZenModel.interfaces import IZenDocProvider 
 38  from Products.ZenUtils.Utils import zenpathsplit, zenpathjoin 
 39  from Products.ZenUtils.Utils import createHierarchyObj, getHierarchyObj 
 40  from Products.ZenUtils.Utils import getObjByPath 
 41   
 42  from Products.ZenUtils.Utils import prepId as globalPrepId, isXmlRpc 
 43  from Products.ZenWidgets import messaging 
 44  from Products.ZenUI3.browser.interfaces import INewPath 
 45   
 46  from ZenossSecurity import * 
 47   
 48  _MARKER = object() 
 49   
 50  # Custom device properties start with c 
 51  iscustprop = re.compile("^c[A-Z]").search 
 52   
53 -class ZenModelBase(object):
54 """ 55 All ZenModel Persistent classes inherit from this class. It provides some 56 screen management functionality, and general utility methods. 57 """ 58 _zendoc = '' 59 60 sub_meta_types = () 61 #prodStateThreshold = 500 62 63 security = ClassSecurityInfo() 64
65 - def __call__(self):
66 """ 67 Invokes the default view. 68 """ 69 if isXmlRpc(self.REQUEST): 70 return self 71 else: 72 newpath = INewPath(self) 73 self.REQUEST.response.redirect(newpath)
74 75 index_html = None # This special value informs ZPublisher to use __call__ 76 77 78 security.declareProtected(ZEN_VIEW, 'view')
79 - def view(self):
80 ''' 81 Returns the default view even if index_html is overridden. 82 83 @permission: ZEN_VIEW 84 ''' 85 return self()
86 87
88 - def __hash__(self):
89 return hash(self.id)
90
91 - def prepId(self, id, subchar='_'):
92 """ 93 Clean out an id of illegal characters. 94 95 @type id: string 96 @param subchar: Character to be substituted with illegal characters 97 @type subchar: string 98 @rtype: string 99 100 >>> dmd.Devices.prepId('ab^*cd') 101 'ab__cd' 102 >>> dmd.Devices.prepId('ab^*cd', subchar='Z') 103 'abZZcd' 104 >>> dmd.Devices.prepId('/boot') 105 'boot' 106 >>> dmd.Devices.prepId('/') 107 '-' 108 >>> dmd.Devices.prepId(' mydev ') 109 'mydev' 110 """ 111 return globalPrepId(id, subchar)
112
113 - def checkValidId(self, id, prep_id = False):
114 """ 115 Checks that an id is a valid Zope id. Looks for invalid characters and 116 checks that the id doesn't already exist in this context. 117 118 @type id: string 119 @type prep_id: boolean 120 @rtype: boolean 121 122 >>> dmd.Devices.checkValidId('^*') 123 'The id "^*" contains characters illegal in URLs.' 124 >>> dmd.Devices.checkValidId('Server') 125 'The id "Server" is invalid - it is already in use.' 126 >>> dmd.Devices.checkValidId('ZenTestId') 127 True 128 """ 129 new_id = unquote(id) 130 if prep_id: new_id = self.prepId(id) 131 try: 132 globalCheckValidId(self, new_id) 133 return True 134 except: 135 return str(sys.exc_info()[1])
136 137
138 - def getUnusedId(self, relName, baseKey, extensionIter=None):
139 """ 140 Return a new id that is not already in use in the relationship. If 141 baseKey is not already in use, return that. Otherwise append values 142 from extensionIter to baseKey until an used key is found. The default 143 extensionIter appends integers starting with 2 and counting up. 144 145 @type relName: string 146 @type baseKey: string 147 @type extensionIter: iterator 148 @rtype: string 149 150 >>> id1 = dmd.Devices.getUnusedId('devices', 'dev') 151 >>> id1 152 'dev' 153 >>> dmd.Devices.createInstance(id1) 154 <Device at /zport/dmd/Devices/devices/dev> 155 >>> id2 = dmd.Devices.getUnusedId('devices', 'dev') 156 >>> id2 157 'dev2' 158 """ 159 import itertools 160 if extensionIter is None: 161 extensionIter = itertools.count(2) 162 rel = getattr(self, relName) 163 candidate = baseKey 164 while candidate in rel.objectIds(): 165 candidate = self.prepId('%s%s' % (baseKey, extensionIter.next())) 166 return candidate
167 168 180 181
182 - def callZenScreen(self, REQUEST, redirect=False):
183 """ 184 Call and return screen specified by zenScreenName value of REQUEST. 185 If zenScreenName is not present call the default screen. This is used 186 in functions that are called from forms to get back to the correct 187 screen with the correct context. 188 """ 189 if REQUEST is None or getattr(REQUEST, 'dontRender', False): 190 # EventView uses a FakeRequest class to avoid the overhead 191 # of rendering pages as result of ajax calls. 192 return '' 193 screenName = REQUEST.get("zenScreenName", "") 194 if not redirect and REQUEST.get("redirect", None) : 195 redirect = True 196 if redirect: 197 nurl = "%s/%s" % (self.getPrimaryUrlPath(), screenName) 198 REQUEST['RESPONSE'].redirect(nurl) 199 else: 200 REQUEST['URL'] = "%s/%s" % (self.absolute_url_path(), screenName) 201 screen = getattr(self, screenName, False) 202 if not screen: return self() 203 return screen()
204 205
206 - def zenScreenUrl(self):
207 """ 208 Return the url for the current screen as defined by zenScreenName. 209 If zenScreenName is not found in the request the request url is used. 210 211 @return: An url to this object 212 @rtype: string 213 """ 214 screenName = self.REQUEST.get("zenScreenName", "") 215 if not screenName: return self.REQUEST.URL 216 return self.getPrimaryUrlPath() + "/" + screenName
217 218 244 245
246 - def getBreadCrumbUrlPath(self):
247 """ 248 Return the url to be used in breadcrumbs for this object. normally 249 this is equal to getPrimaryUrlPath. It can be used as a hook to modify 250 the url so that it points towards a different tab then the default. 251 252 @return: A url to this object 253 @rtype: string 254 255 >>> dmd.Devices.getBreadCrumbUrlPath() 256 '/zport/dmd/Devices' 257 >>> rc = dmd.Reports._getOb('Graph Reports') 258 >>> rc.manage_addGraphReport('test').getBreadCrumbUrlPath() 259 '/zport/dmd/Reports/Graph%20Reports/test/editGraphReport' 260 """ 261 return self.getPrimaryUrlPath()
262 263
264 - def getBreadCrumbName(self):
265 return self.title_or_id()
266 267
268 - def breadCrumbs(self, terminator='dmd', terminate=lambda x: False):
269 """ 270 Return the data to create the breadcrumb links for this object. 271 272 This is a list of tuples where the first value is the URL of the bread 273 crumb and the second is the lable. 274 275 @return: List of tuples to create a bread crumbs 276 @rtype: list 277 278 >>> dmd.Devices.Server.breadCrumbs() 279 [('/zport/dmd/Devices', 'Devices'), 280 ('/zport/dmd/Devices/Server', 'Server')] 281 """ 282 links = [] 283 curDir = self.primaryAq() 284 while curDir.id != terminator and not terminate(curDir): 285 if curDir.meta_type == 'ToManyContRelationship': 286 curDir = curDir.getPrimaryParent() 287 continue 288 if not getattr(aq_base(curDir),"getBreadCrumbUrlPath", False): 289 break 290 url = "" 291 if self.checkRemotePerm("View", curDir): 292 url = curDir.getBreadCrumbUrlPath() 293 links.append((url, curDir.getBreadCrumbName())) 294 curDir = curDir.aq_parent 295 links.reverse() 296 return links
297 298
299 - def upToOrganizerBreadCrumbs(self, terminator='dmd'):
300 301 def isOrganizer(curDir): 302 from Products.ZenModel.Organizer import Organizer 303 try: 304 return isinstance(curDir, Organizer) 305 except: 306 return False
307 308 return ZenModelBase.breadCrumbs(self, terminator, isOrganizer)
309 310 311 security.declareProtected(ZEN_COMMON, 'checkRemotePerm')
312 - def checkRemotePerm(self, permission, robject):
313 """ 314 Look to see if the current user has permission on remote object. 315 316 @param permission: Zope permission to be tested. ie "View" 317 @param robject: remote objecct on which test is run. Will test on 318 primary acquisition path. 319 @rtype: boolean 320 @permission: ZEN_COMMON 321 """ 322 user = getSecurityManager().getUser() 323 return user.has_permission(permission, robject.primaryAq())
324 325 326 327 security.declareProtected(ZEN_VIEW, 'zentinelTabs')
328 - def zentinelTabs(self, templateName, REQUEST=None):
329 """ 330 Return a list of hashes that define the screen tabs for this object. 331 332 Keys in the hash are: 333 - action = the name of the page template for this tab 334 - name = the label used on the tab 335 - permissions = a tuple of permissions to view this template 336 337 @permission: ZEN_VIEW 338 339 >>> dmd.Devices.zentinelTabs('deviceOrganizerStatus') 340 [{'action': 'deviceOrganizerStatus', 'selected': True, 341 'name': 'Classes', 'permissions': ('View',)}, 342 {'action': 'viewEvents', 'name': 'Events', 'permissions': ('View',)}, 343 {'action': 'zPropertyEdit', 'name': 'Configuration Properties', 344 'permissions': ('View',)}, 345 {'action': 'perfConfig', 'name': 'Templates', 346 'permissions': ('Manage DMD',)}] 347 """ 348 tabs = [] 349 user = getSecurityManager().getUser() 350 actions = self.factory_type_information[0]['actions'] 351 selectedTabName = self._selectedTabName(templateName, REQUEST) 352 for a in actions: 353 def permfilter(p): return user.has_permission(p,self) 354 permok = filter(permfilter, a['permissions']) 355 if not a.get('visible', True) or not permok: 356 continue 357 a = a.copy() 358 if a['action'] == selectedTabName: a['selected'] = True 359 tabs.append(a) 360 return tabs
361
362 - def _selectedTabName(self, templateName, REQUEST=None):
363 if REQUEST and REQUEST.get('selectedTabName', '') : 364 selectedTabName = REQUEST.get('selectedTabName', '') 365 else: 366 selectedTabName = templateName 367 requestUrl = REQUEST['URL'] if REQUEST else None 368 if not selectedTabName and requestUrl and requestUrl.rfind('/') != -1: 369 selectedTabName = requestUrl[requestUrl.rfind('/') + 1:] 370 if selectedTabName.startswith('@@'): 371 selectedTabName = selectedTabName[2:] 372 return selectedTabName
373 374 375 security.declareProtected(ZEN_MANAGE_DMD, 'zmanage_editProperties')
376 - def zmanage_editProperties(self, REQUEST=None, redirect=False):
377 """ 378 Edit a ZenModel object and return its proper page template. 379 Object will be reindexed if nessesary. 380 381 @permission: ZEN_MANAGE_DMD 382 """ 383 self.manage_changeProperties(**REQUEST.form) 384 index_object = getattr(self, 'index_object', lambda self: None) 385 index_object() 386 if REQUEST: 387 from Products.ZenUtils.Time import SaveMessage 388 messaging.IMessageSender(self).sendToBrowser( 389 'Properties Saved', 390 SaveMessage() 391 ) 392 return self.callZenScreen(REQUEST, redirect=redirect)
393 394 395 security.declareProtected(ZEN_VIEW, 'getPrimaryDmdId')
396 - def getPrimaryDmdId(self, rootName="dmd", subrel=""):
397 """ 398 Return the full dmd id of this object for instance /Devices/Server. 399 Everything before dmd is removed. A different rootName can be passed 400 to stop at a different object in the path. If subrel is passed any 401 relationship name in the path to the object will be removed. 402 403 @param rootName: Name of root 404 @type rootName: string 405 @param subrel: Name of relation 406 @type subrel: string 407 @return: Path to object 408 @rtype: string 409 @permission: ZEN_VIEW 410 411 >>> d = dmd.Devices.Server.createInstance('test') 412 >>> d.getPrimaryDmdId() 413 '/Devices/Server/devices/test' 414 >>> d.getPrimaryDmdId('Devices') 415 '/Server/devices/test' 416 >>> d.getPrimaryDmdId('Devices','devices') 417 '/Server/test' 418 """ 419 path = list(self.getPrimaryPath()) 420 path = path[path.index(rootName)+1:] 421 if subrel: path = filter(lambda x: x != subrel, path) 422 return '/'+'/'.join(path)
423 424
425 - def zenpathjoin(self, path):
426 """ 427 DEPRECATED Build a Zenoss path based on a list or tuple. 428 429 @type path: list or tuple 430 431 >>> dmd.zenpathjoin(('zport', 'dmd', 'Devices', 'Server')) 432 '/zport/dmd/Devices/Server' 433 """ 434 return zenpathjoin(path)
435 436
437 - def zenpathsplit(self, path):
438 """ 439 DEPRECATED Split a path on its '/'. 440 """ 441 return zenpathsplit(path)
442 443
444 - def createHierarchyObj(self, root, name, factory, relpath="", alog=None):
445 """ 446 DEPRECATED this is only seems to be used in Organizer.createOrganizer - 447 Create an object from its path we use relpath to skip down any missing 448 relations in the path and factory is the constructor for this object. 449 """ 450 return createHierarchyObj(root, name, factory, relpath, alog)
451 452
453 - def getHierarchyObj(self, root, name, relpath):
454 """ 455 DEPRECATED this doesn't seem to be used anywere don't use it!!! 456 """ 457 return getHierarchyObj(root, name, relpath)
458 459
460 - def getDmd(self):
461 """ 462 DEPRECATED Return the dmd root object with unwraped acquisition path. 463 464 >>> dmd.Devices.Server.getDmd() 465 <DataRoot at /zport/dmd> 466 """ 467 for obj in aq_chain(self): 468 if getattr(obj, 'id', None) == 'dmd': return obj
469 470
471 - def getDmdRoot(self, name):
472 """ 473 Return a dmd root organizer such as "Systems". The acquisition path 474 will be cleaned so that it points directly to the root. 475 476 >>> dmd.Devices.Server.getDmdRoot("Systems") 477 <System at /zport/dmd/Systems> 478 """ 479 dmd = self.getDmd() 480 return dmd._getOb(name)
481 482
483 - def getDmdObj(self, path):
484 """ 485 DEPRECATED Return an object from path that starts at dmd. 486 487 >>> dmd.getDmdObj('/Devices/Server') 488 <DeviceClass at /zport/dmd/Devices/Server> 489 """ 490 if path.startswith("/"): path = path[1:] 491 return self.getDmd().getObjByPath(path)
492 493
494 - def getZopeObj(self, path):
495 """ 496 DEPRECATED Return an object from path tat starts at zope root. 497 498 >>> dmd.getZopeObj('/zport/dmd/Devices/Server') 499 <DeviceClass at /zport/dmd/Devices/Server> 500 """ 501 return self.getObjByPath(path)
502 503
504 - def getNowString(self):
505 """ 506 Return the current time as a string in the format '2007/09/27 14:09:53'. 507 508 @rtype: string 509 """ 510 return time.strftime("%Y/%m/%d %H:%M:%S", time.localtime())
511 512
513 - def todayDate(self):
514 """ 515 Return today's date as a string in the format 'mm/dd/yyyy'. 516 517 @rtype: string 518 """ 519 return time.strftime("%m/%d/%Y", time.localtime())
520 521
522 - def yesterdayDate(self):
523 """ 524 Return yesterday's date as a string in the format 'mm/dd/yyyy'. 525 526 @rtype: string 527 """ 528 yesterday = time.time() - 24*3600 529 return time.strftime("%m/%d/%Y", time.localtime(yesterday))
530 531
532 - def all_meta_types(self, interfaces=None):
533 """ 534 DEPRECATED Override the ObjectManager method that is used to control 535 the items available in the add drop down in the ZMI. It uses the 536 attribute sub_menu_items to create the data structures. This is a list 537 of meta_types for the available classes. This functionality is rarely 538 used in Zenoss because the ZMI is not the perfered management 539 interface. 540 """ 541 mts = super(ZenModelBase,self).all_meta_types(interfaces) 542 if self.sub_meta_types: 543 mts = filter(lambda mt: mt['name'] in self.sub_meta_types, mts) 544 return mts
545 546 547 security.declareProtected('Delete objects', 'manage_deleteObjects')
548 - def manage_deleteObjects(self, ids=(), REQUEST=None):
549 """ 550 Delete objects by id from this object and return to the current 551 template as defined by callZenScreen. Uses ObjectManager._delObject to 552 remove the object. 553 554 @permission: ZEN_VIEW 555 """ 556 for id in ids: self._delObject(id) 557 if REQUEST: 558 return self.callZenScreen(REQUEST)
559 560
561 - def custPropertyIds(self):
562 """ 563 List custom properties that are defined at root node. Custom properties 564 start with a lower "c" followed by a uppercase character. 565 """ 566 return self.zenPropertyIds(pfilt=iscustprop)
567 568
569 - def custPropertyMap(self):
570 """ 571 Return custom property definitions. 572 573 @rtype: [{'id':'cName','label':'Name', 'type':'string'},] 574 """ 575 return self.zenPropertyMap(pfilt=iscustprop)
576 577
578 - def visibleCustPropertyMap(self):
579 """ 580 List custom property definitions that are visible using 581 custPropertyMap:: 582 583 @rtype: [{'id':'cName','label':'Name', 'type':'string'},] 584 """ 585 return [ p for p in self.zenPropertyMap(pfilt=iscustprop) \ 586 if p.get('visible', True) ]
587 588 589 security.declareProtected(ZEN_MANAGE_DMD, 'saveCustProperties')
590 - def saveCustProperties(self, REQUEST):
591 """ 592 Save custom properties from REQUEST.form. 593 594 @permission: ZEN_MANAGE_DMD 595 """ 596 return self.saveZenProperties(iscustprop, REQUEST)
597 598
599 - def getObjByPath(self, path):
600 """ 601 Lookup and object by its path. Basically does a Zope unrestricted 602 traverse on the path given. 603 604 @type path: list or string /zport/dmd/Devices 605 606 >>> dmd.getObjByPath(('zport','dmd','Devices')) 607 <DeviceClass at /zport/dmd/Devices> 608 >>> dmd.getObjByPath(('Devices','Server')) 609 <DeviceClass at /zport/dmd/Devices/Server> 610 >>> dmd.getObjByPath('/zport/dmd/Devices/Server') 611 <DeviceClass at /zport/dmd/Devices/Server> 612 >>> dmd.getObjByPath('Devices/Server') 613 <DeviceClass at /zport/dmd/Devices/Server> 614 """ 615 return getObjByPath(self, path)
616 617
618 - def isLocalName(self, name):
619 """ 620 Check to see if a name is local to our current context or if it comes 621 from our acquisition chain. 622 623 @rtype: boolean 624 625 >>> dmd.isLocalName('Devices') 626 True 627 >>> dmd.Devices.Server.isLocalName('Devices') 628 False 629 """ 630 v = getattr(aq_base(self), name, '__ZENMARKER__') 631 return v != '__ZENMARKER__'
632 633 security.declareProtected(ZEN_VIEW, 'helpLink') 662 663 664 security.declareProtected(ZEN_VIEW, 'getIconPath')
665 - def getIconPath(self):
666 """ 667 Return the icon associated with this object. The icon path is defined 668 in the zProperty zIcon. 669 670 @return: Path to icon 671 @rtype: string 672 @permission: ZEN_VIEW 673 674 >>> dmd.Devices.Server.zIcon = '/zport/dmd/img/icons/server.png' 675 >>> d = dmd.Devices.Server.createInstance('test') 676 >>> d.getIconPath() 677 '/zport/dmd/img/icons/server.png' 678 """ 679 try: 680 return self.primaryAq().zIcon 681 except AttributeError: 682 return '/zport/dmd/img/icons/noicon.png'
683 684
685 - def aqBaseHasAttr(self, attr):
686 """ 687 Return hasattr(aq_base(self), attr) 688 This is a convenience function for use in templates, where it's not 689 so easy to make a similar call directly. 690 hasattr itself will swallow exceptions, so we don't want to use that. 691 We also need to allow for values of None, so something like 692 getattr(aq_base(self, attr, None) doesn't really tell us anything. 693 Testing __dict__ is not a good choice because it doesn't allow 694 for properties (and I believe __getitem__ calls.) 695 So while this looks pretty attrocious, it might be the most sane 696 solution. 697 """ 698 return getattr(aq_base(self), attr, _MARKER) is not _MARKER
699 700
701 -class ZenModelZenDocProvider(object):
702 zope.interface.implements(IZenDocProvider) 703 zope.component.adapts(ZenModelBase) 704
705 - def __init__(self, zenModelBase):
706 self._underlyingObject = zenModelBase
707
708 - def getZendoc(self):
709 zendoc = self._underlyingObject._zendoc 710 if not zendoc and self._underlyingObject.aqBaseHasAttr( 'description' ): 711 zendoc = self._underlyingObject.description 712 return zendoc
713
714 - def setZendoc(self, zendocText):
715 self._underlyingObject._zendoc = zendocText
716
717 - def exportZendoc(self,ofile):
718 """Return an xml representation of a RelationshipManagers zendoc 719 <property id='_zendoc' type='string' mode='w'> 720 value 721 </property> 722 """ 723 value = self.getZendoc() 724 if not value: return 725 ofile.write("<property id='zendoc' type='string'>\n") 726 if type(value) not in types.StringTypes: 727 value = unicode(value) 728 elif type(value) == types.StringType: 729 value = value.decode('latin-1') 730 ofile.write(saxutils.escape(value).encode('utf-8')+"\n") 731 ofile.write("</property>\n")
732 733 734 InitializeClass(ZenModelBase) 735