1
2
3
4
5
6
7
8
9
10
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
43 iscustprop = re.compile("^c[A-Z]").search
44
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
52
53 security = ClassSecurityInfo()
54
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
68
69
70 security.declareProtected(ZEN_VIEW, 'view')
72 '''
73 Returns the default view even if index_html is overridden.
74
75 @permission: ZEN_VIEW
76 '''
77 return self()
78
79
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
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
162 """
163 DEPRECATED Return an a link to this object with its id as the name.
164
165 @return: An HTML link to this object
166 @rtype: string
167
168 >>> dmd.Devices.getIdLink()
169 '<a href="/zport/dmd/Devices">/</a>'
170 """
171 return self.urlLink()
172
173
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
183
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
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
209 - def urlLink(self, text=None, url=None, attrs={}):
210 """
211 Return an anchor tag if the user has access to the remote object.
212
213 @param text: the text to place within the anchor tag or string.
214 Defaults to the id of this object.
215 @param url: url for the href. Default is getPrimaryUrlPath
216 @type attrs: dict
217 @param attrs: any other attributes to be place in the in the tag.
218 @return: An HTML link to this object
219 @rtype: string
220 """
221 if not text:
222 text = self.id
223 text = escape(text)
224 if not self.checkRemotePerm("View", self):
225 return text
226 if not url:
227 url = self.getPrimaryUrlPath()
228 if len(attrs):
229 return '<a href="%s" %s>%s</a>' % (url,
230 ' '.join(['%s="%s"' % (x,y) for x,y in attrs.items()]),
231 text)
232 else:
233 return '<a href="%s">%s</a>' % (url, text)
234
235
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
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')
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')
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')
375
376
377 security.declareProtected(ZEN_VIEW, 'getPrimaryDmdId')
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
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
420 """
421 DEPRECATED Split a path on its '/'.
422 """
423 return zenpathsplit(path)
424
425
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
436 """
437 DEPRECATED this doesn't seem to be used anywere don't use it!!!
438 """
439 return getHierarchyObj(root, name, relpath)
440
441
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
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
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
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
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
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
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
527
528
529 security.declareProtected('Delete objects', 'manage_deleteObjects')
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
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
552 """
553 Return custom property definitions.
554
555 @rtype: [{'id':'cName','label':'Name', 'type':'string'},]
556 """
557 return self.zenPropertyMap(pfilt=iscustprop)
558
559
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')
579
580
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
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')
617 """
618 DEPRECATED Return a link to the objects help file.
619
620 @permission: ZEN_VIEW
621 """
622 path = self.__class__.__module__.split('.')
623 className = path[-1].replace('Class','')
624 product = path[-2]
625
626 path = ("", "Control_Panel", "Products", product, "Help",
627 "%s.stx"%className)
628
629
630 app = self.getPhysicalRoot()
631 try:
632 app.restrictedTraverse(path)
633 except (KeyError, Unauthorized):
634 return ""
635
636 url = "/HelpSys?help_url="+ "/".join(path)
637
638 return """<a class="tabletitle" href="%s" \
639 onClick="window.open('%s','zope_help','width=600,height=500, \
640 menubar=yes,toolbar=yes,scrollbars=yes,resizable=yes'); \
641 return false;" onMouseOver="window.status='Open online help'; \
642 return true;" onMouseOut="window.status=''; return true;">Help!</a>
643 """ % (url, url)
644
645
646 security.declareProtected(ZEN_VIEW, 'getIconPath')
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
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