confluence-rest-api 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 6ef648c1789440d8b0568c147ecfa0f73977892eaeed56aae36a22b2d2f97505
4
+ data.tar.gz: 5732c846ff1dda66a7ca5a63939551088cf9906fc10e78efdbcff2d7748b7f5d
5
+ SHA512:
6
+ metadata.gz: b35aeb68b573092496b57cb5dfb4156dc551ac45bbb156485bd8815a99a3a5f6922ce1cc8243b734d20774293f281fbce650d24dc2402bba4d93fa3b83d64e37
7
+ data.tar.gz: f9e68dbdfaaa568b97f154cc223e3969c3e98abb63cba274c5078fb7e5975ae4fc397b9256b8d339c05478470fe7f9c950d9186c57089f98df2ccc99a70c68ba
data/README.md ADDED
@@ -0,0 +1,131 @@
1
+ # Ruby Confluence REST API Client
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/confluence-rest-api.svg)](https://badge.fury.io/rb/confluence-rest-api)
4
+ ### Installation
5
+ ```cassandraql
6
+ gem install confluence-rest-api
7
+ ```
8
+ ### Usage
9
+ ```ruby
10
+ require 'confluence-rest-api'
11
+
12
+ rest_server = 'https://myserver.com'
13
+ user_name = 'username'
14
+ password = 'password'
15
+ space_key = 'space'
16
+
17
+ client = ConfluenceClient.new(rest_server, user_name, password)
18
+
19
+ #################################
20
+ # Query an existing page by title
21
+ #################################
22
+
23
+ page = PageObject.new('page_title', space_key)
24
+ if page.id.nil?
25
+ puts '*** WARNING: Unable to open page: page_title'
26
+ else
27
+ puts "Body: #{page.rendered_body}"
28
+ puts "Fully styled #{page.styled_view}"
29
+ puts "ID: #{page.id}"
30
+ puts "Status: #{page.status}"
31
+ puts "Version: #{page.version}"
32
+ puts "Created By: #{page.created_by}"
33
+ puts "Date Created: #{page.created}"
34
+ puts "Date Updated: #{page.last_update}"
35
+ puts "Page URL: #{page.url}"
36
+ end
37
+
38
+ ###############################
39
+ # Query an existing page by id
40
+ ###############################
41
+
42
+ page = PageObject.new(123456789, space_key)
43
+ if page.title.nil?
44
+ puts '*** WARNING: Unable to open page with id: 123456789'
45
+ else
46
+ puts "Body: #{page.rendered_body}"
47
+ puts "Fully styled #{page.styled_view}"
48
+ puts "ID: #{page.id}"
49
+ puts "Status: #{page.status}"
50
+ puts "Version: #{page.version}"
51
+ puts "Created By: #{page.created_by}"
52
+ puts "Date Created: #{page.created}"
53
+ puts "Date Updated: #{page.last_update}"
54
+ puts "Page URL: #{page.url}"
55
+ end
56
+
57
+ ###########################################################
58
+ # Create a new page with a page titled "Home" as its parent
59
+ ###########################################################
60
+
61
+ home_page = PageObject.new('Home', space_key)
62
+ unless home_page.id.nil?
63
+ client.create_page_with_parent('My Page Title', space_key, 'My Page Body Content', home_page.id)
64
+ end
65
+
66
+ #############################
67
+ # Add an attachment to a page
68
+ #############################
69
+
70
+ page_obj = PageObject.new('My Page Title', space_key)
71
+ unless page_obj.id.nil?
72
+ img_base_name = 'my/image/location'
73
+ image = 'my_image.png'
74
+ if page_obj.attach_binary_file(image, img_base_name).nil?
75
+ puts "*** WARNING: Image attachment #{image} for #{title} was not successful."
76
+ else
77
+ puts "Image attachment #{image} for #{title} was successful."
78
+ end
79
+ end
80
+
81
+ ##################################
82
+ # Remove an attachment from a page
83
+ ##################################
84
+
85
+ page_obj = PageObject.new('My Page Title', space_key)
86
+ id = page_obj.attachment_id('my_image.png')
87
+ if id.nil?
88
+ puts "Attachment doesn't exist."
89
+ elsif page_obj.delete_attachment(id).nil?
90
+ puts "*** WARNING: Attachment with ID #{id} was not deleted."
91
+ else
92
+ puts "Attachment with ID #{id} was deleted"
93
+ end
94
+
95
+
96
+ ##################################################
97
+ # Get an array listing of the page attachment data
98
+ ##################################################
99
+ page_obj = PageObject.new('My Page Title', space_key)
100
+ att_array = get_all_attachments(page_obj.id)
101
+ att_array.each do |line|
102
+ entry_hash = line.to_hash
103
+ title = entry_hash["title"]
104
+ uri = entry_hash["_links"]["download"]
105
+ puts "Attachment title: #{title}"
106
+ puts "Attachment link : #{uri}"
107
+ end
108
+
109
+ ######################################################
110
+ # Save all attachments of a page to the given location
111
+ ######################################################
112
+ page_obj = PageObject.new('My Page Title', space_key)
113
+ page_obj.save_file_attachments(page_obj.id, './')
114
+
115
+ ###############
116
+ # Delete a page
117
+ ###############
118
+
119
+ page_obj = PageObject.new('My Page Title', space_key)
120
+ if page_obj.delete_page(page_obj.id).nil?
121
+ puts "*** WARNING: Page with ID #{page_obj.id} was not deleted."
122
+ else
123
+ puts "Page with ID #{page_obj.id} was deleted."
124
+ end
125
+
126
+
127
+ ````
128
+
129
+ ### TODO
130
+ 1. Add tests
131
+
@@ -0,0 +1,14 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{confluence-rest-api}
3
+ s.version = "1.0.6"
4
+ s.date = %q{2020-04-17}
5
+ s.summary = %q{Ruby REST API Client to create, update, and view pages}
6
+ s.authors = "Gregory J. Miller"
7
+ s.files = [
8
+ "lib/confluence-rest-api.rb", "lib/confluence.rb", "lib/page.rb", "lib/storage_format.rb", "README.md", "confluence-rest-api.gemspec"
9
+ ]
10
+ s.license = "MIT"
11
+ s.homepage = "https://github.com/grmi64/confluence-rest-api"
12
+ s.add_runtime_dependency 'rest-client', '~> 2.0', '>= 2.0.0'
13
+
14
+ end
@@ -0,0 +1,4 @@
1
+ require 'confluence'
2
+ require 'page'
3
+ require 'storage_format'
4
+
data/lib/confluence.rb ADDED
@@ -0,0 +1,91 @@
1
+ require 'rest-client'
2
+ require 'json'
3
+
4
+ class ConfluenceClient
5
+
6
+ def initialize(url, name, password)
7
+ @@conf_url = url
8
+ @@login = name
9
+ @@pwd = password
10
+ @@urn = 'rest/api/content'
11
+ end
12
+
13
+ def create_page_with_parent(title, spacekey, content, parentid)
14
+
15
+ page_meta = { type: 'create_page_with_parent',
16
+ title: title,
17
+ spacekey: spacekey,
18
+ content: content,
19
+ parentid: parentid }
20
+
21
+ create_page(PagePayload.new(page_meta).page_format)
22
+
23
+ end
24
+
25
+ def update_page_with_parent(page_obj, parent_page_obj, spacekey, content)
26
+
27
+ version = page_obj.version + 1
28
+
29
+ page_meta = { type: 'update_page_with_parent',
30
+ pageid: page_obj.id,
31
+ parentid: parent_page_obj.id,
32
+ title: page_obj.title,
33
+ spacekey: spacekey,
34
+ content: content,
35
+ version: version }
36
+
37
+ update_page(PagePayload.new(page_meta).page_format, page_obj.id)
38
+
39
+ end
40
+
41
+ def create_page_with_no_parent(title, spacekey, content)
42
+
43
+ page_meta = { type: 'create_page_with_no_parent',
44
+ title: title,
45
+ spacekey: spacekey,
46
+ content: content }
47
+
48
+ create_page(PagePayload.new(page_meta).page_format)
49
+
50
+ end
51
+
52
+ def update_page_with_no_parent(page_obj, spacekey, content)
53
+
54
+ version = page_obj.version + 1
55
+
56
+ page_meta = { type: 'update_page_with_no_parent',
57
+ pageid: page_obj.id,
58
+ title: page_obj.title,
59
+ spacekey: spacekey,
60
+ content: content,
61
+ version: version }
62
+
63
+ update_page(PagePayload.new(page_meta).page_format, page_obj.id)
64
+
65
+ end
66
+
67
+ private
68
+
69
+ def create_page(payload)
70
+
71
+ url = "#{@@conf_url}/#{@@urn}?os_username=#{@@login}&os_password=#{@@pwd}"
72
+ begin
73
+ RestClient.post url, payload, :content_type => 'application/json'
74
+ rescue RestClient::ExceptionWithResponse => error
75
+ puts '*** ERROR: RestClient.post failed'
76
+ pp error
77
+ end
78
+ end
79
+
80
+ def update_page(payload, id)
81
+
82
+ url = "#{@@conf_url}/#{@@urn}/#{id}?os_username=#{@@login}&os_password=#{@@pwd}"
83
+ begin
84
+ RestClient.put url, payload, :content_type => 'application/json', :accept => 'json'
85
+ rescue RestClient::ExceptionWithResponse => error
86
+ puts '*** ERROR: RestClient.put failed'
87
+ puts error
88
+ end
89
+ end
90
+
91
+ end
data/lib/page.rb ADDED
@@ -0,0 +1,225 @@
1
+ require 'nokogiri'
2
+
3
+ class PageObject < ConfluenceClient
4
+
5
+ attr_reader :title, :id, :version, :status, :created, :created_by, :last_updated
6
+
7
+ def initialize(title_or_id, spacekey)
8
+ if title_or_id.is_a? Integer
9
+ @title, @id, @version, @status, @created, @created_by, @last_updated, @url = get_page_info_by_id(title_or_id.to_s, spacekey)
10
+ else
11
+ @title, @id, @version, @status, @created, @created_by, @last_updated, @url = get_page_info_by_title(title_or_id, spacekey)
12
+ end
13
+ end
14
+
15
+ def url
16
+ unless @url.nil?
17
+ @@conf_url + @url
18
+ end
19
+ end
20
+
21
+ #####################################################
22
+ # Includes entire HTML render (including HEADER etc.)
23
+ #####################################################
24
+ def styled_view
25
+ begin
26
+ res = RestClient.get "#{@@conf_url}/#{@@urn}/#{@id}", {params: {
27
+ :expand => 'body.styled_view', :os_username => @@login, :os_password => @@pwd
28
+ }}
29
+ rescue RestClient::ExceptionWithResponse => e
30
+ puts Nokogiri.XML(e.response)
31
+ end
32
+ JSON.parse(res)['body']['styled_view']['value']
33
+ end
34
+
35
+ ##################################################
36
+ # Includes only the rendered HTML BODY of the page
37
+ ##################################################
38
+ def rendered_body
39
+ begin
40
+ res = RestClient.get "#{@@conf_url}/#{@@urn}/#{@id}", {params: {
41
+ :expand => 'body.view', :os_username => @@login, :os_password => @@pwd
42
+ }}
43
+ rescue RestClient::ExceptionWithResponse => e
44
+ puts Nokogiri.XML(e.response)
45
+ end
46
+ JSON.parse(res)['body']['view']['value']
47
+ end
48
+
49
+ def storage_format
50
+ begin
51
+ res = RestClient.get "#{@@conf_url}/#{@@urn}/#{@id}", {params: {
52
+ :expand => 'body.storage', :os_username => @@login, :os_password => @@pwd
53
+ }}
54
+ rescue RestClient::ExceptionWithResponse => e
55
+ puts Nokogiri.XML(e.response)
56
+ end
57
+ JSON.parse(res)['body']['storage']['value']
58
+ end
59
+
60
+ def delete_page(page_id)
61
+ begin
62
+ RestClient.delete "#{@@conf_url}/#{@@urn}/#{page_id}", {params: {
63
+ :os_username => @@login, :os_password => @@pwd
64
+ }}
65
+ rescue RestClient::ExceptionWithResponse => e
66
+ puts Nokogiri.XML(e.response)
67
+ return nil
68
+ end
69
+ true
70
+ end
71
+
72
+ # Return an array of all page attachment information
73
+ def get_all_attachments(page_id)
74
+
75
+ url = "#{@@conf_url}/#{@@urn}/#{page_id}/child/attachment?os_username=#{@@login}&os_password=#{@@pwd}&status=current"
76
+
77
+ begin
78
+ atts = RestClient.get url, :content_type => 'application/json', :accept => 'json'
79
+ rescue RestClient::ExceptionWithResponse => e
80
+ puts Nokogiri.XML(e.response)
81
+ nil
82
+ end
83
+
84
+ unless atts.nil?
85
+ JSON.parse(atts)["results"]
86
+ end
87
+ end
88
+
89
+ def attach_binary_file(file_name, file_basename)
90
+
91
+ if File.exist?("#{file_basename}/#{file_name}")
92
+ payload = {
93
+ multipart: true,
94
+ file: File.new("#{file_basename}/#{file_name}", 'rb'),
95
+ comment: 'Automated Ruby import',
96
+ minorEdit: true
97
+ }
98
+ url_mod = "#{@@conf_url}/#{@@urn}/#{@id}/child/attachment?os_username=#{@@login}&os_password=#{@@pwd}"
99
+ begin
100
+ RestClient.post(url_mod, payload, {"X-Atlassian-Token" => "nocheck"})
101
+ true
102
+ rescue RestClient::ExceptionWithResponse => e
103
+ puts Nokogiri.XML(e.response)
104
+ nil
105
+ end
106
+ else
107
+ puts "*** WARNING: File can't be found for #{file_basename}/#{file_name}"
108
+ nil
109
+ end
110
+ end
111
+
112
+ def delete_attachment(attach_id)
113
+ begin
114
+ RestClient.delete "#{@@conf_url}/#{@@urn}/#{attach_id}", {params: {
115
+ :os_username => @@login, :os_password => @@pwd
116
+ }}
117
+ rescue RestClient::ExceptionWithResponse => e
118
+ puts Nokogiri.XML(e.response)
119
+ return nil
120
+ end
121
+ true
122
+ end
123
+
124
+ def attachment_id(attachment_name)
125
+
126
+ fname = attachment_name.dup
127
+ fname = CGI.escape(fname)
128
+
129
+ begin
130
+ response = RestClient.get "#{@@conf_url}/#{@@urn}/#{@id}/child/attachment", {params: {
131
+ :filename => fname, 'os_username' => @@login, 'os_password' => @@pwd
132
+ }}
133
+
134
+ response = JSON.parse(response)
135
+ if response['results'].any?
136
+ return response['results'][0]['id']
137
+ end
138
+ rescue RestClient::ExceptionWithResponse => e
139
+ puts Nokogiri.XML(e.response)
140
+ end
141
+ nil
142
+ end
143
+
144
+ def save_file_attachments(page_id, storage_path)
145
+ if File.writable? storage_path
146
+ att_array = get_all_attachments(page_id)
147
+
148
+ att_array.each do |line|
149
+ download_hash = line.to_hash
150
+ title = download_hash["title"]
151
+ url = @@conf_url + download_hash["_links"]["download"] + "&os_username=#{@@login}&os_password=#{@@pwd}"
152
+
153
+ File.open(storage_path + title, 'wb') {|f|
154
+ block = proc { |response|
155
+ response.read_body do |chunk|
156
+ f.write chunk.to_s
157
+ end
158
+ }
159
+ RestClient::Request.execute(method: :get,
160
+ url: url,
161
+ block_response: block)
162
+ }
163
+ end
164
+ else
165
+ puts "*** ERROR: Cannot write to path: #{storage_path}"
166
+ puts " Skipping."
167
+ return false
168
+ end
169
+ true
170
+ end
171
+
172
+ ##################################################################
173
+ private
174
+ ##################################################################
175
+
176
+ # Here we can return various metadata for a given page.
177
+ def get_page_info_by_title(title, spacekey)
178
+ begin
179
+ res = RestClient.get "#{@@conf_url}/#{@@urn}", {params: {
180
+ :title => title, :spaceKey => spacekey, :os_username => @@login, :os_password => @@pwd, :expand => 'version,history'
181
+ }}
182
+ rescue RestClient::ExceptionWithResponse => e
183
+ puts Nokogiri.XML(e.response)
184
+ end
185
+ if res.nil? || JSON.parse(res)['results'][0].nil?
186
+ puts '*** WARNING: Page ID not found.'
187
+ puts " Page: #{title}"
188
+ puts " Space Key: #{spacekey}"
189
+ return nil
190
+ else
191
+ return JSON.parse(res)['results'][0]['title'],
192
+ JSON.parse(res)['results'][0]['id'],
193
+ JSON.parse(res)['results'][0]['version']['number'],
194
+ JSON.parse(res)['results'][0]['status'],
195
+ JSON.parse(res)['results'][0]['history']['createdDate'],
196
+ JSON.parse(res)['results'][0]['history']['createdBy']['username'],
197
+ JSON.parse(res)['results'][0]['version']['when'],
198
+ JSON.parse(res)['results'][0]['_links']['webui']
199
+ end
200
+ end
201
+
202
+ def get_page_info_by_id(id, spacekey)
203
+ begin
204
+ res = RestClient.get "#{@@conf_url}/#{@@urn}/#{id}?os_username=#{@@login}&os_password=#{@@pwd}&expand=version,history"
205
+ rescue RestClient::ExceptionWithResponse => e
206
+ puts Nokogiri.XML(e.response)
207
+ end
208
+ # if res.nil? || JSON.parse(res)['results'].nil?
209
+ if res.nil?
210
+ puts "*** WARNING: Page not found for id: #{id}"
211
+ puts " Space Key: #{spacekey}"
212
+ return nil
213
+ else
214
+ return JSON.parse(res)['title'],
215
+ JSON.parse(res)['id'],
216
+ JSON.parse(res)['version']['number'],
217
+ JSON.parse(res)['status'],
218
+ JSON.parse(res)['history']['createdDate'],
219
+ JSON.parse(res)['history']['createdBy']['username'],
220
+ JSON.parse(res)['version']['when'],
221
+ JSON.parse(res)['_links']['webui']
222
+ end
223
+ end
224
+
225
+ end
@@ -0,0 +1,117 @@
1
+ class StorageFormat
2
+ attr_accessor :page_format
3
+
4
+ VALID_OPTIONS = [:type, :title, :spacekey, :content, :pageid, :parentid, :version]
5
+
6
+ def initialize(**options)
7
+ options.each do |key, value|
8
+ # puts "--> #{key} = #{value}"
9
+ raise "\n*** Error: unknown option #{key.inspect}\nValid option are:\n#{VALID_OPTIONS}" unless (VALID_OPTIONS.include?(key))
10
+
11
+ instance_variable_set("@#{key}", value)
12
+ end
13
+ @page_format = get_type_of_storage(@type)
14
+ end
15
+
16
+ def get_type_of_storage(type)
17
+ case type
18
+ when 'create_page_with_no_parent'
19
+ if [@title, @spacekey, @content].include?(nil)
20
+ puts "*** ERROR: Undefined parameter(s)\n Inspection: #{self.inspect}"
21
+ exit(false)
22
+ else
23
+ %Q(
24
+ {
25
+ "type": "page",
26
+ "title": "#{@title}",
27
+ "space": {
28
+ "key": "#{@spacekey}"
29
+ },
30
+ "body": {
31
+ "storage": {
32
+ "value": "#{@content}",
33
+ "representation": "storage"
34
+ }
35
+ }
36
+ }
37
+ )
38
+ end
39
+ when 'create_page_with_parent'
40
+ if [@parentid, @title, @spacekey, @content].include?(nil)
41
+ puts "*** ERROR: Undefined parameter(s)\n Inspection: #{self.inspect}"
42
+ exit(false)
43
+ else
44
+ %Q(
45
+ {
46
+ "type": "page",
47
+ "ancestors": [{"type":"page","id":"#{@parentid}"}],
48
+ "title": "#{@title}",
49
+ "space": {
50
+ "key": "#{@spacekey}"
51
+ },
52
+ "body": {
53
+ "storage": {
54
+ "value": "#{@content}",
55
+ "representation": "storage"
56
+ }
57
+ }
58
+ }
59
+ )
60
+ end
61
+ when 'update_page_with_no_parent'
62
+ if [@pageid, @title, @spacekey, @content, @version].include?(nil)
63
+ puts "*** ERROR: Undefined parameter(s)\n Inspection: #{self.inspect}"
64
+ exit(false)
65
+ else
66
+ %Q(
67
+ {
68
+ "id":"#{@pageid}",
69
+ "type":"page",
70
+ "title":"#{@title}",
71
+ "space": {
72
+ "key":"#{@spacekey}"
73
+ },
74
+ "body": {
75
+ "storage": {
76
+ "value":"#{@content}",
77
+ "representation":"storage"
78
+ }
79
+ },
80
+ "version": {
81
+ "number":"#{@version}"
82
+ }
83
+ }
84
+ )
85
+ end
86
+ when 'update_page_with_parent'
87
+ if [@pageid, @parentid, @title, @spacekey, @content, @version].include?(nil)
88
+ puts "*** ERROR: Undefined parameter(s)\n Inspection: #{self.inspect}"
89
+ exit(false)
90
+ else
91
+ %Q(
92
+ {
93
+ "id":"#{@pageid}",
94
+ "type":"page",
95
+ "ancestors": [{"type":"page","id":"#{@parentid}"}],
96
+ "title":"#{@title}",
97
+ "space": {
98
+ "key":"#{@spacekey}"
99
+ },
100
+ "body": {
101
+ "storage": {
102
+ "value":"#{@content}",
103
+ "representation":"storage"
104
+ }
105
+ },
106
+ "version": {
107
+ "number":"#{@version}"
108
+ }
109
+ }
110
+ )
111
+ end
112
+ else
113
+ puts "***ERROR: Wrong parameters for #{self.class.name}"
114
+ exit(false)
115
+ end
116
+ end
117
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: confluence-rest-api
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.6
5
+ platform: ruby
6
+ authors:
7
+ - Gregory J. Miller
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2020-04-17 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rest-client
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.0'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.0.0
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2.0'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.0.0
33
+ description:
34
+ email:
35
+ executables: []
36
+ extensions: []
37
+ extra_rdoc_files: []
38
+ files:
39
+ - README.md
40
+ - confluence-rest-api.gemspec
41
+ - lib/confluence-rest-api.rb
42
+ - lib/confluence.rb
43
+ - lib/page.rb
44
+ - lib/storage_format.rb
45
+ homepage: https://github.com/grmi64/confluence-rest-api
46
+ licenses:
47
+ - MIT
48
+ metadata: {}
49
+ post_install_message:
50
+ rdoc_options: []
51
+ require_paths:
52
+ - lib
53
+ required_ruby_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '0'
63
+ requirements: []
64
+ rubyforge_project:
65
+ rubygems_version: 2.7.6
66
+ signing_key:
67
+ specification_version: 4
68
+ summary: Ruby REST API Client to create, update, and view pages
69
+ test_files: []