This is a Perl package, Confluence.pm, which acts as a Perl XML-RPC client for Confluence. It can be used to upload files or users or perform any other remote API accessible function.
Download: Confluence.pm
Synopsis
my $object = new Confluence URL, user, pass; my $result = $object->method(argument,..);
All the XML-RPC methods for Confluence are available through this package.
Data types
- Perl simple data types are mapped to string
- Hash references are mapped to struct
- Array references are mapped to array
This package now automatically converts all scalars to RPC::XML::string, so explicit type conversions should not be required.
Error Handling
This package has two global flags which control error handings.
Confluence::setRaiseError(1); # Enable die Confluence::setPrintError(1); # Enable warn Confluence::setRaiseError(0); # Disable die Confluence::setPrintError(0); # Disable warn
The setRaiseError and setPrintError functions both return the previous setting of the flag so that it may be restored if necessary.
RaiseError is initially set to 1 to preserve the original package behavior.
PrintError is initially set to 0.
If RaiseError is set to 0 then Confluence::lastError() can be used to determine if an error occurred.
Confluence::setRaiseError(0);
my $page = $wiki->getPage($space, $title);
if (Confluence::lastError()) {
print Confluence::lastError(), "\n";
}
Extension Functions
updatePage
This package has a function called updatePage which is not part of the original remote API. If the page id is not specified then the function will call storePage to do an insert. If an "already exists" error is encountered then the function will call getPage to retrieve the page id and version, and then repeat the storePage attempt. This function is intended to be used in situations where the intent is to upload pages, overwriting existing content if it exists. See example below.
Examples
Upload Files
The following Perl script uploads the contents of a directory to the wiki. Each file in the directory is uploaded as a separate page. The page title is the file name with extension removed. This script requires four arguments: the user name, the password, the space key and the directory name.
use strict;
use Confluence;
my $url = "http://localhost:8080/rpc/xmlrpc";
my ($user, $pass, $spaceKey, $directory) = @ARGV;
die "Usage is $0 <user> <password> <spacekey> <directoryname>\n"
unless ($spaceKey and -d $directory);
my $wiki = new Confluence($url, $user, $pass);
opendir DIR, $directory or die "Unable to access directory $directory";
chdir $directory or die "Unable to chdir to $directory";
while (my $filename = readdir DIR) {
next unless -f $filename;
my $title = $filename;
$title =~ s/\.\w\w\w$//; # remove filename extension (.xxx)
# read in the file
open FILE, "<$filename" or die "Unable to open file $filename";
my $content = join "", <FILE>;
# create the page object
my $newPage = {
space => $spaceKey,
title => $title,
content => $content
};
print "loading $title\n";
$wiki->updatePage($newPage);
}
$wiki->logout();
Upload Users
The following Perl script reads and loads a list of users from a file (or stdin). If errors are encountered then the script will print an error message, but continue processing.
use strict;
use Confluence;
my $url = "http://localhost:8080/rpc/xmlrpc";
my $adminuser = "****";
my $adminpass = "****";
my $wiki = new Confluence($url, $adminuser, $adminpass);
Confluence::setRaiseError(0);
Confluence::setPrintError(1);
while (<>) {
chomp;
my ($username, $password, $email, $fullname, $groupname) = split /,/;
my $user = {name => $username, fullname => $fullname, email => $email};
print "adding $username\n";
$wiki->addUser($user, $password);
$wiki->addUserToGroup($username, $groupname);
}
$wiki->logout();
Determine Group Membership
The following perl script prints the group membership of all users.
use strict;
use Confluence;
my $url = "http://localhost:8080/rpc/xmlrpc";
my $adminuser = "*****";
my $adminpass = "*****";
my $wiki = new Confluence($url, $adminuser, $adminpass);
my $users = $wiki->getActiveUsers('true');
foreach my $user (@$users) {
my $groups = $wiki->getUserGroups($user);
foreach my $group (@$groups) {
print "$user is a member of $group\n";
};
}
$wiki->logout();
More information
The package uses the RPC::XML module to do the heavy lifting. Read the perldoc for this package to learn more.
As mentioned above, this package should work with any remote API function. It has been tested with addUserToGroup, getActiveUsers, getPage, getPages, getServerInfo, getUser, and storePage.
Examples
|
|
|
|
See also
This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

