842 lines
31 KiB
Python
842 lines
31 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 Cards Web"""
|
|
|
|
__version__ = '$Revision$'[11:-2]
|
|
|
|
|
|
import cPickle
|
|
|
|
import glasnost.common.context as context
|
|
import glasnost.common.faults as faults
|
|
from glasnost.common.ObjectsCommon import ObjectCommon
|
|
import glasnost.common.slots as slots
|
|
import glasnost.common.system as system
|
|
import glasnost.common.tools_new as commonTools
|
|
import glasnost.common.xhtmlgenerator as X
|
|
|
|
from glasnost.proxy.CardsProxy import *
|
|
|
|
from ObjectsWeb import register, AdminMixin, BaseObjectWebMixin, ObjectsWebMixin
|
|
import properties
|
|
import things
|
|
from tools import *
|
|
|
|
|
|
class Command:
|
|
action = None
|
|
nextModeName = None
|
|
nextObjectId = None
|
|
|
|
def getNextUrl(self):
|
|
return X.idUrl(self.nextObjectId, action = self.nextModeName)
|
|
|
|
|
|
class AdminCards(AdminMixin, AdminCards):
|
|
pass
|
|
register(AdminCards)
|
|
|
|
|
|
class AbstractCard(BaseObjectWebMixin, Card):
|
|
def getEditModeUsersSet(self):
|
|
if self.editModeUsersSet is not None:
|
|
return self.editModeUsersSet
|
|
prototypes = self.getC3PrototypeLinearization()
|
|
for prototype in prototypes:
|
|
if prototype.editModeUsersSet is not None:
|
|
return prototype.editModeUsersSet
|
|
return [system.generalPublicId]
|
|
|
|
def getRequiredFieldSlotNames(self, fields, parentSlot = None):
|
|
allSlotNames = ObjectCommon.getSlotNames(self, parentSlot = parentSlot)
|
|
orderedSlotNames = self.getOrderedFieldSlotNames(
|
|
fields, parentSlot = parentSlot)
|
|
slotNames = []
|
|
for slotName in orderedSlotNames:
|
|
if not slotName in allSlotNames:
|
|
continue
|
|
slotNames.append(slotName)
|
|
for slotName in allSlotNames:
|
|
if slotName in slotNames:
|
|
continue
|
|
slotNames.append(slotName)
|
|
return slotNames
|
|
|
|
def getRequiredLayoutSlotNames(self, fields, parentSlot = None):
|
|
# Skip properties slots.
|
|
allSlotNames = ObjectCommon.getSlotNames(self, parentSlot = parentSlot)
|
|
orderedSlotNames = self.getOrderedLayoutSlotNames(
|
|
parentSlot = parentSlot)
|
|
slotNames = []
|
|
for slotName in orderedSlotNames:
|
|
if not slotName in allSlotNames:
|
|
continue
|
|
slotNames.append(slotName)
|
|
for slotName in allSlotNames:
|
|
if slotName in slotNames:
|
|
continue
|
|
slotNames.append(slotName)
|
|
return slotNames
|
|
|
|
def getViewModeUsersSet(self):
|
|
if self.viewModeUsersSet is not None:
|
|
return self.viewModeUsersSet
|
|
prototypes = self.getC3PrototypeLinearization()
|
|
for prototype in prototypes:
|
|
if prototype.viewModeUsersSet is not None:
|
|
return prototype.viewModeUsersSet
|
|
return [system.generalPublicId]
|
|
|
|
|
|
class Card(AbstractCard):
|
|
pass
|
|
register(Card)
|
|
|
|
|
|
class CardForDefinition(AbstractCard):
|
|
thingName = 'Card'
|
|
|
|
def getFieldSlotNames(self, fields, parentSlot = None):
|
|
allSlotNames = ObjectCommon.getSlotNames(self, parentSlot = parentSlot)
|
|
orderedSlotNames = self.getOrderedFieldSlotNames(
|
|
fields, parentSlot = parentSlot)
|
|
slotNames = []
|
|
for slotName in orderedSlotNames:
|
|
if not slotName in allSlotNames:
|
|
continue
|
|
slotNames.append(slotName)
|
|
for slotName in allSlotNames:
|
|
if slotName in slotNames:
|
|
continue
|
|
slotNames.append(slotName)
|
|
return slotNames
|
|
|
|
def getLayoutSlotNames(self, fields, parentSlot = None):
|
|
# Skip properties slots.
|
|
allSlotNames = ObjectCommon.getSlotNames(self, parentSlot = parentSlot)
|
|
orderedSlotNames = self.getOrderedLayoutSlotNames(
|
|
parentSlot = parentSlot)
|
|
slotNames = []
|
|
for slotName in orderedSlotNames:
|
|
if not slotName in allSlotNames:
|
|
continue
|
|
slotNames.append(slotName)
|
|
for slotName in allSlotNames:
|
|
if slotName in slotNames:
|
|
continue
|
|
slotNames.append(slotName)
|
|
return slotNames
|
|
|
|
## def getSlotNames(self, parentSlot = None):
|
|
## return ObjectCommon.getSlotNames(self, parentSlot = parentSlot)
|
|
|
|
def getSlotToModifyNames(self, parentSlot = None):
|
|
return ObjectCommon.getSlotNames(self, parentSlot = parentSlot)
|
|
|
|
def makeContentTitle(self, contentSlot, contentLabel):
|
|
return X.a(href = X.idUrl(
|
|
self.id, 'definition/%s' % contentSlot.getPath()))(
|
|
contentLabel)
|
|
|
|
|
|
class CardForUse(AbstractCard):
|
|
_c3PrototypeLinearization = None
|
|
|
|
class defaultImplementModeName_kindClass(
|
|
AbstractCard.defaultImplementModeName_kindClass):
|
|
importExport = 'from-server-only'
|
|
stateInEditMode = 'hidden'
|
|
stateInViewMode = 'hidden'
|
|
|
|
class defaultListModeName_kindClass(
|
|
AbstractCard.defaultListModeName_kindClass):
|
|
importExport = 'from-server-only'
|
|
stateInEditMode = 'hidden'
|
|
stateInViewMode = 'hidden'
|
|
|
|
class defaultModeName_kindClass(AbstractCard.defaultModeName_kindClass):
|
|
importExport = 'from-server-only'
|
|
stateInEditMode = 'hidden'
|
|
stateInViewMode = 'hidden'
|
|
|
|
draftKey = None
|
|
class draftKey_kindClass:
|
|
_kindName = 'PythonIdentifier'
|
|
importExport = 'private'
|
|
isRequiredInEditMode = 1
|
|
stateInEditMode = 'hidden'
|
|
stateInViewMode = 'hidden'
|
|
|
|
class editMode_kindClass(AbstractCard.editMode_kindClass):
|
|
importExport = 'from-server-only'
|
|
stateInEditMode = 'hidden'
|
|
stateInViewMode = 'hidden'
|
|
|
|
class editModeUsersSet_kindClass(AbstractCard.editModeUsersSet_kindClass):
|
|
importExport = 'from-server-only'
|
|
stateInEditMode = 'hidden'
|
|
stateInViewMode = 'hidden'
|
|
|
|
class modes_kindClass(AbstractCard.modes_kindClass):
|
|
importExport = 'from-server-only'
|
|
stateInEditMode = 'hidden'
|
|
stateInViewMode = 'hidden'
|
|
|
|
properties_kind_importExport = 'from-server-only'
|
|
properties_kind_stateInEditMode = 'hidden'
|
|
properties_kind_stateInViewMode = 'hidden'
|
|
|
|
# prototypeIds is modified for new implementations.
|
|
# prototypeIds_kind_importExport = 'from-server-only'
|
|
prototypeIds_kind_stateInEditMode = 'hidden'
|
|
prototypeIds_kind_stateInViewMode = 'hidden'
|
|
|
|
thingName = 'Card'
|
|
|
|
class viewMode_kindClass(AbstractCard.viewMode_kindClass):
|
|
importExport = 'from-server-only'
|
|
stateInEditMode = 'hidden'
|
|
stateInViewMode = 'hidden'
|
|
|
|
class viewModeUsersSet_kindClass(AbstractCard.viewModeUsersSet_kindClass):
|
|
importExport = 'from-server-only'
|
|
stateInEditMode = 'hidden'
|
|
stateInViewMode = 'hidden'
|
|
|
|
def getC3PrototypeLinearization(self):
|
|
if self._c3PrototypeLinearization is None:
|
|
self._c3PrototypeLinearization = \
|
|
AbstractCard.getC3PrototypeLinearization(self)
|
|
return self._c3PrototypeLinearization
|
|
|
|
def getSlotToModifyNames(self, parentSlot = None):
|
|
return self.getPropertyNames()
|
|
|
|
# To do later...
|
|
## def makeContentTitle(self, contentSlot, contentLabel):
|
|
## return X.a(href = X.idUrl(
|
|
## self.id, 'content/%s' % contentSlot.getPath()))(
|
|
## contentLabel)
|
|
|
|
|
|
class CardsWeb(ObjectsWebMixin, CardsProxy):
|
|
def definition(self, id, contentPath = ''):
|
|
if not self.hasObject(id):
|
|
return pageNotFound()
|
|
|
|
object = self.getObject(id)
|
|
object.__class__ = CardForDefinition # Important.
|
|
rememberObject(id)
|
|
|
|
try:
|
|
contentSlot = object.getSlotByPath(contentPath)
|
|
except: # FIXME.
|
|
if context.getVar('debug'):
|
|
raise
|
|
return pageNotFound()
|
|
if contentSlot is None:
|
|
contentSlot = slots.Root(object)
|
|
content = contentSlot.getValue()
|
|
contentKind = contentSlot.getKind()
|
|
contentWidget = contentKind.getModelWidget(
|
|
contentSlot, forceEmbedding = 1)
|
|
|
|
layout = X.array()
|
|
|
|
if contentSlot.parent is not None:
|
|
# Add the public path to the layout.
|
|
# FIXME: quick & dirty.
|
|
contentPublicPath = []
|
|
slot = contentSlot
|
|
while slot.parent is not None and slot.parent.parent is not None:
|
|
if slot.parent.parent.parent is None:
|
|
contentPublicPath.append(object.makeContentTitle(
|
|
slot, slot.parent.getLabel()))
|
|
else:
|
|
contentPublicPath.append(
|
|
object.makeContentTitle(slot, slot.getLabel()))
|
|
slot = slot.parent
|
|
contentPublicPath.reverse()
|
|
publicPath = X.array()
|
|
publicPath.append(object.makeContentTitle(
|
|
slots.Root(object), object.getLabel()))
|
|
for itemTitle in contentPublicPath:
|
|
publicPath.append(' / ')
|
|
publicPath.append(itemTitle)
|
|
layout += X.div(_class = 'public-path')(publicPath)
|
|
|
|
layout += contentWidget.getModelPageBodyLayout(contentSlot, None)
|
|
|
|
buttonsBar = X.div(_class = 'buttons-bar')
|
|
layout += buttonsBar
|
|
navigationButtonsBar = X.span(_class = 'navigation-buttons-bar')
|
|
buttonsBar += navigationButtonsBar
|
|
if object.getDefaultModeName() != 'view':
|
|
navigationButtonsBar += X.buttonStandalone('use', X.idUrl(id))
|
|
navigationButtonsBar += X.buttonStandalone('view', X.idUrl(id, 'view'))
|
|
if self.canModifyObject(object.id):
|
|
buttonsBar += X.span(_class = 'action-buttons-bar')(
|
|
X.buttonStandalone(
|
|
'edit',
|
|
X.idUrl(id, 'editDefinition/%s' % contentPath)))
|
|
|
|
return writePageLayout(
|
|
layout, _('Definition of Card "%s"') % object.getLabel())
|
|
definition.isPublicForWeb = 1
|
|
|
|
def edit(self, *arguments, **keywords):
|
|
pass
|
|
edit.isPublicForWeb = 0 # Important, so that self.parseHttpPathAction is
|
|
# called.
|
|
|
|
def editDefinition(self, id, contentPath = ''):
|
|
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)
|
|
|
|
object.__class__ = CardForDefinition # Important.
|
|
|
|
return self.editDefinitionObject(object, id, contentPath)
|
|
editDefinition.isPublicForWeb = 1
|
|
|
|
def editDefinitionObject(self, object, id = '', contentPath = ''):
|
|
try:
|
|
contentSlot = object.getSlotByPath(contentPath)
|
|
except: # FIXME.
|
|
if context.getVar('debug'):
|
|
raise
|
|
return pageNotFound()
|
|
if contentSlot is None:
|
|
contentSlot = slots.Root(object)
|
|
content = contentSlot.getValue()
|
|
contentKind = contentSlot.getKind()
|
|
contentWidget = contentKind.getModelWidget(
|
|
contentSlot, forceEmbedding = 1)
|
|
|
|
if not id:
|
|
headerTitle = _(self.newObjectNameCapitalized)
|
|
else:
|
|
headerTitle = _('Editing Definition of Card "%s"') \
|
|
% object.getLabel()
|
|
|
|
context.push(_level = 'editDefinition',
|
|
isCreateEditMode = not id,
|
|
layoutMode = 'edit')
|
|
try:
|
|
layout = X.array()
|
|
|
|
if contentSlot.parent is not None:
|
|
# Add the public path to the layout.
|
|
# FIXME: quick & dirty.
|
|
contentPublicPath = []
|
|
slot = contentSlot
|
|
while slot.parent is not None \
|
|
and slot.parent.parent is not None:
|
|
if slot.parent.parent.parent is None:
|
|
contentPublicPath.append(slot.parent.getLabel())
|
|
else:
|
|
contentPublicPath.append(slot.getLabel())
|
|
slot = slot.parent
|
|
contentPublicPath.reverse()
|
|
publicPath = X.array()
|
|
publicPath.append(object.getLabel())
|
|
for itemTitle in contentPublicPath:
|
|
publicPath.append(' / ')
|
|
publicPath.append(itemTitle)
|
|
layout += X.div(_class = 'public-path')(publicPath)
|
|
|
|
if context.getVar('error'):
|
|
layout += object.getErrorLayout()
|
|
form = X.form(action = X.actionUrl('submitDefinition'),
|
|
enctype= 'multipart/form-data', method = 'post')
|
|
layout += form
|
|
if content != object:
|
|
form += X.input(name = 'id', type = 'hidden', value = id)
|
|
form += X.input(name = 'contentPath', type = 'hidden',
|
|
value = contentPath)
|
|
|
|
form += contentWidget.getModelPageBodyLayout(contentSlot, None)
|
|
|
|
buttonsBar = X.div(_class = 'buttons-bar')
|
|
form += buttonsBar
|
|
actionButtonsBar = X.span(_class = 'action-buttons-bar')
|
|
buttonsBar += actionButtonsBar
|
|
if not id:
|
|
actionButtonsBar += X.buttonInForm('create', 'createButton')
|
|
else:
|
|
actionButtonsBar += X.buttonInForm('modify', 'modifyButton')
|
|
|
|
return writePageLayout(layout, headerTitle)
|
|
finally:
|
|
context.pull(_level = 'editDefinition')
|
|
|
|
def getViewAllActionButtonsBarLayout(self):
|
|
layout = X.array()
|
|
if self.canAddObject():
|
|
layout += X.buttonStandalone(
|
|
'new', X.actionUrl('editDefinition').add('id', ''))
|
|
return layout
|
|
|
|
def getViewNavigationButtonsBarLayout(self, object, fields):
|
|
layout = X.array()
|
|
if object.getDefaultModeName() != 'view':
|
|
layout += X.buttonStandalone('use', X.idUrl(object.id))
|
|
layout += ObjectsWebMixin.getViewNavigationButtonsBarLayout(
|
|
self, object, fields)
|
|
userToken = context.getVar('userToken', default = '')
|
|
if userToken:
|
|
layout += X.buttonStandalone(
|
|
'view-definition', X.idUrl(object.id, 'definition'))
|
|
return layout
|
|
|
|
def getViewOtherActionButtonsBarLayout(self, object, fields):
|
|
layout = X.array()
|
|
layout += ObjectsWebMixin.getViewOtherActionButtonsBarLayout(
|
|
self, object, fields)
|
|
if self.canAddObject():
|
|
layout += X.buttonStandalone(
|
|
'implement', X.idUrl(object.id, 'new'))
|
|
return layout
|
|
|
|
|
|
def implementations(self, id, slotNames = None):
|
|
if type(slotNames) is not types.ListType:
|
|
slotNames = None
|
|
|
|
if not self.hasObject(id):
|
|
return pageNotFound()
|
|
if not self.canGetObject(id):
|
|
return accessForbidden()
|
|
object = self.getObject(id)
|
|
object.__class__ = CardForUse # Important.
|
|
rememberObject(id)
|
|
#object.execute('onImplementations')
|
|
|
|
if not self.canGetObjects():
|
|
return accessForbidden()
|
|
objects = self.getImplementations(id)
|
|
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)
|
|
|
|
buttonsBar = X.div(_class = 'buttons-bar')
|
|
layout += buttonsBar
|
|
buttonsBar += X.span(_class = 'action-buttons-bar')(
|
|
X.buttonStandalone('new', X.idUrl(id, 'new')))
|
|
|
|
headerTitle = _('"%s" Implementations' % object.getLabelTranslated(
|
|
context.getVar('readLanguages')))
|
|
return writePageLayout(layout, headerTitle)
|
|
implementations.isPublicForWeb = 1
|
|
|
|
def index(self, id, modeName = '', *arguments, **keywords):
|
|
localId = commonTools.extractLocalId(id)
|
|
if localId.startswith('draft/'):
|
|
draftKey = localId
|
|
session = context.getVar('session')
|
|
if session is None or not session.has_key(draftKey):
|
|
return pageNotFound()
|
|
object = cPickle.loads(session[draftKey])
|
|
else:
|
|
if not self.hasObject(id):
|
|
return pageNotFound()
|
|
if not self.canGetObject(id):
|
|
return accessForbidden()
|
|
object = self.getObject(id)
|
|
object.__class__ = CardForUse # Important.
|
|
|
|
if not modeName:
|
|
modeName = object.getDefaultModeName()
|
|
elif not object.hasMode(modeName):
|
|
# modeName is not a mode name, but an action.
|
|
arguments = [modeName] + list(arguments)
|
|
modeName = object.getDefaultModeName()
|
|
if not object.hasMode(modeName):
|
|
return pageNotFound()
|
|
mode = object.getMode(modeName)
|
|
identitiesProxy = getProxyForServerRole('identities')
|
|
if not identitiesProxy.setContainsUser(
|
|
mode.getModelUsersSet(object)):
|
|
return accessForbidden()
|
|
|
|
command = None
|
|
if arguments:
|
|
action = arguments[0]
|
|
if action == 'new':
|
|
prototypeId = id
|
|
id = ''
|
|
if not self.canAddObject():
|
|
return accessForbidden()
|
|
object = self.newObject(keywords)
|
|
object.__class__ = CardForUse # Important.
|
|
object.prototypeIds = [prototypeId]
|
|
command = Command()
|
|
command.action = 'create'
|
|
|
|
if id:
|
|
rememberObject(id)
|
|
|
|
return self.indexObject(object, mode, command)
|
|
index.isPublicForWeb = 1
|
|
|
|
def indexObject(self, object, mode, command):
|
|
modeName = mode.getName()
|
|
if modeName == 'edit':
|
|
layoutMode = 'edit'
|
|
elif modeName == 'view':
|
|
layoutMode = 'view'
|
|
else:
|
|
layoutMode = 'use'
|
|
|
|
create = 0
|
|
if command and (command.action == 'create' or
|
|
command.action == 'submit' and not object.id):
|
|
create = 1
|
|
prototypeId = object.prototypeIds[0]
|
|
|
|
context.push(_level = 'index', layoutMode = layoutMode)
|
|
try:
|
|
headerTitle, pageBodyLayout, buttonsBarLayout, inForm = \
|
|
mode.getModelLayoutInfos(object, None, create)
|
|
layout = X.array()
|
|
if inForm:
|
|
if context.getVar('error'):
|
|
layout += object.getErrorLayout()
|
|
form = X.form(action = X.actionUrl('submit'),
|
|
enctype = 'multipart/form-data', method = 'post')
|
|
layout += form
|
|
if modeName:
|
|
form += X.input(name = 'modeName', type = 'hidden',
|
|
value = modeName)
|
|
if create:
|
|
form += X.input(name = 'prototypeId', type = 'hidden',
|
|
value = prototypeId)
|
|
form += pageBodyLayout
|
|
if buttonsBarLayout:
|
|
form += buttonsBarLayout
|
|
else:
|
|
layout += pageBodyLayout
|
|
if buttonsBarLayout:
|
|
layout += buttonsBarLayout
|
|
|
|
context.push(
|
|
currentObject = WebAPI.GlasnostObject(object = object))
|
|
layout = writePageLayout(layout, headerTitle)
|
|
context.pull()
|
|
return layout
|
|
finally:
|
|
context.pull(_level = 'index')
|
|
|
|
def parseHttpPathAction(self, remaining):
|
|
context.push()
|
|
try:
|
|
if not remaining:
|
|
remaining = [] # Duplicate it for the insert below.
|
|
modeName = None
|
|
else:
|
|
modeName = remaining[0]
|
|
remaining = remaining[1:]
|
|
id = context.getVar('objectId')
|
|
localId = commonTools.extractLocalId(id)
|
|
if localId.startswith('draft/'):
|
|
draftKey = localId
|
|
session = context.getVar('session')
|
|
if session is None or not session.has_key(draftKey):
|
|
return pageNotFound()
|
|
object = cPickle.loads(session[draftKey])
|
|
else:
|
|
if not self.hasObject(id):
|
|
return None
|
|
if not self.canGetObject(id):
|
|
return None
|
|
object = self.getObject(id)
|
|
object.__class__ = CardForUse # Important.
|
|
if not modeName:
|
|
modeName = object.getDefaultModeName()
|
|
elif modeName == 'new':
|
|
modeName = object.getDefaultImplementModeName()
|
|
remaining.insert(0, 'new')
|
|
if not object.hasMode(modeName):
|
|
return None
|
|
context.setVar('function', self.index)
|
|
remaining.insert(0, modeName)
|
|
return context.getVar('application').parseHttpPathArguments(
|
|
remaining)
|
|
finally:
|
|
context.pull()
|
|
|
|
def parseHttpPathId(self, remaining):
|
|
context.push()
|
|
try:
|
|
assert context.getVar('objectId') is None
|
|
assert context.getVar('serverRole') is not None
|
|
if not remaining:
|
|
return None
|
|
if remaining[0] == 'draft':
|
|
if len(remaining) < 2:
|
|
return None
|
|
localId = '%s/%s' % (remaining[0], remaining[1])
|
|
remaining = remaining[2:]
|
|
else:
|
|
localId = remaining[0]
|
|
remaining = remaining[1:]
|
|
objectId = '%s/%s/%s' % (
|
|
context.getVar('dispatcherId'),
|
|
context.getVar('serverRole'),
|
|
localId)
|
|
context.setVar('objectId', objectId)
|
|
result = context.getVar('application').parseHttpPathAction(
|
|
remaining)
|
|
if result is not None:
|
|
return result
|
|
return None
|
|
finally:
|
|
context.pull()
|
|
|
|
def submit(self, id = '', modeName = '', prototypeId = '', **keywords):
|
|
if keywords is None:
|
|
keywords = {}
|
|
keywords['id'] = id # FIXME: not sure it is still useful
|
|
if isButtonSelected('applyButton', keywords):
|
|
context.setVar('again', 1)
|
|
context.setVar('hideErrors', 1)
|
|
|
|
removeDraft = 0
|
|
if id:
|
|
localId = commonTools.extractLocalId(id)
|
|
if localId.startswith('draft/'):
|
|
draftKey = localId
|
|
session = context.getVar('session')
|
|
if session is None or not session.has_key(draftKey):
|
|
if context.getVar('debug'):
|
|
raise
|
|
return accessForbidden()
|
|
object = cPickle.loads(session[draftKey])
|
|
removeDraft = 1
|
|
else:
|
|
object = self.getObject(id)
|
|
object.__class__ = CardForUse # Important.
|
|
else:
|
|
if not prototypeId:
|
|
return accessForbidden()
|
|
object = self.newObject(keywords)
|
|
object.prototypeIds = [prototypeId]
|
|
object.__class__ = CardForUse # Important.
|
|
mode = object.getMode(modeName)
|
|
identitiesProxy = getProxyForServerRole('identities')
|
|
if not identitiesProxy.setContainsUser(
|
|
mode.getModelUsersSet(object)):
|
|
return accessForbidden()
|
|
|
|
command = Command()
|
|
command.action = 'submit'
|
|
command.nextObjectId = id
|
|
context.push(_level = 'submit',
|
|
command = command)
|
|
try:
|
|
mode.submitModelFields(object, keywords)
|
|
finally:
|
|
# I don't like this; why is the submit in its own context ?
|
|
again = context.getVar('again')
|
|
error = context.getVar('error')
|
|
command = context.getVar('command')
|
|
context.pull(_level = 'submit')
|
|
if again:
|
|
context.setVar('again', 1)
|
|
if error:
|
|
context.setVar('error', 1)
|
|
|
|
if context.getVar('again'):
|
|
return self.indexObject(object, mode, command)
|
|
mode.executeModel(object, 'onSubmit', command)
|
|
action = command.action
|
|
if action == 'create' or action == 'submit' and not id:
|
|
try:
|
|
id = self.addObject(object)
|
|
except faults.Fault:
|
|
if context.getVar('debug'):
|
|
raise
|
|
return accessForbidden()
|
|
elif action == 'modify' or action == 'submit' and id:
|
|
slotToModifyNames = mode.getModelSlotToModifyNames(object)
|
|
if slotToModifyNames:
|
|
# The previous test is needed because modifyPartialObject
|
|
# modifies every slot when slotToModifyNames is empty.
|
|
try:
|
|
self.modifyPartialObject(object, slotToModifyNames)
|
|
except faults.WrongVersion:
|
|
context.setVar('again', 1)
|
|
context.setVar('error', 1)
|
|
object.setError('version', 1)
|
|
return self.indexObject(object, mode, command)
|
|
except:
|
|
if context.getVar('debug'):
|
|
raise
|
|
return accessForbidden()
|
|
elif action == 'delete':
|
|
try:
|
|
self.deleteObject(id)
|
|
except faults.Fault:
|
|
if context.getVar('debug'):
|
|
raise
|
|
return accessForbidden()
|
|
elif action == 'draft':
|
|
session = context.getVar('session')
|
|
if session is None:
|
|
if context.getVar('debug'):
|
|
raise
|
|
return accessForbidden()
|
|
if object.draftKey is not None \
|
|
and session.has_key(object.draftKey):
|
|
draftKey = object.draftKey
|
|
else:
|
|
if session.has_key('lastDraftNumber'):
|
|
# A session can store only two drafts.
|
|
draftNumber = (session['lastDraftNumber'] + 1) % 2
|
|
else:
|
|
draftNumber = 0
|
|
session['lastDraftNumber'] = draftNumber
|
|
draftKey = 'draft/%d' % draftNumber
|
|
session[draftKey] = cPickle.dumps(object)
|
|
session['isDirty'] = 1
|
|
defaultDispatcherId = context.getVar('defaultDispatcherId')
|
|
id = '%s/%s' % (commonTools.makeApplicationId(
|
|
defaultDispatcherId, self.serverRole),
|
|
draftKey)
|
|
removeDraft = 0
|
|
elif action:
|
|
if context.getVar('debug'):
|
|
raise faults.UnknownCommandAction(action)
|
|
return accessForbidden()
|
|
else:
|
|
# Accept empty action.
|
|
pass
|
|
|
|
if removeDraft and object.draftKey is not None:
|
|
session = context.getVar('session')
|
|
if session is not None and session.has_key(object.draftKey):
|
|
del session[draftKey]
|
|
session['isDirty'] = 1
|
|
|
|
# FIXME: To improve.
|
|
if not command.nextObjectId:
|
|
command.nextObjectId = id
|
|
return redirect(command.getNextUrl())
|
|
submit.isPublicForWeb = 1
|
|
|
|
def submitDefinition(self, id, contentPath = '', **keywords):
|
|
if keywords is None:
|
|
keywords = {}
|
|
keywords['id'] = id
|
|
keywords['contentPath'] = contentPath
|
|
if isButtonSelected('applyButton', keywords):
|
|
context.setVar('again', 1)
|
|
context.setVar('hideErrors', 1)
|
|
|
|
if id:
|
|
object = self.getObject(id)
|
|
else:
|
|
object = self.newObject(keywords)
|
|
object.__class__ = CardForDefinition # Important.
|
|
try:
|
|
contentSlot = object.getSlotByPath(contentPath)
|
|
except: # FIXME.
|
|
if context.getVar('debug'):
|
|
raise
|
|
return pageNotFound()
|
|
if contentSlot is None:
|
|
contentSlot = slots.Root(object)
|
|
content = contentSlot.getValue()
|
|
contentKind = contentSlot.getKind()
|
|
contentWidget = contentSlot.getWidget()
|
|
|
|
contentWidget.submitEmbedded(contentSlot, keywords)
|
|
|
|
if context.getVar('again'):
|
|
return self.editDefinitionObject(object, contentPath)
|
|
|
|
if not id:
|
|
try:
|
|
id = self.addObject(object)
|
|
except faults.Fault:
|
|
if context.getVar('debug'):
|
|
raise
|
|
return accessForbidden()
|
|
else:
|
|
try:
|
|
self.modifyPartialObject(object, object.getSlotToModifyNames())
|
|
except faults.WrongVersion:
|
|
context.setVar('again', 1)
|
|
context.setVar('error', 1)
|
|
object.setError('version', 1)
|
|
return self.editDefinitionObject(object, contentPath)
|
|
except:
|
|
if context.getVar('debug'):
|
|
raise
|
|
return accessForbidden()
|
|
return redirect(X.idUrl(id, 'definition/%s' % contentPath))
|
|
submitDefinition.isPublicForWeb = 1
|
|
|
|
def use(self, *arguments, **keywords):
|
|
pass
|
|
use.isPublicForWeb = 0 # Important, so that self.parseHttpPathAction is
|
|
# called.
|
|
|
|
def view(self, *arguments, **keywords):
|
|
pass
|
|
view.isPublicForWeb = 0 # Important, so that self.parseHttpPathAction is
|
|
# called.
|
|
|