def index_object(self,idxs=[],log=1): """Index this page in the wiki's catalog, if any, and log problems. Updates only certain indexes, if specified. """ if self.hasCatalog() and self.isCatalogable(): if log: BLATHER('indexing',self.url()) try: self.catalog().catalog_object(self,self.url(),idxs) except: BLATHER('failed to index',self.id(),'\n',formattedTraceback())
def initialize(context): """Initialize the ZWiki product. """ try: # register the wiki page class context.registerClass( ZWikiPage.ZWikiPage, #I want to change the zmi add menu.. but not the meta_type #meta_type=Defaults.PAGE_ADD_MENU_NAME, permission=Permissions.Add, icon='skins/zwiki/wikipage_icon.gif', constructors=( ZWikiPage.manage_addZWikiPageForm, ZWikiPage.manage_addZWikiPage, ), ) # also the PersistentOutline class, so it's zmi-manageable def outlineConstructorStub(self): return MessageDialog( title=_("No need to add a Zwiki Outline Cache"), message=_("""Zwiki Outline Cache appears in the ZMI Add menu for implementation reasons, but should not be added directly. Zwiki will create it for you as needed.""")) context.registerClass( OutlineSupport.PersistentOutline, permission=Permissions.manage_properties, #icon = 'images/ZWikiPage_icon.gif', constructors=(outlineConstructorStub, )) # set up an "add wiki" menu item context.registerClass( Folder, meta_type=Defaults.WIKI_ADD_MENU_NAME, permission=Permissions.AddWiki, #icon = 'images/Wiki_icon.gif' constructors=( manage_addWikiForm, manage_addWiki, listWikis, listZodbWikis, listFsWikis, addWikiFromFs, addWikiFromZodb, )) initializeForCMF(context) initializeForFSS(context) # don't let any error prevent initialization except: INFO('failed to initialise', formattedTraceback())
def index_object(self,idxs=[],log=1): """Index this page in the wiki's catalog, if any, and log problems. Updates only certain indexes, if specified. """ if self.hasCatalog() and self.isCatalogable(): if log: BLATHER('indexing',self.url()) try: # XXX zwiki catalogs prior to 0.60 indexed the text # method, it now returns unicode which standard catalogs # can't handle, we now index SearchableText instead but # the old text index may still be present, we could # specify idxs so as to no longer update it self.catalog().catalog_object(self,self.url(),idxs) except: BLATHER('failed to index',self.id(),'\n',formattedTraceback())
def revertEditsEverywhereBy(self, username, REQUEST=None, batch=0): """ Revert all the most recent edits by username throughout the wiki. """ batch = int(batch) n = 0 for p in self.pageObjects(): if p.last_editor == username: n += 1 try: p.revertEditsBy(username,REQUEST=REQUEST) except (IndexError, AttributeError): # IndexError - we don't have a version that old # AttributeError - new object, no history yet, # due to creation of page in unit tests # - doesn't really happen in real use I guess BLATHER('failed to revert edits by %s at %s: %s' \ % (username,p.id(),formattedTraceback())) if batch and n % batch == 0: BLATHER('committing after %d reverts' % n) get_transaction().commit()
wordboundary = r'\b' except (TypeError, LookupError): # no locale is set, or there was a problem detecting it or a # problem decoding its letters. # XXX must be a less ugly way to do this: # if it's just that there's no locale, don't log a warning try: lang, encoding = locale.getlocale() except locale.Error: lang, encoding = -1, -1 if (lang, encoding) == (None, None): pass else: BLATHER( 'the system locale gave a problem in Regexps.py, so WikiNames will not be locale-aware' ) DEBUG(formattedTraceback()) # define a useful default set of non-ascii letters, mainly european letters # from http://zwiki.org/InternationalCharacterExamples # XXX more have been added to that page (latvian, polish).. how far # should we go with this ? Could we make it always recognise all # letters and forget locale awareness ? Are regexps getting slow ? # XXX needs more work, see failing links at # http://zwiki.org/InternationalCharactersInPageNames uppercase = string.uppercase + '\xc3\x80\xc3\x81\xc3\x82\xc3\x83\xc3\x84\xc3\x85\xc3\x86\xc3\x88\xc3\x89\xc3\x8a\xc3\x8b\xc3\x8c\xc3\x8d\xc3\x8e\xc3\x8f\xc3\x92\xc3\x93\xc3\x94\xc3\x95\xc3\x96\xc3\x98\xc3\x99\xc3\x9a\xc3\x9b\xc3\x9c\xc3\x9d\xc3\x87\xc3\x90\xc3\x91\xc3\x9e' lowercase = string.lowercase + '\xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4\xc3\xa5\xc3\xa6\xc3\xa8\xc3\xa9\xc3\xaa\xc3\xab\xc3\xac\xc3\xad\xc3\xae\xc3\xaf\xc3\xb2\xc3\xb3\xc3\xb4\xc3\xb5\xc3\xb6\xc3\xb8\xc3\xb9\xc3\xba\xc3\xbb\xc3\xbc\xc3\xbd\xc3\xbf\xc2\xb5\xc3\x9f\xc3\xa7\xc3\xb0\xc3\xb1\xc3\xbe' U = '|'.join([c.encode('utf8') for c in unicode(uppercase, 'utf-8')]) L = '|'.join([c.encode('utf8') for c in unicode(lowercase, 'utf-8')]) Ubr = '[%s]' % ''.join( [c.encode('utf8') for c in unicode(uppercase, 'utf-8')]) Lbr = '[%s]' % ''.join( [c.encode('utf8') for c in unicode(lowercase, 'utf-8')])
def sendMailTo( self, recipients, text, REQUEST, subjectSuffix='', subject='', message_id=None, in_reply_to=None, to=None, exclude_address=None, ): # -> none; depends on self, wiki, mailhost, time; other effects: sends encoded msg """Send a mail-out containing text to a list of email addresses. If mail-out is not configured in this wiki or there are no valid recipients, do nothing. Log any errors but don't stop. text can be body text or rfc-822 message text. """ if not self.isMailoutEnabled(): return if exclude_address in recipients: recipients.remove(exclude_address) # help mailin.py avoid loops if not recipients: return try: msgid = message_id or self.messageIdFromTime(self.ZopeTime()) # encode subject with RFC 2047 subj = str( Header(self.subjectHeader(subject, subjectSuffix), self.encoding())) fields = { 'body': '%s\n\n%s' % (self.toencoded(text), self.toencoded(self.signature(msgid))), 'From': self.toencoded(self.fromHeader(REQUEST)), 'Reply-To': self.toencoded(self.replyToHeader()), 'To': self.toencoded(to or self.toHeader()), 'Bcc': self.toencoded(self.bccHeader(recipients)), 'Subject': subj, 'Message-ID': self.toencoded(msgid), 'In-Reply-To': self.toencoded( (in_reply_to and '\nIn-reply-to: %s' % in_reply_to.splitlines()[0]) or ''), 'Content-Type': 'text/plain; charset="%s"' % self.encoding(), 'charset': self.encoding(), 'X-Zwiki-Version': self.zwiki_version(), 'X-BeenThere': self.toencoded(self.xBeenThereHeader()), 'List-Id': self.toencoded(self.listIdHeader()), 'List-Post': self.toencoded(self.listPostHeader()), 'List-Subscribe': '<' + self.pageUrl() + '/subscribeform>', 'List-Unsubscribe': '<' + self.pageUrl() + '/subscribeform>', 'List-Archive': '<' + self.pageUrl() + '>', 'List-Help': '<' + self.wikiUrl() + '>', } GenericMailHost(self.mailhost()).send(fields) BLATHER('sent mail to subscribers:\nTo: %s\nBcc: %s' % (fields['To'], fields['Bcc'])) except: BLATHER('**** failed to send mail to %s: %s' % (recipients, formattedTraceback()))
def upgradeAll(self, render=1, batch=0, REQUEST=None): # -> none # depends on: wiki # modifies: wiki (folder, pages, dtml methods, catalog, outline, revisions..) """ Update, upgrade, pre-render and re-index all pages and data structures. Normally individual pages are upgraded and pre-rendered on demand, when viewed. An administrator may want to do this for all pages ahead of time, particularly after a zwiki upgrade, to ensure all pages have the latest properties and have been rendered by the latest code, minimizing delay and possible problems later on. Also installs a wiki catalog if not present, re-indexes each page, validates page parents, and rebuilds the wiki outline cache. Also installs the index_html and standard_error_message dtml methods. XXX split ? You can set render=0 to skip the page pre-rendering part, completing much faster on large wikis. The optional batch argument forces a commit every N pages. This may be useful to get a complete run in large/busy wikis, which can be difficult due to conflict errors or memory usage. Requires 'Manage properties' permission on the folder. """ if not self.checkPermission(Permissions.manage_properties, self.folder()): raise Unauthorized, ( _('You are not authorized to upgrade all pages.') + \ _('(folder -> Manage properties)')) batch = int(batch) if render: BLATHER('upgrading/reindexing/pre-rendering all pages:') else: BLATHER('upgrading/reindexing all pages:') starttime = clock() n, total = 0, self.pageCount() self.setupCatalog(reindex=0) self.rebuildWikiOutline() for p in self.pageObjects(): # poor caching (not a problem here) n += 1 try: p.upgrade(REQUEST) p.upgradeId(REQUEST) p.fixEncoding() if render: p.preRender(clear_cache=1) msg = 'upgraded and pre-rendered page' else: msg = 'upgraded page' # make sure every page is cataloged - slow but thorough p.index_object(log=0) BLATHER('%s %d/%d %s' % (msg, n, total, p.id())) except: BLATHER('failed to upgrade page %d/%d %s: %s' \ % (n,total,p.id(),formattedTraceback())) if batch and n % batch == 0: BLATHER('committing') get_transaction().commit() self.setupDtmlMethods() endtime = clock() BLATHER('upgrade complete, %d pages processed in %fs, %.1f pages/s' \ %(n, endtime-starttime, n/(endtime-starttime)))
def upgradeAll(self,render=1,batch=0,REQUEST=None): """ Update, upgrade, pre-render and re-index all pages and data structures. Normally individual pages are upgraded and pre-rendered on demand, when viewed. An administrator may want to do this for all pages ahead of time, particularly after a zwiki upgrade, to ensure all pages have the latest properties and have been rendered by the latest code, minimizing delay and possible problems later on. Also installs a wiki catalog if not present, re-indexes each page, validates page parents, and rebuilds the wiki outline cache. Also installs the index_html and standard_error_message dtml methods. XXX split ? You can set render=0 to skip the page pre-rendering part, completing much faster on large wikis. The optional batch argument forces a commit every N pages. This may be useful to get a complete run in large/busy wikis, which can be difficult due to conflict errors or memory usage. Requires 'Manage properties' permission on the folder. """ if not self.checkPermission(Permissions.manage_properties, self.folder()): raise 'Unauthorized', ( _('You are not authorized to upgrade all pages.') + \ _('(folder -> Manage properties)')) batch = int(batch) if render: BLATHER('upgrading/reindexing/pre-rendering all pages:') else: BLATHER('upgrading/reindexing all pages:') starttime = clock() n, total = 0, self.pageCount() self.setupCatalog(reindex=0) for p in self.pageObjects(): # poor caching (not a problem here) n += 1 try: p.upgrade(REQUEST) p.upgradeId(REQUEST) p.fixPageEncoding() if render: p.preRender(clear_cache=1) msg = 'upgraded and pre-rendered page' else: msg = 'upgraded page' # make sure every page is cataloged - slow but thorough p.index_object(log=0) BLATHER('%s %d/%d %s'%(msg,n,total,p.id())) except: BLATHER('failed to upgrade page %d/%d %s: %s' \ % (n,total,p.id(),formattedTraceback())) if batch and n % batch == 0: BLATHER('committing') get_transaction().commit() self.updateWikiOutline() self.setupDtmlMethods() endtime = clock() BLATHER('upgrade complete, %d pages processed in %fs, %f pages/s' \ %(n, endtime-starttime, n/(endtime-starttime)))
def sendMailTo(self, recipients, text, REQUEST, subjectSuffix='', subject='', message_id=None, in_reply_to=None, to=None, exclude_address=None, ): """ Send a mail-out containing text to a list of email addresses. If mail-out is not configured in this wiki or there are no valid recipients, do nothing. Catch and log any errors when sending mail. XXX templatize ? XXX ezmlm won't deliver with precedence: bulk, which these are, what to do """ if not self.isMailoutEnabled(): return # gather bits and pieces msgid = message_id or self.messageIdFromTime(self.ZopeTime()) tohdr = to or self.toHeader() # do some last-minute winnowing-out of recipients we don't want to # send to (and mail we don't want to send) # help mailin.py to exclude a list address to avoid a loop try: recipients.remove(exclude_address) except ValueError: pass if not recipients: return # some lists may deliver duplicated addresses twice; try to avoid # unnecessary #unique = [] #for r in recipients: # if not r in unique: # unique.append(r) #if self.toProperty() in unique: unique.remove(self.toProperty()) mailhost = self.mailhost() if mailhost.meta_type == 'Secure Mail Host': msg = text + "\n\n" + self.signature(msgid) additional_headers = { 'Reply-To':self.replyToHeader(), \ 'X-Zwiki-Version':self.zwiki_version(), \ 'X-BeenThere':self.xBeenThereHeader(), \ 'List-Id':self.listIdHeader(), \ 'List-Post':self.listPostHeader(), \ 'List-Subscribe':'<'+self.pageUrl()+'/subscribeform>', \ 'List-Unsubscribe': '<'+self.pageUrl()+'/subscribeform>', \ 'List-Archive':'<'+self.pageUrl()+'>', \ 'List-Help':'<'+self.wikiUrl()+'>' } if not in_reply_to: additional_headers['Message-ID']=msgid else: additional_headers['Message-ID']=msgid + \ '\nIn-reply-to: %s' % in_reply_to.splitlines()[0] # XXX should we do error checking and reporting here, similar to below # where we do it for normal mail hosts? mailhost.secureSend(msg, mto=tohdr, mfrom=self.fromHeader(REQUEST), \ subject=self.subjectHeader(subject,subjectSuffix), \ mbcc=self.bccHeader(recipients), \ charset='utf-8', \ **additional_headers ) else: # normal "Mail Host" or "Maildrop Host" msg = """\ From: %s Reply-To: %s To: %s Bcc: %s Subject: %s Message-ID: %s%s X-Zwiki-Version: %s X-BeenThere: %s List-Id: %s List-Post: %s List-Subscribe: <%s/subscribeform> List-Unsubscribe: <%s/subscribeform> List-Archive: <%s> List-Help: <%s> Content-Type: text/plain; charset="utf-8" %s %s """ \ % (self.fromHeader(REQUEST), self.replyToHeader(), tohdr, self.bccHeader(recipients), self.subjectHeader(subject,subjectSuffix), msgid, (in_reply_to and '\nIn-reply-to: %s' % in_reply_to.splitlines()[0]) or '', # splitlines to fend off header injection attacks from spammers self.zwiki_version(), self.xBeenThereHeader(), self.listIdHeader(), self.listPostHeader(), self.pageUrl(), self.pageUrl(), self.pageUrl(), self.wikiUrl(), text, self.signature(msgid), ) # send try: mailhost.send(msg) #BLATHER('sent mail:\n%s' % msg) BLATHER('sent mail to subscribers:\nTo: %s\nBcc: %s' % ( tohdr,self.bccHeader(recipients))) # if there is any failure, notify admin or log except: # XXX this bare except doesn't help for a lot of stuff! # e.g. if the MailHost is configured to an inexisting mail server # only the BLATHER would do anything in that case, # admin mails fail too of course BLATHER('failed to send mail to %s: %s' % (recipients, formattedTraceback())) admin = getattr(self.folder(),'mail_admin',None) if admin: try: self.sendMailTo( #XXX possible infinite recursion ? [],text,REQUEST, subjectSuffix='ERROR, subscriber mailout failed', to=admin) except: BLATHER('failed to send error report to admin: %s' % \ formattedTraceback())
L = '|'.join([c.encode('utf8') for c in unicode(string.lowercase, encoding)]) Ubr = '[%s]' % ''.join([c.encode('utf8') for c in unicode(string.uppercase, encoding)]) Lbr = '[%s]' % ''.join([c.encode('utf8') for c in unicode(string.lowercase, encoding)]) relocaleflag = r'(?L)' wordboundary = r'\b' except: # no locale is set, or there was a problem detecting it or a # problem decoding its letters. # XXX must be a less ugly way to do this: # if it's just that there's no locale, don't log a warning try: lang, encoding = locale.getlocale() except: lang, encoding = -1,-1 if (lang, encoding) == (None, None): pass else: BLATHER('the system locale gave a problem in Regexps.py, so WikiNames will not be locale-aware') DEBUG(formattedTraceback()) # define a useful default set of non-ascii letters, mainly european letters # from http://zwiki.org/InternationalCharacterExamples # XXX more have been added to that page (latvian, polish).. how far # should we go with this ? Could we make it always recognise all # letters and forget locale awareness ? Are regexps getting slow ? # XXX needs more work, see failing links at # http://zwiki.org/InternationalCharactersInPageNames uppercase = string.uppercase + '\xc3\x80\xc3\x81\xc3\x82\xc3\x83\xc3\x84\xc3\x85\xc3\x86\xc3\x88\xc3\x89\xc3\x8a\xc3\x8b\xc3\x8c\xc3\x8d\xc3\x8e\xc3\x8f\xc3\x92\xc3\x93\xc3\x94\xc3\x95\xc3\x96\xc3\x98\xc3\x99\xc3\x9a\xc3\x9b\xc3\x9c\xc3\x9d\xc3\x87\xc3\x90\xc3\x91\xc3\x9e' lowercase = string.lowercase + '\xc3\xa0\xc3\xa1\xc3\xa2\xc3\xa3\xc3\xa4\xc3\xa5\xc3\xa6\xc3\xa8\xc3\xa9\xc3\xaa\xc3\xab\xc3\xac\xc3\xad\xc3\xae\xc3\xaf\xc3\xb2\xc3\xb3\xc3\xb4\xc3\xb5\xc3\xb6\xc3\xb8\xc3\xb9\xc3\xba\xc3\xbb\xc3\xbc\xc3\xbd\xc3\xbf\xc2\xb5\xc3\x9f\xc3\xa7\xc3\xb0\xc3\xb1\xc3\xbe' U = '|'.join([c.encode('utf8') for c in unicode(uppercase,'utf-8')]) L = '|'.join([c.encode('utf8') for c in unicode(lowercase,'utf-8')]) Ubr = '[%s]' % ''.join([c.encode('utf8') for c in unicode(uppercase,'utf-8')]) Lbr = '[%s]' % ''.join([c.encode('utf8') for c in unicode(lowercase,'utf-8')]) relocaleflag = '' wordboundary = '(?<![A-Za-z0-9\x80-\xff])'