This repository has been archived on 2023-02-21. You can view files and clone it, but cannot push or open issues or pull requests.
glasnost/shared/web/WebAPI.py

604 lines
18 KiB
Python

# -*- coding: iso-8859-15 -*-
# Glasnost
# By: Odile Bénassy <obenassy@entrouvert.com>
# Romain Chantereau <rchantereau@entrouvert.com>
# Nicolas Clapiès <nclapies@easter-eggs.org>
# Pierre-Antoine Dejace <padejace@entrouvert.be>
# Thierry Dulieu <tdulieu@easter-eggs.com>
# Florent Monnier <monnier@codelutin.com>
# Cédric Musso <cmusso@easter-eggs.org>
# Frédéric Péters <fpeters@entrouvert.be>
# Benjamin Poussin <poussin@codelutin.com>
# Emmanuel Raviart <eraviart@entrouvert.com>
# Sébastien Régnier <regnier@codelutin.com>
# Emmanuel Saracco <esaracco@easter-eggs.com>
#
# Copyright (C) 2000, 2001 Easter-eggs & Emmanuel Raviart
# Copyright (C) 2002 Odile Bénassy, Code Lutin, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Frédéric Péters, Benjamin Poussin, Emmanuel Raviart,
# Emmanuel Saracco & Théridion
# Copyright (C) 2003 Odile Bénassy, Romain Chantereau, Nicolas Clapiès,
# Code Lutin, Pierre-Antoine Dejace, Thierry Dulieu, Easter-eggs,
# Entr'ouvert, Florent Monnier, Cédric Musso, Ouvaton, Frédéric Péters,
# Benjamin Poussin, Rodolphe Quiédeville, Emmanuel Raviart, Sébastien
# Régnier, Emmanuel Saracco, Théridion & Vecam
#
# This program 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.
#
# This program 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 this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
from __future__ import nested_scopes
# lambdas are so much fun with nested scopes...
__doc__ = """Glasnost Web API Module"""
__version__ = '$Revision$'[11:-2]
import locale
import imp
import math
import os
import re
import sys
import time
import glasnost.common.context as context
import glasnost.common.faults as faults
import glasnost.common.parsers as parsers
import glasnost.common.tools_new as commonTools
from glasnost.common.translation import languageLabels
import glasnost.common.xhtmlgenerator as X
import glasnost.proxy.GroupsProxy
import tools_new as webTools
import tools
class GlasnostTime:
def __init__(self, time):
self._time = time
def __repr__(self):
return self.isoDate
def __cmp__(self, other):
return cmp(self._time, other._time)
def __getattr__(self, attr):
formats = {
'isoDateTime': '%Y-%m-%d %H:%M:%S',
'isoDate': '%Y-%m-%d',
'euroDate': '%d-%m-%Y',
'usDate': '%m-%d-%Y',
'time': '%H:%M:%S',
'yearMonth': '%Y-%m'
}
if formats.has_key(attr):
setattr(self, attr, time.strftime(formats[attr],
time.localtime(self._time)))
return getattr(self, attr)
if attr == 'euro':
self.euro = '%s %s' % (self.euroDate, self.time)
return self.euro
if attr == 'us':
self.us = '%s %s' % (self.usDate, self.time)
return self.us
raise AttributeError, 'no such attr'
class GlasnostServerRole:
def __init__(self, web):
if type(web) is type(''):
web = tools.getWebForServerRole(web)
self.web = web
self.labelPlural = _(web.objectsNameCapitalized)
if hasattr(web, 'objectNameCapitalized'):
self.labelSingular = _(web.objectNameCapitalized)
else:
self.labelSingular = self.labelPlural
self.label = self.labelPlural
self.url = X.roleUrl(web.serverRole)
self.urlNew = X.roleUrl(web.serverRole, 'edit')
def getUrl(self):
return self.url
class GlasnostObject:
def __init__(self, id='', object=None):
if object:
self.objectId = object.id
self.resolve(object)
elif id:
if id[0] == '/':
id = context.getVar('dispatcherId') + id
self.objectId = id
self.resolved = 0
else:
raise "You should give an id or an object!"
try:
self.serverRole = commonTools.extractRole(self.objectId)
except IndexError:
pass
except:
# FIXME: this happens with virtualhosts where self.objectId ==
# 'glasnost://www.entrouvert.be' (for example)
self.serverRole = ''
def __getattr__(self, attr):
if attr == 'isAccessible':
self.isAccessible = self._isAccessible()
return self.isAccessible
if attr.startswith('__'):
raise AttributeError, 'No such attribute'
if attr == 'label':
if not self.objectId:
return self.getLabel()
try:
self.label = tools.getObjectLabelTranslated(
self.objectId,
context.getVar('readLanguages'))
except faults.MissingItem:
self.label = '[deleted object]'
return self.label
if attr.startswith('t8d_'):
# won't work on list (ie Multi fields) for now
realAttr = attr[4:]
fieldValue = getattr(self, realAttr)
if not self.objectId:
return fieldValue
path = 'self.%s' % realAttr
translationsProxy = tools.getProxyForServerRole('translations')
if translationsProxy:
fieldValue, destinationLanguage, state = \
translationsProxy.getTranslationInfos(
fieldValue, self.objectId, path, self.language,
context.getVar('readLanguages'))
#language = context.getVar('readLanguages')[0]
setattr(self, attr, fieldValue)
return getattr(self, attr)
if self.resolved and hasattr(self.object, attr):
return getattr(self.object, attr)
if self.resolved:
raise AttributeError, "I don't have a %s attribute" % attr
self.resolve()
if self.__dict__.has_key(attr):
return self.__dict__[attr]
return getattr(self.object, attr)
def _isAccessible(self):
web = tools.getWeb(self.objectId)
return web.canGetObject(self.objectId)
def resolve(self, object = None):
self.resolved = 1
if not object:
web = tools.getWeb(self.objectId)
self.object = web.getObject(self.objectId)
else:
self.object = object
for key, val in self.object.__dict__.items():
# dumb
setattr(self, key, val)
if hasattr(self.object, 'getSlotNames'):
# smart
for slotName in self.object.getSlotNames():
if not hasattr(self.object, slotName) \
or not getattr(self.object, slotName):
continue
if slotName == 'id':
continue
slot = self.getSlot(slotName)
kind = slot.getKind()
if kind.__class__.__name__ == 'Id':
setattr(self, slotName,
GlasnostObject(getattr(self.object, slotName)))
elif kind.__class__.__name__ == 'Sequence' and \
kind.itemKind.__class__.__name__ == 'Id':
kind = [GlasnostObject(x)
for x in getattr(self.object, slotName)]
setattr(self, slotName, kind)
elif kind.__class__.__name__ in (
'Time', 'ModificationTime', 'CreationTime'):
kind = GlasnostTime(getattr(self.object, slotName))
setattr(self, slotName, kind)
def __repr__(self):
return '<GlasnostObject (%s) (resolved: %d)>' % (
self.objectId, self.resolved)
def __cmp__(self, other):
if not self: return -1
if not other: return 1
return cmp(self.objectId, other.objectId)
def __str__(self):
if self.serverRole == 'virtualhosts':
return self.t8d_title
return self.label
def getUrl(self, action='', args=None, absolute=0):
t = X.idUrl(self.objectId, action)
if args:
for k,v in args.items():
t.add(k,v)
if absolute:
return t.getAsAbsoluteUrl()
else:
return t.getAsUrl()
def canAddObject(objectType):
if isinstance(objectType, GlasnostServerRole):
web = objectType.web
else:
web = tools.getWebForServerRole(objectType)
try:
return web.canAddObject()
except: # TODO: tighter check
return 0
def getAPIDict():
module = sys.modules[__name__]
api = {}
for k,v in module.__dict__.items():
if k[0] == '_':
continue
if type(v) not in (type(getMainRubric), type(GlasnostObject)) :
continue
api[k] = v
api['userToken'] = context.getVar('userToken')
api['fileName'] = context.getVar('webFileName')
try:
api['user'] = GlasnostObject(id = context.getVar(
'userId', default = ''))
except: # TODO: tighter check
api['user'] = None
virtualHost = context.getVar('virtualHost')
if virtualHost is not None:
api['virtualHost'] = GlasnostObject(object = virtualHost)
else:
api['virtualHost'] = ''
api['currentURI'] = context.getVar('req')._req.uri
api['math'] = math
api['time'] = time
api['urlargs'] = UrlArgs(api)
api['context'] = context
api['parsers'] = parsers
api['webTools'] = webTools
api['X'] = X
return api
def getGotoObjectsLabelsAndLinks():
return tools.getGotoObjectsLabelsAndLinks()
def getLastObjects(serverRole, number):
web = tools.getWebForServerRole(serverRole)
if not hasattr(web, 'getLastObjects'):
return []
userId = context.getVar('userId', default = '')
if userId:
userSet = [userId]
else:
userSet = None
return [
GlasnostObject(object = x)
for x in web.getLastObjects(number, None, userSet, None)]
def getMainRubric():
try:
object = tools.getWebForServerRole('rubrics').getMainObject()
except: # TODO: should check the exception is MainRubricMissing
return None
glasnostObject = GlasnostObject(object=object)
return glasnostObject
def getMenuIds(roles):
return X.menuIds(roles).getAsXml()
def getNewObjectLabelsAndLinks():
return tools.getNewObjectLabelsAndLinks()
cachedPath = {}
def _getPathToObject(object, source):
if not object:
return None
try:
source.membersSet
except: # TODO: tighter check
# this probably means we don't have read access to this source
return None
if object == source.contentId:
return [source]
if not source.membersSet:
return None
if object in source.membersSet:
return [source]
for m in source.membersSet:
if commonTools.extractRole(m.objectId) != 'rubrics':
# we don't go through getSetContainedIds here
continue
t = _getPathToObject(object, m)
if t:
return [source] + t
return None
def getPathToObject(object):
# this benefits heavily from the cache
mR = getMainRubric()
path = _getPathToObject(object, mR)
if not path:
if not object or not object.serverRole:
return []
path = [ GlasnostServerRole(object.serverRole), ]
return path
def getTree(source, done = None, level=5):
if done is None:
done = []
if commonTools.extractRole(source.objectId) != 'rubrics' or \
level == 0 or source in done:
return (source, [])
try:
source.membersSet
except: # TODO: tighter check
# this probably means we don't have read access to this source
return (source, [])
if not source.membersSet:
return (source, [])
done.append(source)
return (source, [getTree(x, done, level-1) for x in source.membersSet])
def flattenTree(tree, list, indent=0):
list.append( (indent, tree[0]) )
for x in tree[1]:
flattenTree(x, list, indent+1)
return list
def getServerRoles():
serverIds = []
roles = context.getVar('knownRoles')[:]
for role in roles:
try:
web = tools.getWebForServerRole(role)
except: # TODO: tighter check
continue
if not web:
continue
if hasattr(web, 'objectsNameCapitalized'):
s = GlasnostServerRole(web)
serverIds.append(s)
serverIds.sort(lambda x, y: locale.strcoll(x.label, y.label))
return serverIds
def getSetContainedObjects(set, serverRoles=[], sortOn=None):
if not set:
return []
set = [ x.objectId for x in set ]
result = glasnost.proxy.GroupsProxy.getSetContainedIds(set, serverRoles)
result = [ GlasnostObject(x) for x in result ]
if len(result) > 1 and sortOn:
cmpFct = cmp
if sortOn[0] == '-':
sortOn = sortOn[1:]
coeff = -1
else:
coeff = 1
if sortOn == 'label':
cmpFct = locale.strcoll
elif hasattr(result[0].object, sortOn + '_kind'):
kind = getattr(result[0].object, sortOn + '_kind')
cmpFct = kind.getCmpFunction()
result.sort(lambda x, y: coeff*cmpFct(
getattr(x, sortOn),
getattr(y, sortOn)))
#elif sortOn:
# result.sort(lambda x, y: cmp(
# eval(sortOn, {'self': x}),
# eval(sortOn, {'self': y})) )
return result
def loadExtension(name):
directoryPaths = context.getVar('talExtensionsDirectoryPaths')
fileName = name + '.py'
for directoryPath in directoryPaths:
filePath = os.path.join(directoryPath, fileName)
if os.path.exists(filePath):
break
else:
raise Exception('Unable to load extension %s' % filePath)
return imp.load_source(name, filePath)
def pretion(text):
pretion = '<hr />' + text + '<hr />'
hr = re.compile("<hr.*?>", re.I + re.M)
pretion = hr.split(pretion)
return pretion[1:-1]
# pretion = pretion[0] + '<div class="page">' \
# + '</div><div class="page">'.join(pretion[1:-1]) \
# + '</div>' + pretion[-1]
def sortList(l, sortOn):
if len(l) == 0:
return l
cmpFct = cmp
if sortOn[0] == '-':
sortOn = sortOn[1:]
coeff = -1
else:
coeff = 1
if sortOn == 'label':
cmpFct = locale.strcoll
elif hasattr(l[0].object, sortOn + '_kind'):
kind = getattr(l[0].object, sortOn + '_kind')
cmpFct = kind.getCmpFunction()
l.sort(lambda x, y: coeff*cmpFct(
getattr(x, sortOn),
getattr(y, sortOn)))
return l
compiledFiles = {}
def template(filename, xtal=0, **keywords):
from TAL.TALParser import TALParser
from TAL.HTMLTALParser import HTMLTALParser
from glasnost.web.GlasnostTALGenerator import GlasnostTALGenerator
if not os.path.exists(filename):
fallbackPath = context.getVar(
'fallbackTemplatesDirectoryPath')
filename = filename.split('/')[-1]
if os.path.exists('%s/default/%s' % (fallbackPath, filename)):
filename = '%s/default/%s' % (fallbackPath, filename)
else:
raise Exception('Function template() called for inexistant file')
if 0 and compiledFiles.has_key(filename):
t = compiledFiles[filename]
else:
if xtal:
t = TALParser(gen = GlasnostTALGenerator(xml=1))
else:
t = HTMLTALParser(gen = GlasnostTALGenerator(xml=0))
t.parseString(open(filename).read())
compiledFiles[filename] = t
program, macros = t.getCode()
from GlasnostTALInterpreter import GlasnostTALInterpreter
from GlasnostTALEngine import GlasnostTALEngine
engine = GlasnostTALEngine(macros)
#context.setVar('talEngine', engine)
engine.locals = getAPIDict()
for k, v in keywords.items():
engine.locals[k] = v
stream = tools.StringIO()
interp = GlasnostTALInterpreter(program, macros, engine, stream=stream, wrap=80)
interp()
return stream.getvalue()
def aliasUrl(alias, action = None, **keywords):
url = X.aliasUrl(alias, action)
for key, value in keywords.items():
url.add(key, value)
return url
def idUrl(id, action = None, **keywords):
url = X.idUrl(id, action)
for key, value in keywords.items():
url.add(key, value)
return url
def roleUrl(role, action = None, **keywords):
url = X.roleUrl(role, action)
for key, value in keywords.items():
url.add(key, value)
return url
def rootUrl():
return X.rootUrl().getAsUrl()
class UrlArgs:
def __init__(self, dict):
self.dict = dict
def hasArg(self, name):
return self.dict.has_key(name)
def getArg(self, name, default=None):
if self.dict.has_key(name):
return self.dict[name]
else:
return default
def __getattr__(self, name):
return self.dict[name]
def cacheDepends(args):
ids = []
for a in args:
if isinstance(a, GlasnostObject):
ids.append(a.objectId)
else:
ids.append(a)
req = context.getVar('req')
req.depends += ids
def exists(varname):
engine = context.getVar('talEngine')
if not engine:
return 0
return (engine.locals.has_key(varname) or engine.globals.has_key(varname))
def getPossibleLanguagesLabelAndUrl(objectId = None, notSelf = 0):
translationsProxy = tools.getProxyForServerRole('translations')
if not objectId:
objectId = context.getVar('objectId')
if objectId:
languages = translationsProxy.getLanguagesForObjectId(objectId)
else:
languages = translationsProxy.getPossibleLanguages()
if notSelf and context.getVar('readLanguages')[0] in languages:
languages.remove(context.getVar('readLanguages')[0])
result = []
cleanedUpUri = tools.cleanUpUnparsedUri([], 'http')
for l in languages:
result.append((l, _(languageLabels[l]),
X.roleUrl('switchLang').add('lang', l).add(
'nextUri', cleanedUpUri)))
return result