1306 lines
48 KiB
Python
1306 lines
48 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 confirmMakeVersionCurrent(self, id, versionNumber):
|
|
layout = X.array()
|
|
object = self.getObject(id)
|
|
layout += X.p(_('Are you sure you want to replace the current version (%s) of "%s" by this previous version (%s) ?') % (object.version, object.getLabel(), versionNumber))
|
|
layout += X.div(_class = 'buttons-bar')(
|
|
X.buttonStandalone('replace',
|
|
X.idUrl(id, 'makeVersionCurrent/%s' % versionNumber)),
|
|
X.buttonStandalone('cancel',
|
|
X.idUrl(id, 'version/%s' % versionNumber)) )
|
|
return writePageLayout(layout, _('Confirm Replacement'))
|
|
confirmMakeVersionCurrent.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 diff(self, id, newVersionNumber, oldVersionNumber = ''):
|
|
newVersionNumber = int(newVersionNumber)
|
|
if oldVersionNumber:
|
|
oldVersionNumber = int(oldVersionNumber)
|
|
else:
|
|
oldVersionNumber = newVersionNumber - 1
|
|
newObject = self.getObjectWithVersion(id, int(newVersionNumber))
|
|
oldObject = self.getObjectWithVersion(id, int(oldVersionNumber))
|
|
|
|
slotNames = newObject.getLayoutSlotNames(None)
|
|
if 'modificationTime' in slotNames:
|
|
slotNames.remove('modificationTime')
|
|
slotNames.insert(slotNames.index('version')+1, 'modificationTime')
|
|
layout = X.array()
|
|
for slotName in slotNames:
|
|
newObjectSlot = newObject.getSlot(slotName)
|
|
newValue = newObjectSlot.getValue()
|
|
oldObjectSlot = oldObject.getSlot(slotName)
|
|
oldValue = oldObjectSlot.getValue()
|
|
|
|
if newValue == oldValue:
|
|
continue
|
|
|
|
widget = newObjectSlot.getWidget()
|
|
newObjectSlot.getKind().isTranslatable = 0
|
|
oldObjectSlot.getKind().isTranslatable = 0
|
|
diffValue = widget.getHtmlViewDiffValue(
|
|
oldObjectSlot, newObjectSlot)
|
|
|
|
row = X.div(_class = 'field')
|
|
layout += row
|
|
row += X.span(_class = 'label')(
|
|
_(widget.getModelLabel(newObjectSlot)))
|
|
cell = X.enclose(diffValue, _class = 'cell')
|
|
row += cell
|
|
|
|
return writePageLayout(layout,
|
|
_('%s - Differences between versions') % newObject.getLabel())
|
|
diff.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'] = \
|
|
'attachment; filename="%s"' % dataFileName
|
|
# voodoo solution so that the right filename is used in MSIE
|
|
# (from <http://groups.google.com/groups?selm=
|
|
# pan.2003.12.11.14.18.31.315803%40ezglkhzglihzrhg.com>)
|
|
req.headers_out['Cache-Control'] = ''
|
|
req.headers_out['Pragma'] = ''
|
|
|
|
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())
|
|
layout += X.buttonStandalone(
|
|
'history', X.idUrl(object.id, 'history'))
|
|
return layout
|
|
|
|
def getViewOtherActionButtonsBarLayout(self, object, fields):
|
|
return None
|
|
|
|
def history(self, id):
|
|
revisions = self.getRevisionsInfos(id)
|
|
revisions.reverse()
|
|
object = self.getObject(id)
|
|
label = object.getLabelTranslated(context.getVar('readLanguages'))
|
|
pageTitle = '%s - %s - %s' % (
|
|
_('History'), _(self.objectNameCapitalized), label)
|
|
if not revisions:
|
|
layout = X.p(_("""No revision informations are available for this object."""))
|
|
return writePageLayout(layout, pageTitle)
|
|
table = X.table()
|
|
table += X.tr(
|
|
X.th(_('Date')),
|
|
X.th(_('User')),
|
|
X.th(''))
|
|
for revision in revisions:
|
|
revisionTime = time.strftime('%Y-%m-%d %H:%M:%S',
|
|
time.localtime(revision['time']))
|
|
if revision['userId']:
|
|
userLabel = X.objectHypertextLabel(revision['userId'])
|
|
else:
|
|
userLabel = _('Unknown')
|
|
td = X.td(X.buttonStandalone('version',
|
|
X.idUrl(id,
|
|
'version/%d' % revision['version'])))
|
|
if revision is not revisions[-1]:
|
|
td += X.buttonStandalone('diff',
|
|
X.idUrl(id, 'diff/%d' % revision['version']))
|
|
table += X.tr(
|
|
X.td(revisionTime),
|
|
X.td(userLabel),
|
|
td)
|
|
return writePageLayout(table, pageTitle)
|
|
history.isPublicForWeb = 1
|
|
|
|
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 makeVersionCurrent(self, id, versionNumber):
|
|
oldObject = self.getObjectWithVersion(id, int(versionNumber))
|
|
currentObject = self.getObject(id)
|
|
oldObject.version = currentObject.version
|
|
self.modifyObject(oldObject)
|
|
return redirect(X.idUrl(id))
|
|
makeVersionCurrent.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 = 'field')
|
|
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 = 'field')
|
|
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 version(self, id, versionNumber):
|
|
#return self.viewObject(object)
|
|
object = self.getObjectWithVersion(id, int(versionNumber))
|
|
slot = slots.Root(object)
|
|
widget = slot.getWidget()
|
|
layout = widget.getModelPageBodyLayout(slot, None)
|
|
buttonsBar = X.div(_class = 'buttons-bar')
|
|
layout += buttonsBar
|
|
buttonsBar += X.buttonStandalone('history', X.idUrl(id, 'history'))
|
|
buttonsBar += X.buttonStandalone(_('Make this version current'),
|
|
X.idUrl(id, 'confirmMakeVersionCurrent/%s' % versionNumber))
|
|
return writePageLayout(layout,
|
|
_('%s - Version %d') % (object.getLabel(), object.version))
|
|
version.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)
|
|
return self.viewObject(object)
|
|
view.isPublicForWeb = 1
|
|
|
|
def viewObject(self, object):
|
|
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
|
|
|
|
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
|
|
|