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/ObjectsWeb.py

1197 lines
44 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.
__doc__ = """Glasnost Objects Web"""
__version__ = '$Revision$'[11:-2]
import md5
import time
import types
import glasnost.common.context as context
import glasnost.common.faults as faults
import glasnost.common.slots as slots
import glasnost.common.system as system
import glasnost.common.translation as translation
import glasnost.common.tools_new as commonTools
import glasnost.common.xhtmlgenerator as X
from glasnost.proxy.DispatcherProxy import MultiCall
import kinds # Do not remove!
import things
from tools import *
import WebAPI
register = things.register
class BaseObjectWebMixin(things.ThingMixin):
id_kind_stateInEditMode = 'hidden'
id_kind_stateInViewMode = 'hidden'
id_kind_widget_fieldLabel = N_('ID')
id_kind_widgetName = 'InputText'
serverRole_kind_stateInEditMode = 'hidden'
serverRole_kind_stateInViewMode = 'hidden'
version_kind_defaultValue = 0
version_kind_stateInEditMode = 'hidden'
version_kind_stateInViewMode = 'hidden'
version_kind_widget_fieldLabel = N_('Version Number')
version_kind_widgetName = 'InputText'
def getEmbeddedViewLayout(self):
return self.getCompactViewLayout(None, parentSlot = None)
def getLabelTranslated(self, destinationLanguages = None, multiCall = None):
translationsProxy = getProxyForServerRole('translations')
if translationsProxy:
if not destinationLanguages:
destinationLanguages = context.getVar('destinationLanguages')
try:
return translationsProxy.getTranslation(
self.getLabel(), self.getId(), 'self.getLabel()',
self.getLabelLanguage(), destinationLanguages,
multiCall = multiCall)
except faults.UnknownStringDigest:
return self.getLabel()
else:
return self.getLabel()
def getSlotToModifyNames(self, parentSlot = None):
return None # Modify all slots.
def getViewLayoutSlotNames(self, fields, parentSlot = None):
slotNames = things.ThingMixin.getViewLayoutSlotNames(
self, fields, parentSlot = parentSlot)
userToken = context.getVar('userToken', default = '')
if context.getVar('useCompactLayout', default = 0) or (
self.id and not (hasattr(self.getWeb(), 'canModifyObject')
and self.getWeb().canModifyObject(self.id))):
slotNames = slotNames[:]
for slotName in ('language',):
if slotName in slotNames:
slotNames.remove(slotName)
return slotNames
def getWeb(self):
return getWebForServerRole(self.serverRole)
def makeContentTitle(self, contentSlot, contentLabel):
return contentLabel
def newWidget(self, parentSlot = None):
return commonTools.newThing('widget', 'Thing')
class AdminWithoutWritersMixin(BaseObjectWebMixin):
adminsSet_kind_widget_fieldLabel = N_('Administrators')
def newWidget(self, parentSlot = None):
return commonTools.newThing('widget', 'Thing')
class AdminMixin(AdminWithoutWritersMixin):
readersSet_kind_itemKind_value_defaultValue = system.generalPublicId
writersSet_kind_itemKind_value_defaultValue = None
class ObjectWebMixin(BaseObjectWebMixin):
# this class had methods to add an object to another
pass
class WebMixin(things.ThingMixin):
thingCategory = 'web'
class AdministrableWebMixin(WebMixin):
def admin(self):
context.push(_level = 'admin',
defaultDispatcherId = context.getVar('dispatcherId'))
try:
if not self.canGetAdmin():
return accessForbidden()
admin = self.getAdmin()
layout = X.array()
layout += admin.getViewLayout(fields = None)
buttonsBar = X.div(_class = 'buttons-bar')
layout += buttonsBar
navigationButtonsBar = X.span(_class = 'navigation-buttons-bar')
buttonsBar += navigationButtonsBar
navigationButtonsBar += X.buttonStandalone(
'view-list', X.actionUrl())
if self.canModifyAdmin():
actionButtonsBar = X.span(_class = 'action-buttons-bar')
buttonsBar += actionButtonsBar
actionButtonsBar += X.buttonStandalone(
'edit', X.actionUrl('adminEdit'))
finally:
context.pull(_level = 'admin')
return writePageLayout(
layout,_('%s Settings') % _(self.objectsNameCapitalized))
admin.isPublicForWeb = 1
def adminEdit(self):
if not self.isAdmin():
return accessForbidden()
admin = self.getAdmin()
return self.adminObjectEdit(admin)
adminEdit.isPublicForWeb = 1
def adminObjectEdit(self, admin):
context.push(_level = 'adminEdit',
defaultDispatcherId = context.getVar('dispatcherId'),
layoutMode = 'edit')
try:
layout = X.array()
if context.getVar('error'):
layout += admin.getErrorLayout()
form = X.form(
action = X.actionUrl('adminSubmit'),
enctype= 'multipart/form-data', method = 'post')
layout += form
form += admin.getEditLayout(fields = None)
buttonsBar = X.div(_class = 'buttons-bar')
form += buttonsBar
actionButtonsBar = X.span(_class = 'action-buttons-bar')
buttonsBar += actionButtonsBar
actionButtonsBar += X.buttonInForm('modify', 'modifyButton')
finally:
context.pull(_level = 'adminEdit')
return writePageLayout(layout, _('Editing %s Settings') \
% _(self.objectsNameCapitalized))
def adminSubmit(self, **keywords):
uri = None
context.push(_level = 'adminSubmit',
defaultDispatcherId = context.getVar('dispatcherId'))
try:
if keywords is None:
keywords = {}
if not self.isAdmin():
return accessForbidden()
if isButtonSelected('applyButton', keywords):
context.setVar('again', 1)
context.setVar('hideErrors', 1)
admin = self.newAdmin(keywords)
admin.submitFields(keywords)
if context.getVar('again'):
return self.adminObjectEdit(admin)
try:
self.modifyAdmin(admin)
except faults.WrongVersion:
context.setVar('again', 1)
context.setVar('error', 1)
admin.setError('version', 1)
return self.adminObjectEdit(admin)
except:
if context.getVar('debug'):
raise
return accessForbidden()
uri = X.actionUrl('admin')
# The redirect(uri) will be returned by the finally instruction.
finally:
context.pull(_level = 'adminSubmit')
if uri:
return redirect(uri)
adminSubmit.isPublicForWeb = 1
class ObjectsWebMixin(AdministrableWebMixin):
def canViewAll(self, serverId = None):
return hasattr(self, 'canGetObjects') \
and self.canGetObjects(serverId = serverId)
def clone(self, id):
if not id or not self.hasObject(id):
return pageNotFound()
if not self.canCloneObject(id):
return accessForbidden()
object = self.getObject(id)
object.id = None
object.version = 0
return self.editObject(object)
clone.isPublicForWeb = 1
def confirmDelete(self, id):
if id and not self.hasObject(id):
return pageNotFound()
return confirmDelete(
X.idUrl(id, 'delete'),
id = id,
objectName = self.objectName)
confirmDelete.isPublicForWeb = 1
def confirmDelete(self, id):
if id and not self.hasObject(id):
return pageNotFound()
return confirmDelete(
X.idUrl(id, 'delete'),
id = id,
objectName = self.objectName)
confirmDelete.isPublicForWeb = 1
def delete(self, id):
method = context.getVar('httpMethod')
if id and self.hasObject(id):
try:
self.deleteObject(id)
except faults.Fault:
if context.getVar('debug'):
raise
return accessForbidden()
if method == 'DELETE':
return HTTP_NO_CONTENT
uri = X.actionUrl()
return redirect(uri)
else:
# TODO: error page when user tries to delete an object that doesn't
# exist.
return pageNotFound()
delete.isPublicForWeb = 1
def download(self, id, filename = '', path = 'self'):
localId = commonTools.extractLocalId(id)
if localId == '__admin__':
if not self.canGetAdmin():
return accessForbidden()
object = self.getAdmin()
else:
if not self.hasObject(id):
return pageNotFound()
if not self.canGetObject(id):
return accessForbidden()
object = self.getObject(id)
rememberObject(id)
req = context.getVar('req')
uploadSlot = object.getSlotByPath(path)
upload = uploadSlot.getValue()
data = upload.getSlot('data', parentSlot = uploadSlot).getValue()
dataFileName = upload.getSlot(
'dataFileName', parentSlot = uploadSlot).getValue()
if dataFileName:
if not filename:
uri = X.idUrl(id, 'download/%s' % dataFileName).add(
'path', path)
return redirect(uri)
req.headers_out['Content-Disposition'] = \
'inline; filename="%s"' % dataFileName
req.headers_out['Content-Length'] = str(len(data))
req.content_type = upload.getSlot(
'dataType', parentSlot = uploadSlot).getValue()
setHttpCookie()
req.send_http_header()
if req.method == 'HEAD':
return OK
req.write(data)
return OK
download.isPublicForWeb = 1
def edit(self, id = ''):
if id and not self.hasObject(id):
return pageNotFound()
if id:
if not self.canModifyObject(id):
return accessForbidden()
object = self.getObject(id)
rememberObject(id)
else:
if not self.canAddObject():
return accessForbidden()
object = self.newObject(None)
if not object.id:
object.fillWithDefaultValues()
return self.editObject(object)
edit.isPublicForWeb = 1
def editObject(self, object):
if not object.id:
headerTitle = _(self.newObjectNameCapitalized)
else:
headerTitle = _('Editing %s - %s') % (
_(self.objectNameCapitalized), object.getLabel())
if context.getVar('headerTitle'):
headerTitle = context.getVar('headerTitle')
context.push(_level = 'edit',
isCreateEditMode = not object.id,
layoutMode = 'edit')
try:
layout = X.array()
leadIn = self.getEditLeadIn(object)
if leadIn:
layout += X.enclose(leadIn, _class = 'lead-in')
if context.getVar('error'):
layout += object.getErrorLayout()
form = X.form(action = X.actionUrl('submit'),
enctype = 'multipart/form-data', method = 'post')
layout += form
if context.getVar('nextUri'):
form += X.input(name = 'nextUri', type = 'hidden',
value = context.getVar('nextUri'))
slot = slots.Root(object)
widget = slot.getWidget()
form += widget.getModelPageBodyLayout(slot, fields = None)
buttonsBar = X.div(_class = 'buttons-bar')
form += buttonsBar
actionButtonsBar = X.span(_class = 'action-buttons-bar')
buttonsBar += actionButtonsBar
if not object.id:
actionButtonsBar += X.buttonInForm('create', 'createButton')
else:
# The button Delete is also added here, so that the user can
# delete the object he is editing without having to make it
# valid, clic modify and then delete it.
if self.canDeleteObject(object.id):
actionButtonsBar += X.buttonStandalone(
'delete', X.idUrl(object.id, 'confirmDelete'))
actionButtonsBar += X.buttonInForm('modify', 'modifyButton')
return writePageLayout(layout, headerTitle)
finally:
context.pull(_level = 'edit')
def getEditLeadIn(self, object):
return None
def getObjectsLayout(self, partialObjects, objectIds,
slotNames = None):
layout = None
translationsProxy = getProxyForServerRole('translations')
if len(partialObjects) > 0:
if translationsProxy:
labelsMultiCall = MultiCall()
for objectId in objectIds:
partialObjects[objectId].getLabelTranslated(
context.getVar('readLanguages'),
multiCall = labelsMultiCall)
layout = X.array()
if slotNames:
table = X.table(_class = 'objects-table')
layout += table
partialObject = partialObjects.values()[0]
thead = X.thead()
table += thead
tr = X.tr()
thead += tr
tr += X.th()(X.nbsp)
for slotName in slotNames:
slot = partialObject.getSlot(slotName)
tr += slot.getWidget().getHtmlColumnLabel(slot)
tbody = X.tbody()
table += tbody
even = 0
else:
ul = X.ul()
layout += ul
if translationsProxy:
lazyLabels = labelsMultiCall.call()
else:
lazyLabels = objectIds # fastest way to get a list of same len
for objectId, lazyLabel in zip(objectIds, lazyLabels):
if translationsProxy:
try:
label = lazyLabel()
except faults.UnknownStringDigest:
label = partialObjects[objectId].getLabel()
else:
label = partialObjects[objectId].getLabel()
partialObject = partialObjects[objectId]
fields = {}
if slotNames:
tr = X.tr(_class = ((even and 'even') or 'odd'))
even = not even
tbody += tr
tr += X.td()(
X.a(href = X.idUrl(partialObject.id))(label))
context.push(inForm = 0,
readOnly = 0)
try:
for slotName in slotNames:
slot = partialObject.getSlot(slotName)
widget = slot.getWidget()
tr += widget.getHtmlColumnValue(slot, fields)
finally:
context.pull()
else:
ul += X.li()(
X.a(href = X.idUrl(partialObject.id))(label))
return layout
def getObjectsSectionLayout(self, partialObjects, intertitle,
slotNames = None):
layout = None
translationsProxy = getProxyForServerRole('translations')
if len(partialObjects) > 0:
if translationsProxy:
labelsMultiCall = MultiCall()
for partialObject in partialObjects:
partialObject.getLabelTranslated(
context.getVar('readLanguages'),
multiCall = labelsMultiCall)
layout = X.array(X.h2()(intertitle))
table = X.table(_class = 'objects-table')
layout += table
partialObject = partialObjects[0]
if slotNames:
thead = X.thead()
table += thead
tr = X.tr()
thead += tr
tr += X.th()(X.nbsp)
for slotName in slotNames:
slot = partialObject.getSlot(slotName)
tr += slot.getWidget().getHtmlColumnLabel(slot)
tbody = X.tbody()
table += tbody
else:
tbody = table
even = 0
if translationsProxy:
lazyLabels = labelsMultiCall.call()
else:
lazyLabels = partialObjects # fastest way to get a list of same len
for partialObject, lazyLabel in zip(partialObjects, lazyLabels):
if translationsProxy:
label = lazyLabel()
else:
label = partialObject.getLabel()
fields = {}
tr = X.tr(_class = ((even and 'even') or 'odd'))
even = not even
tbody += tr
tr += X.td()(X.a(href = X.idUrl(partialObject.id))(label))
if slotNames:
context.push(inForm = 0,
readOnly = 0)
try:
for slotName in slotNames:
slot = partialObject.getSlot(slotName)
widget = slot.getWidget()
tr += widget.getHtmlColumnValue(slot, fields)
finally:
context.pull()
layout += X.br()
return layout
def getSortedIds(self, objects):
translationsProxy = getProxyForServerRole('translations')
labels = {}
ids = objects.keys()
if not translationsProxy:
for k, v in objects.items():
labels[k] = v.getLabel()
else:
objectsByDispatcherId = {}
for id, object in objects.items():
dispatcherId = commonTools.extractDispatcherId(id)
if not objectsByDispatcherId.has_key(dispatcherId):
objectsByDispatcherId[dispatcherId] = {}
objectsByDispatcherId[dispatcherId][id] = object
readLanguages = context.getVar('readLanguages')
for sameDispatcherObjects in objectsByDispatcherId.values():
labelsMultiCall = MultiCall()
sameDispatcherIds = []
for id, object in sameDispatcherObjects.items():
sameDispatcherIds.append(id)
object.getLabelTranslated(
readLanguages, multiCall = labelsMultiCall)
for id, lazyLabel in zip(sameDispatcherIds,
labelsMultiCall.call()):
try:
labels[id] = lazyLabel()
except faults.UnknownStringDigest:
labels[id] = objects[id].getLabel()
ids.sort(lambda id1, id2, labels = labels:
locale.strcoll(labels[id1], labels[id2]))
return ids
def getViewAboveButtonsBarLayout(self, object, fields):
return None
def getViewActionButtonsBarLayout(self, object, fields):
layout = X.array()
if self.canDeleteObject(object.id):
layout += X.buttonStandalone(
'delete', X.idUrl(object.id, 'confirmDelete'))
if self.canCloneObject(object.id):
layout += X.buttonStandalone(
'clone', X.idUrl(object.id, 'clone'))
if self.canModifyObject(object.id):
layout += X.buttonStandalone('edit', X.idUrl(object.id, 'edit'))
return layout
def getViewAllActionButtonsBarLayout(self):
layout = X.array()
if self.canAddObject():
layout += X.buttonStandalone('new', X.actionUrl('edit'))
return layout
def getViewAllButtonsBarLayout(self):
layout = X.div(_class = 'buttons-bar')
layout += X.span(_class = 'navigation-buttons-bar')(
self.getViewAllNavigationButtonsBarLayout())
layout += X.span(_class = 'other-action-buttons-bar')(
self.getViewAllOtherActionButtonsBarLayout())
layout += X.span(_class = 'action-buttons-bar')(
self.getViewAllActionButtonsBarLayout())
return layout
def getViewAllLeadIn(self):
return None
def getViewAllNavigationButtonsBarLayout(self):
layout = X.array()
userToken = context.getVar('userToken')
if self.canModifyAdmin() and userToken:
layout += X.buttonStandalone('settings', X.actionUrl('admin'))
return layout
def getViewAllOtherActionButtonsBarLayout(self):
return None
def getViewBelowButtonsBarLayout(self, object, fields):
if hasattr(self, 'addComment') and \
'comments' in context.getVar('knownRoles'):
return getWebForServerRole(
'comments').getBothCommentsLayout(object.id)
return None
def getViewButtonsBarLayout(self, object, fields):
layout = X.div(_class = 'buttons-bar')
buttons = self.getViewNavigationButtonsBarLayout(object, fields)
if buttons:
layout += X.span(_class = 'navigation-buttons-bar')(buttons)
buttons = self.getViewOtherActionButtonsBarLayout(object, fields)
if buttons:
layout += X.span(_class = 'other-action-buttons-bar')(buttons)
buttons = self.getViewActionButtonsBarLayout(object, fields)
if buttons:
layout += X.span(_class = 'action-buttons-bar')(buttons)
if not layout.children:
return None
return layout
def getViewLeadIn(self, object):
return None
def getViewNavigationButtonsBarLayout(self, object, fields):
layout = X.array()
userToken = context.getVar('userToken', default = '')
if userToken:
layout += X.buttonStandalone('view-list', X.actionUrl())
return layout
def getViewOtherActionButtonsBarLayout(self, object, fields):
return None
def id(self, id):
if not self.hasObject(id):
return pageNotFound()
if not self.canGetObject(id):
return accessForbidden()
object = self.getObject(id)
return writePageLayout(
X.p(id),
_('Id for "%s"') % object.getLabel())
id.isPublicForWeb = 1
image = download
image.isPublicForWeb = 1
def imageEdit(self, id = '', path = ''):
if id:
localId = commonTools.extractLocalId(id)
if localId == '__admin__':
if not self.canModifyAdmin():
return accessForbidden()
object = self.getAdmin()
else:
if not self.hasObject(id):
return pageNotFound()
if not self.canModifyObject(id):
return accessForbidden()
object = self.getObject(id)
rememberObject(id)
else:
if not self.canAddObject():
return accessForbidden()
object = self.newObject()
uploadSlot = object.getSlotByPath(path)
upload = uploadSlot.getValue()
data = upload.getSlot('data', parentSlot = uploadSlot).getValue()
req = context.getVar('req')
dataFileName = upload.getSlot(
'dataFileName', parentSlot = uploadSlot).getValue()
if dataFileName:
req.headers_out['Content-disposition'] = \
'attachment; filename="%s"' % dataFileName
req.headers_out['Content-length'] = str(len(data))
req.content_type = upload.getSlot(
'dataType', parentSlot = uploadSlot).getValue()
setHttpCookie()
req.send_http_header()
if req.method == 'HEAD':
return OK
req.write(data)
return OK
imageEdit.isPublicForWeb = 1
def rss(self):
lastObjects = self.getLastObjects(20, None, None, None)
req = context.getVar('req')
req.content_type = 'application/rss+xml'
req.send_http_header()
if req.caching:
req.openCachePage()
req.write("""\
<?xml version="1.0" encoding="iso-8859-15"?>
<rss version="2.0"
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:content="http://purl.org/rss/1.0/modules/content/">
<channel>
<title>%(websiteTitle)s (%(objectsName)s)</title>
<link>http://%(websiteUrl)s</link>
""" % {
'websiteTitle': context.getVar('virtualHost').getLabel(),
'websiteUrl': context.getVar('virtualHost').hostName,
'objectsName': _(self.objectsNameCapitalized),
})
# Workaround Python Emacs mode bug: """
for object in lastObjects:
req.write("""\
<item>
<title>%s</title>
<dc:language>%s</dc:language>
<link>%s</link>
</item>
""" % (
xmlEncode(object.getLabel()),
object.language,
X.idUrl(object.id).getAsAbsoluteUrl()))
req.write("""\
</channel>
</rss>
""")
if req.caching:
req.closeCachePage()
return OK
rss.isPublicForWeb = 1
def search(self, slotNames = None, **keywords):
if 'terms' in keywords.keys():
terms = keywords['terms']
del keywords['terms']
terms = terms.split(' ')
object = self.newObject(keywords)
allSlotNames = object.getSlotNames()
for slotName in ['serverRole', 'thingName', 'thingCategory']:
if slotName in allSlotNames:
allSlotNames.remove(slotName)
for slotName in allSlotNames:
kind = object.getSlot(slotName).getKind()
if kind.__class__.__name__ == 'String':
keywords['%s_PT' % slotName] = terms
for key in keywords.keys():
if not '_' in key:
del keywords[key]
if type(slotNames) is not types.ListType:
slotNames = None
if not self.canGetObjects():
return accessForbidden()
if slotNames:
objects = self.searchPartialObjects(requiredSlotNames = slotNames,
**keywords)
else:
objects = self.searchObjects(**keywords)
layout = X.array()
ids = self.getSortedIds(objects)
layout += self.getObjectsLayout(objects, ids, slotNames = slotNames)
layout += self.getViewAllButtonsBarLayout()
title = _(self.objectsNameCapitalized) + ' ' + _('Search Results')
return writePageLayout(layout, title)
search.isPublicForWeb = 1
def submit(self, id = '', **keywords):
if keywords is None:
keywords = {}
if id and not self.hasObject(id):
return pageNotFound()
keywords['id'] = id
if isButtonSelected('applyButton', keywords):
context.setVar('again', 1)
context.setVar('hideErrors', 1)
object = self.newObject(keywords)
object.submitFields(keywords)
if context.getVar('again'):
return self.editObject(object = object)
try:
if not id:
result = self.submitAddObject(object)
else:
result = self.submitModifyObject(object)
except:
if context.getVar('debug'):
raise
return accessForbidden() # TODO: return failure ?
if result:
return result
if context.getVar('nextUri'):
return redirect(context.getVar('nextUri'))
return redirect(X.idUrl(object.id))
submit.isPublicForWeb = 1
def submitAddObject(self, object):
try:
object.id = self.addObject(object)
except faults.UserAccessDenied:
if context.getVar('debug'):
raise
return accessForbidden()
def submitModifyObject(self, object):
try:
self.modifyPartialObject(object, object.getSlotToModifyNames())
except faults.WrongVersion:
context.setVar('again', 1)
context.setVar('error', 1)
object.setError('version', 1)
return self.editObject(object)
except faults.UserAccessDenied:
return accessForbidden()
def thumbnail(self, id, path, width = '', height = ''):
localId = commonTools.extractLocalId(id)
if localId == '__admin__':
if not self.canGetAdmin():
return accessForbidden()
object = self.getAdmin()
else:
if not self.hasObject(id):
return pageNotFound()
if not self.canGetObject(id):
return accessForbidden()
object = self.getObject(id)
rememberObject(id)
try:
width = int(width)
except ValueError:
width = 128
try:
height = int(height)
except ValueError:
height = 128
uploadSlot = object.getSlotByPath(path)
upload = uploadSlot.getValue()
data = upload.getSlot('data', parentSlot = uploadSlot).getValue()
if data and upload.isType('image'):
import cStringIO
# From Python Imaging Library.
try:
import Image as PILImage
except ImportError:
PILImage = None
if PILImage:
imageFile = cStringIO.StringIO(data)
imageObject = PILImage.open(imageFile)
imageObject.thumbnail((width, height))
thumbnailFile = cStringIO.StringIO()
imageObject.save(thumbnailFile, imageObject.format)
data = thumbnailFile.getvalue()
width, height = imageObject.size
req = context.getVar('req')
dataFileName = upload.getSlot(
'dataFileName', parentSlot = uploadSlot).getValue()
if dataFileName:
req.headers_out['Content-disposition'] = \
'attachment; filename="%s"' % dataFileName
req.headers_out['Content-length'] = str(len(data))
req.content_type = upload.getSlot(
'dataType', parentSlot = uploadSlot).getValue()
setHttpCookie()
req.send_http_header()
if req.method == 'HEAD':
return OK
req.write(data)
return OK
thumbnail.isPublicForWeb = 1
def translation(self, id, language):
translationsProxy = getProxyForServerRole('translations')
if not translationsProxy:
return pageNotFound
object = self.getObject(id)
title = _('Translation')
title += ' (%s -> %s)' % (
_(translation.languageLabels[object.language]),
_(translation.languageLabels[language]))
context.push(_level = 'translation', layoutMode = 'edit')
try:
form = X.form(
action = X.idUrl(id, 'translationSubmit/%s' % language),
enctype= 'multipart/form-data', method = 'post')
for slotName in object.getLayoutSlotNames(None):
slot = object.getSlot(slotName)
kind = slot.getKind()
widget = slot.getWidget()
if not kind.isTranslatable:
continue
if not slot.getValue():
continue
stringTranslated, destinationLanguage, stringState = \
translationsProxy.getTranslationInfos(
slot.getValue() or '', object.id, slot.getPath(),
object.getLanguage(), [language])
if stringState not in ('translated', 'fuzzy', 'obsolete'):
stringTranslated = ''
row = X.div(_class = 'row')
form += row
row += X.span(_class = 'label')(
_(widget.getModelLabel(slot)) + ' (%s):' % object.getLanguage())
kind.isTranslatable = 0
widget.viewInTextArea = 1 # FIXME: not clean
cell = X.enclose(widget.getHtmlViewValue(slot, None), _class = 'cell')
del(widget.viewInTextArea)
kind.isTranslatable = 1
row += cell
row = X.div(_class = 'row')
form += row
row += X.span(_class = 'label')(
_(widget.getModelLabel(slot)) + ' (%s):' % language)
widget.preview = 0 # FIXME: not clean
class NotTotallyDummy(slots.Dummy):
def getFieldName(self):
return self.fieldName
dummySlot = NotTotallyDummy(kind)
dummySlot.fieldName = slot.getFieldName()
cell = X.enclose(widget.getHtmlFormValue(dummySlot, None),
_class = 'cell')
del(widget.preview)
row += cell
buttonsBar = X.div(_class = 'buttons-bar')
form += buttonsBar
actionButtonsBar = X.span(_class = 'action-buttons-bar')
buttonsBar += actionButtonsBar
actionButtonsBar += X.buttonInForm('translate', 'translateButton')
return writePageLayout(form, title)
finally:
context.pull(_level = 'translation')
translation.isPublicForWeb = 1
def translationSubmit(self, id, language, **keywords):
translationsProxy = getProxyForServerRole('translations')
if not translationsProxy:
return pageNotFound
object = self.getObject(id)
transObject = self.newObject()
transObject.submitFields(keywords)
for slotName in object.getLayoutSlotNames(None):
slot = object.getSlot(slotName)
kind = slot.getKind()
widget = slot.getWidget()
if not kind.isTranslatable:
continue
if not slot.getValue():
continue
transSlot = transObject.getSlot(slotName)
if not transSlot.getValue():
continue
localization = commonTools.newThing('object',
'translations.Localization')
localization.sourceStringDigest = \
md5.new(slot.getValue().replace('\r\n', '\n')).hexdigest()
localization.destinationLanguage = language
localization.destinationString = transSlot.getValue()
localization.isFuzzy = 0
localization.sourceString = object.title
localization.sourceLanguage = object.language
localization.isTranslatable = 1
try:
translationsProxy.modifyLocalization(localization)
except Fault, fault:
return accessForbidden()
return redirect(X.idUrl(object.id))
translationSubmit.isPublicForWeb = 1
def use(self, id):
return self.view(id)
use.isPublicForWeb = 1
def view(self, id):
if not self.hasObject(id):
return pageNotFound()
if not self.canGetObject(id):
return accessForbidden()
object = self.getObject(id)
rememberObject(id)
label = object.getLabelTranslated(context.getVar('readLanguages'))
layout = X.array()
leadIn = self.getViewLeadIn(object)
if leadIn:
layout += X.enclose(leadIn, _class = 'lead-in')
slot = slots.Root(object)
widget = slot.getWidget()
layout += widget.getModelPageBodyLayout(slot, None)
pageTitle = context.getVar('pageTitle', default = None)
layout += self.getViewAboveButtonsBarLayout(object, None)
layout += self.getViewButtonsBarLayout(object, None)
layout += self.getViewBelowButtonsBarLayout(object, None)
context.push(
currentObject = WebAPI.GlasnostObject(object = object),
)
if not pageTitle:
pageTitle = '%s - %s' % (_(self.objectNameCapitalized), label)
layout = writePageLayout(layout, pageTitle)
context.pull()
return layout
view.isPublicForWeb = 1
def viewAll(self, slotNames = None):
if type(slotNames) is not types.ListType:
slotNames = None
context.push(_level = 'viewAll',
defaultDispatcherId = context.getVar('dispatcherId'))
try:
if not self.canGetObjects():
return accessForbidden()
objects = self.getObjects()
layout = X.array()
leadIn = self.getViewAllLeadIn()
if leadIn:
layout += X.enclose(leadIn, _class = 'lead-in')
ids = self.getSortedIds(objects)
layout += self.getObjectsLayout(
objects, ids, slotNames = slotNames)
layout += self.getViewAllButtonsBarLayout()
finally:
context.pull(_level = 'viewAll')
return writePageLayout(layout, _(self.objectsNameCapitalized))
viewAll.isPublicForWeb = 1
def viewAllPy(self, **keywords):
context.push(_level = 'viewAllPy',
defaultDispatcherId = context.getVar('dispatcherId'))
try:
keywords['objects'] = [WebAPI.GlasnostObject(id)
for id in self.getObjectIds()]
finally:
context.pull(_level = 'viewAllPy')
req = context.getVar('req')
keywords['req'] = req
stdO = sys.stdout
sys.stdout = req
try:
execfile(context.getVar('PyFile'), keywords)
sys.stdout = stdO
except:
sys.stdout = stdO
raise apache.SERVER_RETURN, HTTP_INTERNAL_SERVER_ERROR
return OK
def viewAllTal(self, **keywords):
context.push(_level = 'viewAllTal',
defaultDispatcherId = context.getVar('dispatcherId'))
try:
keywords['objects'] = [WebAPI.GlasnostObject(id)
for id in self.getObjectIds()]
finally:
context.pull(_level = 'viewAllTal')
file = context.getVar('TALFile')
return processTALFile(
'',
xtal = context.getVar('TALFileIsXTAL'),
file = file,
**keywords)
def viewTal(self, id, **keywords):
if not self.hasObject(id):
return pageNotFound()
if not self.canGetObject(id):
return accessForbidden()
file = context.getVar('TALFile')
keywords['currentObject'] = WebAPI.GlasnostObject(id)
rememberObject(id)
return processTALFile(
'',
xtal = context.getVar('TALFileIsXTAL'),
file = file,
**keywords)
def viewPy(self, id, **keywords):
req = context.getVar('req')
keywords['currentObject'] = WebAPI.GlasnostObject(id)
keywords['req'] = context.req
for k, v in getTemplateVars().items():
keywords[k] = v
rememberObject(id)
stdO = sys.stdout
sys.stdout = req
try:
execfile(context.getVar('PyFile'), keywords)
sys.stdout = stdO
except:
sys.stdout = stdO
raise apache.SERVER_RETURN, HTTP_INTERNAL_SERVER_ERROR
return OK
class CommentableObjectMixin(things.ThingMixin):
def addComment(self, id):
if not self.hasObject(id):
return pageNotFound()
webRole = getWebForServerRole('comments')
if not webRole:
return pageNotFound()
object = webRole.newObject(None)
object.fillWithDefaultValues()
return self.addCommentObject(id, object)
addComment.isPublicForWeb = 1
def addCommentObject(self, id, object):
webRole = getWebForServerRole('comments')
object.parentId = id
context.push(_level = 'edit', layoutMode = 'edit')
try:
layout = X.array()
leadIn = webRole.getEditLeadIn(object)
if leadIn:
layout += X.enclose(leadIn, _class = 'lead-in')
if context.getVar('error'):
layout += object.getErrorLayout()
form = X.form(action = X.idUrl(id, 'addCommentSubmit'),
enctype = 'multipart/form-data', method = 'post')
layout += form
slot = slots.Root(object)
widget = slot.getWidget()
form += widget.getModelPageBodyLayout(slot, None)
buttonsBar = X.div(_class = 'buttons-bar')(
X.buttonInForm('add', 'addButton'))
form += buttonsBar
return writePageLayout(layout, _(webRole.newObjectNameCapitalized))
finally:
context.pull(_level = 'edit')
def addCommentSubmit(self, id, **keywords):
if keywords is None:
keywords = {}
webRole = getWebForServerRole('comments')
object = webRole.newObject(keywords)
object.submitFields(keywords)
object.parentId = id
if context.getVar('again'):
return self.addCommentObject(id, object)
try:
webRole.submitAddObject(object)
except:
if context.getVar('debug'):
raise
return accessForbidden()
return redirect(X.idUrl(id))
addCommentSubmit.isPublicForWeb = 1