diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..015e7ac --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +**/__pycache__ +/dist/ +/*.egg-info +/*.egg +build +tmp +README.rst \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..9ecfe3e --- /dev/null +++ b/.travis.yml @@ -0,0 +1,7 @@ +language: python +python: + - "2.7" +before_install: + - bundle install +install: "pip install flake8 pylint" +script: "rake" diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..5917b1c --- /dev/null +++ b/Gemfile @@ -0,0 +1,3 @@ +source 'https://rubygems.org' +gem 'rubocop', '~> 0.41.0' +gem 'rake' diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..9561fb1 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include README.rst diff --git a/README.md b/README.md index 5c20180..7bb429a 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,32 @@ +[![Build Status](https://travis-ci.org/funkwerk/confluence-python-cli.svg)](https://travis-ci.org/funkwerk/confluence-python-cli) +[![PyPi downloads](https://img.shields.io/pypi/dm/confluence_python_cli.svg)](https://pypi.python.org/pypi/confluence_python_cli/) +[![PyPi version](https://img.shields.io/pypi/v/confluence_python_cli.svg)](https://pypi.python.org/pypi/confluence_python_cli/) + # Confluence.py -Simple python script to use a Atlassian Confluence Wiki via the CLI. +Simple python script to use a Atlassian Confluence Wiki via the CLI. ## Usage - - $ python confluence.py --help + + $ python confluence.py --help usage: confluence.py [-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} + {addpage,updatepage,copypage,listpages,removepage,getpagecontent,getpagesummary,getpagesource,getattachments,getattachment,listspaces,addspace,removespace,adduser,removeuser,deactivateuser,reactivateuser,changeuserpassword,addgroup,removegroup,listgroups,listusers,getallpages,addusertogroup,removeusergromgroup,listusergroups,pagesbylabel} ... - + Confluence wiki API - + positional arguments: - {addpage,updatepage,listpages,removepage,getpagecontent,getpagesummary,listspaces,addspace,removespace,adduser,removeuser,deactivateuser,reactivateuser,changeuserpassword,addgroup,removegroup,listgroups,listusers,getallpages,addusertogroup,removeusergromgroup,listusergroups} + {addpage,updatepage,copypage,listpages,removepage,getpagecontent,getpagesummary,getpagesource,getattachments,getattachment,listspaces,addspace,removespace,adduser,removeuser,deactivateuser,reactivateuser,changeuserpassword,addgroup,removegroup,listgroups,listusers,getallpages,addusertogroup,removeusergromgroup,listusergroups,pagesbylabel} addpage Add a page + copypage Copies a page updatepage Update a page listpages List pages in one or all spaces removepage Remove a page getpagecontent Get page content + getpagesource Get page source getpagesummary Get page summary + getattachments Get a list of all attachments + getattachment Get a specific attachment listspaces List all spaces addspace Add a space removespace Remove a space @@ -36,7 +44,8 @@ Simple python script to use a Atlassian Confluence Wiki via the CLI. removeusergromgroup Remove user from a group listusergroups List groups user is in - + pagesbylabel Pages by Label + optional arguments: -h, --help show this help message and exit -w WIKIURL, --wikiurl WIKIURL @@ -109,4 +118,5 @@ For more actions, run `./confluence.py -h` or see the usage section above. ## More info -[Raymii.org](https://raymii.org) + - Original Author: [Raymii.org](https://raymii.org) + - Updates: [Funkwerk](https://github.com/confluence-pyhton-cli) diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..fc10dd9 --- /dev/null +++ b/Rakefile @@ -0,0 +1,36 @@ +task default: :audit + +desc 'Publishes the PyPi' +task push: :generate +task :push do + sh 'python3 setup.py sdist upload' +end + +desc 'Checks style' +task audit: :rubocop +task :audit do + ignores = %w( + B901 + C812 + D100 D101 D102 D103 + E121 E201 E225 E231 E302 E303 E305 E401 E501 I201 + F811 F841 + I101 + N802 N803 + P101 + Q000 + ) + + FILES = FileList[%w(*.py)] + sh "flake8 --ignore='#{ignores * ','}' #{FILES}" + sh "pylint -E #{FILES}" +end + +desc 'Checks ruby style' +task :rubocop do + sh 'rubocop' +end + +task :generate do + sh 'pandoc --from=markdown --to=rst --output=README.rst README.md' +end diff --git a/confluence.py b/confluence.py index e6d4f95..f33a1a5 100755 --- a/confluence.py +++ b/confluence.py @@ -57,6 +57,16 @@ def get_all_pages(self,spaceKey): self.spacekey = spaceKey return self.server.confluence2.getPages(self.token, self.spacekey) + def pages_by_label(self, label): + return self.server.confluence2.getLabelContentByName(self.token, label) + + def get_attachments(self, page): + return self.server.confluence2.getAttachments(self.token, page) + + def get_attachment(self, page, name, version): + return self.server.confluence2.getAttachmentData(self.token, page, name, version) + + class ConfluenceGroup(object): def __init__(self,token,server,groupname): self.server = server @@ -143,26 +153,19 @@ def add(self,parent_id=0,content=""): 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) + page = self.server.confluence2.getPage(self.token, self.spaceKey, self.name) + page["content"] = content + self.server.confluence2.storePage(self.token, page) 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 get_source(self): + return self.get() def remove(self): self.page = self.server.confluence2.getPage(self.token, self.spaceKey, self.name) @@ -242,11 +245,23 @@ def Parser(): parser_getpage.add_argument("-n", "--name", help="Page name", required=True) parser_getpage.add_argument("-s", "--spacekey", help="Space Key", required=True) + parser_getpage_source = subparsers.add_parser('getpagesource', help='Get page source') + parser_getpage_source.add_argument("-n", "--name", help="Page name", required=True) + parser_getpage_source.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_getattachments = subparsers.add_parser('getattachments', help='Get Attachments for a Page') + parser_getattachments.add_argument("-i", "--id", help="Page id", required=True) + + parser_getattachment = subparsers.add_parser('getattachment', help='Download Attachment for a Page') + parser_getattachment.add_argument("-i", "--id", help="Page id", required=True) + parser_getattachment.add_argument("-f", "--file", help="File Name", required=True) + parser_getattachment.add_argument("-v", "--version", help="Version", required=True) + parser_listspaces = subparsers.add_parser('listspaces', help='List all spaces') parser_addspace = subparsers.add_parser('addspace', help='Add a space') @@ -298,6 +313,9 @@ def Parser(): 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) + parser_pagesbylabel = subparsers.add_parser('pagesbylabel', help='Pages by Label') + parser_pagesbylabel.add_argument("-l", "--label", help="Label to filter by.", required=True) + args = parser.parse_args() return args @@ -340,6 +358,7 @@ def Actions(token,xml_server,args,content): token,xml_server,args.name,args.spacekey,content,label=args.label) copy_page.add(args.parentpage) print(copy_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) @@ -348,12 +367,15 @@ def Actions(token,xml_server,args,content): elif args.action == "getpagecontent": get_page = ConfluencePage(token,xml_server,args.name,args.spacekey,content).get_content() - print(get_page) + print(get_page.encode('utf-8')) + elif args.action == "getpagesource": + get_page = ConfluencePage(token,xml_server,args.name,args.spacekey,content).get_source() + print(get_page['content'].encode('utf-8')) 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'])) + print(args.delimiter.join([ + page['id'], page['space'], page['parentId'], page['title'], page['url']])) elif args.action == "listpages": if args.spacekey == "": @@ -363,8 +385,8 @@ def Actions(token,xml_server,args,content): 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'])) + 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() @@ -400,6 +422,16 @@ def Actions(token,xml_server,args,content): except IOError: error_out('Could not write file: %s' % page['title']) + elif args.action == "getattachments": + space = ConfluenceSpace(token,xml_server) + + print(space.get_attachments(args.id)) + + elif args.action == "getattachment": + space = ConfluenceSpace(token,xml_server) + + print(space.get_attachment(args.id, args.file, args.version)) + elif args.action == "adduser": add_user = ConfluenceUser(token,xml_server,args.newusername).create(args.fullname,args.email,args.userpassword) @@ -447,6 +479,15 @@ def Actions(token,xml_server,args,content): for group in user_groups: print(group) + elif args.action == "pagesbylabel": + all_spaces = ConfluenceSpace(token,xml_server).get_all() + + for page in ConfluenceSpace(token,xml_server).pages_by_label(args.label): + try: + print('{0}.{1}'.format(page['url'].split('/')[4].decode('utf-8'), page['title'].decode('utf-8'))) + except: + pass # TODO: Pages with unicode should work as well! + except xmlrpclib.Fault as err: print(("Error: %d: %s") % (err.faultCode, err.faultString)) diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..5bc313e --- /dev/null +++ b/setup.py @@ -0,0 +1,27 @@ +from setuptools import setup + + +def readme(): + with open('README.rst') as file: + return file.read() + +setup( + name='confluence_python_cli', + version='0.1.0', + description='REST API for confluence', + long_description=readme(), + url='http://github.com/funkwerk/confluence-python-cli', + author='Remy from github.com/RaymiiOrg, Stefan Rohe', + install_requires=[], + zip_safe=False, + classifiers=[ + 'License :: OSI Approved :: MIT License', + 'Programming Language :: Python :: 3', + 'Topic :: Software Development', + 'Environment :: Console', + 'Operating System :: OS Independent', + ], + keywords='confluence rest api', + include_package_data=True, + scripts=['confluence.py'], +)