diff data/plugin/action/submitbase.py @ 622:12465aa315be

add code from ActionMarket/FormSubmit (form_submit-1.7.tar.gz) - outdated code for moin 1.7/1.8
author Thomas Waldmann <tw AT waldmann-edv DOT de>
date Mon, 25 Mar 2013 17:09:15 +0100
parents
children 5f499a634857
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/plugin/action/submitbase.py	Mon Mar 25 17:09:15 2013 +0100
@@ -0,0 +1,243 @@
+# -*- coding: iso-8859-1 -*-
+
+"""
+    MoinMoin - submitbase Action
+
+    All actions handling forms should extend SubmitBase class.
+    
+    Basic methods to override:
+        - validate
+        - sanitize
+        - submit
+        
+    Base class methods should be called at first from overriding methods.
+    All data sent from user are filtered by _exlude_metadata() and then stored in 
+    fields dictionary. Data are then sorted into labels and values lists.
+    
+    @copyright: 2008 by Peter Bodi <petrdll@centrum.sk>
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import os, sys, copy, codecs
+
+from MoinMoin import wikiutil
+from MoinMoin.action import ActionBase
+from MoinMoin.Page import Page
+from MoinMoin.action import AttachFile
+from MoinMoin.action import getHandler
+from MoinMoin.security.textcha import TextCha
+
+def execute(pagename, request):
+    raise NotImplementedError
+
+class SubmitBase(ActionBase):
+    """ submit base class with some generic stuff to inherit """
+    
+    debug = True
+    msgtype = 'text/html'
+
+    metadata = [
+        'doit', 
+        'action', 
+        'actions[]', 
+        'labels', 
+        'targetfile', 
+        'targetpage', 
+        'targetemail', 
+        'file', 
+        'file__filename__', 
+        'uploadlabel',
+        'textcha-question',
+        'textcha-answer'
+        ]
+    
+    def __init__(self, pagename, request):
+        ActionBase.__init__(self, pagename, request)
+        
+        self.msg = ""
+        self.actions = []
+        self.fields = {}
+        self.labels = []
+        self.values = []
+        self.attachFile = ""
+        self.attachContent = ""
+        self.targetpage = self.pagename
+        self.module = self.__module__.split(".").pop()
+        
+        if self.request.form.has_key("actions[]"):
+            self.actions = copy.copy(self.request.form.get("actions[]"))
+        else:
+            self.actions.append(self.module)
+        
+        self.fields = self._exclude_metadata(self.request.form)
+        
+        # file upload is present
+        if request.form.has_key("file"):
+            self.attachFile = request.form.get("file__filename__")
+            self.attachContent = request.form.get("file")[0]
+            self.attachLabel = request.form.get("uploadlabel")[0]
+            self.attachLabel = self.attachLabel.encode('utf-8')
+            
+        # page where all submited data will be stored
+        if request.form.has_key("targetpage"):
+            targetpage = request.form.get("targetpage")[0]
+            page = Page(self.request, targetpage)
+            if page.isStandardPage(False):
+                self.targetpage = targetpage
+
+    def is_last(self):
+        """ Evaluates whether currently executed action is last action from actions array
+        """
+        module = self.module
+        lastAction = self.actions.pop()
+        
+        if module == lastAction:
+            return True
+        else:
+            return False
+        
+    def append_link(self):
+        """ Makes formated link and apends it to fields dictionary
+        """
+        if self.attachFile:
+            attachUrl = AttachFile.getAttachUrl(self.targetpage, self.attachFile, self.request)
+            attachLink = self.request.getQualifiedURL() + attachUrl
+            self.fields[self.attachLabel] = attachLink
+        elif self.request.form.has_key("file"):
+            self.fields[self.attachLabel] = ""
+            
+    def validate(self):
+        """ Validates user input.
+            
+        On error raise Exception and assign error message to self.msg property
+        """      
+        if not TextCha(self.request).check_answer_from_form(self.form):
+            self.msg = self._("Incorrect answer to control question")
+            raise SubmitValidationError(self.msg)
+        
+        empty = True
+        for name, value in self.fields.iteritems():
+            if value:
+                empty = False
+                break
+        if empty:
+            self.msg = self._("Form is empty")
+            raise SubmitValidationError(self.msg)
+    
+    def sanitize(self):
+        """ Sanitize input data passed by validation """        
+        for label, value in self.fields.iteritems():
+            self.fields[label] = wikiutil.escape(value)
+    
+    def submit(self):
+        """ Main submit logic
+        
+        Works with validated and sanitized data 
+        """
+        self.append_link()
+        self.labels, self.values = self._sort_fields(self.fields, self.request.form)
+    
+    def do_action(self):
+        """ Executes core methods: validate, sanitize, submit.
+        
+        Method is executed from ActionBase.render()
+        """
+        if not self.debug:
+            try:
+                self.validate()
+                self.sanitize()
+                self.submit()
+            except SubmitValidationError:
+                return False, self.msg
+            except Exception, e:
+                """ TODO: Log exception """
+                return False, e
+        else:
+            try:
+                self.validate()
+                self.sanitize()
+                self.submit()
+            except SubmitValidationError:
+                return False, self.msg
+            
+        
+        self.msg = self._("Data has been processed successfuly")
+        
+        return True, self.msg
+    
+    def do_action_finish(self, success):
+        if success:
+            if self.is_last():
+                self.render_success(self.error, self.msgtype)
+        else:
+            self.render_msg(self.error, self.msgtype)
+            if not self.is_last():
+                raise SubmitError
+            
+    def render_success(self, msg, msgtype):
+        """ Triggered on success """
+        self._delete_cache()
+        ActionBase.render_success(self, msg, self.msgtype)
+        
+    def render_msg(self, msg, msgtype):
+        """ Triggered on error """
+        if not msg:
+            msg = self._("Failed to process data")
+        msg = self._("Error - %s") % msg
+        self._delete_cache()
+        ActionBase.render_msg(self, msg, self.msgtype)
+        
+    def _delete_cache(self):
+        """ Delete cache after each form submit """
+        pagename = self.pagename
+        request = self.request
+        
+        arena = request.form.get('arena', ['Page.py'])[0]
+        if arena == 'Page.py':
+            arena = Page(request, pagename)
+        key = request.form.get('key', ['text_html'])[0]
+    
+        # Remove cache entry (if exists), and send the page
+        from MoinMoin import caching
+        caching.CacheEntry(request, arena, key, scope='item').remove()
+        caching.CacheEntry(request, arena, "pagelinks", scope='item').remove()
+        
+    def _exclude_metadata(self, form):
+        """ Filter all form metadata and returns only data send by user """
+        fields = copy.deepcopy(form)
+        
+        for label, value in form.iteritems():
+            if self.metadata.count(label) > 0:
+                del fields[label]
+            else:
+                fields[label] = value[0]
+        
+        return fields
+            
+    def _sort_fields(self, fields, form):
+        """ Sort form fields to order defined in CGI labels parameter
+        
+        labels is string containing field names separated by semicolon
+        Generation should be defined in FormFooter macro
+        """
+        labels = []
+        values = []                    
+        
+        if form.has_key('labels'):
+            _labels = form.get('labels')[0].split(";")
+            for label in _labels:
+                label = label.encode('utf-8')
+                labels.append(label)
+                values.append(fields[label])
+        else:
+            labels = fields.keys();
+            values = fields.values();
+        
+        return labels, values
+            
+class SubmitError(Exception):
+    """ Exception raised for submit action errors """
+    
+class SubmitValidationError(Exception):
+    """ Exception raised for errors during validation """
+