Below is a modified version of the PageEditor.py file that is a part of moin 1.0. It's licensed, like all of moin, under the terms of the LGPL. It provides the cvs-style commit message functionality. It should be possible to use it as a drop-in replacement for your existing PageEditor.py file in a moin 1.0 installation. Note it won't work for other versions of moin!

All rights reserved, see COPYING for details. $Id: PageEditor.py,v 1.11 2002/05/09 11:33:07 jhermann Exp $ """ # Imports import cStringIO, os, re, sys, string, time, urllib from MoinMoin import caching, config, user, util, wikiutil, webapi from MoinMoin.Page import Page from MoinMoin.i18n import _, getText ############################################################################# ### PageEditor - Edit pages ############################################################################# class PageEditor(Page): """ Editor for a wiki page """ def __init__(self, page_name, **keywords): """ Create page editor object. """ apply(Page.__init__, (self, page_name), keywords) def set_raw_body(self, body): """Set the raw body text (prevents loading from disk)""" self.raw_body = body def send_editor(self, request, **kw): """ Send the editor form page. Keywords: preview - if true, show preview comment - comment field (when preview is true) """ from cgi import escape try: from MoinMoin.action import SpellCheck except ImportError: SpellCheck = None form = request.form # check edit permissions if not request.user.may.edit: self.send_page(request, msg=_("""You are not allowed to edit any pages.""")) return webapi.http_headers(request, webapi.nocache) if self.prev_date: print 'Cannot edit old revisions' return # check for preview submit title = _('Edit "%(pagename)s"') preview = kw.get('preview', 0) if preview: title = _('Preview of "%(pagename)s"') try: newtext = form['savetext'].value except KeyError: newtext = "" newtext = string.replace(newtext, "\r", "") self.set_raw_body(newtext) # send header stuff wikiutil.send_title( title % {'pagename': self.split_title(),}, pagename=self.page_name) template_param = '' if form.has_key('template'): template_param = '&template=' + form['template'].value print '%s' % ( wikiutil.quoteWikiname(self.page_name), template_param, _('Reduce editor size')) print "|", wikiutil.getSysPage('HelpOnFormatting').link_to() if preview: print '| %s' % _('Skip to preview') # send form try: text_rows = int(form['rows'].value) except StandardError: text_rows = config.edit_rows if request.user.valid: text_rows = int(request.user.edit_rows) try: text_cols = int(form['cols'].value) except StandardError: text_cols = 80 if request.user.valid: text_cols = int(request.user.edit_cols) print '
' % ( webapi.getScriptname(), wikiutil.quoteWikiname(self.page_name), '#preview', ) print '' if os.path.isfile(self._text_filename()): mtime = os.path.getmtime(self._text_filename()) else: mtime = 0 print '' % (mtime,) # get the text body for the editor field if form.has_key('template'): # "template" parameter contains the name of the template page template_page = wikiutil.unquoteWikiname(form['template'].value) raw_body = Page(template_page).get_raw_body() if raw_body: print _("[Content of new page loaded from %s]") % (template_page,) else: print _("[Template %s not found]") % (template_page,) else: raw_body = self.get_raw_body() # generate default content if not raw_body: raw_body = _('Describe %s here.') % (self.page_name,) # replace CRLF with LF raw_body = string.replace(raw_body, '\r\n', '\n') # print the editor textarea and the save button print ('' % (text_rows, text_cols, escape(raw_body))) notify = '' if config.mail_smarthost: notify = ''' %s
''' % ( ('', ' checked')[not preview or (form.getvalue('notify') == '1')], _('Send mail notification'), ) if preview: print '' print "
", _("Optional comment about this change") + \ '
' % ( escape(kw.get('comment', ''), 1), text_cols,) button_spellcheck = (SpellCheck and '   ' % _('Check Spelling')) or '' print '''
    %s     
''' % (_('Save Changes'), _('Preview'), button_spellcheck, _('Cancel'),) print '''%s %s ''' % ( notify, ('', ' checked')[preview and (form.getvalue('rstrip') == '1')], _('Remove trailing whitespace from each line') ) badwords_re = None if preview: if SpellCheck and ( form.has_key('button_spellcheck') or form.has_key('button_newwords')): badwords, badwords_re, msg = SpellCheck.checkSpelling(self, request, own_form=0) print "

", msg print '' print "

" if preview: print ('
' '' '
') % (config.url_prefix,) self.send_page(request, content_only=1, hilite_re=badwords_re) print '
' # QuickHelp originally by Georg Mischler print _("""
Emphasis: ''italics''; '''bold'''; '''''bold italics'''''; ''mixed '''bold''' and italics''; ---- horizontal rule.
Headings: = Title 1 =; == Title 2 ==; === Title 3 ===; ==== Title 4 ====; ===== Title 5 =====.
Lists: space and one of * bullets; 1., a., A., i., I. numbered items; 1.#n start numbering at n; space alone indents.
Links: JoinCapitalizedWords; ["brackets and double quotes"]; url; [url]; [url label].
Tables: || cell text |||| cell text spanning two columns ||; no trailing white space allowed after tables or titles.

