Back to index

plone3  3.1.7
BaseFormAction.py
Go to the documentation of this file.
00001 from zope.tales.tales import CompilerError
00002 
00003 from AccessControl import Role, ClassSecurityInfo
00004 from Acquisition import aq_base, aq_parent, aq_inner
00005 from Products.CMFCore.Expression import Expression
00006 from Products.PageTemplates.Expressions import getEngine
00007 from Products.PageTemplates.Expressions import SecureModuleImporter
00008 
00009 from Products.CMFCore.utils import getToolByName
00010 from Products.CMFFormController.config import URL_ENCODING
00011 from Products.CMFFormController.utils import log
00012 from IFormAction import IFormAction
00013 from ZTUtils.Zope import make_query
00014 
00015 class BaseFormAction(Role.RoleManager):
00016     __implements__ = IFormAction,
00017 
00018     security = ClassSecurityInfo()
00019     security.declareObjectPublic()
00020     security.setDefaultAccess('allow')
00021 
00022     expression = None
00023 
00024     def __init__(self, arg=None):
00025         if arg is None:
00026             log('No argument specified for action.  This means that some of your CMFFormController actions may have been corrupted.  You may be able to fix them by editing the actions in question via the Actions tab and re-saving them.')
00027         else:
00028             try:
00029                 self.expression = Expression(arg)
00030             except:
00031                 raise CompilerError, 'Bad action expression %s' % str(arg)
00032 
00033 
00034     def __call__(self, controller_state):
00035         raise NotImplementedError
00036 
00037 
00038     def getArg(self, controller_state):
00039         """Generate an expression context for the TALES expression used as
00040         the argument to the action and evaluate the expression."""
00041         context = controller_state.getContext()
00042 
00043         portal = getToolByName(context, 'portal_url').getPortalObject()
00044         portal_membership = getToolByName(portal, 'portal_membership')
00045 
00046         if context is None or not hasattr(context, 'aq_base'):
00047             folder = portal
00048         else:
00049             folder = context
00050             # Search up the containment hierarchy until we find an
00051             # object that claims to be a folder.
00052             while folder is not None:
00053                 if getattr(aq_base(folder), 'isPrincipiaFolderish', 0):
00054                     # found it.
00055                     break
00056                 else:
00057                     folder = aq_parent(aq_inner(folder))
00058 
00059         object_url = context.absolute_url()
00060 
00061         if portal_membership.isAnonymousUser():
00062             member = None
00063         else:
00064             member = portal_membership.getAuthenticatedMember()
00065         data = {
00066             'object_url':   object_url,
00067             'folder_url':   folder.absolute_url(),
00068             'portal_url':   portal.absolute_url(),
00069             'object':       context,
00070             'folder':       folder,
00071             'portal':       portal,
00072             'nothing':      None,
00073             'request':      getattr( context, 'REQUEST', None ),
00074             'modules':      SecureModuleImporter,
00075             'member':       member,
00076             'state':        controller_state,
00077             }
00078         exprContext = getEngine().getContext(data)
00079         return self.expression(exprContext)
00080 
00081 
00082     def combineArgs(self, url, kwargs):
00083         """Utility method that takes a URL, parses its existing query string,
00084         and combines the resulting dict with kwargs"""
00085         import urlparse
00086         import cgi
00087 
00088         # parse the existing URL
00089         parsed_url = list(urlparse.urlparse(url))
00090         # get the existing query string
00091         qs = parsed_url[4]
00092         # parse the query into a dict
00093         d = cgi.parse_qs(qs, 1)
00094         # update with stuff from kwargs
00095         for k, v in kwargs.items():
00096             if isinstance(v, unicode):
00097                 v = v.encode(URL_ENCODING)
00098             d[k] = [v] # put in a list to be consistent with parse_qs
00099         # parse_qs behaves a little unexpectedly -- all query string args
00100         # are represented as lists.  I think the reason is so that you get
00101         # consistent behavior for things like http://myurl?a=1&a=2&a=3
00102         # For this case parse_qs returns d['a'] = ['1','2','3']
00103         # However, that means that http://myurl?a=1 comes back as d['a']=['1']
00104         # unmunge some of parse_qs's weirdness
00105         dnew = {}
00106         for k, v in d.items():
00107             if v and len(v) == 1:
00108                 dnew[k] = v[0]
00109             else:
00110                 dnew[k] = v
00111         return dnew
00112 
00113 
00114     def updateQuery(self, url, kwargs):
00115         """Utility method that takes a URL, parses its existing query string,
00116         url encodes
00117         and updates the query string using the values in kwargs"""
00118         d = self.combineArgs(url, kwargs)
00119         
00120         import urlparse
00121 
00122         # parse the existing URL
00123         parsed_url = list(urlparse.urlparse(url))
00124             
00125         # re-encode the string
00126         # We use ZTUtils.make_query here because it
00127         # does Zope-specific marshalling of lists,
00128         # dicts, integers and DateTime.
00129         # XXX *Normal* people should not be affected by this.
00130         # but one can argue about the need of using
00131         # standard query encoding instead for non-Zope
00132         # destination urls.
00133         parsed_url[4] = make_query(**d)
00134         # rebuild the URL
00135         return urlparse.urlunparse(parsed_url)
00136