def subscribe(self, pagename): """ Subscribe to a wiki page. To enable shared farm users, if the wiki has an interwiki name, page names are saved as interwiki names. @param pagename: name of the page to subscribe @type pagename: unicode @rtype: bool @return: if page was subscribed """ if self._cfg.interwikiname: pagename = self._interWikiName(pagename) if pagename not in self.subscribed_pages: self.subscribed_pages.append(pagename) self.save() # Send a notification from MoinMoin.events import SubscribedToPageEvent, send_event e = SubscribedToPageEvent(self._request, pagename, self.name) send_event(e) return True return False
def add_attachment(request, pagename, target, filecontent, overwrite=0): """ save <filecontent> to an attachment <target> of page <pagename> filecontent can be either a str (in memory file content), or an open file object (file content in e.g. a tempfile). """ # replace illegal chars target = wikiutil.taintfilename(target) # get directory, and possibly create it attach_dir = getAttachDir(request, pagename, create=1) fpath = os.path.join(attach_dir, target).encode(config.charset) exists = os.path.exists(fpath) if exists: if overwrite: remove_attachment(request, pagename, target) else: raise AttachmentAlreadyExists # save file stream = open(fpath, 'wb') try: _write_stream(filecontent, stream) finally: stream.close() _addLogEntry(request, 'ATTNEW', pagename, target) filesize = os.path.getsize(fpath) event = FileAttachedEvent(request, pagename, target, filesize) send_event(event) return target, filesize
def save(self): """ Save user account data to user account file on disk. This saves all member variables, except "id" and "valid" and those starting with an underscore. """ if not self.id: return user_dir = self._cfg.user_dir if not os.path.exists(user_dir): os.makedirs(user_dir) self.last_saved = str(time.time()) # !!! should write to a temp file here to avoid race conditions, # or even better, use locking data = codecs.open(self.__filename(), "w", config.charset) data.write("# Data saved '%s' for id '%s'\n" % ( time.strftime(self._cfg.datetime_fmt, time.localtime(time.time())), self.id)) attrs = self.persistent_items() attrs.sort() for key, value in attrs: # Encode list values if isinstance(value, list): key += '[]' value = encodeList(value) # Encode dict values elif isinstance(value, dict): key += '{}' value = encodeDict(value) line = u"%s=%s" % (key, unicode(value)) line = line.replace('\n', ' ').replace('\r', ' ') # no lineseps data.write(line + '\n') data.close() arena = 'user' key = 'name2id' caching.CacheEntry(self._request, arena, key, scope='wiki').remove() try: del self._request.cfg.cache.name2id except: pass key = 'openid2id' caching.CacheEntry(self._request, arena, key, scope='wiki').remove() try: del self._request.cfg.cache.openid2id except: pass if not self.disabled: self.valid = 1 if not self._stored: self._stored = True event = events.UserCreatedEvent(self._request, self) events.send_event(event)
def save(self): """ Save user account data to user account file on disk. This saves all member variables, except "id" and "valid" and those starting with an underscore. """ if not self.id: return user_dir = self._cfg.user_dir if not os.path.exists(user_dir): os.makedirs(user_dir) self.last_saved = str(time.time()) # !!! should write to a temp file here to avoid race conditions, # or even better, use locking data = codecs.open(self.__filename(), "w", config.charset) data.write("# Data saved '%s' for id '%s'\n" % (time.strftime( self._cfg.datetime_fmt, time.localtime(time.time())), self.id)) attrs = self.persistent_items() attrs.sort() for key, value in attrs: # Encode list values if isinstance(value, list): key += '[]' value = encodeList(value) # Encode dict values elif isinstance(value, dict): key += '{}' value = encodeDict(value) line = u"%s=%s" % (key, unicode(value)) line = line.replace('\n', ' ').replace('\r', ' ') # no lineseps data.write(line + '\n') data.close() arena = 'user' key = 'name2id' caching.CacheEntry(self._request, arena, key, scope='wiki').remove() try: del self._request.cfg.cache.name2id except: pass key = 'openid2id' caching.CacheEntry(self._request, arena, key, scope='wiki').remove() try: del self._request.cfg.cache.openid2id except: pass if not self.disabled: self.valid = 1 if not self._stored: self._stored = True event = events.UserCreatedEvent(self._request, self) events.send_event(event)
def move_file(request, pagename, new_pagename, attachment, new_attachment): _ = request.getText newpage = Page(request, new_pagename) if newpage.exists(includeDeleted=1) and request.user.may.write( new_pagename) and request.user.may.delete(pagename): new_attachment_path = os.path.join( getAttachDir(request, new_pagename, create=1), new_attachment).encode(config.charset) attachment_path = os.path.join(getAttachDir(request, pagename), attachment).encode(config.charset) if os.path.exists(new_attachment_path): upload_form( pagename, request, msg= _("Attachment '%(new_pagename)s/%(new_filename)s' already exists." ) % { 'new_pagename': new_pagename, 'new_filename': new_attachment }) return if new_attachment_path != attachment_path: filesize = os.path.getsize(attachment_path) filesys.rename(attachment_path, new_attachment_path) _addLogEntry(request, 'ATTDEL', pagename, attachment) event = FileRemovedEvent(request, pagename, attachment, filesize) send_event(event) _addLogEntry(request, 'ATTNEW', new_pagename, new_attachment) event = FileAttachedEvent(request, new_pagename, new_attachment, filesize) send_event(event) upload_form( pagename, request, msg= _("Attachment '%(pagename)s/%(filename)s' moved to '%(new_pagename)s/%(new_filename)s'." ) % { 'pagename': pagename, 'filename': attachment, 'new_pagename': new_pagename, 'new_filename': new_attachment }) else: upload_form(pagename, request, msg=_("Nothing changed")) else: upload_form( pagename, request, msg= _("Page '%(new_pagename)s' does not exist or you don't have enough rights." ) % {'new_pagename': new_pagename})
def move_file(request, pagename, new_pagename, attachment, new_attachment): """ move a file attachment from pagename:attachment to new_pagename:new_attachment @param pagename: original pagename @param new_pagename: new pagename (may be same as original pagename) @param attachment: original attachment filename note: attachment filename must not contain a path, use wikiutil.taintfilename() before calling move_file @param new_attachment: new attachment filename (may be same as original filename) note: attachment filename must not contain a path, use wikiutil.taintfilename() before calling move_file """ _ = request.getText newpage = Page(request, new_pagename) if newpage.exists(includeDeleted=1) and request.user.may.write(new_pagename) and request.user.may.delete(pagename): new_attachment_path = os.path.join(getAttachDir(request, new_pagename, create=1), new_attachment).encode(config.charset) attachment_path = os.path.join(getAttachDir(request, pagename), attachment).encode(config.charset) if os.path.exists(new_attachment_path): upload_form(pagename, request, msg=_("Attachment '%(new_pagename)s/%(new_filename)s' already exists.") % { 'new_pagename': new_pagename, 'new_filename': new_attachment}) return if new_attachment_path != attachment_path: filesize = os.path.getsize(attachment_path) filesys.rename(attachment_path, new_attachment_path) _addLogEntry(request, 'ATTDEL', pagename, attachment) event = FileRemovedEvent(request, pagename, attachment, filesize) send_event(event) _addLogEntry(request, 'ATTNEW', new_pagename, new_attachment) event = FileAttachedEvent(request, new_pagename, new_attachment, filesize) send_event(event) upload_form(pagename, request, msg=_("Attachment '%(pagename)s/%(filename)s' moved to '%(new_pagename)s/%(new_filename)s'.") % { 'pagename': pagename, 'filename': attachment, 'new_pagename': new_pagename, 'new_filename': new_attachment}) else: upload_form(pagename, request, msg=_("Nothing changed")) else: upload_form(pagename, request, msg=_("Page '%(new_pagename)s' does not exist or you don't have enough rights.") % { 'new_pagename': new_pagename})
def remove_attachment(request, pagename, target): """ remove attachment <target> of page <pagename> """ # replace illegal chars target = wikiutil.taintfilename(target) # get directory, do not create it attach_dir = getAttachDir(request, pagename, create=0) # remove file fpath = os.path.join(attach_dir, target).encode(config.charset) try: filesize = os.path.getsize(fpath) os.remove(fpath) except: # either it is gone already or we have no rights - not much we can do about it filesize = 0 else: _addLogEntry(request, 'ATTDEL', pagename, target) event = FileRemovedEvent(request, pagename, target, filesize) send_event(event) return target, filesize
def move_file(request, pagename, new_pagename, attachment, new_attachment): _ = request.getText newpage = Page(request, new_pagename) if newpage.exists(includeDeleted=1) and request.user.may.write(new_pagename) and request.user.may.delete(pagename): new_attachment_path = os.path.join(getAttachDir(request, new_pagename, create=1), new_attachment).encode(config.charset) attachment_path = os.path.join(getAttachDir(request, pagename), attachment).encode(config.charset) if os.path.exists(new_attachment_path): upload_form(pagename, request, msg=_("Attachment '%(new_pagename)s/%(new_filename)s' already exists.") % { 'new_pagename': new_pagename, 'new_filename': new_attachment}) return if new_attachment_path != attachment_path: filesize = os.path.getsize(attachment_path) filesys.rename(attachment_path, new_attachment_path) _addLogEntry(request, 'ATTDEL', pagename, attachment) event = FileRemovedEvent(request, pagename, attachment, filesize) send_event(event) _addLogEntry(request, 'ATTNEW', new_pagename, new_attachment) event = FileAttachedEvent(request, new_pagename, new_attachment, filesize) send_event(event) upload_form(pagename, request, msg=_("Attachment '%(pagename)s/%(filename)s' moved to '%(new_pagename)s/%(new_filename)s'.") % { 'pagename': pagename, 'filename': attachment, 'new_pagename': new_pagename, 'new_filename': new_attachment}) else: upload_form(pagename, request, msg=_("Nothing changed")) else: upload_form(pagename, request, msg=_("Page '%(new_pagename)s' does not exist or you don't have enough rights.") % { 'new_pagename': new_pagename})
def test_send_event(request): """Test if event handlers are called and if proper messages are returned""" py.test.skip('broken test - global state is changed somehow that test_GetVal looks broken') return_string = u"test_send_event" def event_handler(event): return notification.Failure("Just a test") request.cfg.event_handlers = [event_handler] event = events.Event(request) print "A proper event handler must be called and an 1-element list of results returned" results = events.send_event(event) assert issubclass(results[0].__class__, events.EventResult)
def test_send_event(request): """Test if event handlers are called and if proper messages are returned""" py.test.skip( 'broken test - global state is changed somehow that test_GetVal looks broken' ) return_string = u"test_send_event" def event_handler(event): return notification.Failure("Just a test") request.cfg.event_handlers = [event_handler] event = events.Event(request) print "A proper event handler must be called and an 1-element list of results returned" results = events.send_event(event) assert issubclass(results[0].__class__, events.EventResult)
def _save_user_prefs(self): _ = self._ form = self.request.form request = self.request if request.request_method != 'POST': return if not 'name' in request.user.auth_attribs: # Require non-empty name new_name = form.get('name', [request.user.name])[0] # Don't allow changing the name to an invalid one if not user.isValidName(request, new_name): return 'error', _("""Invalid user name {{{'%s'}}}. Name may contain any Unicode alpha numeric character, with optional one space between words. Group page name is not allowed.""", wiki=True) % wikiutil.escape(new_name) # Is this an existing user trying to change information or a new user? # Name required to be unique. Check if name belong to another user. existing_id = user.getUserId(request, new_name) if existing_id is not None and existing_id != request.user.id: return 'error', _("This user name already belongs to somebody else.") if not new_name: return 'error', _("Empty user name. Please enter a user name.") # done sanity checking the name, set it request.user.name = new_name if not 'email' in request.user.auth_attribs: # try to get the email new_email = wikiutil.clean_input(form.get('email', [request.user.email])[0]) new_email = new_email.strip() # Require email if not new_email and 'email' not in request.cfg.user_form_remove: return 'error', _("Please provide your email address. If you lose your" " login information, you can get it by email.") # Email should be unique - see also MoinMoin/script/accounts/moin_usercheck.py if new_email and request.cfg.user_email_unique: other = user.get_by_email_address(request, new_email) if other is not None and other.id != request.user.id: return 'error', _("This email already belongs to somebody else.") # done checking the email, set it request.user.email = new_email if not 'jid' in request.user.auth_attribs: # try to get the jid new_jid = wikiutil.clean_input(form.get('jid', [''])[0]).strip() jid_changed = request.user.jid != new_jid previous_jid = request.user.jid if new_jid and request.cfg.user_jid_unique: other = user.get_by_jabber_id(request, new_jid) if other is not None and other.id != request.user.id: return 'error', _("This jabber id already belongs to somebody else.") if jid_changed: set_event = events.JabberIDSetEvent(request, new_jid) unset_event = events.JabberIDUnsetEvent(request, previous_jid) events.send_event(unset_event) events.send_event(set_event) # done checking the JID, set it request.user.jid = new_jid if not 'aliasname' in request.user.auth_attribs: # aliasname request.user.aliasname = wikiutil.clean_input(form.get('aliasname', [''])[0]) # editor size request.user.edit_rows = util.web.getIntegerInput(request, 'edit_rows', request.user.edit_rows, 10, 60) # try to get the editor request.user.editor_default = form.get('editor_default', [self.cfg.editor_default])[0] request.user.editor_ui = form.get('editor_ui', [self.cfg.editor_ui])[0] # time zone request.user.tz_offset = util.web.getIntegerInput(request, 'tz_offset', request.user.tz_offset, -84600, 84600) # datetime format try: dt_d_combined = Settings._date_formats.get(form['datetime_fmt'][0], '') request.user.datetime_fmt, request.user.date_fmt = dt_d_combined.split(' & ') except (KeyError, ValueError): request.user.datetime_fmt = '' # default request.user.date_fmt = '' # default # try to get the (optional) theme theme_name = form.get('theme_name', [self.cfg.theme_default])[0] if theme_name != request.user.theme_name: # if the theme has changed, load the new theme # so the user has a direct feedback # WARNING: this should be refactored (i.e. theme load # after userform handling), cause currently the # already loaded theme is just replaced (works cause # nothing has been emitted yet) request.user.theme_name = theme_name if request.loadTheme(theme_name) > 0: theme_name = wikiutil.escape(theme_name) return 'error', _("The theme '%(theme_name)s' could not be loaded!") % locals() # try to get the (optional) preferred language request.user.language = form.get('language', [''])[0] if request.user.language == u'': # For language-statistics from MoinMoin import i18n request.user.real_language = i18n.get_browser_language(request) else: request.user.real_language = '' # I want to handle all inputs from user_form_fields, but # don't want to handle the cases that have already been coded # above. # This is a horribly fragile kludge that's begging to break. # Something that might work better would be to define a # handler for each form field, instead of stuffing them all in # one long and inextensible method. That would allow for # plugins to provide methods to validate their fields as well. already_handled = ['name', 'email', 'aliasname', 'edit_rows', 'editor_default', 'editor_ui', 'tz_offset', 'datetime_fmt', 'theme_name', 'language', 'real_language', 'jid'] for field in self.cfg.user_form_fields: key = field[0] if ((key in self.cfg.user_form_disable) or (key in already_handled)): continue default = self.cfg.user_form_defaults[key] value = form.get(key, [default])[0] setattr(request.user, key, value) # checkbox options for key, label in self.cfg.user_checkbox_fields: if key not in self.cfg.user_checkbox_disable and key not in self.cfg.user_checkbox_remove: value = form.get(key, ["0"])[0] try: value = int(value) except ValueError: pass else: setattr(request.user, key, value) # quicklinks for navibar request.user.quicklinks = self._decode_pagelist('quicklinks') # save data request.user.save() if request.user.disabled: # set valid to false so the current request won't # show the user as logged-in any more request.user.valid = False result = _("User preferences saved!") if _debug: result = result + util.dumpFormData(form) return result
def _save_user_prefs(self): _ = self._ form = self.request.form request = self.request if not 'name' in request.user.auth_attribs: # Require non-empty name new_name = wikiutil.clean_input(form.get('name', request.user.name)).strip() # Don't allow changing the name to an invalid one if not user.isValidName(request, new_name): return 'error', _("""Invalid user name {{{'%s'}}}. Name may contain any Unicode alpha numeric character, with optional one space between words. Group page name is not allowed.""", wiki=True) % wikiutil.escape(new_name) # Is this an existing user trying to change information or a new user? # Name required to be unique. Check if name belong to another user. existing_id = user.getUserId(request, new_name) if existing_id is not None and existing_id != request.user.id: return 'error', _("This user name already belongs to somebody else.") if not new_name: return 'error', _("Empty user name. Please enter a user name.") # done sanity checking the name, set it request.user.name = new_name if not 'email' in request.user.auth_attribs: # try to get the email new_email = wikiutil.clean_input(form.get('email', request.user.email)).strip() # Require email if not new_email and 'email' not in request.cfg.user_form_remove: return 'error', _("Please provide your email address. If you lose your" " login information, you can get it by email.") # Email should be unique - see also MoinMoin/script/accounts/moin_usercheck.py if new_email and request.cfg.user_email_unique: other = user.get_by_email_address(request, new_email) if other is not None and other.id != request.user.id: return 'error', _("This email already belongs to somebody else.") # done checking the email, set it request.user.email = new_email if not 'jid' in request.user.auth_attribs: # try to get the jid new_jid = wikiutil.clean_input(form.get('jid', '')).strip() jid_changed = request.user.jid != new_jid previous_jid = request.user.jid if new_jid and request.cfg.user_jid_unique: other = user.get_by_jabber_id(request, new_jid) if other is not None and other.id != request.user.id: return 'error', _("This jabber id already belongs to somebody else.") if jid_changed: set_event = events.JabberIDSetEvent(request, new_jid) unset_event = events.JabberIDUnsetEvent(request, previous_jid) events.send_event(unset_event) events.send_event(set_event) # done checking the JID, set it request.user.jid = new_jid if not 'aliasname' in request.user.auth_attribs: # aliasname request.user.aliasname = wikiutil.clean_input(form.get('aliasname', '')).strip() # editor size request.user.edit_rows = util.web.getIntegerInput(request, 'edit_rows', request.user.edit_rows, 0, 999) # try to get the editor request.user.editor_default = wikiutil.clean_input(form.get('editor_default', self.cfg.editor_default)) request.user.editor_ui = wikiutil.clean_input(form.get('editor_ui', self.cfg.editor_ui)) # time zone request.user.tz_offset = util.web.getIntegerInput(request, 'tz_offset', request.user.tz_offset, -84600, 84600) # datetime format try: dt_d_combined = Settings._date_formats.get(form['datetime_fmt'], '') request.user.datetime_fmt, request.user.date_fmt = dt_d_combined.split(' & ') except (KeyError, ValueError): request.user.datetime_fmt = '' # default request.user.date_fmt = '' # default # try to get the (optional) theme theme_name = wikiutil.clean_input(form.get('theme_name', self.cfg.theme_default)) if theme_name != request.user.theme_name: # if the theme has changed, load the new theme # so the user has a direct feedback # WARNING: this should be refactored (i.e. theme load # after userform handling), cause currently the # already loaded theme is just replaced (works cause # nothing has been emitted yet) request.user.theme_name = theme_name if load_theme_fallback(request, theme_name) > 0: theme_name = wikiutil.escape(theme_name) return 'error', _("The theme '%(theme_name)s' could not be loaded!") % locals() # try to get the (optional) preferred language request.user.language = wikiutil.clean_input(form.get('language', '')) if request.user.language == u'': # For language-statistics from MoinMoin import i18n request.user.real_language = i18n.get_browser_language(request) else: request.user.real_language = '' # I want to handle all inputs from user_form_fields, but # don't want to handle the cases that have already been coded # above. # This is a horribly fragile kludge that's begging to break. # Something that might work better would be to define a # handler for each form field, instead of stuffing them all in # one long and inextensible method. That would allow for # plugins to provide methods to validate their fields as well. already_handled = ['name', 'email', 'aliasname', 'edit_rows', 'editor_default', 'editor_ui', 'tz_offset', 'datetime_fmt', 'theme_name', 'language', 'real_language', 'jid'] for field in self.cfg.user_form_fields: key = field[0] if ((key in self.cfg.user_form_disable) or (key in already_handled)): continue default = self.cfg.user_form_defaults[key] value = form.get(key, default) value = wikiutil.clean_input(value) setattr(request.user, key, value) # checkbox options for key, label in self.cfg.user_checkbox_fields: if key not in self.cfg.user_checkbox_disable and key not in self.cfg.user_checkbox_remove: value = form.get(key, "0") try: value = int(value) except ValueError: # value we got is crap, do not setattr this value, just pass pass else: setattr(request.user, key, value) # quicklinks for navibar request.user.quicklinks = self._decode_pagelist('quicklinks') # save data request.user.save() if request.user.disabled: # set valid to false so the current request won't # show the user as logged-in any more request.user.valid = False result = _("User preferences saved!") return result
def save(self): """ Save user account data to user account file on disk. This saves all member variables, except "id" and "valid" and those starting with an underscore. """ if not self.id: return user_dir = self._cfg.user_dir if not os.path.exists(user_dir): os.makedirs(user_dir) self.last_saved = str(time.time()) # !!! should write to a temp file here to avoid race conditions, # or even better, use locking temp = file(os.path.join(user_dir, 'temp-' + uuid.uuid4().get_hex()), 'w') try: data = codecs.getwriter(config.charset)(temp) data.write("# Data saved '%s' for id '%s'\n" % ( time.strftime(self._cfg.datetime_fmt, time.localtime(time.time())), self.id)) attrs = self.persistent_items() attrs.sort() for key, value in attrs: # Encode list values if isinstance(value, list): key += '[]' value = encodeList(value) # Encode dict values elif isinstance(value, dict): key += '{}' value = encodeDict(value) line = u"%s=%s" % (key, unicode(value)) line = line.replace('\n', ' ').replace('\r', ' ') # no lineseps data.write(line + '\n') # atomically put it in place (except on windows) filesys.rename(temp.name, self.__filename()) except IOError as err: _ = self._request.getText # throw a nicer exception if err.errno == errno.ENOSPC: raise SaveError( _("Cannot save user %s, no storage space left.") % self.name) else: raise SaveError( _("An I/O error occurred while saving user %s (errno=%d)")\ % (self.name, err.errno)) finally: try: os.remove(temp.name) except: pass # we don't care for errors in the os.remove finally: temp.close() if not self.disabled: self.valid = 1 self.updateLookupCaches() if not self._stored: self._stored = True event = events.UserCreatedEvent(self._request, self) events.send_event(event) # update page subscriber's cache after saving user preferences self.updatePageSubCache()