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 copy
21 import re
22 import time
23
24 import sys
25 from urllib import unquote
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.CMFCore.utils import _verifyActionPermissions
33
34 from Products.ZenUtils.Utils import zenpathsplit, zenpathjoin
35 from Products.ZenUtils.Utils import createHierarchyObj, getHierarchyObj
36 from Products.ZenUtils.Utils import getObjByPath
37
38 from Products.ZenUtils.Utils import prepId as globalPrepId
39
40 from ZenossSecurity import *
41
42
43
44 iscustprop = re.compile("^c[A-Z]").search
45
47 """
48 All ZenModel Persistent classes inherit from this class. It provides some
49 screen management functionality, and general utility methods.
50 """
51 sub_meta_types = ()
52
53
54 security = ClassSecurityInfo()
55
57 """
58 Invokes the default view.
59 """
60 view = "view"
61 if hasattr(self, "factory_type_information"):
62 view = self.factory_type_information[0]['immediate_view']
63 else:
64 raise 'Not Found', ('Cannot find default view for "%s"' %
65 '/'.join(self.getPhysicalPath()))
66 return self.restrictedTraverse(view)()
67
68 index_html = None
69
70
71 security.declareProtected(ZEN_VIEW, 'view')
73 '''
74 Returns the default view even if index_html is overridden.
75
76 @permission: ZEN_VIEW
77 '''
78 return self()
79
80
83
84 - def prepId(self, id, subchar='_'):
85 """
86 Clean out an id of illegal characters.
87
88 @type id: string
89 @param subchar: Character to be substituted with illegal characters
90 @type subchar: string
91 @rtype: string
92
93 >>> dmd.Devices.prepId('ab^*cd')
94 'ab__cd'
95 >>> dmd.Devices.prepId('ab^*cd', subchar='Z')
96 'abZZcd'
97 >>> dmd.Devices.prepId('/boot')
98 'boot'
99 >>> dmd.Devices.prepId('/')
100 '-'
101 """
102 return globalPrepId(id, subchar)
103
105 """
106 Checks that an id is a valid Zope id. Looks for invalid characters and
107 checks that the id doesn't already exist in this context.
108
109 @type id: string
110 @type prep_id: boolean
111 @rtype: boolean
112
113 >>> dmd.Devices.checkValidId('^*')
114 'The id "^*" contains characters illegal in URLs.'
115 >>> dmd.Devices.checkValidId('Server')
116 'The id "Server" is invalid - it is already in use.'
117 >>> dmd.Devices.checkValidId('ZenTestId')
118 True
119 """
120 new_id = unquote(id)
121 if prep_id: new_id = self.prepId(id)
122 try:
123 globalCheckValidId(self, new_id)
124 return True
125 except:
126 return str(sys.exc_info()[1])
127
128
130 """
131 Return a new id that is not already in use in the relationship. If
132 baseKey is not already in use, return that. Otherwise append values
133 from extensionIter to baseKey until an used key is found. The default
134 extensionIter appends integers starting with 2 and counting up.
135
136 @type relName: string
137 @type baseKey: string
138 @type extensionIter: iterator
139 @rtype: string
140
141 >>> id1 = dmd.Devices.getUnusedId('devices', 'dev')
142 >>> id1
143 'dev'
144 >>> dmd.Devices.createInstance(id1)
145 <Device at /zport/dmd/Devices/devices/dev>
146 >>> id2 = dmd.Devices.getUnusedId('devices', 'dev')
147 >>> id2
148 'dev2'
149 """
150 import itertools
151 if extensionIter is None:
152 extensionIter = itertools.count(2)
153 rel = getattr(self, relName)
154 candidate = baseKey
155 while candidate in rel.objectIds():
156 candidate = self.prepId('%s%s' % (baseKey, extensionIter.next()))
157 return candidate
158
159
161 """
162 DEPRECATED Return an a link to this object with its id as the name.
163
164 @return: An HTML link to this object
165 @rtype: string
166
167 >>> dmd.Devices.getIdLink()
168 '<a href="/zport/dmd/Devices">/</a>'
169 """
170 return self.urlLink()
171
172
174 """
175 Call and return screen specified by zenScreenName value of REQUEST.
176 If zenScreenName is not present call the default screen. This is used
177 in functions that are called from forms to get back to the correct
178 screen with the correct context.
179 """
180 if REQUEST is None or getattr(REQUEST, 'dontRender', False):
181
182
183 return ''
184 screenName = REQUEST.get("zenScreenName", "")
185 if redirect:
186 nurl = "%s/%s" % (self.getPrimaryUrlPath(), screenName)
187 REQUEST['RESPONSE'].redirect(nurl)
188 else:
189 REQUEST['URL'] = "%s/%s" % (self.absolute_url_path(), screenName)
190 screen = getattr(self, screenName, False)
191 if not screen: return self()
192 return screen()
193
194
196 """
197 Return the url for the current screen as defined by zenScreenName.
198 If zenScreenName is not found in the request the request url is used.
199
200 @return: An url to this object
201 @rtype: string
202 """
203 screenName = self.REQUEST.get("zenScreenName", "")
204 if not screenName: return self.REQUEST.URL
205 return self.getPrimaryUrlPath() + "/" + screenName
206
207
209 """
210 Return an anchor tag if the user has access to the remote object.
211
212 @param text: the text to place within the anchor tag or string.
213 Defaults to the id of this object.
214 @param url: url for the href. Default is getPrimaryUrlPath
215 @type attrs: dict
216 @param attrs: any other attributes to be place in the in the tag.
217 @return: An HTML link to this object
218 @rtype: string
219 """
220 if not text:
221 text = self.id
222 if not self.checkRemotePerm("View", self):
223 return text
224 if not url:
225 url = self.getPrimaryUrlPath()
226 if len(attrs):
227 return '<a href="%s" %s>%s</a>' % (url,
228 ' '.join(['%s="%s"' % (x,y) for x,y in attrs.items()]),
229 text)
230 else:
231 return '<a href="%s">%s</a>' % (url, text)
232
233
235 """
236 Return the url to be used in breadcrumbs for this object. normally
237 this is equal to getPrimaryUrlPath. It can be used as a hook to modify
238 the url so that it points towards a different tab then the default.
239
240 @return: A url to this object
241 @rtype: string
242
243 >>> dmd.Devices.getBreadCrumbUrlPath()
244 '/zport/dmd/Devices'
245 >>> rc = dmd.Reports._getOb('Graph Reports')
246 >>> rc.manage_addGraphReport('test').getBreadCrumbUrlPath()
247 '/zport/dmd/Reports/Graph%20Reports/test/editGraphReport'
248 """
249 return self.getPrimaryUrlPath()
250
251
253 """
254 Return the data to create the breadcrumb links for this object.
255
256 This is a list of tuples where the first value is the URL of the bread
257 crumb and the second is the lable.
258
259 @return: List of tuples to create a bread crumbs
260 @rtype: list
261
262 >>> dmd.Devices.Server.breadCrumbs()
263 [('/zport/dmd/Devices', 'Devices'),
264 ('/zport/dmd/Devices/Server', 'Server')]
265 """
266 links = []
267 curDir = self.primaryAq()
268 while curDir.id != terminator:
269 if curDir.meta_type == 'ToManyContRelationship':
270 curDir = curDir.getPrimaryParent()
271 continue
272 if not getattr(aq_base(curDir),"getBreadCrumbUrlPath", False):
273 break
274 url = ""
275 if self.checkRemotePerm("View", curDir):
276 url = curDir.getBreadCrumbUrlPath()
277 links.append((url, curDir.id))
278 curDir = curDir.aq_parent
279 links.reverse()
280 return links
281
282
283 security.declareProtected(ZEN_VIEW, 'getZ')
284 - def getZ(self, zpropname):
285 """
286 Return the value of a zProperty on this object. This method is used to
287 lookup zProperties for a user with a role that doesn't have direct
288 access to an attribute further up the acquisition path.
289
290 @param zpropname: Name of zProperty
291 @type zpropname: string
292 @return: Value of zProperty
293 @permission: ZEN_VIEW
294
295 >>> dmd.Devices.getZ('zSnmpPort')
296 161
297 """
298 return getattr(self, zpropname)
299
300
301 security.declareProtected(ZEN_COMMON, 'checkRemotePerm')
303 """
304 Look to see if the current user has permission on remote object.
305
306 @param permission: Zope permission to be tested. ie "View"
307 @param robject: remote objecct on which test is run. Will test on
308 primary acquisition path.
309 @rtype: boolean
310 @permission: ZEN_COMMON
311 """
312 user = getSecurityManager().getUser()
313 return user.has_permission(permission, robject.primaryAq())
314
315
316
317 security.declareProtected(ZEN_VIEW, 'zentinelTabs')
319 """
320 Return a list of hashes that define the screen tabs for this object.
321
322 Keys in the hash are:
323 - action = the name of the page template for this tab
324 - name = the label used on the tab
325 - permissions = a tuple of permissions to view this template
326
327 @permission: ZEN_VIEW
328
329 >>> dmd.Devices.zentinelTabs('deviceOrganizerStatus')
330 [{'action': 'deviceOrganizerStatus', 'selected': True,
331 'name': 'Classes', 'permissions': ('View',)},
332 {'action': 'viewEvents', 'name': 'Events', 'permissions': ('View',)},
333 {'action': 'viewHistoryEvents', 'name': 'History',
334 'permissions': ('View',)},
335 {'action': 'zPropertyEdit', 'name': 'zProperties',
336 'permissions': ('View',)},
337 {'action': 'perfConfig', 'name': 'Templates',
338 'permissions': ('Manage DMD',)}]
339 """
340 tabs = []
341 user = getSecurityManager().getUser()
342 actions = self.factory_type_information[0]['actions']
343 for a in actions:
344 def permfilter(p): return user.has_permission(p,self)
345 permok = filter(permfilter, a['permissions'])
346 if not a.get('visible', True) or not permok:
347 continue
348 a = a.copy()
349 if a['action'] == templateName: a['selected'] = True
350 tabs.append(a)
351 return tabs
352
353
354 security.declareProtected(ZEN_MANAGE_DMD, 'zmanage_editProperties')
369
370
371 security.declareProtected(ZEN_VIEW, 'getPrimaryDmdId')
373 """
374 Return the full dmd id of this object for instance /Devices/Server.
375 Everything before dmd is removed. A different rootName can be passed
376 to stop at a different object in the path. If subrel is passed any
377 relationship name in the path to the object will be removed.
378
379 @param rootName: Name of root
380 @type rootName: string
381 @param subrel: Name of relation
382 @type subrel: string
383 @return: Path to object
384 @rtype: string
385 @permission: ZEN_VIEW
386
387 >>> d = dmd.Devices.Server.createInstance('test')
388 >>> d.getPrimaryDmdId()
389 '/Devices/Server/devices/test'
390 >>> d.getPrimaryDmdId('Devices')
391 '/Server/devices/test'
392 >>> d.getPrimaryDmdId('Devices','devices')
393 '/Server/test'
394 """
395 path = list(self.getPrimaryPath())
396 path = path[path.index(rootName)+1:]
397 if subrel: path = filter(lambda x: x != subrel, path)
398 return '/'+'/'.join(path)
399
400
402 """
403 DEPRECATED Build a Zenoss path based on a list or tuple.
404
405 @type path: list or tuple
406
407 >>> dmd.zenpathjoin(('zport', 'dmd', 'Devices', 'Server'))
408 '/zport/dmd/Devices/Server'
409 """
410 return zenpathjoin(path)
411
412
414 """
415 DEPRECATED Split a path on its '/'.
416 """
417 return zenpathsplit(path)
418
419
421 """
422 DEPRECATED this is only seems to be used in Organizer.createOrganizer -
423 Create an object from its path we use relpath to skip down any missing
424 relations in the path and factory is the constructor for this object.
425 """
426 return createHierarchyObj(root, name, factory, relpath, log)
427
428
430 """
431 DEPRECATED this doesn't seem to be used anywere don't use it!!!
432 """
433 return getHierarchyObj(root, name, relpath)
434
435
437 """
438 DEPRECATED Return the dmd root object with unwraped acquisition path.
439
440 >>> dmd.Devices.Server.getDmd()
441 <DataRoot at /zport/dmd>
442 """
443 for obj in aq_chain(self):
444 if obj.id == 'dmd': return obj
445
446
448 """
449 Return a dmd root organizer such as "Systems". The acquisition path
450 will be cleaned so that it points directly to the root.
451
452 >>> dmd.Devices.Server.getDmdRoot("Systems")
453 <System at /zport/dmd/Systems>
454 """
455 dmd = self.getDmd()
456 return dmd._getOb(name)
457
458
460 """
461 DEPRECATED Return an object from path that starts at dmd.
462
463 >>> dmd.getDmdObj('/Devices/Server')
464 <DeviceClass at /zport/dmd/Devices/Server>
465 """
466 if path.startswith("/"): path = path[1:]
467 return self.getDmd().getObjByPath(path)
468
469
471 """
472 DEPRECATED Return an object from path tat starts at zope root.
473
474 >>> dmd.getZopeObj('/zport/dmd/Devices/Server')
475 <DeviceClass at /zport/dmd/Devices/Server>
476 """
477 return self.getObjByPath(path)
478
479
481 """
482 Return the current time as a string in the format '2007/09/27 14:09:53'.
483
484 @rtype: string
485 """
486 return time.strftime("%Y/%m/%d %H:%M:%S", time.localtime())
487
488
490 """
491 Return today's date as a string in the format 'mm/dd/yyyy'.
492
493 @rtype: string
494 """
495 return time.strftime("%m/%d/%Y", time.localtime())
496
497
499 """
500 Return yesterday's date as a string in the format 'mm/dd/yyyy'.
501
502 @rtype: string
503 """
504 yesterday = time.time() - 24*3600
505 return time.strftime("%m/%d/%Y", time.localtime(yesterday))
506
507
521
522
523 security.declareProtected('Delete objects', 'manage_deleteObjects')
525 """
526 Delete objects by id from this object and return to the current
527 template as defined by callZenScreen. Uses ObjectManager._delObject to
528 remove the object.
529
530 @permission: ZEN_VIEW
531 """
532 for id in ids: self._delObject(id)
533 if REQUEST:
534 return self.callZenScreen(REQUEST)
535
536
538 """
539 List custom properties that are defined at root node. Custom properties
540 start with a lower "c" followed by a uppercase character.
541 """
542 return self.zenPropertyIds(pfilt=iscustprop)
543
544
546 """
547 Return custom property definitions.
548
549 @rtype: [{'id':'cName','label':'Name', 'type':'string'},]
550 """
551 return self.zenPropertyMap(pfilt=iscustprop)
552
553
555 """
556 List custom property definitions that are visible using
557 custPropertyMap::
558
559 @rtype: [{'id':'cName','label':'Name', 'type':'string'},]
560 """
561 return [ p for p in self.zenPropertyMap(pfilt=iscustprop) \
562 if p.get('visible', True) ]
563
564
565 security.declareProtected(ZEN_MANAGE_DMD, 'saveCustProperties')
573
574
576 """
577 Lookup and object by its path. Basically does a Zope unrestricted
578 traverse on the path given.
579
580 @type path: list or string /zport/dmd/Devices
581
582 >>> dmd.getObjByPath(('zport','dmd','Devices'))
583 <DeviceClass at /zport/dmd/Devices>
584 >>> dmd.getObjByPath(('Devices','Server'))
585 <DeviceClass at /zport/dmd/Devices/Server>
586 >>> dmd.getObjByPath('/zport/dmd/Devices/Server')
587 <DeviceClass at /zport/dmd/Devices/Server>
588 >>> dmd.getObjByPath('Devices/Server')
589 <DeviceClass at /zport/dmd/Devices/Server>
590 """
591 return getObjByPath(self, path)
592
593
595 """
596 Check to see if a name is local to our current context or if it comes
597 from our acquisition chain.
598
599 @rtype: boolean
600
601 >>> dmd.isLocalName('Devices')
602 True
603 >>> dmd.Devices.Server.isLocalName('Devices')
604 False
605 """
606 v = getattr(aq_base(self), name, '__ZENMARKER__')
607 return v != '__ZENMARKER__'
608
609 security.declareProtected(ZEN_VIEW, 'helpLink')
611 """
612 DEPRECATED Return a link to the objects help file.
613
614 @permission: ZEN_VIEW
615 """
616 path = self.__class__.__module__.split('.')
617 className = path[-1].replace('Class','')
618 product = path[-2]
619
620 path = ("", "Control_Panel", "Products", product, "Help",
621 "%s.stx"%className)
622
623
624 app = self.getPhysicalRoot()
625 try:
626 app.restrictedTraverse(path)
627 except (KeyError, Unauthorized):
628 return ""
629
630 url = "/HelpSys?help_url="+ "/".join(path)
631
632 return """<a class="tabletitle" href="%s" \
633 onClick="window.open('%s','zope_help','width=600,height=500, \
634 menubar=yes,toolbar=yes,scrollbars=yes,resizable=yes'); \
635 return false;" onMouseOver="window.status='Open online help'; \
636 return true;" onMouseOut="window.status=''; return true;">Help!</a>
637 """ % (url, url)
638
639
640 security.declareProtected(ZEN_VIEW, 'getIconPath')
642 """
643 Return the icon associated with this object. The icon path is defined
644 in the zPropoerty zIcon.
645
646 @return: Path to icon
647 @rtype: string
648 @permission: ZEN_VIEW
649
650 >>> d = dmd.Devices.Server.createInstance('test')
651 >>> d.getIconPath()
652 '/zport/dmd/img/icons/server.png'
653 """
654 return self.dmd.getIconPath(self)
655
656
657 InitializeClass(ZenModelBase)
658