diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0d20b64 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.pyc diff --git a/README.md b/README.md index 5c20180..d962186 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,35 @@ -# Confluence.py +# confluence-py -Simple python script to use a Atlassian Confluence Wiki via the CLI. +Simple python module to use a Atlassian Confluence Wiki. CLI available. -## Usage +## Installation + +Via pip: + + pip install confluence-py + +## Module usage + +Initialise the Api: + + from confluence import Api + wiki_url = "" # your wiki url + user, pw = "", "" # your credentials + api = Api(wiki_url, user, pw) + +Create a page: + + api.addpage("My new page", "SPACE_KEY", "This is my new page, yay!") + +Create a page with a parent: + + api.addpage(..., parentpage="xxxx") # with parent id + + +## CLI Usage - $ python confluence.py --help - usage: confluence.py [-h] -w WIKIURL -u USERNAME -p PASSWORD + $ confluence-cli --help + usage: confluence-cli [-h] -w WIKIURL -u USERNAME -p PASSWORD {addpage,updatepage,listpages,removepage,getpagecontent,getpagesummary,listspaces,addspace,removespace,adduser,removeuser,deactivateuser,reactivateuser,changeuserpassword,addgroup,removegroup,listgroups,listusers,getallpages,addusertogroup,removeusergromgroup,listusergroups} ... @@ -52,60 +76,60 @@ Simple python script to use a Atlassian Confluence Wiki via the CLI. Add page: - $ ./confluence.py --wikiurl="http://wiki.raymii.org" -u "api" -p "" addpage -f ./content.txt -n "CLI New Page" -s "RAY" + $ confluence-cli --wikiurl="http://wiki.raymii.org" -u "api" -p "" addpage -f ./content.txt -n "CLI New Page" -s "RAY" http://wiki.raymii.org/display/RAY/CLI+New+Page Remove Page: - $ ./confluence.py --wikiurl="http://wiki.raymii.org" -u "api" -p "" removepage -n "CLI New Page" -s "RAY" + $ confluence-cli --wikiurl="http://wiki.raymii.org" -u "api" -p "" removepage -n "CLI New Page" -s "RAY" Update Page: - $ ./confluence.py --wikiurl="http://wiki.raymii.org" -u "api" -p "" updatepage -f ./content.txt -n "CLI New Page" -s "RAY" + $ confluence-cli --wikiurl="http://wiki.raymii.org" -u "api" -p "" updatepage -f ./content.txt -n "CLI New Page" -s "RAY" http://wiki.raymii.org/display/RAY/CLI+New+Page Get page content (HTML): - $ ./confluence.py --wikiurl="http://wiki.raymii.org" -u "api" -p "" getpagecontent -n "CLI New Page" -s "RAY" + $ confluence-cli --wikiurl="http://wiki.raymii.org" -u "api" -p "" getpagecontent -n "CLI New Page" -s "RAY"

Table of Contents

Information