Comments (33)
Mar 30, 2006
scud says:
very good to usevery good to use
Apr 03, 2006
Cheryl Chase says:
I think that there may be something wrong with the way that getAttachmentData(St...I think that there may be something wrong with the way that getAttachmentData(String token, String pageId, String fileName, String versionNumber) works. What does the versionNumber refer to? Attachments do have version numbers in Confluence, but there is no version number in the Perl hash returned by getAttachments (see dump below).
Don't I need this to get the correct version? Should I steal it from the url?
DB<2> x $attachment 0 HASH(0x1adc854) 'comment' => '' 'contentType' => 'application/pdf' 'created' => 'Thu Mar 16 17:22:20 GMT-08:00 2006' 'creator' => 'bo' 'fileName' => 'DFTSX_4.pdf' 'fileSize' => 14797 'id' => 137 'pageId' => 1088 'title' => 'DFTSX_4.pdf' 'url' => 'http://mydomain.com/download/attachments/1088/DFTSX_4.pdf?version=3'Apr 03, 2006
Jens Schumacher says:
Cheryl, If you provide a version of 0 or less, you'll get the most recent versi...Cheryl,
If you provide a version of 0 or less, you'll get the most recent version of the attachment.
Hope that helps.
Cheers,
Jens
Apr 03, 2006
Cheryl Chase says:
I'm trying to upload a jpg file as an attachment. I get the following error. I w...I'm trying to upload a jpg file as an attachment. I get the following error. I wonder if this is because the guts of LWP is trying to interpret the binary content I want to attach as UTF-8?
Here's the code I am using. $content is about 16kb of binary content read in from a jpg file. I show the content of %newAttachment as a debugger dump.
$wiki->addAttachment($$attachment{pageId}, \%newAttachment, $content); DB<2> x %newAttachment 0 'fileSize' 1 167896 2 'comment' 3 'auto JPG of DFTSX_4.pdf' 4 'fileName' 5 'DFTSX_4.jpg' 6 'title' 7 'auto JPG of DFTSX_4.pdf' 8 'pageId' 9 1088 10 'contentType' 11 'application/jpg'If I try to attach contents of a textfile, I get this message instead:
Apr 03, 2006
Cheryl Chase says:
This code can be used to enable tracing the xmlrpc as it operates: $Confluen...This code can be used to enable tracing the xmlrpc as it operates:
Jun 04, 2006
Giles Lewis says:
Has anyone successfully used the perl API to upload or download JPG or GIF file ...Has anyone successfully used the perl API to upload or download JPG or GIF file attachments?
Jul 03, 2006
Varindarpal Bhaura says:
Hi I am very new to Confluence and getting the following when I try to determine...Hi I am very new to Confluence and getting the following when I try to determine the Group Memberships, code taken from above,
Result={faultString => 'java.lang.NoSuchMethodException: login',faultCode => '0'
}
REMOTE ERROR: java.lang.NoSuchMethodException: login
Using version 2.1.5
Thanks in advance
Jul 09, 2006
Matt Ryall (Atlassian) says:
Usually these remote errors are duplicated in the Confluence server logs with mo...Usually these remote errors are duplicated in the Confluence server logs with more information. Is there anything there that will help?
If you're still having trouble, please raise a support request and attach your Confluence logs together with the Perl script.
Jul 23, 2006
Dave Murray-Rust says:
Hi! Can anyone post some addAttachment code which works. I'm currently gett...Hi!
Can anyone post some addAttachment code which works. I'm currently getting no such method exceptions:
warn Dumper( $page->{ id } ); warn Dumper( $config); warn Dumper( $binData );gives:
(data) '930' at /usr/local/lib/site_perl/Production/Oncampus/Confluence/ConfluenceRoutines.pm line 165. {fileSize => 5,comment => 'testing',fileName => 'hello.txt',contentType => 'text/html'} at /usr/local/lib/site_perl/Production/Oncampus/Confluence/ConfluenceRoutines.pm line 166. 'hello' at /usr/local/lib/site_perl/Production/Oncampus/Confluence/ConfluenceRoutines.pm line 167. (result) Sending confluence1.addAttachment bless( do{\(my $o = '930')}, 'RPC::XML::string' ), {fileSize => bless( do{\(my $o = 5)}, 'RPC::XML::string' ),comment => bless( do{\(my $o = 'testing')}, 'RPC::XML::string' ),fileName => bless( do{\(my $o = 'hello.txt')}, 'RPC::XML::string' ),contentType => bless( do{\(my $o = 'text/html')}, 'RPC::XML::string' )}, bless( do{\(my $o = 'hello')}, 'RPC::XML::string' ) Result={faultString => 'java.lang.NoSuchMethodException: $Proxy43.addAttachment(java.lang.String, java.lang.String, java.util.Hashtable, java.lang.String)',faultCode => '0'} REMOTE ERROR: java.lang.NoSuchMethodException: $Proxy43.addAttachment(java.lang.String, java.lang.String, java.util.Hashtable, java.lang.String) at /usr/local/lib/site_perl/Production/Oncampus/Confluence/ConfluenceRoutines.pm line 168 {imageDestination => \'',imageID => \'2'}Cheers for any help!
Dave
Jul 23, 2006
Cheryl Chase says:
while (my ($ticker) = $select->fetchrow) { # Fetch page my $page =...Jul 24, 2006
Dave Murray-Rust says:
It looks like your earlier code used the XML-RPC interface, while this one uses ...It looks like your earlier code used the XML-RPC interface, while this one uses the SOAP interface - is that because the RPC stuff doesn't work for uploading attachments?
Jul 24, 2006
Cheryl Chase says:
Sorry, I posted that snippet of code quickly w/o looking at it carefully. Now th...Sorry, I posted that snippet of code quickly w/o looking at it carefully. Now that I look at it, yes, it seems that I could not get xmlrpc to work, so I changed just the attachment part to SOAP. Here's more context:
Jul 24, 2006
Dave Murray-Rust says:
Fantastic, that works perfectly! Thanks very much!Fantastic, that works perfectly!
Thanks very much!
Jul 24, 2006
Dave Murray-Rust says:
By the way, using my $bindata = SOAP::Data->type( base64 => $data ); Ca...By the way, using
Catches the condition where a string is all text, and treated as a string, resulting in the wrong message signature for the Java stack at the other end.
Jul 23, 2006
Cheryl Chase says:
PS: "No such method" generally means wrong number or type of arguments.PS: "No such method" generally means wrong number or type of arguments.
Jul 24, 2006
Dave Murray-Rust says:
Of course the bit I missed out of my report was the code I was using to do the u...Of course the bit I missed out of my report was the code I was using to do the upload with:
my $attachment = $self->{ api }->addAttachment( $page->{ id }, $config, $binData )( $self->
As far as I can tell, I'm using the same method signature as in Cheryl's code - a string id, a hash of params and a string with the binary data in. Is this a difference between the SOAP and XML-RPC API's? I'll try knocking up a quick SOAP version and see if that solves the problem.
Cheers!
Jul 25, 2006
Varindarpal Bhaura says:
Has anyone experienced not being able to access a user if the username is a numb...Has anyone experienced not being able to access a user if the username is a number.
For example I created a user called joeb and could use the api to move him to groups etc, however when i created a user called 12345, i could create the user using the api but then was unable to getUser, set a group or anything to this user.
Any ideas as to why this is happening?
Here is the corresponding code:
# Login into Confluence
$confluence = XMLRPC::Lite->proxy($proxy);
# This token must be used with every remote call
$token = $confluence->call("confluence1.login", $userLogin, $pwdLogin)->result();
my($user) = '12345';
getUser($user);
$confluence->call("confluence1.logout", $token);
##############################################################
# User getUser(String username)
##############################################################
sub getUser{
my($username) = @_;
print "Getting user: $username\n";
infoDumper('getUser', $username);
}
#############################################################
# infoDumper --
# executes the API requests and prints out the result
# 1 = SUCCESS
# 0 = FAIL
##############################################################
sub infoDumper{
my($apiReq, @apiReqElements) = @_;
$apiReq = 'confluence1.'.$apiReq;
#print "$apiReq, $token, @apiReqElements\n";
print Dumper($confluence->call($apiReq, $token, @apiReqElements)->result()), "\n";
}
Results:
Getting user: 12345
$VAR1 = undef;
We have determined that it is not the LDAP integration but turning that off and trying it.
Any help would be appreciated!
Jul 25, 2006
Cheryl Chase says:
Try this: sub getUser{ my($username) = @_; if ($username eq $usernam...Try this:
sub getUser{ my($username) = @_; if ($username eq $username+0) { $username = sprintf("%f", $username ); #convert number to string } print "Getting user: $username\n"; infoDumper('getUser', $username); }Jul 25, 2006
Asgeir S. Nilsen says:
Are you sure you're using a current version? The module should autoconvert all ...Are you sure you're using a current version? The module should autoconvert all scalars to RPC::XML::string.
Nov 08, 2006
eugene wu says:
i'm not entirely sure on how to use perl-xml-rpc client to update a page to set ...i'm not entirely sure on how to use perl-xml-rpc client to update a page to set a parentID in batch... could i get some sort of tutorial in this?
Feb 28, 2007
Eric Sorenson says:
I'm attaching a fully-functional multiple file uploader that does the attachment...I'm attaching a fully-functional multiple file uploader that does the attachments tapdance properly, using only the passthrough RPC::XML module.
The problem that Dave Murray-Rust and Cheryl Chase experienced is that Confluence.pm is not binary-encoding the attachments properly. You have to pass the addAttachments arguments like so:
Hope this helps someone else out, I have tried to make the script as generic as possible. Just customise your '$url' at the top and you should be good to go.
Apr 04, 2007
matthew venn says:
there is a bug in Confluence.pm, where a password that is all numbers will resul...there is a bug in Confluence.pm, where a password that is all numbers will result in a 'nosuchmethod' exception. The following modification forces strings to be used instead of numbers.
(edited by Charles Miller to add: this is CONF-8208)
Jan 25, 2008
Daniel Frett says:
with version 2.1 of Confluence.pm when an RPC call returns a boolean that is fal...with version 2.1 of Confluence.pm when an RPC call returns a boolean that is false it is reported that
there was an error connecting to the XML-RPC webservice.
To fix this bug the test to see if it's a valid response returned from the webservice should be:
$LastError = defined $result ? ( ref($result) eq 'HASH' ? (exists $result->{faultString} ? "REMOTE ERROR: " . $result->{faultString} : '') : '') : "XML-RPC ERROR: Unable to connect to " . $self->{url};The only difference between this code and the existing code is the use of the defined operator.
Feb 10, 2008
Martin Ellis says:
Please note there are two places in the that need to fixed (though only place is...Please note there are two places in the that need to fixed (though only place is a real problem).
Mar 13, 2008
Owen says:
When trying to use the Confluence.pm module to update existing pages in my wiki,...When trying to use the Confluence.pm module to update existing pages in my wiki, I kept getting this error:
REMOTE ERROR: java.lang.Exception: com.atlassian.confluence.rpc.VersionMismatchException: You're trying to edit an outdated version of that page.
This was with the following code taken from the upload page example:
my $newPage = { space => $spaceKey, title => $title, content => $content }; print "Updating wiki page...\n"; $wiki->updatePage($newPage); $wiki->logout();It seems like the Confluence module doesn't retrieve the current page version if this error is returned, so it doesn't retry with it. I was able to fix this by changing this line in Confluence.pm:
if ($LastError =~ /already exists/)with
if ($LastError =~ /already exists/ || $LastError =~ /outdated/)Now my example script works, updating the same page with new content each time I run it.
Apr 23, 2008
Patricia Kale says:
I have been successfully using xml-rpc and the confluence.pm module to send cont...I have been successfully using xml-rpc and the confluence.pm module to send content to our confluence server from a perl script. However, I modified the script which resulted in an increase in the size of the content being sent back to confluence. An error is being flagged at the call to updatePage. I am now getting the following error in my apache log file. Am I bumping up against a maximum size limit?
From the apache error_log:
Content-Length header value was wrong, fixed at /.../lib/site_perl/LWP/Protocol/http.pm line 189.
XML-RPC ERROR: Unable to connect to https://.../rpc/xmlrpc at /var/apache2/cgi-bin/confluence_test.cgi line 285
Premature end of script headers: confluence_test.cgi
Thanks,
Pat
Apr 24, 2008
Patricia Kale says:
I found the source of my problem in a csv input file. The data from the csv file...I found the source of my problem in a csv input file. The data from the csv file was interpolated in the html string I passed to confluence. One of the rows in the csv file contained a string that had a space character at the end. This caused the http.pm module to flag the error. After I removed the trailing space, the script worked fine.
-Pat
May 30, 2008
Max Piskunov says:
When uploading big files (I can reproduce it with a 1MB file) the addAttachment(...When uploading big files (I can reproduce it with a 1MB file) the addAttachment() call fails with a generic error:
The code is pretty much straightforward:
What's the source of the problem?
Thanks,
Max
Jul 28
Greg Miller says:
I'm having a problem retrieving content and then saving it back into the wiki. I...I'm having a problem retrieving content and then saving it back into the wiki. I'm getting messages like the following:
Content-Length header value was wrong, fixed at /usr/lib/perl5/vendor_perl/5.8.3/LWP/Protocol/http.pm line 188
The issue seems to be that many of our pages have special characters (like the greek symbol pi or other non-standard ascii characters) - is there a way around this?
Thanks,
-Greg
Sep 18
Mario Pohlmann says:
Hi, Same problem as Mr. Miller: when I use this tool, I get this MSG: Conte...Hi,
Same problem as Mr. Miller:
when I use this tool, I get this MSG:
Any idea how I can fix this?
Oct 07
Erkki Aalto says:
Hi, I tried adding a user: $wiki = new Confluence($url, $adminuser, $adminpas...Hi,
I tried adding a user:
$wiki = new Confluence($url, $adminuser, $adminpass);
Confluence::setRaiseError(0);
Confluence::setPrintError(1);
$newuser =
;
$wiki->addUser($wiki,$newuser,"salasana");
I got this error message from debugger:
REMOTE ERROR: java.lang.NoSuchMethodException: $Proxy65.addUser(java.lang.String, java.util.Vector, java.util.Hashtable, java.lang.String) at /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi/Confluence.pm line 161.
at /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi/Confluence.pm line 161
Confluence::_rpc('Confluence=ARRAY(0x9a17b7c)', 'addUser', 'Confluence=ARRAY(0x9a17b7c)', 'HASH(0x9aa660c)', 'salasana') called at /usr/lib/perl5/site_perl/5.8.8/i386-linux-thread-multi/Confluence.pm line 182
Confluence::AUTOLOAD('Confluence=ARRAY(0x9a17b7c)', 'Confluence=ARRAY(0x9a17b7c)', 'HASH(0x9aa660c)', 'salasana') called at adduser.pl line 21
Any ideas what I did wrong?