1.1 --- a/README.txt Wed Jul 17 18:07:43 2013 +0200
1.2 +++ b/README.txt Thu Jul 18 19:24:46 2013 +0200
1.3 @@ -136,6 +136,31 @@
1.4 or it should be placed in a different location and the MAPPING_ID_TO_PAGE
1.5 variable changed in the script to refer to this different location.
1.6
1.7 +Identifying and Migrating Users
1.8 +-------------------------------
1.9 +
1.10 +Confluence export archives do not contain user profile information, but page
1.11 +versions are marked with user identifiers. Therefore, a list of user
1.12 +identifiers can be obtained by running a script extracting these identifiers.
1.13 +The following command writes to standard output the users involved with
1.14 +editing the wiki in four different spaces (exported to four directories):
1.15 +
1.16 +tools/users.sh COM DEV DOC SEC
1.17 +
1.18 +This output can be edited and then passed to a special user administration
1.19 +program as follows:
1.20 +
1.21 +tools/users.sh COM DEV DOC SEC > users.txt # for editing
1.22 +cat users.txt | tools/addusers.py wiki http://wiki.list.org/
1.23 +
1.24 +If no users are to be removed in migration, the following command could be
1.25 +issued:
1.26 +
1.27 +tools/users.sh COM DEV DOC SEC | tools/addusers.py wiki http://wiki.list.org/
1.28 +
1.29 +The addusers.py program needs to be told the directory containing the wiki
1.30 +configuration as well as the URL of the original Confluence site.
1.31 +
1.32 Output Structure
1.33 ----------------
1.34
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/tools/addusers.py Thu Jul 18 19:24:46 2013 +0200
2.3 @@ -0,0 +1,62 @@
2.4 +#!/usr/bin/env python
2.5 +
2.6 +"""
2.7 +Add users to a MoinMoin wiki, fetching the profile of each user from a
2.8 +Confluence site in order to obtain name and e-mail details.
2.9 +
2.10 +User details are written to standard output in a tab-separated sequence using
2.11 +the following format:
2.12 +
2.13 +USERNAME FULLNAME EMAIL IMAGE-URL PASSWORD
2.14 +"""
2.15 +
2.16 +from time import sleep
2.17 +from os.path import split
2.18 +from subprocess import call
2.19 +import random, string
2.20 +import sys
2.21 +
2.22 +this_dir = split(sys.argv[0])[0]
2.23 +sys.path.append(this_dir)
2.24 +
2.25 +from get_profile import get_profile
2.26 +
2.27 +def randompass():
2.28 + return "".join(random.sample(string.ascii_letters, 10))
2.29 +
2.30 +def add_user(wiki, username, fullname, email, password):
2.31 + cmd = ["moin", "--config-dir=%s" % wiki, "account", "create",
2.32 + "--name=%s" % username,
2.33 + "--email=%s" % email,
2.34 + "--password=%s" % password] + \
2.35 + (fullname and ["--alias=%s" % fullname] or [])
2.36 + call(cmd)
2.37 +
2.38 +def main():
2.39 + progname = split(sys.argv[0])[-1]
2.40 +
2.41 + try:
2.42 + wiki = sys.argv[1]
2.43 + url = sys.argv[2]
2.44 + delay = int((sys.argv[3:4] or ["1"])[0])
2.45 + except (IndexError, ValueError):
2.46 + print >>sys.stderr, "%s <wiki configuration directory> <wiki URL> [ <retrieval delay> ]" % progname
2.47 + print >>sys.stderr
2.48 + print >>sys.stderr, "Example: %s wiki http://wiki.list.org/" % progname
2.49 + sys.exit(1)
2.50 +
2.51 + line = sys.stdin.readline()
2.52 + while line:
2.53 + username = line.strip()
2.54 + username, fullname, email, image = get_profile(url, username)
2.55 + password = randompass()
2.56 + add_user(wiki, username, fullname, email, password)
2.57 + print "\t".join([username, fullname, email, image, password])
2.58 +
2.59 + sleep(delay)
2.60 + line = sys.stdin.readline()
2.61 +
2.62 +if __name__ == "__main__":
2.63 + main()
2.64 +
2.65 +# vim: tabstop=4 expandtab shiftwidth=4
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/tools/get_profile.py Thu Jul 18 19:24:46 2013 +0200
3.3 @@ -0,0 +1,48 @@
3.4 +#!/usr/bin/env python
3.5 +
3.6 +"""
3.7 +Fetch the profile of a user from a Confluence site, printing their profile
3.8 +details in a tab-separated sequence using the following format:
3.9 +
3.10 +USERNAME FULLNAME EMAIL IMAGE-URL
3.11 +"""
3.12 +
3.13 +from os.path import split
3.14 +from urllib import basejoin
3.15 +import libxml2dom, sys
3.16 +
3.17 +def get_profile(url, username):
3.18 + try:
3.19 + d = libxml2dom.parseURI("%s/display/~%s" % (url.rstrip("/"), username), html=True)
3.20 +
3.21 + fullname = d.xpath("//span[@id='fullName']")
3.22 + fullname = fullname and fullname[0].textContent or ""
3.23 + email = d.xpath("//span[@id='email']")
3.24 + email = email and email[0].textContent.replace(" at ", "@").replace(" dot ", ".") or ""
3.25 + image = d.xpath("//img[contains(@class, 'userLogo')]/@src")
3.26 + image = image and image[0].textContent or ""
3.27 +
3.28 + return [username, fullname, email, image and basejoin(url, image) or ""]
3.29 +
3.30 + except libxml2dom.LSException:
3.31 + return [username, "", username, ""]
3.32 +
3.33 +def main():
3.34 + progname = split(sys.argv[0])[-1]
3.35 +
3.36 + try:
3.37 + url = sys.argv[1]
3.38 + username = sys.argv[2]
3.39 + except IndexError:
3.40 + print >>sys.stderr, "%s <wiki URL> <username>" % progname
3.41 + print >>sys.stderr
3.42 + print >>sys.stderr, "Example: %s http://wiki.list.org/ <username>" % progname
3.43 + sys.exit(1)
3.44 +
3.45 + details = get_profile(url, username)
3.46 + print "\t".join(details)
3.47 +
3.48 +if __name__ == "__main__":
3.49 + main()
3.50 +
3.51 +# vim: tabstop=4 expandtab shiftwidth=4