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

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