source: ZMS/trunk/ZMSGlobals.py @ 1878

Revision 1878, 50.0 KB checked in by fhoffmann, 6 days ago (diff)

Applied fix for timezone handling (contributed by W. Huber, Uni Linz)

Line 
1################################################################################
2# ZMSGlobals.py
3#
4# This program is free software; you can redistribute it and/or
5# modify it under the terms of the GNU General Public License
6# as published by the Free Software Foundation; either version 2
7# of the License, or (at your option) any later version.
8#
9# This program is distributed in the hope that it will be useful,
10# but WITHOUT ANY WARRANTY; without even the implied warranty of
11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12# GNU General Public License for more details.
13#
14# You should have received a copy of the GNU General Public License
15# along with this program; if not, write to the Free Software
16# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17################################################################################
18
19# Imports.
20from AccessControl import AuthEncoding
21from AccessControl import ClassSecurityInfo
22from App.Common import package_home
23from App.special_dtml import HTMLFile
24from DateTime.DateTime import DateTime
25from cStringIO import StringIO
26from types import StringTypes
27from binascii import b2a_base64, a2b_base64
28import Globals
29import base64
30import copy
31import fnmatch
32import operator
33import os
34import re
35import tempfile
36import time
37import urllib
38import zExceptions
39import zope.interface
40# Product Imports.
41import _blobfields
42import _fileutil
43import _filtermanager
44import _globals
45import _mimetypes
46import _pilutil
47import _xmllib
48
49__all__= ['ZMSGlobals']
50
51# ------------------------------------------------------------------------------
52#  MD5:
53# ------------------------------------------------------------------------------
54try: # Python >= 2.5
55  import hashlib
56
57  class MD5DigestScheme:
58
59    def encrypt(self, pw):
60      enc = hashlib.md5(pw)
61      enc = enc.hexdigest()
62      return enc
63
64    def validate(self, reference, attempt):
65      compare = self.encrypt(attempt)[:-1]
66      return (compare == reference)
67
68except: # Python < 2.5
69  import md5
70
71  class MD5DigestScheme:
72
73    def encrypt(self, pw):
74      enc = md5.new(pw)
75      enc = enc.hexdigest()
76      return enc
77
78    def validate(self, reference, attempt):
79      compare = self.encrypt(attempt)[:-1]
80      return (compare == reference)
81
82AuthEncoding.registerScheme('MD5', MD5DigestScheme())
83
84
85# ------------------------------------------------------------------------------
86#  sort_item:
87# ------------------------------------------------------------------------------
88def sort_item( i):
89  if type( i) is str:
90    i = unicode(i,'utf-8')
91    mapping = _globals.umlautMapping
92    for key in mapping.keys():
93      try: i = i.replace(key,mapping[key])
94      except: pass
95  return i
96
97
98################################################################################
99################################################################################
100###
101###   class ZMSGlobals:
102###
103################################################################################
104################################################################################
105class ZMSGlobals:
106    """
107    @group PIL (Python Imaging Library): pil_img_*
108    @group Local File-System: localfs_*
109    @group Logging: writeBlock, writeLog
110    @group Mappings: *_list
111    @group Operators: operator_*
112    @group Styles / CSS: parse_stylesheet, get_colormap
113    @group Regular Expressions: re_*
114    @group: XML: getXmlHeader, toXmlString, parseXmlString, xslProcess, processData, xmlParse, xmlNodeSet
115    """
116
117    # Create a SecurityInfo for this class. We will use this
118    # in the rest of our class definition to make security
119    # assertions.
120    security = ClassSecurityInfo()
121
122
123    # --------------------------------------------------------------------------
124    #  Meta-Type Selectors.
125    # --------------------------------------------------------------------------
126    PAGES = 0         #: virtual meta_type for all Pages (Containers)
127    PAGEELEMENTS = 1  #: virtual meta_type for all Page-Elements
128    NOREF = 4         #: virtual meta_type-flag for resolving meta-type of ZMSLinkElement-target-object.
129    NORESOLVEREF = 5  #: virtual meta_type-flag for not resolving meta-type of ZMSLinkElement-target-object.
130
131
132    # --------------------------------------------------------------------------
133    #  ZMSGlobals.getPRODUCT_HOME:
134    # --------------------------------------------------------------------------
135    def getPRODUCT_HOME( self):
136      PRODUCT_HOME = os.path.dirname(os.path.abspath(__file__))
137      return PRODUCT_HOME
138
139
140    # --------------------------------------------------------------------------
141    #  ZMSGlobals.createBlobInContext:
142    # --------------------------------------------------------------------------
143    def createBlobInContext( self, id, blob, container):
144      """
145      Creates a new Zope native-representative (Image/File) of given blob in container.
146      """
147      filename = blob.getFilename()
148      data = blob.getData()
149      if blob.getContentType().startswith('image'):
150        container.manage_addImage( id=id, title=filename, file=data)
151      else:
152        container.manage_addImage( id=id, title=filename, file=data)
153      ob = getattr(container,id)
154      return ob
155
156
157    # --------------------------------------------------------------------------
158    #  ZMSGlobals.FileFromData:
159    # --------------------------------------------------------------------------
160    def FileFromData( self, data, filename='', content_type=None):
161      """
162      Creates a new instance of a file from given data.
163      @param data: File-data (binary)
164      @type data: C{string}
165      @param filename: Filename
166      @type filename: C{string}
167      @return: New instance of file.
168      @rtype: L{MyFile}
169      """
170      file = {}
171      file['data'] = data
172      file['filename'] = filename
173      if content_type: file['content_type'] = content_type
174      return _blobfields.createBlobField( self, _globals.DT_FILE, file=file, mediadbStorable=False)
175
176
177    # --------------------------------------------------------------------------
178    #  ZMSGlobals.ImageFromData:
179    # --------------------------------------------------------------------------
180    def ImageFromData( self, data, filename='', content_type=None):
181      """
182      Creates a new instance of an image from given data.
183      @param data: Image-data (binary)
184      @type data: C{string}
185      @param filename: Filename
186      @type filename: C{string}
187      @return: New instance of image.
188      @rtype: L{MyImage}
189      """
190      f = _blobfields.createBlobField( self, _globals.DT_IMAGE, file={'data':data,'filename':filename,'content_type':content_type}, mediadbStorable=False)
191      f.aq_parent = self
192      return f
193
194
195    # --------------------------------------------------------------------------
196    #  ZMSGlobals.nvl:
197    # --------------------------------------------------------------------------
198    def inline_if(self, cond, v1, v2):
199      """
200      Inline conditional:
201      - Java: cond?v1:v2
202      - Python >2.5: v1 if cond else v2
203     
204      @param v1: 1st argument
205      @type v1: C{any}
206      @param v2: 2nd argument
207      @type v2: C{any}
208      @rtype: C{any}
209      """
210      if cond:
211          return v1
212      else:
213          return v2
214
215    # --------------------------------------------------------------------------
216    #  ZMSGlobals.nvl:
217    # --------------------------------------------------------------------------
218    def nvl(self, a1, a2, n=None):
219      """
220      Returns its first argument if it is not equal to third argument (None),
221      otherwise it returns its second argument.
222      @param a1: 1st argument
223      @type a1: C{any}
224      @param a2: 2nd argument
225      @type a2: C{any}
226      @rtype: C{any}
227      """
228      return _globals.nvl( a1, a2, n)
229
230
231    """
232    Returns int (0/1) for Boolean Type new in Python 2.3.
233    @param v: Value
234    @type v: C{bool}
235    @return: New instance of file.
236    @rtype: C{int}
237    @deprecated: use int instead!
238    """
239    def boolint(self, v):
240      return int(v)
241
242    """
243    Execute given DTML-snippet.
244    @param value: DTML-snippet
245    @type value: C{string}
246    @param REQUEST: the triggering request
247    @type REQUEST: C{ZPublisher.HTTPRequest}
248    @return: Result of the execution or None
249    @rtype: C{any}
250    """
251    def dt_html(self, value, REQUEST):
252      return _globals.dt_html(self,value,REQUEST)
253
254
255    """
256    Available encryption-schemes.
257    @return: list of encryption-scheme ids
258    @rtype: C{list}
259    """
260    def encrypt_schemes(self):
261      ids = []
262      for id, prefix, scheme in AuthEncoding._schemes:
263        ids.append( id)
264      return ids
265
266
267    """
268    Encrypts given password.
269    @param pw: Password
270    @type pw: C{string}
271    @param algorithm: Encryption-algorithm (md5, sha-1, etc.)
272    @type algorithm: C{string}
273    @param hex: Hexlify
274    @type hex: C{bool}
275    @return: Encrypted password
276    @rtype: C{string}
277    """
278    def encrypt_password(self, pw, algorithm='md5', hex=False):
279      enc = None
280      if algorithm.upper() == 'SHA-1':
281        import sha
282        enc = sha.new(pw)
283        if hex:
284          enc = enc.hexdigest()
285        else:
286          enc = enc.digest()
287      else:
288        for id, prefix, scheme in AuthEncoding._schemes:
289          if algorithm.upper() == id:
290            enc = scheme.encrypt(pw)
291      return enc
292
293
294    """
295    Encrypts given string with entities by random algorithm.
296    @param s: String
297    @type s: C{string}
298    @return: Encrypted string
299    @rtype: C{string}
300    """
301    def encrypt_ordtype(self, s):
302      from binascii import hexlify
303      new = ''
304      for ch in s:
305        whichCode=self.rand_int(2)
306        if whichCode==0:
307          new += ch
308        elif whichCode==1:
309          new += '&#%d;'%ord(ch)
310        else:
311          new += '&#x%s;'%str(hexlify(ch))
312      return new
313
314
315    """
316    Random integer in given range.
317    @param n: Range
318    @type n: C{int}
319    @return: Random integer
320    @rtype: C{int}
321    """
322    def rand_int(self, n):
323      from random import randint
324      return randint(0,n)
325
326
327    """
328    Renders diff of two values in HTML.
329    @param v1: Value #1
330    @type v1: C{any}
331    @param v2: Value #2
332    @type v2: C{any}
333    @param datatype: Datatype
334    @type datatype: C{string}
335    @return: Diff rendered in HTML.
336    @rtype: C{string}
337    """
338    def get_diff(self, v1, v2, datatype='string'):
339      diff = ''
340      if v1 == v2:
341        return diff
342      #-- Lists
343      if (type( v1) is list and type( v2) is list) or datatype in [ 'list']:
344        for c in range( min( len( v1), len( v2))):
345          if v1[c] != v2[c]:
346            d1 = self.get_diff(v1[c],v2[c])
347            if d1:
348              if len( diff) == 0:
349                diff += '<table border="0" cellspacing="0" cellpadding="0">'
350              diff += '<tr valign="top">'
351              diff += '<td class="form-small">[%i]</td>'%(c+1)
352              diff += '<td class="form-small">'+d1+'</td>'
353              diff += '</tr>'
354        if len( diff) > 0:
355          diff += '</table>'
356      #-- Dictionaries
357      elif (type( v1) is dict and type( v2) is dict) or datatype in [ 'dictionary']:
358        for k1 in v1.keys():
359          if k1 in v2.keys():
360            d1 = self.get_diff(v1[k1],v2[k1])
361            if d1:
362              if len( diff) == 0:
363                diff += '<table border="0" cellspacing="0" cellpadding="0">'
364              diff += '<tr valign="top">'
365              diff += '<td class="form-small">%s=</td>'%k1
366              diff += '<td class="form-small">'+d1+'</td>'
367              diff += '</tr>'
368        if len( diff) > 0:
369          diff += '</table>'
370      #-- Strings
371      elif datatype in [ 'string', 'text']:
372        # Untag strings.
373        v1 = self.search_quote( v1, len( v1))
374        v2 = self.search_quote( v2, len( v2))
375        i = 0
376        while i < min(len(v1),len(v2)) and v1[i]==v2[i]:
377          i += 1
378        if v1[:i].rfind('<') >= 0 and v1[:i].rfind('<') > v1[:i].rfind('>') and \
379           v1[i:].find('>') >= 0 and v1[i:].find('>') < v1[i:].find('<'):
380          i = v1[:i].rfind('<')
381        j = 0
382        while j < min(len(v1),len(v2))-i and v1[len(v1)-j-1]==v2[len(v2)-j-1]:
383          j += 1
384        if v1[i:len(v1)-j].find('<') >= 0 and v1[len(v1)-j:].find('<') > v1[len(v1)-j:].find('>') and \
385           v2[i:-j].find('<') >= 0 and v2[-j:].find('<') > v2[-j:].find('>'):
386          j -= (v2[-j:].find('>') + 1)
387        if j == 0:
388          red = v2[i:]
389        else:
390          red = v2[i:-j]
391        diff = v1[:i] + '<ins class="diff">' + v1[i:len(v1)-j] + '</ins><del class="diff">' + red + '</del>' + v1[len(v1)-j:]
392      #-- Date/Time
393      elif datatype in [ 'date', 'datetime', 'time']:
394        v1 = self.getLangFmtDate( v1, 'eng', '%s_FMT'%datatype.upper())
395        v2 = self.getLangFmtDate( v1, 'eng', '%s_FMT'%datatype.upper())
396        diff = '<ins class="diff">' + v1 + '</ins><del class="diff">' + v2 + '</del>'
397      #-- Numbers
398      elif datatype in [ 'amount', 'float', 'int']:
399        v1 = str( v1)
400        v2 = str( v2)
401        diff = '<ins class="diff">' + v1 + '</ins><del class="diff">' + v2 + '</del>'
402      return diff
403
404
405    """
406    Returns string with specified maximum-length. If original string exceeds
407    maximum-length '...' is appended at the end.
408    @param s: String
409    @type s: C{string}
410    @param maxlen: Maximum-length
411    @type maxlen: C{int}
412    @param etc: Characters to be appended if maximum-length is exceeded
413    @type etc: C{string}
414    @param encoding: Encoding
415    @type encoding: C{string}
416    @rtype: C{string}
417    """
418    def string_maxlen(self, s, maxlen=20, etc='...', encoding=None):
419      if encoding is not None:
420        s = unicode( s, encoding)
421      # remove all tags.
422      s = re.sub( '<script((.|\n|\r|\t)*?)>((.|\n|\r|\t)*?)</script>', '', s)
423      s = re.sub( '<style((.|\n|\r|\t)*?)>((.|\n|\r|\t)*?)</style>', '', s)
424      s = re.sub( '<((.|\n|\r|\t)*?)>', '', s)
425      if len(s) > maxlen:
426        if s[:maxlen].rfind('&') >= 0 and not s[:maxlen].rfind('&') < s[:maxlen].rfind(';') and \
427           s[maxlen:].find(';') >= 0 and not s[maxlen:].find(';') > s[maxlen:].find('&'):
428          maxlen = maxlen + s[maxlen:].find(';')
429        if s[:maxlen].endswith(chr(195)) and maxlen < len(s):
430          maxlen += 1
431        s = s[:maxlen] + etc
432      return s
433
434
435    """
436    Replace special characters in string using the %xx escape. Letters, digits,
437    and the characters '_.-' are never quoted. By default, this function is
438    intended for quoting the path section of the URL. The optional safe
439    parameter specifies additional characters that should not be quoted,
440    its default value is '/'.
441    """
442    def url_quote(self, string, safe='/'):
443      return urllib.quote(string,safe)
444
445
446    """
447    Send Http-Request and return Response-Body.
448    @param url: Remote-URL
449    @type url: C{string}
450    @param method: Method
451    @type method: C{string}, values are GET or POST
452    @param auth: Authentication
453    @type auth: C{string}
454    @param parse_qs: Parse Query-String
455    @type parse_qs: C{int}, values are 0 or 1
456    @return: Response-Body
457    @rtype: C{string}
458    """
459    def http_import(self, url, method='GET', auth=None, parse_qs=0):
460      return _globals.http_import( self, url, method, auth, parse_qs)
461
462
463    """
464    Append params from dict to given url.
465    @param url: Url
466    @type url: C{string}
467    @param dict: dictionary of params (key/value pairs)
468    @type dict: C{dict}
469    @return: New url
470    @rtype: C{string}
471    """
472    def url_append_params(self, url, dict, sep='&amp;'):
473      anchor = ''
474      i = url.rfind('#')
475      if i > 0:
476        anchor = url[i:]
477        url = url[:i]
478      if url.find( 'http://') < 0 and url.find( '../') < 0:
479        try:
480          if self.REQUEST.get('ZMS_REDIRECT_PARENT'):
481            url = '../' + url
482        except:
483          pass
484      targetdef = ''
485      i = url.find('#')
486      if i >= 0:
487        targetdef = url[i:]
488        url = url[:i]
489      qs = '?'
490      i = url.find(qs)
491      if i >= 0:
492        qs = sep
493      for key in dict.keys():
494        value = dict[key]
495        if type(value) is list:
496          for item in value:
497            qi = key + ':list=' + urllib.quote(str(item))
498            url += qs + qi
499            qs = sep
500        else:
501          qi = key + '=' + urllib.quote(str(value))
502          if url.find( '?' + qi) < 0 and url.find( '&' + qi) < 0 and url.find( '&amp;' + qi) < 0:
503            url += qs + qi
504          qs = sep
505      url += targetdef
506      return url+anchor
507
508
509    # --------------------------------------------------------------------------
510    #  ZMSGlobals.url_inherit_params:
511    # --------------------------------------------------------------------------
512    def url_inherit_params(self, url, REQUEST, exclude=[], sep='&amp;'):
513      anchor = ''
514      i = url.rfind('#')
515      if i > 0:
516        anchor = url[i:]
517        url = url[:i]
518      if REQUEST.form:
519        for key in REQUEST.form.keys():
520          if not key in exclude:
521            v = REQUEST.form.get( key, None )
522            if key is not None:
523              if url.find('?') < 0:
524                url += '?'
525              else:
526                url += sep
527              if type(v) is int:
528                url += urllib.quote(key+':int') + '=' + urllib.quote(str(v))
529              elif type(v) is float:
530                url += urllib.quote(key+':float') + '=' + urllib.quote(str(v))
531              elif type(v) is list:
532                c = 0
533                for i in v:
534                  if c > 0:
535                    url += sep
536                  url += urllib.quote(key+':list') + '=' + urllib.quote(str(i))
537                  c = c + 1
538              else:
539                url += key + '=' + urllib.quote(str(v))
540      return url+anchor
541
542
543    """
544    Converts given string to identifier (removes special-characters and
545    replaces German umlauts).
546    @param s: String
547    @type s: C{string}
548    @return: Identifier
549    @rtype: C{string}
550    """
551    def id_quote(self, s):
552      return _globals.id_quote(s)
553
554
555    """
556    Returns prefix from identifier (which is the non-numeric part at the
557    beginning).
558    @param s: Identifier
559    @type s: C{string}
560    @return: Prefix
561    @rtype: C{string}
562    """
563    def get_id_prefix(self, s):
564      return _globals.id_prefix(s)
565
566
567    """
568    Replace special characters in string for javascript.
569    """
570    def js_quote(self, text, charset=None):
571      if type(text) is unicode:
572        text= text.encode([charset, 'utf-8'][charset==None])
573      text = text.replace("\r", "\\r").replace("\n", "\\n")
574      text = text.replace('"', '\\"').replace("'", "\\'")
575      return text
576
577
578    """
579    @rtype: C{Boolean}
580    """
581    def isPreviewRequest(self, REQUEST):
582      return _globals.isPreviewRequest(REQUEST)
583
584
585    """
586    Returns display string for file-size (KB).
587    @param len: length (bytes)
588    @type len: C{int}
589    @rtype: C{string}
590    """
591    def getDataSizeStr(self, len):
592      return _fileutil.getDataSizeStr(len)
593
594
595    """
596    Returns the absolute-url of an icon representing the specified MIME-type.
597    @param mt: MIME-Type (e.g. image/gif, text/xml).
598    @type mt: C{string}
599    @rtype: C{string}
600    """
601    def getMimeTypeIconSrc(self, mt):
602      return self.MISC_ZMS + _mimetypes.dctMimeType.get( mt, _mimetypes.content_unknown)
603
604
605    ############################################################################
606    #
607    #( Operators
608    #
609    ############################################################################
610
611    """
612    Returns python-type of given value.
613    @param v: Value
614    @type v: C{any}
615    @rtype: C{type}
616    """
617    def operator_gettype(self, v):
618      return type(v)
619
620    """
621    Applies value for key in python-dictionary.
622    This is a convenience-function since it is not possible to use expressions
623    like a[b]=c in DTML.
624    @param a: Dictionary
625    @type a: C{dict}
626    @param b: Key
627    @type b: C{any}
628    @param c: Value
629    @type c: C{any}
630    @rtype: C{dict}
631    """
632    def operator_setitem(self, a, b, c):
633      operator.setitem(a,b,c)
634      return a
635
636    """
637    Retrieves value for key from python-dictionary.
638    @param a: Dictionary
639    @type a: C{dict}
640    @param b: Key
641    @type b: C{any}
642    @rtype: C{any}
643    """
644    def operator_getitem(self, a, b):
645      return operator.getitem(a,b)
646
647    """
648    Delete key from python-dictionary.
649    @param a: Dictionary
650    @type a: C{dict}
651    @param b: Key
652    @type b: C{any}
653    """
654    def operator_delitem(self, a, b):
655      operator.delitem(a, b)
656
657    """
658    Applies value for key to python-object.
659    This is a convenience-function since the use expressions like
660    setattr(a,b,c) is restricted in DTML.
661    @param a: Object
662    @type a: C{any}
663    @param b: Key
664    @type b: C{string}
665    @param c: Value
666    @type c: C{any}
667    @rtype: C{object}
668    """
669    def operator_setattr(self, a, b, c):
670      setattr(a,b,c)
671      return a
672
673    """
674    Retrieves value for key from python-object.
675    This is a convenience-function since the use expressions like
676    getattr(a,b,c) is restricted in DTML.
677    @param a: Object
678    @type a: C{any}
679    @param b: Key
680    @type b: C{any}
681    @param c: Default-Value
682    @type c: C{any}
683    @rtype: C{any}
684    """
685    def operator_getattr(self, a, b, c=None):
686      return getattr(a,b,c)
687
688    """
689    Delete key from python-object.
690    @param a: Object
691    @type a: C{any}
692    @param b: Key
693    @type b: C{any}
694    """
695    def operator_delattr(self, a, b):
696      return delattr(a,b)
697
698    #)
699
700
701    ############################################################################
702    #
703    #( Logging
704    #
705    ############################################################################
706
707    """
708    Write to standard-out (only allowed for development-purposes!).
709    @param info: Object
710    @type info: C{any}
711    """
712    def writeStdout(self, info):
713      print info
714
715
716    """
717    Log debug-information.
718    @param info: Debug-information
719    @type info: C{any}
720    """
721    def writeLog(self, info):
722      _globals.writeLog( self, info)
723
724    """
725    Log information.
726    @param info: Information
727    @type info: C{any}
728    """
729    def writeBlock(self, info):
730      _globals.writeBlock( self, info)
731
732    #)
733
734
735    ############################################################################
736    #
737    #( Regular Expressions
738    #
739    ############################################################################
740
741    """
742    Performs a search-and-replace across subject, replacing all matches of
743    regex in subject with replacement. The result is returned by the sub()
744    function. The subject string you pass is not modified.
745    @rtype: C{string}
746    """
747    def re_sub( self, pattern, replacement, subject, ignorecase=False):
748      if ignorecase:
749        return re.compile( pattern, re.IGNORECASE).sub( replacement, subject)
750      else:
751        return re.compile( pattern).sub( replacement, subject)
752
753
754    """
755    Scan through string looking for a location where the regular expression
756    pattern produces a match, and return a corresponding MatchObject
757    instance. Return None if no position in the string matches the pattern;
758    note that this is different from finding a zero-length match at some
759    point in the string.
760    """
761    def re_search( self, pattern, subject, ignorecase=False):
762      if ignorecase:
763        s = re.compile( pattern, re.IGNORECASE).split( subject)
764      else:
765        s = re.compile( pattern).split( subject)
766      return map( lambda x: s[x*2+1], range(len(s)/2))
767
768    #)
769
770
771    ############################################################################
772    #
773    #( Styles / CSS
774    #
775    ############################################################################
776
777    """
778    Parses default-stylesheet and returns elements.
779    @return: Elements
780    @rtype: C{dict}
781    """
782    def parse_stylesheet(self):
783      REQUEST = self.REQUEST
784     
785      #-- [ReqBuff]: Fetch buffered value from Http-Request.
786      reqBuffId = 'parse_stylesheet'
787      try:
788        value = self.fetchReqBuff( reqBuffId, REQUEST)
789        return value
790      except:
791       
792        stylesheet = self.getStylesheet()
793        if stylesheet.meta_type in ['DTML Document','DTML Method']:
794          data = stylesheet.raw
795        elif stylesheet.meta_type in ['File']:
796          data = stylesheet.data
797        data = re.sub( '/\*(.*?)\*/', '', data)
798        value = {}
799        for elmnt in data.split('}'):
800          i = elmnt.find('{')
801          keys = elmnt[:i].strip()
802          v = elmnt[i+1:].strip()
803          for key in keys.split(','):
804            key = key.strip()
805            if len(key) > 0:
806              value[key] = value.get(key,'') + v
807       
808        #-- [ReqBuff]: Returns value and stores it in buffer of Http-Request.
809        return self.storeReqBuff( reqBuffId, value, REQUEST)
810
811
812    """
813    Parses default-stylesheet and returns color-map.
814    @return: Color-map
815    @rtype: C{dict}
816    """
817    def get_colormap(self):
818      REQUEST = self.REQUEST
819     
820      #-- [ReqBuff]: Fetch buffered value from Http-Request.
821      reqBuffId = 'get_colormap'
822      try:
823        forced = True
824        value = self.fetchReqBuff( reqBuffId, REQUEST, forced)
825        return value
826      except:
827        stylesheet = self.parse_stylesheet()
828        value = {}
829        for key in stylesheet.keys():
830          if key.find('.') == 0 and \
831             key.find('Color') > 0 and \
832             key.find('.cms') < 0 and \
833             key.find('.zmi') < 0:
834            for elmnt in stylesheet[key].split(';'):
835              i = elmnt.find(':')
836              if i > 0:
837                elmntKey = elmnt[:i].strip().lower()
838                elmntValue = elmnt[i+1:].strip().lower()
839                if elmntKey == 'color' or elmntKey == 'background-color':
840                  value[key[1:]] = elmntValue
841       
842        #-- [ReqBuff]: Returns value and stores it in buffer of Http-Request.
843        return self.storeReqBuff( reqBuffId, value, REQUEST)
844
845    #)
846
847
848    ############################################################################
849    #
850    #( Mappings
851    #
852    ############################################################################
853
854    """
855    Intersection of two lists (li & l2).
856    @param l1: List #1
857    @type l1: C{list}
858    @param l2: List #2
859    @type l2: C{list}
860    @returns: Intersection list
861    @rtype: C{list}
862    """
863    def intersection_list(self, l1, l2):
864      l1 = list(l1)
865      l2 = list(l2)
866      return filter(lambda x: x in l2, l1)
867
868
869    """
870    Difference of two lists (l1 - l2).
871    @param l1: List #1
872    @type l1: C{list}
873    @param l2: List #2
874    @type l2: C{list}
875    @returns: Difference list
876    @rtype: C{list}
877    """
878    def difference_list(self, l1, l2):
879      l1 = list(l1)
880      l2 = list(l2)
881      return filter(lambda x: x not in l2, l1)
882
883
884    """
885    Concatinates two lists (l1 + l2).
886    @param l1: List #1
887    @type l1: list
888    @param l2: List #2
889    @type l2: list
890    @returns: Concatinated list
891    @rtype: C{list}
892    """
893    def concat_list(self, l1, l2):
894      l1 = list(l1)
895      l2 = list(l2)
896      l = self.copy_list(l1)
897      l.extend(filter(lambda x: x not in l1, l2))
898      return l
899
900
901    """
902    Converts list to dictionary: key=l[x*2], value=l[x*2+1]
903    @param l: List
904    @type l: C{list}
905    @return: Dictionary
906    @rtype: C{dict}
907    """
908    def dict_list(self, l):
909      dict = {}
910      for i in range(0,len(l)/2):
911        key = l[i*2]
912        value = l[i*2+1]
913        dict[key] = value
914      return dict
915
916
917    """
918    Returns distinct values of given field from list.
919    @param l: List
920    @type l: C{list}
921    @rtype: C{list}
922    """
923    def distinct_list(self, l, i):
924      k = []
925      for x in l:
926        if type(i) is str:
927          v = x.get(i,None)
928        else:
929          v = x[i]
930        if not v in k:
931          k.append(v)
932      return k
933
934
935    """
936    Sorts list by given field.
937    @return: Sorted list.
938    @rtype: C{list}
939    """
940    def sort_list(self, l, qorder, qorderdir='asc', ignorecase=1):
941      if type(qorder) is str:
942        sorted = map(lambda x: (sort_item(x.get(qorder,None)),x),l)
943      elif type(qorder) is list:
944        sorted = map(lambda x: (','.join(map(lambda y: sort_item(x[y]), qorder)),x),l)
945      else:
946        sorted = map(lambda x: (sort_item(x[qorder]),x),l)
947      if ignorecase==1 and len(sorted) > 0 and type(sorted[0][0]) is str:
948        sorted = map(lambda x: (str(x[0]).upper(),x[1]),sorted)
949      sorted.sort()
950      sorted = map(lambda x: x[1],sorted)
951      if qorderdir == 'desc': sorted.reverse()
952      return sorted
953
954
955    """
956    @rtype: C{list}
957    """
958    def string_list(self, s, sep='\n'):
959      l = []
960      for i in s.split(sep):
961        i = i.strip()
962        while len(i) > 0 and ord(i[-1]) < 32:
963          i = i[:-1]
964        if len(i) > 0:
965          l.append(i)
966      return l
967
968
969    """
970    Returns parents for linked list.
971    """
972    def tree_parents(self, l, i='id', r='idId', v='', deep=1, reverse=1):
973      k = []
974      for x in l:
975        if x.get(i)==v:
976          k.append(x)
977          if deep:
978            k.extend(self.tree_parents(l,i,r,x[r],deep,0))
979      if reverse:
980        k.reverse()
981      return k
982
983
984    """
985    Returns children for linked list.
986    """
987    def tree_list(self, l, i='id', r='idId', v='', deep=0):
988      k = []
989      for x in l:
990        if x.get(r)==v:
991          k.append(x)
992          if deep:
993            k.extend(self.tree_list(l,i,r,x[i],deep))
994      return k
995
996
997    """
998    Returns a json-string representation of the object.
999    """
1000    def str_json(self, i):
1001      if type(i) is list or type(i) is tuple:
1002        return '['+','.join(map(lambda x: self.str_json(x),i))+']'
1003      elif type(i) is dict:
1004        return '{'+','.join(map(lambda x: '\'%s\':%s'%(x,self.str_json(i[x])),i.keys()))+'}'
1005      elif type(i) is time.struct_time:
1006        try:
1007          return '\'%s\''%self.getLangFmtDate(i)
1008        except:
1009          pass
1010      elif type(i) is int or type(i) is float:
1011        return str(i)
1012      elif i is not None:
1013        return '\'%s\''%(str(i).replace('\\','\\\\').replace('\'','\\\'').replace('\n','\\n').replace('\r','\\r'))
1014      return '\'\''
1015
1016
1017    """
1018    Returns a string representation of the item.
1019    @rtype: C{list}
1020    """
1021    def str_item(self, i):
1022      if type(i) is list or type(i) is tuple:
1023        return '\n'.join(map(lambda x: self.str_item(x),i))
1024      elif type(i) is dict:
1025        return '\n'.join(map(lambda x: self.str_item(i[x]),i.keys()))
1026      elif type(i) is time.struct_time:
1027        try:
1028          return self.getLangFmtDate(i)
1029        except:
1030          pass
1031      if i is not None:
1032        return str(i)
1033      return ''
1034
1035
1036    """
1037    Filters list by given field.
1038    @param l: List
1039    @type l: C{list}
1040    @param i: Field-name or -index
1041    @type i: C{string} or C{int}
1042    @param v: Field-value
1043    @type v: C{any}
1044    @param v: Match-operator
1045    @type v: C{string}, values are '%' (full-text), '=', '==', '>', '<', '>=', '<=', '!=', '<>'
1046    @return: Filtered list.
1047    @rtype: C{list}
1048    """
1049    def filter_list(self, l, i, v, o='%'):
1050      # Full-text scan.
1051      if i is None or len(str(i))==0:
1052        str_item = self.str_item
1053        v = str(v)
1054        k = []
1055        if len(v.split(' OR '))>1:
1056          for s in v.split(' OR '):
1057            s = s.replace('*','').strip()
1058            if len( s) > 0:
1059              s = _globals.umlaut_quote(s).lower()
1060              k.extend(filter(lambda x: x not in k and _globals.umlaut_quote(str_item(x)).lower().find(s)>=0, l))
1061        elif len(v.split(' AND '))>1:
1062          k = l
1063          for s in v.split(' AND '):
1064            s = s.replace('*','').strip()
1065            if len( s) > 0:
1066              s = _globals.umlaut_quote(s).lower()
1067              k = filter(lambda x: _globals.umlaut_quote(str_item(x)).lower().find(s)>=0, k)
1068        else:
1069          v = v.replace('*','').strip().lower()
1070          if len( v) > 0:
1071            v = _globals.umlaut_quote(v).lower()
1072            k = filter(lambda x: _globals.umlaut_quote(str_item(x)).lower().find(v)>=0, l)
1073        return k
1074      # Extract Items.
1075      if type(i) is str:
1076        k=map(lambda x: (x.get(i,None),x), l)
1077      else:
1078        k=map(lambda x: (x[i],x), l)
1079      # Filter Date-Tuples
1080      if type(v) is tuple or type(v) is time.struct_time:
1081        v = DateTime('%4d/%2d/%2d'%(v[0],v[1],v[2]))
1082      # Filter Strings.
1083      if type(v) is str or o=='%':
1084        str_item = self.str_item
1085        if o=='=' or o=='==':
1086          k=filter(lambda x: str_item(x[0])==v, k)
1087        elif o=='<>' or o=='!=':
1088          k=filter(lambda x: str_item(x[0])!=v, k)
1089        else:
1090          v = str_item(v).lower()
1091          if v.find('*')>=0 or v.find('?')>=0:
1092            k=filter(lambda x: fnmatch.fnmatch(str_item(x[0]).lower(),v), k)
1093          else:
1094            k=filter(lambda x: str_item(x[0]).lower().find(v)>=0, k)
1095      # Filter Numbers.
1096      elif type(v) is int or type(v) is float:
1097        if o=='=' or o=='==':
1098          k=filter(lambda x: x[0]==v, k)
1099        elif o=='<':
1100          k=filter(lambda x: x[0]<v, k)
1101        elif o=='>':
1102          k=filter(lambda x: x[0]>v, k)
1103        elif o=='<=':
1104          k=filter(lambda x: x[0]<=v, k)
1105        elif o=='>=':
1106          k=filter(lambda x: x[0]>=v, k)
1107        elif o=='<>' or o=='!=':
1108          k=filter(lambda x: x[0]!=v, k)
1109      # Filter Lists.
1110      elif type(v) is list:
1111        if o=='=' or o=='==':
1112          k=filter(lambda x: x[0]==v, k)
1113        elif o=='in':
1114          k=filter(lambda x: x[0] in v, k)
1115      # Filter DateTimes.
1116      elif isinstance(v,DateTime):
1117        dt = _globals.getDateTime
1118        k=filter(lambda x: x[0] is not None, k)
1119        k=map(lambda x: (dt(x[0]),x[1]), k)
1120        k=map(lambda x: (DateTime('%4d/%2d/%2d'%(x[0][0],x[0][1],x[0][2])),x[1]), k)
1121        if o=='=' or o=='==':
1122          k=filter(lambda x: x[0].equalTo(v), k)
1123        elif o=='<':
1124          k=filter(lambda x: x[0].lessThan(v), k)
1125        elif o=='>':
1126          k=filter(lambda x: x[0].greaterThan(v), k)
1127        elif o=='<=':
1128          k=filter(lambda x: x[0].lessThanEqualTo(v), k)
1129        elif o=='>=':
1130          k=filter(lambda x: x[0].greaterThanEqualTo(v), k)
1131        elif o=='<>':
1132          k=filter(lambda x: not x[0].equalTo(v), k)
1133      return map(lambda x: x[1], k)
1134
1135
1136    """
1137    Copies list l.
1138    @param l: List
1139    @type l: C{list}
1140    @return: Copy of list.
1141    @rtype: C{list}
1142    """
1143    def copy_list(self, l):
1144      try:
1145        v = copy.deepcopy(l)
1146      except:
1147        v = copy.copy(l)
1148      return v
1149
1150
1151    """
1152    Syncronizes list l with new list nl using the column i as identifier.
1153    """
1154    def sync_list(self, l, nl, i):
1155      k = []
1156      for x in l:
1157        k.extend([x[i],x])
1158      for x in nl:
1159        if x[i] in k:
1160          j = k.index(x[i])+1
1161          if type(x) is dict:
1162            v = k[j]
1163            for xk in x.keys():
1164              v[xk] = x[xk]
1165            x = v
1166          k[j] = x
1167        else:
1168          k.extend([x[i],x])
1169      return map(lambda x: k[x*2+1], range(0,len(k)/2))
1170
1171
1172    """
1173    Aggregates given field in list.
1174    """
1175    def aggregate_list(self, l, i):
1176      k = []
1177      for li in copy.deepcopy(l):
1178        del li[i]
1179        if li not in k:
1180          k.append(li)
1181      m = []
1182      for ki in k:
1183        mi = copy.deepcopy(ki)
1184        mi[i] = []
1185        ks = ki.keys()
1186        for li in l:
1187          if len(ks) == len(filter(lambda x: x==i or ki[x]==li[x],ks)):
1188            mi[i].append(li[i])
1189        m.append(mi)
1190      return m
1191
1192    #)
1193
1194
1195    ############################################################################
1196    #
1197    #() Local File-System
1198    #
1199    ############################################################################
1200
1201    """
1202    Returns util with PIL functions.
1203    """
1204    def pilutil( self):
1205      return _pilutil.pilutil(self)
1206
1207
1208    """
1209    Extract files from zip-archive and return list of extracted files.
1210    @return: Extracted files (binary)
1211    @rtype: C{list}
1212    """
1213    def getZipArchive(self, f):
1214      return _fileutil.getZipArchive(f)
1215
1216
1217    """
1218    Extract zip-archive.
1219    """
1220    security.declarePrivate('extractZipArchive')
1221    def extractZipArchive(self, f):
1222      return _fileutil.extractZipArchive(f)
1223
1224
1225    """
1226    Pack zip-archive and return data.
1227    @return: zip-archive (binary)
1228    @rtype: C{string}
1229    """
1230    def buildZipArchive( self, files, get_data=True):
1231      return _fileutil.buildZipArchive( files, get_data)
1232
1233
1234    """
1235    Returns package_home on local file-system.
1236    @return: package_home()
1237    @rtype: C{string}
1238    """
1239    def localfs_package_home(self):
1240      return package_home(globals())
1241
1242
1243    """
1244    Creates temp-folder on local file-system.
1245    @rtype: C{string}
1246    """
1247    def localfs_tempfile(self):
1248      tempfolder = tempfile.mktemp()
1249      return tempfolder
1250
1251
1252    """
1253    Reads file from local file-system.
1254    You must grant permissions for reading from local file-system to
1255    directories in Config-Tab / Miscelleaneous-Section.
1256    @param filename: Filepath
1257    @type filename: C{string}
1258    @param filename: Access mode
1259    @type filename: C{string}, values are 'b' - binary
1260    @var REQUEST: the triggering request
1261    @type REQUEST: C{ZPublisher.HTTPRequest}
1262    @return: Contents of file
1263    @rtype: C{string} or C{filestream_iterator}
1264    """
1265    security.declareProtected('View', 'localfs_read')
1266    def localfs_read(self, filename, mode='b', REQUEST=None):
1267      """
1268      ZMSGlobals.localfs_read
1269      """
1270      try:
1271        filename = unicode(filename,'utf-8').encode('latin-1')
1272      except:
1273        pass
1274      _globals.writeLog( self, '[localfs_read]: filename=%s'%filename)
1275     
1276      # Get absolute filename.
1277      filename = _fileutil.absoluteOSPath(filename)
1278     
1279      # Check permissions.
1280      request = self.REQUEST
1281      authorized = False
1282      perms = self.getConfProperty('ZMS.localfs_read','').split(';')
1283      perms.append(tempfile.gettempdir())
1284      perms.append(package_home(globals()))
1285      mediadb = self.getMediaDb()
1286      if mediadb:
1287          perms.append(mediadb.location)
1288      for perm in map(lambda x: x.strip(), perms):
1289          authorized = authorized or ( len( perm) > 0 and filename.lower().startswith( _fileutil.absoluteOSPath(perm).lower()))
1290      if not authorized:
1291          raise zExceptions.Unauthorized
1292     
1293      # Read file.
1294      if type( mode) is dict:
1295        fdata, mt, enc, fsize = _fileutil.readFile( filename, mode.get('mode','b'), mode.get('threshold',-1))
1296      else:
1297        fdata, mt, enc, fsize = _fileutil.readFile( filename, mode)
1298      if REQUEST is not None:
1299        RESPONSE = REQUEST.RESPONSE
1300        RESPONSE.setHeader('Content-Type', mt)
1301        RESPONSE.setHeader('Content-Encoding', enc)
1302        RESPONSE.setHeader('Content-Length', fsize)
1303        RESPONSE.setHeader('Content-Disposition','inline;filename="%s"'%_fileutil.extractFilename(filename))
1304        RESPONSE.setHeader('Accept-Ranges', 'bytes')
1305      return fdata
1306
1307
1308    """
1309    Writes file to local file-system.
1310    """
1311    def localfs_write(self, filename, v, mode='b', REQUEST=None):
1312      _globals.writeLog( self, '[localfs_write]: filename=%s'%filename)
1313     
1314      # Get absolute filename.
1315      filename = _fileutil.absoluteOSPath(filename)
1316     
1317      # Check permissions.
1318      request = self.REQUEST
1319      authorized = False
1320      perms = self.getConfProperty('ZMS.localfs_write','').split(';')
1321      perms.append(tempfile.gettempdir())
1322      perms.append(package_home(globals()))
1323      mediadb = self.getMediaDb()
1324      if mediadb:
1325          perms.append(mediadb.location)
1326      for perm in map(lambda x: x.strip(), perms):
1327          authorized = authorized or ( len( perm) > 0 and filename.lower().startswith( _fileutil.absoluteOSPath(perm).lower()))
1328      if not authorized:
1329          raise zExceptions.Unauthorized
1330     
1331      # Write file.
1332      _fileutil.exportObj( v, filename, mode)
1333
1334
1335    """
1336    Removes file from local file-system.
1337    """
1338    def localfs_remove(self, path, deep=0):
1339      _globals.writeLog( self, '[localfs_remove]: path=%s'%path)
1340     
1341      # Get absolute filename.
1342      filename = _fileutil.absoluteOSPath(path)
1343     
1344      # Check permissions.
1345      request = self.REQUEST
1346      authorized = False
1347      perms = self.getConfProperty('ZMS.localfs_write','').split(';')
1348      perms.append(tempfile.gettempdir())
1349      perms.append(package_home(globals()))
1350      mediadb = self.getMediaDb()
1351      if mediadb:
1352          perms.append(mediadb.location)
1353      for perm in map(lambda x: x.strip(), perms):
1354        authorized = authorized or ( len( perm) > 0 and filename.lower().startswith( _fileutil.absoluteOSPath(perm.lower())))
1355      if not authorized:
1356        raise zExceptions.Unauthorized
1357     
1358      # Remove file.
1359      _fileutil.remove( path, deep)
1360
1361
1362    """
1363    Reads path from local file-system.
1364    @rtype: C{list}
1365    """
1366    security.declareProtected('View', 'localfs_readPath')
1367    def localfs_readPath(self, filename, data=False, recursive=False, REQUEST=None):
1368      """
1369      ZMSGlobals.localfs_readPath
1370      """
1371      try:
1372        filename = unicode(filename,'utf-8').encode('latin-1')
1373      except:
1374        pass
1375      _globals.writeLog( self, '[localfs_readPath]: filename=%s'%filename)
1376     
1377      # Get absolute filename.
1378      filename = _fileutil.absoluteOSPath(filename)
1379     
1380      # Check permissions.
1381      request = self.REQUEST
1382      authorized = False
1383      perms = self.getConfProperty('ZMS.localfs_read','').split(';')
1384      perms.append(tempfile.gettempdir())
1385      perms.append(package_home(globals()))
1386      mediadb = self.getMediaDb()
1387      if mediadb:
1388          perms.append(mediadb.location)
1389      for perm in map(lambda x: x.strip(), perms):
1390        authorized = authorized or ( len( perm) > 0 and filename.lower().startswith( _fileutil.absoluteOSPath(perm).lower()))
1391      if not authorized:
1392        raise zExceptions.Unauthorized
1393     
1394      # Read path.
1395      return _fileutil.readPath(filename, data, recursive)
1396
1397    #)
1398
1399
1400    ############################################################################
1401    #
1402    #  XML
1403    #
1404    ############################################################################
1405
1406    """
1407    Returns XML-Header (encoding=utf-8)
1408    @param encoding: Encoding
1409    @type encoding: C{string}
1410    @rtype: C{string}
1411    """
1412    def getXmlHeader(self, encoding='utf-8'):
1413      return _xmllib.xml_header(encoding)
1414
1415
1416    """
1417    Serializes value to ZMS XML-Structure.
1418    @rtype: C{string}
1419    """
1420    def toXmlString(self, v, xhtml=False, encoding='utf-8'):
1421      return _xmllib.toXml(self, v, xhtml=xhtml, encoding=encoding)
1422
1423
1424    """
1425    Parse value from ZMS XML-Structure.
1426    @return: C{list} or C{dict}
1427    @rtype: C{any}
1428    """
1429    def parseXmlString(self, xml, mediadbStorable=True):
1430      builder = _xmllib.XmlAttrBuilder()
1431      if type(xml) is str:
1432        xml = StringIO(xml)
1433      v = builder.parse( xml, mediadbStorable)
1434      return v
1435
1436
1437    """
1438    Process xml with xsl transformation.
1439    @deprecated: Use ZMSGlobals.processData('xslt') instead.
1440    """
1441    def xslProcess(self, xsl, xml):
1442      return self.processData('xslt', xml, xsl)
1443
1444
1445    """
1446    Process data with custom transformation.
1447    """
1448    def processData(self, processId, data, trans=None):
1449      return _filtermanager.processData(self, processId, data, trans)
1450
1451
1452    """
1453    Parse arbitrary XML-Structure into dictionary.
1454    @return: Dictionary of XML-Structure.
1455    @rtype: C{dict}
1456    """
1457    def xmlParse(self, xml):
1458      builder = _xmllib.XmlBuilder()
1459      if type(xml) is str:
1460        xml = StringIO(xml)
1461      v = builder.parse(xml)
1462      return v
1463
1464
1465    """
1466    Retrieve node-set for given tag-name from dictionary of XML-Node-Structure.
1467    @return: List of dictionaries of XML-Structure.
1468    @rtype: C{list}
1469    """
1470    def xmlNodeSet(self, mNode, sTagName='', iDeep=0):
1471      return _xmllib.xmlNodeSet( mNode, sTagName, iDeep)
1472
1473
1474    ############################################################################
1475    #
1476    #  PLUGINS
1477    #
1478    ############################################################################
1479
1480    """
1481    Executes plugin.
1482    @param path: the plugin path in $ZMS_HOME/plugins/
1483    @type path: C{string}
1484    @param REQUEST: the triggering request
1485    @type REQUEST: C{ZPublisher.HTTPRequest}
1486    @param pars: the request parameters
1487    @type pars: C{dict}
1488    @return: Result of the execution or error-message
1489    """
1490    def getPlugin( self, path, REQUEST, pars={}):
1491     
1492      # Check permissions.
1493      request = self.REQUEST
1494      authorized = path.find('..') < 0
1495      if not authorized:
1496        raise zExceptions.Unauthorized
1497     
1498      try:
1499        # Set request-parameters.
1500        for k in pars.keys():
1501          v = REQUEST.get( k, None)
1502          REQUEST.set( k, pars[k])
1503          pars[k] = v
1504        # Execute plugin.
1505        filename = self.localfs_package_home()+'/plugins/'+path
1506        fdata, mt, enc, fsize = _fileutil.readFile( filename, mode='b')
1507        rtn = self.dt_html( fdata, REQUEST)
1508        # Restore request-parameters.
1509        for k in pars.keys():
1510          REQUEST.set( k, pars[k])
1511      except:
1512        rtn = _globals.writeError( self, '[getPlugin]')
1513      return rtn
1514
1515
1516    ############################################################################
1517    #
1518    #  DATE TIME
1519    #
1520    ############################################################################
1521
1522    # ==========================================================================
1523    # Index  Field  Values 
1524    # 0  year (for example, 1993)
1525    # 1  month range [1,12]
1526    # 2  day range [1,31]
1527    # 3  hour range [0,23]
1528    # 4  minute range [0,59]
1529    # 5  second range [0,61]; see (1) in strftime() description
1530    # 6  weekday range [0,6], Monday is 0
1531    # 7  Julian day range [1,366]
1532    # 8  daylight savings flag 0, 1 or -1; see below
1533    # ==========================================================================
1534
1535    # --------------------------------------------------------------------------
1536    #  ZMSGlobals.getLangFmtDate:
1537    # --------------------------------------------------------------------------
1538    def getLangFmtDate(self, t, lang=None, fmt_str='SHORTDATETIME_FMT'):
1539      try:
1540        if lang is None:
1541          lang = self.get_manage_lang()
1542        # Convert to struct_time
1543        t = _globals.getDateTime(t)
1544        # Return DateTime
1545        if fmt_str == 'DateTime':
1546          dt = DateTime('%4d/%2d/%2d'%(t[0],t[1],t[2]))
1547          return dt
1548        # Return name of weekday
1549        elif fmt_str == 'Day':
1550          dt = DateTime('%4d/%2d/%2d'%(t[0],t[1],t[2]))
1551          return self.getLangStr('DAYOFWEEK%i'%(dt.dow()%7),lang)
1552        # Return name of month
1553        elif fmt_str == 'Month':
1554          return self.getLangStr('MONTH%i'%t[1],lang)
1555        elif fmt_str.replace('-','').replace(' ','') in ['ISO8601','RFC2822']:
1556          # DST is Daylight Saving Time, an adjustment of the timezone by
1557          # (usually) one hour during part of the year. DST rules are magic
1558          # (determined by local law) and can change from year to year.
1559          #
1560          # DST in t[8] ! -1 (unknown), 0 (off), 1 (on)
1561          if t[8] == 1:
1562            tz = time.altzone
1563          elif t[8] == 0:
1564            tz = time.timezone
1565          else:
1566            tz = 0
1567          #  The offset of the local (non-DST) timezone, in seconds west of UTC
1568          # (negative in most of Western Europe, positive in the US, zero in the
1569          # UK).
1570          #
1571          # ==> quite the opposite to the usual definition as eg in RFC 822.
1572          tch = '-'
1573          if tz < 0:
1574            tch = '+'
1575          tz = abs(tz)
1576          tzh = tz/60/60
1577          tzm = (tz-tzh*60*60)/60
1578          colon = ''
1579          if fmt_str.replace('-','').replace(' ','') in ['ISO8601']:
1580            colon = ':'
1581          return time.strftime('%Y-%m-%dT%H:%M:%S',t)+tch+('00%d'%tzh)[-2:]+colon+('00%d'%tzm)[-2:]
1582        # Return date/time
1583        fmt = self.getLangStr(fmt_str,lang)
1584        time_fmt = self.getLangStr('TIME_FMT',lang)
1585        date_fmt = self.getLangStr('DATE_FMT',lang)
1586        if fmt.find(time_fmt) >= 0:
1587          if t[3] == 0 and \
1588             t[4] == 0 and \
1589             t[5]== 0:
1590            fmt = fmt[:-len(time_fmt)]
1591        fmt = fmt.strip()
1592        return time.strftime(fmt,t)
1593      except:
1594        #-- _globals.writeError(self,"[getLangFmtDate]: t=%s"%str(t))
1595        return str(t)
1596
1597    # --------------------------------------------------------------------------
1598    #  ZMSGlobals.parseLangFmtDate:
1599    # --------------------------------------------------------------------------
1600    def parseLangFmtDate(self, s, lang=None, fmt_str=None, recflag=None):
1601      return _globals.parseLangFmtDate(s)
1602
1603    # --------------------------------------------------------------------------
1604    #  ZMSGlobals.compareDate:
1605    # --------------------------------------------------------------------------
1606    def compareDate(self, t0, t1):
1607      return _globals.compareDate(t0, t1)
1608
1609    # --------------------------------------------------------------------------
1610    #  ZMSGlobals.daysBetween:
1611    # --------------------------------------------------------------------------
1612    def daysBetween(self, t0, t1):
1613      return _globals.daysBetween(t0, t1)
1614
1615
1616# call this to initialize framework classes, which
1617# does the right thing with the security assertions.
1618Globals.InitializeClass(ZMSGlobals)
1619
1620################################################################################
Note: See TracBrowser for help on using the repository browser.