Add Space: - ./confluence.py --wikiurl="http://wiki.raymii.org" -u "api" -p "" addspace -n "New Space" -s "NS" + $ confluence-cli --wikiurl="http://wiki.raymii.org" -u "api" -p "" addspace -n "New Space" -s "NS" Remove Space: - ./confluence.py --wikiurl="http://wiki.raymii.org" -u "api" -p "" removespace -s "NS" + $ confluence-cli --wikiurl="http://wiki.raymii.org" -u "api" -p "" removespace -s "NS" List all spaces: - $ ./confluence.py --wikiurl="http://wiki.raymii.org" -u "api" -p "" listspaces + $ confluence-cli --wikiurl="http://wiki.raymii.org" -u "api" -p "" listspaces NS, New Space, http://wiki.raymii.org/display/NS ITS, IT Staff, http://wiki.raymii.org/display/ITS Add user: - $ ./confluence.py --wikiurl="http://wiki.raymii.org" -u "api" -p "" adduser -U "newuser" -N "New user" -E "newuser@raymii.org" -X "password" + $ confluence-cli --wikiurl="http://wiki.raymii.org" -u "api" -p "" adduser -U "newuser" -N "New user" -E "newuser@raymii.org" -X "password" Remove user: - $ ./confluence.py --wikiurl="http://wiki.raymii.org" -u "api" -p "" removeuser -U newuser + $ confluence-cli --wikiurl="http://wiki.raymii.org" -u "api" -p "" removeuser -U newuser Deactivate user: - $ ./confluence.py --wikiurl="http://wiki.raymii.org" -u "api" -p "" deactivateuser -U newuser + $ confluence-cli --wikiurl="http://wiki.raymii.org" -u "api" -p "" deactivateuser -U newuser Reactivate user: - $ ./confluence.py --wikiurl="http://wiki.raymii.org" -u "api" -p "" reactivateuser -U newuser + $ confluence-cli --wikiurl="http://wiki.raymii.org" -u "api" -p "" reactivateuser -U newuser -For more actions, run `./confluence.py -h` or see the usage section above. +For more actions, run `confluence-cli -h` or see the usage section above. ## More info diff --git a/bin/confluence-cli b/bin/confluence-cli new file mode 100755 index 0000000..c20d8e9 --- /dev/null +++ b/bin/confluence-cli @@ -0,0 +1,276 @@ +#!/usr/bin/env python +# Copyright (C) 2013 Remy van Elst + +# 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 3 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, see . + +import sys, xmlrpclib, argparse, string, logging + +from confluence import Api + +# +# Logging +# + +logger = logging.getLogger(__name__.rpartition('.')[0]) +logger.setLevel(logging.DEBUG) +console_handler = logging.StreamHandler() +console_handler.setLevel(logging.INFO) +formatter = logging.Formatter('%(levelname)s: [%(name)s] %(message)s') +console_handler.setFormatter(formatter) +logger.addHandler(console_handler) + + +def error_out(error_message): + print("Error: ") + print(error_message) + exit() + + +def Parser(): + parser = argparse.ArgumentParser(description="Confluence wiki API") + parser.add_argument("-w", "--wikiurl", help="Wiki URL (only FQDN, no / and such)", required=True) + parser.add_argument("-u", "--username", help="Login Username", required=True) + parser.add_argument("-p", "--password", help="Login Password", required=True) + parser.add_argument("-v", "--verbose", help="Enable debug logging", action="store_true") + subparsers = parser.add_subparsers(dest="action") + + parser_addpage = subparsers.add_parser('addpage', help='Add a page') + parser_addpage.add_argument("-n", "--name", help="(New) page name", required=True) + parser_addpage.add_argument("-P", "--parentpage", help="Parent page ID", default="0") + parser_addpage.add_argument("-l", "--label", help="Page label", default="created_via_api") + parser_addpage.add_argument("-s", "--spacekey", help="Space Key", required=True) + files_addpage = parser_addpage.add_mutually_exclusive_group() + files_addpage.add_argument("-f", "--file", help="Read content from this file") + files_addpage.add_argument("-S", "--stdin", help="Read content from STDIN", action="store_true") + + parser_updatepage = subparsers.add_parser('updatepage', help='Update a page') + parser_updatepage.add_argument("-n", "--name", help="Page name", required=True) + parser_updatepage.add_argument("-s", "--spacekey", help="Space Key", required=True) + parser_updatepage.add_argument("-P", "--parentpage", help="Parent page ID", default="0") + parser_updatepage.add_argument("-l", "--label", help="Page label", default="created_via_api") + files_updatepage = parser_updatepage.add_mutually_exclusive_group() + files_updatepage.add_argument("-f", "--file", help="Read content from this file") + files_updatepage.add_argument("-S", "--stdin", help="Read content from STDIN", action="store_true") + + parser_listpages = subparsers.add_parser('listpages', help='List pages in one or all spaces') + parser_listpages.add_argument("-s", "--spacekey", help="Space Key", default="") + parser_listpages.add_argument("-d", "--delimiter", help="Field delimiter", default=", ") + + parser_removepage = subparsers.add_parser('removepage', help='Remove a page') + parser_removepage.add_argument("-n", "--name", help="Page name", required=True) + parser_removepage.add_argument("-s", "--spacekey", help="Space Key", required=True) + + parser_getpage = subparsers.add_parser('getpagecontent', help='Get page content') + parser_getpage.add_argument("-n", "--name", help="Page name", required=True) + parser_getpage.add_argument("-s", "--spacekey", help="Space Key", required=True) + + parser_getpagesummary = subparsers.add_parser('getpagesummary', help='Get page summary') + parser_getpagesummary.add_argument("-s", "--spacekey", help="Space Key", required=True) + parser_getpagesummary.add_argument("-n", "--name", help="Page name", required=True) + parser_getpagesummary.add_argument("-d", "--delimiter", help="Field delimiter", default=", ") + + parser_listspaces = subparsers.add_parser('listspaces', help='List all spaces') + + parser_addspace = subparsers.add_parser('addspace', help='Add a space') + parser_addspace.add_argument("-s", "--spacekey", help="Space Key", required=True) + parser_addspace.add_argument("-D", "--description", help="Space description", required=True) + + parser_removespace = subparsers.add_parser('removespace', help='Remove a space') + parser_removespace.add_argument("-s", "--spacekey", help="Space Key", required=True) + + parser_adduser = subparsers.add_parser('adduser', help='Add a user') + parser_adduser.add_argument("-U", "--newusername", help="Username to perform action on.", required=True) + parser_adduser.add_argument("-N", "--fullname", help="Full name for new user", required=True) + parser_adduser.add_argument("-E", "--email", help="Email address for new user", required=True) + parser_adduser.add_argument("-X", "--userpassword", help="Password for new user", required=True) + + parser_removeuser = subparsers.add_parser('removeuser', help='Remove a user') + parser_removeuser.add_argument("-U", "--newusername", help="Username to perform action on.", required=True) + + parser_deactuser = subparsers.add_parser('deactivateuser', help='Deactivate a user') + parser_deactuser.add_argument("-U", "--newusername", help="Username to perform action on.", required=True) + + parser_reactuser = subparsers.add_parser('reactivateuser', help='Reactivate a user') + parser_reactuser.add_argument("-U", "--newusername", help="Username to perform action on.", required=True) + + parser_changepass = subparsers.add_parser('changeuserpassword', help='Change user password') + parser_changepass.add_argument("-U", "--newusername", help="Username to perform action on.", required=True) + parser_changepass.add_argument("-X", "--userpassword", help="Password for user", required=True) + + parser_addgroup = subparsers.add_parser('addgroup', help='Add a goup') + parser_addgroup.add_argument("-G", "--groupname", help="Group name to perform action on.", required=True) + + parser_removegroup = subparsers.add_parser('removegroup', help='Remove a goup') + parser_removegroup.add_argument("-G", "--groupname", help="Group name to perform action on.", required=True) + + parser_listgroups = subparsers.add_parser('listgroups', help='List all goup') + + parser_usersgroups = subparsers.add_parser('listusers', help='List all users') + + parser_allpages = subparsers.add_parser('getallpages', help='Save all pages to local files.') + + parser_addutog = subparsers.add_parser('addusertogroup', help='Add user to a group') + parser_addutog.add_argument("-G", "--groupname", help="Group name to perform action on.", required=True) + parser_addutog.add_argument("-U", "--newusername", help="Username to perform action on.", required=True) + + parser_removeufromg = subparsers.add_parser('removeusergromgroup', help='Remove user from a group') + parser_removeufromg.add_argument("-G", "--groupname", help="Group name to perform action on.", required=True) + parser_removeufromg.add_argument("-U", "--newusername", help="Username to perform action on.", required=True) + + parser_listusergroups = subparsers.add_parser('listusergroups', help='List groups user is in') + parser_listusergroups.add_argument("-U", "--newusername", help="Username to perform action on.", required=True) + + args = parser.parse_args() + return args + +def Content(args): + if not hasattr(args, 'file') or not hasattr(args, 'stdin'): + content = "" + elif args.file: + try: + content = open(args.file, 'rb').read() + except: + error = "Cannot open file: ", args.file + raise + elif args.stdin: + content = sys.stdin.read() + else: + content = "" + return content + +def Connect(args): + try: + api = Api(args.wikiurl, args.username, args.password) + except xmlrpclib.Fault as err: + error_out("%d: %s" % (err.faultCode, err.faultString)) + return api + + +def Actions(api, args, content): + + try: + if args.action == "addpage": + logger.debug('Command: "addpage", args.name = "{}", args.label = "{}"'.format( + args.name, args.label)) + new_page = api.addpage(args.name, args.spacekey, content, args.label, args.parentpage) + print(new_page.get()["url"]) + + elif args.action == "updatepage": + page = api.updatepage(args.name, args.spacekey, content, args.parentpage, args.label) + print(page.get()['url']) + + elif args.action == "getpagecontent": + content = api.getpagecontent(args.name, args.spacekey) + print(content) + + elif args.action == "getpagesummary": + page = api.getpage(args.name, args.spacekey) + print args.delimiter.join(( + page['id'], page['space'], page['parentId'], page['title'], page['url'])) + + elif args.action == "listpages": + all_pages = api.listpages(args.spacekey) + for page, _ in all_pages: + print args.delimiter.join(( + page['id'], page['space'], page['parentId'], page['title'], page['url'])) + + elif args.action == "removepage": + removed_page = api.removepage(args.name, args.spacekey) + + elif args.action == "addspace": + add_space = api.addspace(args.spacekey, args.name) + + elif args.action == "removespace": + remove_space = api.removespace(args.spacekey) + + elif args.action == "listspaces": + all_spaces = api.listspaces() + for space in all_spaces: + print(("%s, %s, %s") % ( + space['key'], space['name'], space['url'])) + + elif args.action == "getallpages": + all_pages = api.getallpages() + for page, page_content in all_pages: + valid_chars = "-_.() %s%s" % (string.ascii_letters, string.digits) + page_filename = page['space'] + "_" + page['title'] + ".html" + page_filename = ''.join(c for c in page_filename if c in valid_chars) + with open(page_filename, "w") as page_file: + try: + page_file.write(page_content) + page_file.close() + print("Saved page: %s" % page_filename) + except IOError: + error_out('Could not write file: %s' % page['title']) + + elif args.action == "adduser": + add_user = api.adduser(args.newusername, args.fullname, args.email, args.userpassword) + + elif args.action == "removeuser": + remove_user = api.removeuser(args.newusername) + + elif args.action == "deactivateuser": + deactivate_user = api.deactivateuser(args.newusername) + + elif args.action == "reactivateuser": + reactivate_user = api.reactivateuser(args.newusername) + + elif args.action == "changeuserpassword": + change_pass = api.changeuserpassword(args.newusername, args.userpassword) + + elif args.action == "listuserinfo": + user_info = api.getuserinfo(args.newusername) + for key,value in user_info.items(): + print(("%s: %s") % (key,value)) + + elif args.action == "addgroup": + add_group = api.addgroup(args.groupname) + + elif args.action == "removegroup": + remove_group = api.removegroup(args.groupname) + + elif args.action == "addusertogroup": + add_user_to_group = api.addusertogroup(args.newusername, args.groupname) + + elif args.action == "removeuserfromgroup": + remove_user_from_group = api.removeuserfromgroup(args.newusername, args.groupname) + + elif args.action == "listgroups": + allgroups = api.getgroups() + for group in allgroups: + print(group) + + elif args.action == "listusers": + allusers = api.getusers() + for user in allusers: + print(user) + + elif args.action == "listusergroups": + user_groups = api.getusergroups(args.newusername) + for group in user_groups: + print(group) + + except xmlrpclib.Fault as err: + print(("Error: %d: %s") % (err.faultCode, err.faultString)) + + +if __name__ == "__main__": + args = Parser() + + if args.verbose: + console_handler.setLevel(logging.DEBUG) + + content = Content(args) + api = Connect(args) + Actions(api, args, content) diff --git a/confluence.py b/confluence.py deleted file mode 100755 index daca23b..0000000 --- a/confluence.py +++ /dev/null @@ -1,459 +0,0 @@ -#!/usr/bin/env python -# Copyright (C) 2013 Remy van Elst - -# 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 3 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, see . - -import sys, xmlrpclib, argparse, string, logging - -# -# Logging -# - -logger = logging.getLogger(__name__.rpartition('.')[0]) -logger.setLevel(logging.DEBUG) -console_handler = logging.StreamHandler() -console_handler.setLevel(logging.INFO) -formatter = logging.Formatter('%(levelname)s: [%(name)s] %(message)s') -console_handler.setFormatter(formatter) -logger.addHandler(console_handler) - - -class ConfluenceSpace(object): - def __init__(self, token, server): - self.server = server - self.token = token - - def get_all(self): - self.spaces = self.server.confluence2.getSpaces(self.token) - return self.spaces - - def get_by_key(self,space_key): - self.space_key = space_key - self.space = self.server.confluence2.getSpace(self.token,self.space_key) - return self.space - - def create(self,space_key,space_name): - self.space_key = space_key - self.space_name = space_name - self.space_to_create = {"key":self.space_key,"name":self.space_name} - self.server.confluence2.addSpace(self.token,self.space_to_create) - return self.get_by_key(space_key) - - def remove(self,space_key): - self.space_key = space_key - self.server.confluence2.removeSpace(self.token,self.space_key) - - def get_all_pages(self,spaceKey): - self.spacekey = spaceKey - return self.server.confluence2.getPages(self.token, self.spacekey) - -class ConfluenceGroup(object): - def __init__(self,token,server,groupname): - self.server = server - self.token = token - self.groupname = groupname - - def get_all(self): - return self.server.confluence2.getGroups(self.token) - - def add(self): - self.server.confluence2.addGroup(self.token,self.groupname) - - def remove(self): - self.server.confluence2.removeGroup(self.token,self.groupname,"confluence-users") - - -class ConfluenceUser(object): - def __init__(self,token,server,username): - self.server = server - self.token = token - self.username = username - - def create(self,full_name,email,password): - self.password = password - self.email = email - self.full_name = full_name - self.user_to_create = {"name":self.username,"fullname":self.full_name,"email":self.email} - self.server.confluence2.addUser(self.token,self.user_to_create,self.password) - - def get_info(self): - return self.server.confluence2.getUser(self.token,self.username) - - def get_groups(self): - return self.server.confluence2.getUserGroups(self.token,self.username) - - def remove(self): - self.server.confluence2.removeUser(self.token,self.username) - - def deactivate(self): - self.server.confluence2.deactivateUser(self.token,self.username) - - def reactivate(self): - self.server.confluence2.reactivateUser(self.token,self.username) - - def add_to_group(self,group): - self.group = group - self.server.confluence2.addUserToGroup(self.token,self.username,self.group) - - def remove_from_group(self,group): - self.group = group - self.server.confluence2.removeUserFromGroup(self.token,self.username,self.group) - - def change_password(self,password): - self.password = password - self.server.confluence2.changeUserPassword(self.token,self.username,self.password) - - def get_all(self): - return self.server.confluence2.getActiveUsers(self.token, True) - - - -class ConfluencePage(object): - def __init__(self,token,server,name,spaceKey,content,page_id="",label=""): - self.server = server - self.token = token - self.name = name - self.spaceKey = spaceKey - self.content = content - self.label = label - self.logger = logging.getLogger( - __name__ + '.'+ self.__class__.__name__ - ) - self.logger.debug('Creating a new instance (name="{}", label="{}")'.format(name, label)) - - def add(self,parent_id=0,content=""): - self.logger.debug("Add page '{}'; label = [{}]".format(self.name, self.label)) - if content: - self.content = content - self.parent_id = parent_id - self.newPost = {"title":self.name,"content":self.content,"space":self.spaceKey,"parentId":str(self.parent_id)} - self.post_to_wiki = self.server.confluence2.storePage(self.token,self.newPost) - self.created_page = self.server.confluence2.getPage(self.token, self.spaceKey, self.name) - self.page_url = self.created_page["url"] - self.page_id = self.created_page["id"] - if self.label: - self.set_label() - return {"url": self.page_url, "id": self.page_id} - - def update(self,content,parent_id=0): - self.remove() - self.parent_id = parent_id - self.add(str(parent_id),content) - - def get(self): - self.wanted_page = self.server.confluence2.getPage(self.token, self.spaceKey, self.name) - return self.wanted_page - - def get_content(self): - self.wanted_page_id = self.get_page_id - self.content_values = {"style": "clean"} - self.page_content = self.wanted_page = self.server.confluence2.renderContet(self.token, self.wanted_page_id,self.content_values) - return self.page_content - - - def get_id(self): - return self.get()['id'] - - def get_content(self): - return self.get()['content'] - - def remove(self): - self.page = self.server.confluence2.getPage(self.token, self.spaceKey, self.name) - self.server.confluence2.removePage(self.token, self.page["id"]) - - def set_label(self): - self.page_id = self.get_id() - self.logger.debug("Set label '{}' on page {}".format( - self.label, self.page_id)) - if not self.server.confluence2.addLabelByName(self.token, self.label, self.page_id): - self.logger.debug("Unable to set label '{}' on page ID {}".format( - self.label, self.page_id)) - - def get_content(self): - return self.get()['content'] - - def get_version(self): - return self.get()['version'] - -class ConfluenceAuth(object): - def __init__(self,server,username,password): - self.server = server - self.username = username - self.password = password - - def login(self): - self.token = self.server.confluence2.login(self.username, self.password) - return self.token - -def error_out(error_message): - print("Error: ") - print(error_message) - exit() - - -def Parser(): - parser = argparse.ArgumentParser(description="Confluence wiki API") - parser.add_argument("-w", "--wikiurl", help="Wiki URL (only FQDN, no / and such)", required=True) - parser.add_argument("-u", "--username", help="Login Username", required=True) - parser.add_argument("-p", "--password", help="Login Password", required=True) - parser.add_argument("-v", "--verbose", help="Enable debug logging", action="store_true") - subparsers = parser.add_subparsers(dest="action") - - parser_addpage = subparsers.add_parser('addpage', help='Add a page') - parser_addpage.add_argument("-n", "--name", help="(New) page name", required=True) - parser_addpage.add_argument("-P", "--parentpage", help="Parent page ID", default="0") - parser_addpage.add_argument("-l", "--label", help="Page label", default="created_via_api") - parser_addpage.add_argument("-s", "--spacekey", help="Space Key", required=True) - files_addpage = parser_addpage.add_mutually_exclusive_group() - files_addpage.add_argument("-f", "--file", help="Read content from this file") - files_addpage.add_argument("-S", "--stdin", help="Read content from STDIN", action="store_true") - - parser_updatepage = subparsers.add_parser('updatepage', help='Update a page') - parser_updatepage.add_argument("-n", "--name", help="Page name", required=True) - parser_updatepage.add_argument("-s", "--spacekey", help="Space Key", required=True) - parser_updatepage.add_argument("-P", "--parentpage", help="Parent page ID", default="0") - parser_updatepage.add_argument("-l", "--label", help="Page label", default="created_via_api") - files_updatepage = parser_updatepage.add_mutually_exclusive_group() - files_updatepage.add_argument("-f", "--file", help="Read content from this file") - files_updatepage.add_argument("-S", "--stdin", help="Read content from STDIN", action="store_true") - - parser_listpages = subparsers.add_parser('listpages', help='List pages in one or all spaces') - parser_listpages.add_argument("-s", "--spacekey", help="Space Key", default="") - parser_listpages.add_argument("-d", "--delimiter", help="Field delimiter", default=", ") - - parser_removepage = subparsers.add_parser('removepage', help='Remove a page') - parser_removepage.add_argument("-n", "--name", help="Page name", required=True) - parser_removepage.add_argument("-s", "--spacekey", help="Space Key", required=True) - - parser_getpage = subparsers.add_parser('getpagecontent', help='Get page content') - parser_getpage.add_argument("-n", "--name", help="Page name", required=True) - parser_getpage.add_argument("-s", "--spacekey", help="Space Key", required=True) - - parser_getpagesummary = subparsers.add_parser('getpagesummary', help='Get page summary') - parser_getpagesummary.add_argument("-s", "--spacekey", help="Space Key", required=True) - parser_getpagesummary.add_argument("-n", "--name", help="Page name", required=True) - parser_getpagesummary.add_argument("-d", "--delimiter", help="Field delimiter", default=", ") - - parser_listspaces = subparsers.add_parser('listspaces', help='List all spaces') - - parser_addspace = subparsers.add_parser('addspace', help='Add a space') - parser_addspace.add_argument("-s", "--spacekey", help="Space Key", required=True) - parser_addspace.add_argument("-D", "--description", help="Space description", required=True) - - parser_removespace = subparsers.add_parser('removespace', help='Remove a space') - parser_removespace.add_argument("-s", "--spacekey", help="Space Key", required=True) - - parser_adduser = subparsers.add_parser('adduser', help='Add a user') - parser_adduser.add_argument("-U", "--newusername", help="Username to perform action on.", required=True) - parser_adduser.add_argument("-N", "--fullname", help="Full name for new user", required=True) - parser_adduser.add_argument("-E", "--email", help="Email address for new user", required=True) - parser_adduser.add_argument("-X", "--userpassword", help="Password for new user", required=True) - - parser_removeuser = subparsers.add_parser('removeuser', help='Remove a user') - parser_removeuser.add_argument("-U", "--newusername", help="Username to perform action on.", required=True) - - parser_deactuser = subparsers.add_parser('deactivateuser', help='Deactivate a user') - parser_deactuser.add_argument("-U", "--newusername", help="Username to perform action on.", required=True) - - parser_reactuser = subparsers.add_parser('reactivateuser', help='Reactivate a user') - parser_reactuser.add_argument("-U", "--newusername", help="Username to perform action on.", required=True) - - parser_changepass = subparsers.add_parser('changeuserpassword', help='Change user password') - parser_changepass.add_argument("-U", "--newusername", help="Username to perform action on.", required=True) - parser_changepass.add_argument("-X", "--userpassword", help="Password for user", required=True) - - parser_addgroup = subparsers.add_parser('addgroup', help='Add a goup') - parser_addgroup.add_argument("-G", "--groupname", help="Group name to perform action on.", required=True) - - parser_removegroup = subparsers.add_parser('removegroup', help='Remove a goup') - parser_removegroup.add_argument("-G", "--groupname", help="Group name to perform action on.", required=True) - - parser_listgroups = subparsers.add_parser('listgroups', help='List all goup') - - parser_usersgroups = subparsers.add_parser('listusers', help='List all users') - - parser_allpages = subparsers.add_parser('getallpages', help='Save all pages to local files.') - - parser_addutog = subparsers.add_parser('addusertogroup', help='Add user to a group') - parser_addutog.add_argument("-G", "--groupname", help="Group name to perform action on.", required=True) - parser_addutog.add_argument("-U", "--newusername", help="Username to perform action on.", required=True) - - parser_removeufromg = subparsers.add_parser('removeusergromgroup', help='Remove user from a group') - parser_removeufromg.add_argument("-G", "--groupname", help="Group name to perform action on.", required=True) - parser_removeufromg.add_argument("-U", "--newusername", help="Username to perform action on.", required=True) - - parser_listusergroups = subparsers.add_parser('listusergroups', help='List groups user is in') - parser_listusergroups.add_argument("-U", "--newusername", help="Username to perform action on.", required=True) - - args = parser.parse_args() - return args - -def Content(args): - if not hasattr(args, 'file') or not hasattr(args, 'stdin'): - content = "" - elif args.file: - try: - content = open(args.file, 'rb').read() - except: - error = "Cannot open file: ", args.file - raise - elif args.stdin: - content = sys.stdin.read() - else: - content = "" - return content - -def Connect(args): - wiki_url = args.wikiurl + "/rpc/xmlrpc" - xml_server = xmlrpclib.Server(wiki_url) - try: - token = ConfluenceAuth(xml_server,args.username,args.password).login() - except xmlrpclib.Fault as err: - error_out("%d: %s" % ( err.faultCode, err.faultString)) - return {"token":token,"xml_server":xml_server} - - -def Actions(token,xml_server,args,content): - - try: - if args.action == "addpage": - logger.debug('Command: "addpage", args.name = "{}", args.label = "{}"'.format( - args.name, args.label)) - new_page = ConfluencePage( - token,xml_server,args.name,args.spacekey,content,label=args.label) - new_page.add(args.parentpage) - print(new_page.get()["url"]) - - elif args.action == "updatepage": - update_page = ConfluencePage(token,xml_server,args.name,args.spacekey,content,args.parentpage,label=args.label) - update_page.update(content,args.parentpage) - update_page.set_label() - print(update_page.get()['url']) - - elif args.action == "getpagecontent": - get_page = ConfluencePage(token,xml_server,args.name,args.spacekey,content).get_content() - print(get_page) - - elif args.action == "getpagesummary": - page = ConfluencePage(token,xml_server,args.name,args.spacekey,content).get() - print args.delimiter.join(( - page['id'], page['space'], page['parentId'], page['title'], page['url'])) - - elif args.action == "listpages": - if args.spacekey == "": - spaces = ConfluenceSpace(token,xml_server).get_all() - else: - spaces = [ConfluenceSpace(token,xml_server).get_by_key(args.spacekey)] - for space in spaces: - all_pages = ConfluenceSpace(token,xml_server).get_all_pages(space['key']) - for page in all_pages: - print args.delimiter.join(( - page['id'], page['space'], page['parentId'], page['title'], page['url'])) - - elif args.action == "removepage": - removed_page = ConfluencePage(token,xml_server,args.name,args.spacekey,"").remove() - - elif args.action == "addspace": - add_space = ConfluenceSpace(token,xml_server).create(args.spacekey,args.name) - - elif args.action == "removespace": - remove_space = ConfluenceSpace(token,xml_server).remove(args.spacekey) - - elif args.action == "listspaces": - all_spaces = ConfluenceSpace(token,xml_server).get_all() - for space in all_spaces: - print(("%s, %s, %s") % ( - space['key'], space['name'], space['url'])) - - elif args.action == "getallpages": - all_spaces = ConfluenceSpace(token,xml_server).get_all() - for space in all_spaces: - all_pages = ConfluenceSpace(token,xml_server).get_all_pages(space['key']) - print("Saving space: %s" % space['name']) - print("------------") - for page in all_pages: - page_content = ConfluencePage(token,xml_server,page['title'],space['key'],"").get_content() - valid_chars = "-_.() %s%s" % (string.ascii_letters, string.digits) - page_filename = space['key'] + "_" + page['title'] + ".html" - page_filename = ''.join(c for c in page_filename if c in valid_chars) - with open(page_filename, "w") as page_file: - try: - page_file.write(page_content) - page_file.close() - print("Saved page: %s" % page_filename) - except IOError: - error_out('Could not write file: %s' % page['title']) - - elif args.action == "adduser": - add_user = ConfluenceUser(token,xml_server,args.newusername).create(args.fullname,args.email,args.userpassword) - - elif args.action == "removeuser": - remove_user = ConfluenceUser(token,xml_server,args.newusername).remove() - - elif args.action == "deactivateuser": - deactivate_user = ConfluenceUser(token,xml_server,args.newusername).deactivate() - - elif args.action == "reactivateuser": - reactivate_user = ConfluenceUser(token,xml_server,args.newusername).reactivate() - - elif args.action == "changeuserpassword": - change_pass = ConfluenceUser(token,xml_server,args.newusername).change_password(args.userpassword) - - elif args.action == "listuserinfo": - user_info = ConfluenceUser(token,xml_server,args.newusername).get_info() - for key,value in user_info.items(): - print(("%s: %s") % (key,value)) - - elif args.action == "addgroup": - add_group = ConfluenceGroup(token,xml_server,args.groupname).add() - - elif args.action == "removegroup": - remove_group = ConfluenceGroup(token,xml_server,args.groupname).remove() - - elif args.action == "addusertogroup": - add_user_to_group = ConfluenceUser(token,xml_server,args.newusername).add_to_group(args.groupname) - - elif args.action == "removeuserfromgroup": - remove_user_from_group = ConfluenceUser(token,xml_server,args.newusername).remove_from_group(args.groupname) - - elif args.action == "listgroups": - allgroups = ConfluenceGroup(token,xml_server,"users").get_all() - for group in allgroups: - print(group) - - elif args.action == "listusers": - allusers = ConfluenceUser(token,xml_server,"users").get_all() - for user in allusers: - print(user) - - elif args.action == "listusergroups": - user_groups = ConfluenceUser(token,xml_server,args.newusername).get_groups() - for group in user_groups: - print(group) - - except xmlrpclib.Fault as err: - print(("Error: %d: %s") % (err.faultCode, err.faultString)) - - -def main(): - args = Parser() - - if args.verbose: - console_handler.setLevel(logging.DEBUG) - - content = Content(args) - server = Connect(args) - Actions(server["token"],server["xml_server"],args,content) - -main() diff --git a/confluence/__init__.py b/confluence/__init__.py new file mode 100644 index 0000000..f132ba4 --- /dev/null +++ b/confluence/__init__.py @@ -0,0 +1,6 @@ +from .api import Api +from .auth import ConfluenceAuth +from .group import ConfluenceGroup +from .page import ConfluencePage +from .space import ConfluenceSpace +from .user import ConfluenceUser diff --git a/confluence/api.py b/confluence/api.py new file mode 100644 index 0000000..0917919 --- /dev/null +++ b/confluence/api.py @@ -0,0 +1,112 @@ +import xmlrpclib + +from .auth import ConfluenceAuth +from .group import ConfluenceGroup +from .page import ConfluencePage +from .space import ConfluenceSpace +from .user import ConfluenceUser + + +class Api(object): + + def __init__(self, url, username, password): + self.connect(url, username, password) + + def connect(self, url, username, password): + url = "%s/rpc/xmlrpc" % url + self.server = xmlrpclib.Server(url) + self.token = ConfluenceAuth(self.server, username, password).login() + + def addpage(self, name, spacekey, content, label="", parentpage=""): + new_page = ConfluencePage( + self.token, self.server, name, + spacekey, content, label=label + ) + new_page.add(parentpage) + return new_page + + def updatepage(self, name, spacekey, content, page_id, label=""): + page = ConfluencePage(self.token, self.server, name, spacekey, page_id, label=label) + page.update(content, page_id) + page.set_label() + return page + + def getpagecontent(self, name, spacekey): + return ConfluencePage(self.token, self.server, name, spacekey).get_content() + + def getpage(self, name, spacekey): + return ConfluencePage(self.token, self.server, name, spacekey).get() + + def update_or_add_page(self, *args, **kwargs): + try: + return self.updatepage(*args, **kwargs) + except xmlrpclib.Fault: + return self.addpage(*args, **kwargs) + + def listpages(self, spacekey=""): + if not spacekey: + spaces = ConfluenceSpace(self.token, self.server).get_all() + else: + spaces = [ConfluenceSpace(self.token, self.server).get_by_key(spacekey)] + + for space in spaces: + all_pages = ConfluenceSpace(self.token, self.server).get_all_pages(space['key']) + for page in all_pages: + yield page, space + + def getallpages(self, spacekey=""): + all_pages = api.listpages() + for page, space in all_pages: + page_content = ConfluencePage(self.token, self.server, page['title'],space['key']).get_content() + yield page, page_content + + def removepage(self, name, spacekey): + return ConfluencePage(self.token, self.server, name, spacekey).remove() + + def addspace(self, spacekey, name): + return ConfluenceSpace(self.token, self.server).create(spacekey, name) + + def removespace(self, spacekey): + return ConfluenceSpace(self.token, self.server).remove(spacekey) + + def listspaces(self): + return ConfluenceSpace(self.token, self.server).get_all() + + def adduser(self, newusername, fullname, email, userpassword): + return ConfluenceUser(self.token, self.server, newusername).create(fullname, email, userpassword) + + def removeuser(self, username): + return ConfluenceUser(self.token, self.server, username).remove() + + def deactivateuser(self, username): + return ConfluenceUser(self.token, self.server, username).deactivate() + + def reactivateuser(self, username): + return ConfluenceUser(self.token, self.server, username).reactivate() + + def changeuserpassword(self, username, newpassword): + return ConfluenceUser(self.token, self.server, username).change_password(newpassword) + + def getuserinfo(self, username): + return ConfluenceUser(self.token, self.server, username).get_info() + + def addgroup(self, groupname): + return ConfluenceGroup(self.token, self.server, groupname).add() + + def removegroup(self, groupname): + return ConfluenceGroup(self.token, self.server, groupname).remove() + + def addusertogroup(self, username, groupname): + return ConfluenceUser(self.token, self.server, username).add_to_group(groupname) + + def removeuserfromgroup(self, username, groupname): + return ConfluenceUser(self.token, self.server, username).remove_from_group(groupname) + + def getgroups(self): + return ConfluenceGroup(self.token, self.server, "users").get_all() + + def getusers(self): + return ConfluenceUser(self.token, self.server, "users").get_all() + + def getusergroups(self, username): + return ConfluenceUser(self.token, self.server, username).get_groups() diff --git a/confluence/auth.py b/confluence/auth.py new file mode 100644 index 0000000..3bda035 --- /dev/null +++ b/confluence/auth.py @@ -0,0 +1,9 @@ +class ConfluenceAuth(object): + def __init__(self,server,username,password): + self.server = server + self.username = username + self.password = password + + def login(self): + self.token = self.server.confluence2.login(self.username, self.password) + return self.token diff --git a/confluence/group.py b/confluence/group.py new file mode 100644 index 0000000..92ed17d --- /dev/null +++ b/confluence/group.py @@ -0,0 +1,14 @@ +class ConfluenceGroup(object): + def __init__(self,token,server,groupname): + self.server = server + self.token = token + self.groupname = groupname + + def get_all(self): + return self.server.confluence2.getGroups(self.token) + + def add(self): + self.server.confluence2.addGroup(self.token,self.groupname) + + def remove(self): + self.server.confluence2.removeGroup(self.token,self.groupname,"confluence-users") diff --git a/confluence/page.py b/confluence/page.py new file mode 100644 index 0000000..1e63463 --- /dev/null +++ b/confluence/page.py @@ -0,0 +1,68 @@ +import logging + + +class ConfluencePage(object): + def __init__(self,token,server,name,spaceKey,content="",page_id="",label=""): + self.server = server + self.token = token + self.name = name + self.spaceKey = spaceKey + self.content = content + self.label = label + self.logger = logging.getLogger( + __name__ + '.'+ self.__class__.__name__ + ) + self.logger.debug('Creating a new instance (name="{}", label="{}")'.format(name, label)) + + def add(self,parent_id=0,content=""): + self.logger.debug("Add page '{}'; label = [{}]".format(self.name, self.label)) + if content: + self.content = content + self.parent_id = parent_id + self.newPost = {"title":self.name,"content":self.content,"space":self.spaceKey,"parentId":str(self.parent_id)} + self.post_to_wiki = self.server.confluence2.storePage(self.token,self.newPost) + self.created_page = self.server.confluence2.getPage(self.token, self.spaceKey, self.name) + self.page_url = self.created_page["url"] + self.page_id = self.created_page["id"] + if self.label: + self.set_label() + return {"url": self.page_url, "id": self.page_id} + + def update(self,content,parent_id=0): + self.remove() + self.parent_id = parent_id + self.add(str(parent_id),content) + + def get(self): + self.wanted_page = self.server.confluence2.getPage(self.token, self.spaceKey, self.name) + return self.wanted_page + + def get_content(self): + self.wanted_page_id = self.get_page_id + self.content_values = {"style": "clean"} + self.page_content = self.wanted_page = self.server.confluence2.renderContet(self.token, self.wanted_page_id,self.content_values) + return self.page_content + + def get_id(self): + return self.get()['id'] + + def get_content(self): + return self.get()['content'] + + def remove(self): + self.page = self.server.confluence2.getPage(self.token, self.spaceKey, self.name) + self.server.confluence2.removePage(self.token, self.page["id"]) + + def set_label(self): + self.page_id = self.get_id() + self.logger.debug("Set label '{}' on page {}".format( + self.label, self.page_id)) + if not self.server.confluence2.addLabelByName(self.token, self.label, self.page_id): + self.logger.debug("Unable to set label '{}' on page ID {}".format( + self.label, self.page_id)) + + def get_content(self): + return self.get()['content'] + + def get_version(self): + return self.get()['version'] diff --git a/confluence/space.py b/confluence/space.py new file mode 100644 index 0000000..8f1da37 --- /dev/null +++ b/confluence/space.py @@ -0,0 +1,28 @@ +class ConfluenceSpace(object): + def __init__(self, token, server): + self.server = server + self.token = token + + def get_all(self): + self.spaces = self.server.confluence2.getSpaces(self.token) + return self.spaces + + def get_by_key(self,space_key): + self.space_key = space_key + self.space = self.server.confluence2.getSpace(self.token,self.space_key) + return self.space + + def create(self,space_key,space_name): + self.space_key = space_key + self.space_name = space_name + self.space_to_create = {"key":self.space_key,"name":self.space_name} + self.server.confluence2.addSpace(self.token,self.space_to_create) + return self.get_by_key(space_key) + + def remove(self,space_key): + self.space_key = space_key + self.server.confluence2.removeSpace(self.token,self.space_key) + + def get_all_pages(self,spaceKey): + self.spacekey = spaceKey + return self.server.confluence2.getPages(self.token, self.spacekey) diff --git a/confluence/user.py b/confluence/user.py new file mode 100644 index 0000000..4107170 --- /dev/null +++ b/confluence/user.py @@ -0,0 +1,42 @@ +class ConfluenceUser(object): + def __init__(self,token,server,username): + self.server = server + self.token = token + self.username = username + + def create(self,full_name,email,password): + self.password = password + self.email = email + self.full_name = full_name + self.user_to_create = {"name":self.username,"fullname":self.full_name,"email":self.email} + self.server.confluence2.addUser(self.token,self.user_to_create,self.password) + + def get_info(self): + return self.server.confluence2.getUser(self.token,self.username) + + def get_groups(self): + return self.server.confluence2.getUserGroups(self.token,self.username) + + def remove(self): + self.server.confluence2.removeUser(self.token,self.username) + + def deactivate(self): + self.server.confluence2.deactivateUser(self.token,self.username) + + def reactivate(self): + self.server.confluence2.reactivateUser(self.token,self.username) + + def add_to_group(self,group): + self.group = group + self.server.confluence2.addUserToGroup(self.token,self.username,self.group) + + def remove_from_group(self,group): + self.group = group + self.server.confluence2.removeUserFromGroup(self.token,self.username,self.group) + + def change_password(self,password): + self.password = password + self.server.confluence2.changeUserPassword(self.token,self.username,self.password) + + def get_all(self): + return self.server.confluence2.getActiveUsers(self.token, True) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..2a06720 --- /dev/null +++ b/setup.py @@ -0,0 +1,27 @@ +#!/usr/bin/env python + +from distutils.core import setup + +setup( + name='Confluence-py', + version='1.0.1', + description='Python Confluence module and command line', + author='Raymii / Mvdb', + author_email='mvdb@work4labs.com', + url='https://github.com/m-vdb/confluence-python', + packages=['confluence'], + scripts=["bin/confluence-cli"], + classifiers=[ + 'Intended Audience :: Developers', + 'Operating System :: OS Independent', + 'Programming Language :: Python', + 'Programming Language :: Python :: 2', + 'Programming Language :: Python :: 2.6', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.2', + 'Programming Language :: Python :: 3.3', + 'Topic :: Software Development :: Libraries :: Application Frameworks', + 'Topic :: Software Development :: Libraries :: Python Modules', + ], +)