""") def deletePage(self, request, comment=None): """Delete the page (but keep the backups)""" # First save a final backup copy of the current page # (recreating the page allows access to the backups again) self.save_text(request, "deleted", '0', comment=comment or '') # Then really delete it try: os.remove(self._text_filename()) except OSError, er: import errno if er.errno <> errno.ENOENT: raise er # delete pagelinks arena = "pagelinks" key = wikiutil.quoteFilename(self.page_name) cache = caching.CacheEntry(arena, key) cache.remove() # change lists self._commitMessage(request, kw.get('comment', ''), 1) def _sendNotification(self, request, comment, emails, email_lang, oldversions): """ Send notification email for a single language. Returns sendmail result. """ _ = lambda s, l=email_lang: getText(s, lang=l) mailBody = _("Dear Wiki user,\n\n" 'You have subscribed to a wiki page or wiki category on "%(sitename)s" for change notification.\n\n' "The following page has been changed by %(editor)s:\n" "%(pagelink)s\n\n") % { 'editor': request.user.name or os.environ.get('REMOTE_ADDR', _("")), 'pagelink': webapi.getQualifiedURL(self.url()), 'sitename': config.sitename or webapi.getBaseURL(), } if comment: mailBody = mailBody + \ _("The comment on the change is:\n%(comment)s\n\n") % locals() # append a diff if not oldversions: mailBody = mailBody + \ _("No older revisions of the page stored, diff not available.") else: rc, page_file, backup_file, lines = wikiutil.pagediff(self.page_name, oldversions[0]) if lines and len(lines) > 2: mailBody = "%s%s\n%s" % ( mailBody, ("-" * 78), string.join(lines[2:], '')) else: mailBody = mailBody + _("No differences found!\n") if rc: mailBody = mailBody + '\n\n' + \ _('The external diff utility returned with error code %(rc)s!') % locals() return util.sendmail(emails, _('[%(sitename)s] Update of "%(pagename)s"') % { 'sitename': config.sitename or "Wiki", 'pagename': self.page_name, }, mailBody, mail_from=request.user.email) def _notifySubscribers(self, request, comment): """ Send email to all subscribers of this page. Return message, indicating success or errors. """ # extract categories of this page pageList = self.getPageLinks(request) CATEGORY_RE = re.compile("^Category") pageList = filter(CATEGORY_RE.match, pageList) # add current page name for list matching pageList.append(self.page_name) # get email addresses of the all wiki user which have a profile stored; # add the address only if the user has subscribed to the page and # the user is not the current editor userlist = user.getUserList() emails = {} for uid in userlist: if uid == request.user.id: continue # no self notification subscriber = user.User(uid) if not subscriber.email: continue # skip empty email address if subscriber.isSubscribedTo(pageList): lang = subscriber.language or 'en' if not emails.has_key(lang): emails[lang] = [] emails[lang].append(subscriber.email) if emails: # get a list of old revisions, and append a diff oldversions = wikiutil.getBackupList(config.backup_dir, self.page_name) # send email to all subscribers results = [_('Status of sending notification mails:')] for lang in emails.keys(): status = self._sendNotification(request, comment, emails[lang], lang, oldversions) recipients = string.join(emails[lang], ", ") results.append(_('[%(lang)s] %(recipients)s: %(status)s') % locals()) return string.join(results, '
') return _('Nobody subscribed to this page, no mail sent.') def _user_variable(self, request): """If user has a profile return the user name from the profile else return the remote address or "anonymous" If the user name contains spaces it is wiki quoted to allow links to the wiki user homepage (if one exists). """ username = request.user.name if username and config.allow_extended_names and \ string.count(username, ' ') and Page(username).exists(): username = '["%s"]' % username return username or os.environ.get('REMOTE_ADDR', 'anonymous') def _expand_variables(self, request, text): """Expand @VARIABLE@ in `text`and return the expanded text.""" #!!! TODO: Allow addition of variables via moin_config (and/or a text file) now = time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime(time.time())) system_vars = { 'PAGE': lambda s=self: s.page_name, 'TIME': lambda t=now: "[[DateTime(%s)]]" % t, 'DATE': lambda t=now: "[[Date(%s)]]" % t, 'USERNAME': lambda s=self, r=request: s._user_variable(r), 'USER': lambda s=self, r=request: "-- %s" % (s._user_variable(r),), 'SIG': lambda s=self, r=request, t=now: "-- %s [[DateTime(%s)]]" % (s._user_variable(r), t,), } if request.user.valid and request.user.name and request.user.email: system_vars['MAILTO'] = lambda u=request.user: \ "[mailto:%s %s]" % (u.email, u.name) #!!! TODO: Use a more stream-lined re.sub algorithm for name, val in system_vars.items(): text = string.replace(text, '@' + name + '@', val()) return text def _write_file(self, text): is_deprecated = string.lower(text[:11]) == "#deprecated" # save to tmpfile tmp_filename = self._tmp_filename() tmp_file = open(tmp_filename, 'wb') tmp_file.write(text) tmp_file.close() page_filename = self._text_filename() if not os.path.isdir(config.backup_dir): os.mkdir(config.backup_dir, 0777 & config.umask) if os.path.isfile(page_filename) \ and not is_deprecated: os.rename(page_filename, os.path.join(config.backup_dir, wikiutil.quoteFilename(self.page_name) + '.' + str(os.path.getmtime(page_filename)))) else: if os.name == 'nt': # Bad Bill! POSIX rename ought to replace. :-( try: os.remove(page_filename) except OSError, er: import errno if er.errno <> errno.ENOENT: raise er # set in-memory content self.set_raw_body(text) # replace old page by tmpfile os.chmod(tmp_filename, 0666 & config.umask) os.rename(tmp_filename, page_filename) return os.path.getmtime(page_filename) def save_text(self, request, newtext, datestamp, **kw): """ Save new text for a page. Keyword parameters: stripspaces - strip whitespace from line ends (default: 0) notify - send email notice tp subscribers (default: 0) comment - comment field (when preview is true) """ msg = "" if not request.user.may.edit: msg = _("""You are not allowed to edit any pages.""") if not newtext: msg = _("""You cannot save empty pages.""") elif datestamp == '0': pass elif datestamp != str(os.path.getmtime(self._text_filename())): msg = _("""Sorry, someone else saved the page while you edited it.

