Mercurial > public > src > moin > extensions
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) +