# -*- coding: utf-8 # $Id$ # Copyright 2001, 2002 by IVA Team and contributors # # This file is part of IVA. # # IVA is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # IVA is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with IVA; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA """Contains miscellaneous utility functions that are needed often in FLE.""" __version__ = "$Revision$"[11:-2] __doc__ = """Holds some common global defintions/functions used in Fle.""" import os import string from urllib import quote_plus from copy import deepcopy # The path to stuff, duh if __name__ != '__main__': file_path = __import__('Globals').package_home(globals()) import os.path image_file_path = os.path.join(file_path, 'ui', 'images') styles_path = os.path.join(file_path, 'ui', 'styles') ui_path = os.path.join(file_path, 'ui') ########################################################### # fle_roles # The zope roles Fle will use. It is important that these are sorted # so that a lower indexnumber will yield a lower priviledged role. # NOTE: Why? --jmp 2001-10-10 I don't know/remember ;) --granbo # Please *NOTE* that if these are changed, the fle object needs to # be reinstalled. # FIXME: replace these with config hooks. fle_roles = ('User', 'Staff', 'IVAAdmin') roles_admin = ('Manager','IVAAdmin') roles_staff = ('Manager','IVAAdmin','Staff') roles_user = ('Manager','IVAAdmin','Staff','User') perm_view = 'View' perm_edit = 'Edit' perm_manage = 'Manage FLE' perm_add_lo = 'Add FLE LO' perm_access = 'Access contents information' course_level_roles = ('Student', 'Teacher') roles_teacher = ('Manager','Teacher','IVAAdmin') roles_tutor = ('Manager','Teacher','Tutor','IVAAdmin') roles_student = ('Manager','Teacher','Student','IVAAdmin') def mkTime(REQUEST, name): """ return time.mktime() object constructed from REQUEST object's variables """ import time m = (int(getattr(REQUEST, name+"Aasta")), int(getattr(REQUEST, name+"Kuu")), int(getattr(REQUEST, name+"Paev")), int(getattr(REQUEST, name+"Tund")), int(getattr(REQUEST, name+"Minut")),0,0,0,-1) return time.mktime(m) from zope.i18nmessageid import MessageFactory _ = MessageFactory('iva') from zope.i18n import translate as zope_translate from zope.i18n.interfaces import IUserPreferredLanguages def translate(self, msgid, default='', target='', domain='iva', mapping=None): if not target: langs = IUserPreferredLanguages(self.REQUEST).getPreferredLanguages() target = 'en' try: target = langs[0] except IndexError: pass if not default: default = msgid return zope_translate(msgid, domain='iva', default=default, target_language=target, mapping=mapping) # ('dd', 'mm', 'yyyy') def convert_date(dd, mm, yyyy): """Take date, month and year in string format and return date in time.time() format.""" import time from string import atoi date = 0 try: year = atoi(yyyy) month = atoi(mm) day = atoi(dd) except: raise 'Dates not in a string format.' if not (1 <= month <= 12): raise 'Month value must be in 1-12' if not (1 <= day <= 31): raise 'Day value must be in 1-31' try: date_tuple = (atoi(yyyy), atoi(mm), atoi(dd), 0,0,0,0,0,0) date = time.mktime(date_tuple) except: raise 'Date conversion failed' return date def install_subskin(self, out, globals=globals(), product_skins_dir='skins'): """ copied here from Archetypes.Extensions.utils don't want to create dependency because of one method """ from Products.CMFCore.utils import getToolByName, minimalpath from OFS.ObjectManager import BadRequestException import os from os.path import isdir, join from Globals import package_home from Products.CMFCore.DirectoryView import addDirectoryViews, \ registerDirectory, manage_listAvailableDirectories skinstool=getToolByName(self, 'portal_skins') fullProductSkinsPath = os.path.join(package_home(globals), product_skins_dir) productSkinsPath = minimalpath(fullProductSkinsPath) registered_directories = manage_listAvailableDirectories() if productSkinsPath not in registered_directories: try: registerDirectory(product_skins_dir, globals) except OSError, ex: if ex.errno == 2: # No such file or directory return raise try: addDirectoryViews(skinstool, product_skins_dir, globals) except BadRequestException, e: # XXX: find a better way to do this, but that seems not feasible # until Zope stops using string exceptions if str(e).endswith(' is reserved.'): # trying to use a reserved identifier, let the user know # # remember the cmf reserve ids of objects in the root of the # portal ! raise # directory view has already been added pass files = os.listdir(fullProductSkinsPath) for productSkinName in files: # skip directories with a dot or special dirs # or maybe just startswith('.')? if productSkinName.find('.') != -1 or productSkinName in ('CVS', '{arch}'): continue if isdir(join(fullProductSkinsPath, productSkinName)): for skinName in skinstool.getSkinSelections(): path = skinstool.getSkinPath(skinName) path = [i.strip() for i in path.split(',')] try: if productSkinName not in path: path.insert(path.index('custom') +1, productSkinName) except ValueError: if productSkinName not in path: path.append(productSkinName) path = ','.join(path) skinstool.addSkinSelection(skinName, path) def get_text(elem): res = u'' for line in elem.childNodes: res += line.nodeValue return to_utf8(res) def get_attr(elem, name): return to_utf8(elem.getAttribute(name)) def to_utf8(s): return s.encode('utf-8') def to_unicode(s, encoding='utf-8'): if type(s)==UnicodeType: return s try: return unicode(s, encoding) except UnicodeError: return unicode(s, 'iso-8859-1') def delete_pt(obj, tuple_of_tuples, raise_exc_on_error=0): """ deletes all pagetemplates from zodb """ for tup in tuple_of_tuples: (id, title, file) = tup try: container = obj.unrestrictedTraverse(id).aq_parent container._delObject(id.split('/')[-1]) except: pass def make_action(action, *args): retval = action + '?' for arg in args: retval += arg[0] + '=' + quote_plus(arg[1]) + '&' return retval[:-1] ########################################################### # Randomness stuff. # strong_random() # Returns a strong pseudorandom signed integer. # FIXME: check if zope seeds random again on each new request. # FIXME: If it does, we need to think things over. I neither # FIXME: think this is thread-safe, blah blah. def _strong_random(): from random import random from sys import maxint rv = 0 seed = 0 b = maxint for shift in range(0, 32, 8): # we use only the least significant byte, so .. seed = seed ^ int(round(random() * b)) rv = rv ^ ((seed&0xff) << shift) return rv # random() random = _strong_random ################################################## # a_char() # Returns a printable character, duh. #_printable_char = __import__('string').letters _printable_char = [chr(x) for x in range(ord('a'), ord('z') + 1)] + \ [chr(x) for x in range(ord('A'), ord('Z') + 1)] def a_char(idx, _7bit_only=0): if type(idx) != type(1): raise TypeError, 'a_char requires int argument' char_tbl = _printable_char return char_tbl[idx%len(char_tbl)] def add_image_obj(obj, id, title, file): f = open(file,"rb") content = f.read() f.close() obj.manage_addImage(id, content, title) img = getattr(obj, id) img.ZCacheable_setManagerId('HTTPCache') # This returns all roles the person has in the given object # and acquired from above. # XXX: slow! def get_roles(obj, person): tmpobj=obj while 1: if hasattr(tmpobj, 'acl_users'): if tmpobj.acl_users.getUser(person): acl_obj = tmpobj break try: tmpobj=tmpobj.aq_parent except: return () roles = list(acl_obj.acl_users.getUser(person).getRoles()) # global roles try: roles = list(acl_obj.acl_users.getUser(person).getRoles()) # global roles except AttributeError: return () for o in obj.aq_chain[:-1]: o=o.aq_base if hasattr(o,'get_local_roles'): for tuples in o.get_local_roles(): if str(tuples[0]) == str(person): roles = roles + list(tuples[1]) return tuple(roles) # This returns the local roles for the given object exactly. # (no acquired roles) def get_local_roles(obj, person): roles = [] o=obj.aq_base if hasattr(o,'get_local_roles'): for tuples in o.get_local_roles(): if str(tuples[0]) == str(person): roles = roles + list(tuples[1]) return tuple(roles) ################################################## # get_url() # Generalization of reading the contents of an url. def get_url(url): import urllib try: rv = urllib.urlopen(url).read() except IOError: return None return rv # HTML Conversion table def _get_all_conv_table(): from string import upper rv = {} my_range = range(1,256) char_tbl = [chr(x) for x in my_range] conv = [upper(hex(x)[2:]) for x in my_range] for (char, con) in map(None, char_tbl, conv): rv[char] = '%%%s' % con return rv def _get_conv_table(sc=None): rv = {} if sc is None: for char in range(1, 128): rv[chr(char)] = chr(char) for char in range(128, 256): rv[chr(char)] = '&#%d;' % char else: # There is a special case thingy. for char in range(1, 256): if chr(char) in sc.keys(): # This is freaking slow. rv[chr(char)] = sc[chr(char)] else: rv[chr(char)] = chr(char) return rv # Convert normal text to html quoted html text. This only applies on the # 8-bit char set, not 7-bit. def quote_html(str, special_case=None): """This function converts string html to html quotes faster than a lightning.""" import string conv_tbl = _get_conv_table(special_case) rv = [] for char in str: rv.append(conv_tbl[char]) return string.join(rv, '') def quote_html_hack(str): from string import join conv_tbl = _get_all_conv_table() rv = [] return join([conv_tbl[c] for c in str], '') def iterate_fs_files(dir, suffix, func): """Calls func(filename) for each file in dir ending with suffix.""" for file in filter(lambda x,s=suffix:x[-(len(s)):]==s, os.listdir(dir)): apply(func, (file,)) def iterate_fle_path(dir, suffix, func): """Same as iterate_fs_files, but in fle fs directory.""" iterate_fs_files(os.path.join(file_path, dir), suffix, func) # Compare two strings. def str_cmp(x, y): from types import StringType if (not type(x) is StringType) or (not type(y) is StringType): raise 'FLE Error', 'common.str_cmp called with non string arguments: x="%s" y="%s"' % (str(x), str(y)) x_buf = map(ord, x.lower()) y_buf = map(ord, y.lower()) x_len = len(x_buf) y_len = len(y_buf) tot_len = max(x_len, y_len) if x_len < y_len: x_buf = x_buf + [0]*tot_len elif x_len > y_len: y_buf = y_buf + [0]*tot_len for (xval, yval) in map(None, x_buf, y_buf): if xval < yval: return -1 elif xval > yval: return 1 return 0 def convert_to_days(time): """Converts a time (in seconds) into days.""" time = float(time) return int(time/86400) # 24 hours * 60 minutes * 60 seconds # Intersect two lists, and if there is one equal in both lists, # return true. def intersect_bool(seq1, seq2): if not seq1 or not seq2: return 0 for x in seq1: if x in seq2: return 1 return 0 # FLE color specs colours = { 'red': "#ff0000", 'green': "#00ff00", 'blue': "#0000ff", 'yellow': "#ffff00", 'black': "#000000", 'pink': "pink", # WTF is the code for pink? 'dark_blue': "#0000aa", 'dark_red': "#aa0000", 'brown': "brown", # WTF is the code for brown? 'white': "#ffffff", } class FakeUpload: """A class to mimic an http upload.""" def __init__(self,name,data,content_type): self.filename=name self.data=data self.headers={} if content_type: self.headers['content-type']=content_type else: self.headers['content-type']=None def getContentType(self): try: return self.headers['content-type'] except KeyError: return None def read(self,size=-1): if size==-1: return self.data else: return self.data[self.offset:(self.offset+size)] def seek(self,offset,base=0): if base==0: self.offset=offset elif base==2: self.offset=len(self.data)+offset elif base==1: self.offset=self.offset+offset def tell(self): return self.offset import UserDict class FakeRequest(UserDict.UserDict): """A class to mimic an http request.""" def __init__(self,user='user1'): self.AUTHENTICATED_USER = user self.RESPONSE=FakeResponse() self.data={} self.data['SERVER_URL']='http://localhost/' self.data['SCRIPT_NAME']='foobar' self._script=['foo','bar'] def has_key(self,value): return 0 class FakeResponse: """A class to mimic an http reply.""" def redirect(self,*args): pass from Products.Five.bridge import fromZ2Interface import zope.interface def classImplements(class_, *interfaces): # convert any Zope 2 interfaces to Zope 3 using fromZ2Interface interfaces = flatten(interfaces) normalized_interfaces = [] for i in interfaces: try: i = fromZ2Interface(i) except ValueError: # already a Zope 3 interface pass assert issubclass(i, zope.interface.Interface) normalized_interfaces.append(i) return zope.interface.classImplements(class_, *normalized_interfaces) def flatten(interfaces): flattened = [] _detuplize(interfaces, flattened.append) return tuple(flattened) def _detuplize(interfaces, append): if isinstance(interfaces, (tuple, list)): for sub in interfaces: _detuplize(sub, append) else: append(interfaces) from interfaces import IFLE def _mergedLocalRoles(object, limit=False): """Returns a merging of object and its ancestors' __ac_local_roles__.""" # Modified from AccessControl.User.getRolesInContext(). merged = {} object = getattr(object, 'aq_inner', object) while 1: if limit and IFLE.providedBy(object): break if hasattr(object, '__ac_local_roles__'): dict = object.__ac_local_roles__ or {} if callable(dict): dict = dict() for k, v in dict.items(): if merged.has_key(k): try: merged[k] = merged[k] + v except TypeError: if isinstance(merged[k], list): merged[k] = merged[k] + list(v) if isinstance(merged[k], tuple): merged[k] = merged[k] + tuple(v) else: merged[k] = v if hasattr(object, 'aq_parent'): object=object.aq_parent object=getattr(object, 'aq_inner', object) continue if hasattr(object, 'im_self'): object=object.im_self object=getattr(object, 'aq_inner', object) continue break return deepcopy(merged) from zope.app.container.interfaces import IObjectAddedEvent from OFS.interfaces import IObjectWillBeRemovedEvent from zope.component import adapter from interfaces import ICalendar, IEvent #@adapter(ICalendar, IObjectAddedEvent) #@adapter(IEvent, IObjectAddedEvent) def added(obj, event): """ common action after adding event """ obj.index_object() #@adapter(ICalendar, IObjectWillBeRemovedEvent) #@adapter(IEvent, IObjectWillBeRemovedEvent) def removing(obj, event): """ common action for removing """ obj.unindex_object() IVA_VERSION = "IVA " f = open(os.path.join(os.sep.join(__file__.split('/')[:-1]),'version.txt')) IVA_VERSION += f.read().strip() f.close() if __name__ == '__main__': pass # EOF