+
+
+
+
+
+ Loading kupu link maintenance...
+
+
+
+
+
+
+
+
From duncan at codespeak.net Tue Oct 10 20:08:07 2006
From: duncan at codespeak.net (duncan at codespeak.net)
Date: Tue, 10 Oct 2006 20:08:07 +0200 (CEST)
Subject: [kupu-checkins] r33133 - in kupu/trunk/kupu: common
plone/kupu_plone_layer
Message-ID: <20061010180807.6969010127@code0.codespeak.net>
Author: duncan
Date: Tue Oct 10 20:08:05 2006
New Revision: 33133
Modified:
kupu/trunk/kupu/common/kupu_kjax.js
kupu/trunk/kupu/plone/kupu_plone_layer/kupu_migration.xml.pt
Log:
Fixes to get link checker working with IE
Modified: kupu/trunk/kupu/common/kupu_kjax.js
==============================================================================
--- kupu/trunk/kupu/common/kupu_kjax.js (original)
+++ kupu/trunk/kupu/common/kupu_kjax.js Tue Oct 10 20:08:05 2006
@@ -10,7 +10,7 @@
/* Javascript to aid migration page. */
-function Migration() {};
+function KJax() {};
(function(p){
var fudge = new LibraryDrawer();
p._loadXML = fudge._loadXML;
@@ -19,6 +19,7 @@
this.updateDisplay();
};
p.updateDisplay = function() {
+ Sarissa.setXpathNamespaces(this.xmldata, "xmlns:kj='http://kupu.oscom.org/namespaces/kjax'");
var nodes = this.xmldata.selectNodes("//*[@kj:mode]");
for (var i = 0; i < nodes.length; i++) {
var n = nodes[i];
@@ -89,6 +90,6 @@
var el = document.getElementById("log");
if (el) el.appendChild(newElement("div", [s]));
};
-})(Migration.prototype);
+})(KJax.prototype);
-var kj = new Migration();
+var kj = new KJax();
Modified: kupu/trunk/kupu/plone/kupu_plone_layer/kupu_migration.xml.pt
==============================================================================
--- kupu/trunk/kupu/plone/kupu_plone_layer/kupu_migration.xml.pt (original)
+++ kupu/trunk/kupu/plone/kupu_plone_layer/kupu_migration.xml.pt Tue Oct 10 20:08:05 2006
@@ -74,11 +74,10 @@
-
-
+ tal:content="string:${m/position} of ${m/total}" />
From MAILER-DAEMON at codespeak.net Wed Oct 11 21:14:21 2006
From: MAILER-DAEMON at codespeak.net (Mail Administrator)
Date: Wed, 11 Oct 2006 14:14:21 -0500
Subject: [kupu-checkins] (no subject)
Message-ID: <20061011191442.QISD23490.ibm59aec.bellsouth.net@codespeak.net>
This message has been processed by Symantec AntiVirus.
transcript.scr was infected with the malicious virus W32.Mydoom!gen and has been deleted because the file cannot be cleaned.
-------------- next part --------------
An embedded message was scrubbed...
From: "Mail Administrator"
Subject:
Date: Wed, 11 Oct 2006 14:14:21 -0500
Size: 4099
Url: http://codespeak.net/pipermail/kupu-checkins/attachments/20061011/fe715c94/attachment.eml
From duncan at codespeak.net Mon Oct 16 15:02:36 2006
From: duncan at codespeak.net (duncan at codespeak.net)
Date: Mon, 16 Oct 2006 15:02:36 +0200 (CEST)
Subject: [kupu-checkins] r33328 - in kupu/trunk/kupu: common plone
plone/kupu_plone_layer plone/kupu_references
Message-ID: <20061016130236.3503E10119@code0.codespeak.net>
Author: duncan
Date: Mon Oct 16 15:02:33 2006
New Revision: 33328
Modified:
kupu/trunk/kupu/common/kupu_kjax.js
kupu/trunk/kupu/plone/html2captioned.py
kupu/trunk/kupu/plone/kupu_plone_layer/kupu_kjax_support.xml.pt
kupu/trunk/kupu/plone/kupu_plone_layer/kupu_migration.xml.pt
kupu/trunk/kupu/plone/kupu_references/referencebrowser.js
kupu/trunk/kupu/plone/kupu_references/referencebrowser.pt
kupu/trunk/kupu/plone/plonedrawers.py
kupu/trunk/kupu/plone/plonelibrarytool.py
kupu/trunk/kupu/plone/zmi_links.pt
Log:
Link migration now does a dry run than lets you select which pages to update from the dry run output.
Also lets you restrict the search to specific folders.
Modified: kupu/trunk/kupu/common/kupu_kjax.js
==============================================================================
--- kupu/trunk/kupu/common/kupu_kjax.js (original)
+++ kupu/trunk/kupu/common/kupu_kjax.js Mon Oct 16 15:02:33 2006
@@ -12,13 +12,66 @@
function KJax() {};
(function(p){
- var fudge = new LibraryDrawer();
- p._loadXML = fudge._loadXML;
+ p._loadXML = function(uri, callback, body, reload, extra) {
+ function _sarissaCallback() {
+ /* callback for Sarissa
+ when the callback is called because the data's ready it
+ will get the responseXML DOM and call user_callback
+ with the DOM as the first argument and the uri loaded
+ as the second
+
+ note that this method should be called in the context of an
+ xmlhttp object
+ */
+ if (xmlhttp.readyState == 4) {
+ this.xmlhttp = null;
+ if (xmlhttp.status && xmlhttp.status != 200) {
+ var errmessage = 'Error '+xmlhttp.status+' loading '+(uri||'XML');
+ alert(errmessage);
+ throw "Error loading XML";
+ };
+ var dom = xmlhttp.responseXML;
+ if (!dom || !dom.documentElement) { /* IE bug! */
+ dom = Sarissa.getDomDocument();
+ dom.loadXML(xmlhttp.responseText);
+ }
+ callback.apply(self, [dom, uri, extra]);
+ };
+ };
+ var self = this;
+ /* load the XML from a uri
+ calls callback with one arg (the XML DOM) when done
+ the (optional) body arg should contain the body for the request
+ */
+ var xmlhttp = new XMLHttpRequest();
+ var method = body?'POST':'GET';
+ // be sure that body is null and not an empty string or
+ // something
+ body=body?body:null;
+
+ try {
+ xmlhttp.open(method, uri, true);
+ xmlhttp.onreadystatechange = _sarissaCallback;
+ if (method == "POST") {
+ // by default, we would send a 'text/xml' request, which
+ // is a dirty lie; explicitly set the content type to what
+ // a web server expects from a POST.
+ xmlhttp.setRequestHeader('content-type', 'application/x-www-form-urlencoded');
+ };
+ if (reload) {
+ xmlhttp.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 2000 00:00:00 GMT");
+ }
+ this.xmlhttp = xmlhttp;
+ xmlhttp.send(body);
+ } catch(e) {
+ if (e && e.name && e.message) { // Microsoft
+ e = e.name + ': ' + e.message;
+ }
+ alert(e);
+ }
+ };
p._xmlcallback = function(dom) {
this.xmldata = dom;
- this.updateDisplay();
- };
- p.updateDisplay = function() {
Sarissa.setXpathNamespaces(this.xmldata, "xmlns:kj='http://kupu.oscom.org/namespaces/kjax'");
var nodes = this.xmldata.selectNodes("//*[@kj:mode]");
for (var i = 0; i < nodes.length; i++) {
@@ -58,13 +111,14 @@
};
};
p.newRequest = function(uri) {
+ if (this.xmlhttp) this.xmlhttp.abort();
this._loadXML(uri, this._xmlcallback);
};
p.clearLog = function() {
var el = document.getElementById("log");
while (el.firstChild) el.removeChild(el.firstChild);
};
- p.submitForm = function(form) {
+ p.submitForm = function(form, uri, extra) {
var fields = [];
function push(el, v) {
fields.push(el.name+"="+encodeURIComponent(v));
@@ -82,8 +136,14 @@
push(el, el.value);
};
}
- //alert(fields.join('\n'));
- this._loadXML(form.getAttribute('action'), this._xmlcallback, fields.join('&'));
+ if (!uri) { uri = form.getAttribute('action'); };
+ if (extra) {
+ for (var name in extra) {
+ fields.push(name+"="+encodeURIComponent(extra[name]));
+ }
+ }
+ this.trace("submit form: "+uri);
+ this._loadXML(uri, this._xmlcallback, fields.join('&'));
return false;
};
p.trace = function(s) {
Modified: kupu/trunk/kupu/plone/html2captioned.py
==============================================================================
--- kupu/trunk/kupu/plone/html2captioned.py (original)
+++ kupu/trunk/kupu/plone/html2captioned.py Mon Oct 16 15:02:33 2006
@@ -14,6 +14,7 @@
import re
from cgi import escape
from urlparse import urlsplit, urljoin, urlunsplit
+from Acquisition import aq_base
__revision__ = '$Id$'
@@ -160,8 +161,9 @@
class Migration:
FIELDS = ('portal_type', 'typename', 'fieldname',
- 'fieldlabel', 'position', 'action', 'dryrun',
- 'image_tails'
+ 'fieldlabel', 'position', 'action', 'commit_changes',
+ 'image_tails', 'paths', 'pathuids', 'uids', 'found',
+ 'batch_size',
)
def __init__(self, tool):
@@ -175,11 +177,17 @@
self.reference_tool = getToolByName(tool, 'reference_catalog')
self.portal_catalog = getToolByName(tool, 'portal_catalog')
self._continue = True
+ self._firstoutput = False
+ self.commit_changes = False
+ self._objects = []
def initFromRequest(self):
self.image_tails = self.tool._getImageSizes()
+ self.uids = None
+ self.found = 0
request = self.tool.REQUEST
- fields = [f for f in request.form.get('fields',()) if f.get('selected',0)]
+ rfg = request.form.get
+ fields = [f for f in rfg('fields',()) if f.get('selected',0)]
if fields:
f = fields[0]
self.portal_type = f.portal_type
@@ -187,13 +195,33 @@
self.fieldname = f.name
self.fieldlabel = f.label
else:
- self.portal_type = None
+ self.portal_type = rfg('portal_type', None)
self.fieldname = None
self.fieldlabel = None
+ self.typename = None
self.position = 0
- self.action = request.form.get('button', None)
- self.dryrun = request.form.get('dryrun', '') != 'I agree'
+ self.action = rfg('button', None)
+ self.commit_changes = rfg('commit', False)
+ self.batch_size = 10
+ if self.commit_changes:
+ self.uids = rfg('uids', [])
+
+ pathuids = rfg('folderpaths', [])
+ self.paths = self.tool.convertUidsToPaths(pathuids)
+ self.pathuids = pathuids
+
+ def initCommit(self):
+ """Reset counters for a commit pass"""
+ self.restoreState()
+ request = self.tool.REQUEST
+ rfg = request.form.get
+ self.commit_changes = True
+ self._firstoutput = True
+ self.found = 0
+ self.position = 0
+ self.batch_size = 1
+ self.uids = rfg('uids')
def saveState(self):
SESSION = self.tool.REQUEST.SESSION
@@ -205,20 +233,34 @@
for f in self.FIELDS:
setattr(self, f, state[f])
- def clearState(self):
- SESSION = self.tool.REQUEST.SESSION
- if SESSION.has_key('kupu_migrator'):
- del SESSION['kupu_migrator']
+# def clearState(self):
+# return
+# SESSION = self.tool.REQUEST.SESSION
+# if SESSION.has_key('kupu_migrator'):
+# del SESSION['kupu_migrator']
def status(self):
s = [ '%s=%s' % (f,getattr(self, f, 'unset')) for f in
self.FIELDS ]
return '\n'.join(s)
- def getInfo(self):
+ def mkQuery(self):
+ query = {}
+ if self.portal_type:
+ query['portal_type'] = self.portal_type
+ if self.paths:
+ query['path'] = self.paths
+ return query
+
+ def getInfo(self, saveState=True):
info = {}
if self._continue:
info['nexturi'] = self.tool.absolute_url_path()+'/kupu_migration.xml?button=continue'
+ else:
+ info['nexturi'] = None
+
+ info['firstoutput'] = self._firstoutput
+
if hasattr(self, '_total'):
info['total'] = self._total
info['position'] = self.position
@@ -226,49 +268,61 @@
info['percent'] = '100%'
else:
info['percent'] = '%d%%' % ((100.*self.position)/self._total)
- info['objects'] = getattr(self, '_objects', [])
- action = getattr(self, 'action', '')
- if action:
- headings = { 'check': 'Bad links',
- 'touid': 'Links converted to resolveuid form',
- 'topath': 'Links converted to relative path',
- }
- heading = headings[action]
- if self.typename:
- heading += ' for %s (%s)' % (self.typename, self.fieldlabel)
- info['heading'] = heading
-
- if not self.action=='check':
- if self.dryrun:
- dryrun = 'Dryrun only, no changes are being made to your data'
- else:
- dryrun = '''Content is being updated
- (actually that's a lie: until the code is more tested I'm not updating anything)'''
- info['dryrun'] = dryrun
+ info['objects'] = self._objects
+ info['action'] = action = self.action
+ info['action_check'] = action=='check'
+ info['action_touid'] = action=='touid'
+ info['action_topath'] = action=='topath'
+ info['typename'] = self.typename
+ info['fieldlabel'] = self.fieldlabel
+ info['checkboxes'] = action != 'check' and not self.commit_changes
+ info['commit_changes'] = self.commit_changes
+ info['dryrun'] = not (self.action == 'check' or self.commit_changes)
+ info['found'] = self.found
+
+ if saveState:
+ self.saveState()
return info
def docontinue(self):
"""Scan selected documents looking for convertible links"""
- brains = self.portal_catalog.searchResults(portal_type=self.portal_type)
+ uids = self.uids
+ if uids is None:
+ self.uids = uids = []
+ brains = self.portal_catalog.searchResults(self.mkQuery())
+ for b in brains:
+ uid = self.UIDfromBrain(b)
+ if uid:
+ uids.append(uid)
+ self._firstoutput = True
+ self._continue = True
+ return True
+
pos = self.position
- self._total = total = len(brains)
- brains = brains[pos:pos+10]
- self.position = pos + len(brains)
- if not brains:
+ self._total = total = len(uids)
+
+ uids = uids[pos:pos+self.batch_size]
+ self.position = pos + len(uids)
+ if not uids:
self._continue = False
return False # Done
-
+
self._objects = res = []
- for b in brains:
- braininfo = self.brain_check(b)
- if braininfo:
- res.append(braininfo)
+ for uid in uids:
+ obj = self.reference_tool.lookupObject(uid)
+ objinfo = self.object_check(obj)
+ if objinfo:
+ res.append(objinfo)
self._continue = True
return True
def brain_check(self, brain):
+ object = brain.getObject()
+ return self.object_check(object)
+
+ def object_check(self, object):
"""Check the relative links within this object."""
def checklink(match):
matched = match.group(0)
@@ -299,32 +353,51 @@
info = []
changes = []
- object = brain.getObject()
- objuid = getattr(object.aq_base, 'UID', None)
- if objuid:
- objuid = objuid
+ try:
+ objuid = aq_base(object).UID
+ except:
+ return None # only archetypes objects
base = object.absolute_url()
if getattr(object.aq_explicit, 'isPrincipiaFolderish', 0):
base += '/'
field = object.getField(self.fieldname)
- data = field.getRaw(object)
+ data = field.getEditAccessor(object)()
+ __traceback_info__ = (object, data)
newdata = LINK_PATTERN.sub(checklink, data)
+ if data != newdata and self.commit_changes:
+ mutator = field.getMutator(object)
+ print "set field"
+ print repr(newdata)
+ print mutator
+ mutator(newdata)
if info or changes:
- title = brain.Title
+ self.found += 1
+ title = object.Title()
if not title:
- title = getattr(brain, 'getId')
+ title = object.getId()
if not title:
title = ''
if data != newdata:
diffs = htmlchanges(data, changes)
else:
diffs = None
- return dict(title=title, info=info, url=object.absolute_url_path(),
+ return dict(title=title, uid = objuid, info=info, url=object.absolute_url_path(),
diffs=diffs)
return None
+ def UIDfromBrain(self, brain):
+ """Convert a brain to a UID without hitting the object"""
+ path = brain.getPath()
+ if not path.startswith(self.portal_base):
+ return None
+ try:
+ metadata = self.uid_catalog.getMetadataForUID(path[self.prefix_length:])
+ except KeyError:
+ return None
+ return metadata.get('UID', None)
+
def UIDfromURL(self, url):
"""Convert an absolute URL to a UID"""
if not url.startswith(self.portal_base_url):
@@ -343,6 +416,8 @@
if not url.startswith(self.portal_base_url):
return None
url = self.portal_base + url[len(self.portal_base_url):]
+ if isinstance(url, unicode):
+ url = url.encode('utf8') # ExtendedPathIndex can't cope with unicode paths
brains = self.portal_catalog.searchResults(path=url)
if len(brains) != 1:
# Happens on Plone 2.0 :(
Modified: kupu/trunk/kupu/plone/kupu_plone_layer/kupu_kjax_support.xml.pt
==============================================================================
--- kupu/trunk/kupu/plone/kupu_plone_layer/kupu_kjax_support.xml.pt (original)
+++ kupu/trunk/kupu/plone/kupu_plone_layer/kupu_kjax_support.xml.pt Mon Oct 16 15:02:33 2006
@@ -3,6 +3,7 @@
xmlns:tal="http://xml.zope.org/namespaces/tal"
xmlns:metal="http://xml.zope.org/namespaces/metal"
xmlns:html="http://www.w3.org/TR/REC-html40"
+ xmlns:i18n="http://xml.zope.org/namespaces/i18n"
define="charset here/portal_properties/site_properties/default_charset|here/portal_properties/default_charset|string:utf-8;
content_type python:request.RESPONSE.setHeader('Content-Type', 'text/xml;;charset=%s' % charset);">
+
+
+
+
+
+
+
+
+ No reference set. Click the browse button to select.
+
+
+ No reference set. Click the browse button to select.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Modified: kupu/trunk/kupu/plone/kupu_plone_layer/kupu_migration.xml.pt
==============================================================================
--- kupu/trunk/kupu/plone/kupu_plone_layer/kupu_migration.xml.pt (original)
+++ kupu/trunk/kupu/plone/kupu_plone_layer/kupu_migration.xml.pt Mon Oct 16 15:02:33 2006
@@ -17,59 +17,71 @@