Please do the following: Use the back button of your browser, and cut&paste your changes from there. Then go forward to here, and click EditText again. Now re-add your changes to the current page contents.

Do not just replace the content editbox with your version of the page, because that would delete the changes of the other person, which is excessively rude! """) # save only if no error occured (msg is empty) if not msg: # set success msg msg = _("""Thank you for your changes. Your attention to detail is appreciated.""") # remove CRs (so Win32 and Unix users save the same text) newtext = string.replace(newtext, "\r", "") # possibly strip trailing spaces if kw.get('stripspaces', 0): newtext = string.join(map(string.rstrip, string.split(newtext, '\n')), '\n') # add final newline if not present in textarea, better for diffs # (does not include former last line when just adding text to # bottom; idea by CliffordAdams) if newtext and newtext[-1] != '\n': newtext = newtext + '\n' # expand variables, unless it's a template or form page if not (wikiutil.isTemplatePage(self.page_name) or wikiutil.isFormPage(self.page_name)): newtext = self._expand_variables(request, newtext) # write the page file mtime = self._write_file(newtext) # write the editlog entry from MoinMoin import editlog log = editlog.makeLogStore() remote_name = os.environ.get('REMOTE_ADDR', '') log.addEntry(self.page_name, remote_name, mtime, kw.get('comment', '')) # add event log entry request.getEventLogger().add('SAVEPAGE', {'pagename': self.page_name}) # send notification mails if config.mail_smarthost and kw.get('notify', 0): msg = msg + "

" + self._notifySubscribers(request, kw.get('comment', '')) # change lists msg = msg + "

" + self._commitMessage(request, kw.get('comment', '')) + "

" return msg def _commitMessage(self, request, comment, removed=0): """ Send email to the mailing list associated with this wiki. """ fromAddr = ""+config.mail_commit_address; toAddr = ""+config.mail_commit_address; now = time.strftime("%Y-%m-%dT%H:%M:%S", time.localtime(time.time())) # create body mailBody = _(" Date: %(date)s\n" " Editor: %(editor)s <%(email)s>\n" " Wiki: %(sitename)s\n" " Page: %(pagelink)s\n\n" " %(comment)s\n\n") % { 'date': now, 'editor': request.user.name or os.environ.get('REMOTE_ADDR', 'unknown'), 'email': request.user.email or '', 'pagelink': webapi.getQualifiedURL(self.url()), 'sitename': config.sitename or webapi.getBaseURL(), 'comment': comment or "no comment" } subject = "[wiki] " # get a list of old revisions, and append a diff oldversions = wikiutil.getBackupList(config.backup_dir, self.page_name) if removed: mailBody = mailBody + "****Page Removed***" subject = subject + "Removed: " elif oldversions: mailBody = mailBody + "Change Log:\n\n" rc, page_file, backup_file, lines = wikiutil.pagediff(self.page_name, oldversions[0]) if lines and len(lines) > 2: mailBody = "%s%s\n%s" % ( mailBody, ("-" * 78), string.join(lines[2:], '')) else: if rc: mailBody = mailBody + '\n\n' + \ _('The external diff utility returned with error code %(rc)s!') % locals() else: #mailBody = mailBody + _("No differences found!\n") return 0; # no change...okay! subject = subject + "Updated: " else: mailBody = mailBody + "New Page:\n\n" mailBody = mailBody + self.get_raw_body() subject = subject + "New: " subject = subject + _(" %(pagename)s") % { 'pagename': self.page_name } util.sendmail2(toAddr,subject, mailBody, mail_from=fromAddr) return "Sent commit message to " + toAddr + " from " + fromAddr

]]>