changeset 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 a8d1eb833705
children 5f499a634857
files data/plugin/action/loadactions.py data/plugin/action/submitattachment.py data/plugin/action/submitbase.py data/plugin/action/submitcsv.py data/plugin/action/submitemail.py
diffstat 5 files changed, 503 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/plugin/action/loadactions.py	Mon Mar 25 17:09:15 2013 +0100
@@ -0,0 +1,31 @@
+# -*- coding: iso-8859-1 -*-
+
+"""
+    MoinMoin - loadactions Action
+    
+    Triggers multiple actions at once.
+    Actions are defined in actions[] CGI parameter, 
+    where actions[] is array of action names.
+
+    @copyright: 2008 by Peter Bodi <petrdll@centrum.sk>
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import os, sys
+
+from MoinMoin import wikiutil
+from MoinMoin.Page import Page
+from MoinMoin.action import ActionBase
+from MoinMoin.action import getHandler
+
+from submitbase import SubmitError
+
+def execute(pagename, request):
+    for action in request.form.get("actions[]"):
+        handler = getHandler(request, action)
+        try:
+            handler(pagename, request)
+        except SubmitError:
+            # Stop executing next actions while there is an error
+            break
+         
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/plugin/action/submitattachment.py	Mon Mar 25 17:09:15 2013 +0100
@@ -0,0 +1,67 @@
+# -*- coding: iso-8859-1 -*-
+
+"""
+    MoinMoin - submitattachment Action
+
+    Attach file into standard MoinMoin attachment folder or defined in
+    targetpage CGI parameter.
+    
+    If attachment with same name already exists, numeric index
+    is added to new attachment. (file_1.txt, file_2.txt, ...)
+    
+    @copyright: 2008 by Peter Bodi <petrdll@centrum.sk>
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import os, sys, copy
+
+from MoinMoin import wikiutil
+from MoinMoin.Page import Page
+from MoinMoin.action import AttachFile
+
+from submitbase import SubmitBase, SubmitValidationError
+
+def execute(pagename, request):
+    submitattachment(pagename, request).render()
+
+class submitattachment(SubmitBase):
+    
+    def rewrite_filename(self, filename):
+        """ Rewrites filename if there already exists attachment with the same name
+        """
+        attachFile = filename
+        i = 0 
+        while AttachFile.exists(self.request, self.targetpage, attachFile):
+            attachFile = self.attachFile
+            attachFileSplit = attachFile.split(".", 2)
+            ext = attachFileSplit.pop()
+            name = '.'.join(attachFileSplit)
+            attachFile = "%(name)s_%(index)d.%(extension)s" % {'name':name, 'index':i, 'extension':ext}
+            i += 1
+            
+        filename = attachFile
+        
+        return filename
+            
+    def validate(self):
+        """ Evaluates whethere valid file was specified """
+        SubmitBase.validate(self)
+        
+        if not self.attachFile:
+            self.msg = self._("File was not specified")
+            raise SubmitValidationError(self.msg)
+        
+        if not self.attachContent:
+            self.msg = self._("Invalid file '%(file)s'") % {'file' : self.attachFile}
+            raise SubmitValidationError(self.msg)
+     
+    def sanitize(self):
+        SubmitBase.sanitize(self)
+        self.request.form['file__filename__'] = self.attachFile = self.rewrite_filename(self.attachFile)  
+         
+    def submit(self):
+        AttachFile.add_attachment(self.request, self.targetpage, self.attachFile, self.attachContent, 0)
+        
+        
+    
+    
--- /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 """
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/plugin/action/submitcsv.py	Mon Mar 25 17:09:15 2013 +0100
@@ -0,0 +1,109 @@
+# -*- coding: iso-8859-1 -*-
+
+"""
+    MoinMoin - submitcsv Action
+    
+    Store submited data into CSV file. CSV file is located
+    in standard MoinMoin attchment folder or defined in 
+    targetpage CGI parameter.
+    
+    @copyright: 2008 by Peter Bodi <petrdll@centrum.sk>
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import os, csv, sys, codecs, cStringIO
+
+from MoinMoin import config, wikiutil
+from MoinMoin.Page import Page
+from MoinMoin.action import AttachFile
+
+from submitbase import SubmitBase
+
+def execute(pagename, request):
+    submitcsv(pagename, request).render()           
+
+class submitcsv(SubmitBase):
+        
+    def __init__(self, pagename, request):
+        SubmitBase.__init__(self, pagename, request)
+        
+        self.delimiter = ';'
+        self.targetFile = ""
+        
+        if(request.form.has_key("targetfile")):
+            self.targetFile = request.form.get("targetfile")[0]
+        else:
+            self.targetFile = u"list.csv"
+        
+    def sanitize(self):
+        SubmitBase.sanitize(self)
+        self.targetFile = wikiutil.clean_input(self.targetFile)
+            
+    def submit(self):
+        SubmitBase.submit(self)        
+        request = self.request
+        pagename = self.targetpage
+                                
+        attachDir = AttachFile.getAttachDir(request, pagename, create=1)
+            
+        targetFile = self.targetFile
+        
+        filePath = os.path.join(attachDir, targetFile).encode(config.charset)
+        
+        # save header
+        if not os.path.exists(filePath):
+            fh = open(filePath, 'wb')
+            
+            # Encoded Input to writer.writerow
+            writer = csv.writer(fh, delimiter=self.delimiter)
+            writer.writerow(self.labels)
+            
+            # Decoded Input to writer.writerow
+            #writer = UnicodeWriter(fh, delimiter=self.delimiter)
+            #writer.writerow(self.labels)
+            
+            fh.close()
+        
+        # save content
+        fh = open(filePath, 'ab')
+        
+        # Encoded Input to writer.writerow
+        #writer = csv.writer(fh, delimiter=self.delimiter, quoting=csv.QUOTE_MINIMAL)
+        #writer.writerow(self.values)
+        
+        # Decoded Input to writer.writerow
+        writer = UnicodeWriter(fh, delimiter=self.delimiter, quoting=csv.QUOTE_MINIMAL)
+        writer.writerow(self.values)
+        
+        fh.close()
+        
+class UnicodeWriter:
+    """
+    A CSV writer which will write rows to CSV file "f",
+    which is encoded in the given encoding.
+    """
+
+    def __init__(self, f, dialect=csv.excel, encoding="utf-8", **kwds):
+        # Redirect output to a queue
+        self.queue = cStringIO.StringIO()
+        self.writer = csv.writer(self.queue, dialect=dialect, **kwds)
+        self.stream = f
+        self.encoder = codecs.getincrementalencoder(encoding)()
+
+    def writerow(self, row):
+        self.writer.writerow([s.encode("utf-8") for s in row])
+        # Fetch UTF-8 output from the queue ...
+        data = self.queue.getvalue()
+        data = data.decode("utf-8")
+        # ... and reencode it into the target encoding
+        data = self.encoder.encode(data)
+        # write to the target stream
+        self.stream.write(data)
+        # empty queue
+        self.queue.truncate(0)
+
+    def writerows(self, rows):
+        for row in rows:
+            self.writerow(row)
+     
+    
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/plugin/action/submitemail.py	Mon Mar 25 17:09:15 2013 +0100
@@ -0,0 +1,53 @@
+# -*- coding: iso-8859-1 -*-
+
+"""
+    MoinMoin - submitemail Action
+    
+    Send submited data email address specified in targetemail CGI parameter
+
+    @copyright: 2008 by Peter Bodi <petrdll@centrum.sk>
+    @license: GNU GPL, see COPYING for details.
+"""
+
+import os, sys, codecs
+
+from MoinMoin import wikiutil
+from MoinMoin.action import ActionBase
+from MoinMoin.Page import Page
+from MoinMoin.mail.sendmail import sendmail
+
+from submitbase import SubmitBase
+
+def execute(pagename, request):
+    submitemail(pagename, request).render()
+
+class submitemail(SubmitBase):          
+    
+    def __init__(self, pagename, request):
+        SubmitBase.__init__(self, pagename, request)
+        
+        self.targetemail = ""
+        self.subject = "Moinmoin mail"
+        
+        if(request.form.has_key("targetemail")):
+            self.targetemail = request.form.get("targetemail")[0]
+        
+    def build_content(self):
+        """ Builds simple 'label: value' string """
+        text = ""
+        for label in self.labels:
+            index = self.labels.index(label)
+            label = label.decode('utf-8')
+            value = self.values[index]
+            text += "%(label)s: %(value)s \n" % {'label': label, 'value':value}
+        
+        return text
+        
+    def submit(self):
+        SubmitBase.submit(self)   
+        text = self.build_content()
+        status, msg = sendmail(self.request, self.targetemail, self.subject, text, mail_from=self.targetemail)
+        self.msg = self._(msg)
+        if status!=1:
+            raise Exception(self.msg)
+