confluence-rest-api 1.0.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []