tableau_api 1.0.0 → 1.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 30da344a82d4ce33c21a5e921b40b9efbdc4493c
4
- data.tar.gz: 97271bab0ec0bbc33a94cbbe60e3af0aa9e48f70
3
+ metadata.gz: 79d15e26e8441669e7c04c13794a049dc968d69e
4
+ data.tar.gz: 05e49453e17574474a356d20cb21fc0ce094e6e0
5
5
  SHA512:
6
- metadata.gz: a340b001cd5d0ffbb75707fc2059f65342424d696e8cb5851f5078f9b9ad6ac641437e20816f7abf6bdece110681cc1993528397eafa34918dd37ab3215542e4
7
- data.tar.gz: 33ee40ceee96a90680e7daaa1b87acd96cdbb99d24644854818f1d363b184d3717da4e00879b2e8d60915059829ff66eb30f515f665cc34c76371caf7098e709
6
+ metadata.gz: 8e69aba0b041e655e0e93b1fc0de62f069c966148675b755365bac2572a01dd78fbc322ce1020e1e588bef1600a554e77b8e54089c5936390573d3bb0137d018
7
+ data.tar.gz: ca5ebe0289ac4af7c5ccf6c0e1945ce61f01d693b31f027cf1ed8baafcfbf7e980042afb09167c48befbf074a1a46e1d003367d1565fc30ede71cee7f2884957
data/.rubocop.yml CHANGED
@@ -1,6 +1,9 @@
1
1
  AllCops:
2
2
  TargetRubyVersion: 2.2
3
3
 
4
+ ClassLength:
5
+ Max: 200
6
+
4
7
  Style/Documentation:
5
8
  Enabled: false
6
9
 
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- 2.2.5
1
+ 2.4.1
data/.travis.yml CHANGED
@@ -4,6 +4,7 @@ branches:
4
4
  - master
5
5
  language: ruby
6
6
  rvm:
7
- - 2.3.1
8
- - 2.2.5
9
- - 2.1.9
7
+ - 2.4.1
8
+ - 2.3.4
9
+ - 2.2.7
10
+ - 2.1.10
data/CHANGELOG.md CHANGED
@@ -1,12 +1,69 @@
1
1
  # Change Log
2
+
2
3
  All notable changes to this project will be documented in this file.
3
4
  This project adheres to [Semantic Versioning](http://semver.org/).
4
5
 
5
6
  ## [Unreleased]
6
7
 
7
- ## [1.0.0] - 2016-06-06
8
+ ## [1.1.2] - 2017-05-24
9
+
10
+ ### Fixed
11
+
12
+ - Replaced corrupt `.gem` upload to RubyGems
13
+
14
+ ## [1.1.1] - 2017-05-24 - [YANKED]
15
+
16
+ ### Added
17
+
18
+ - Added Ruby 2.4.1 to the Travis matrix build
19
+
20
+ ### Changed
21
+
22
+ - Bumped the Ruby versions in the Travis matrix build to 2.3.4, 2.2.7, and
23
+ 2.1.10
24
+ - Bumped the Ruby version for development to 2.4.1
25
+ - Bumped the RSpec version for development to 3.6
26
+ - Bumped the WebMock version for development to 3.0
27
+ - Updated the authors
28
+
29
+ ### Fixed
30
+
31
+ - Updated `TableauApi::VERSION`
32
+
33
+ ## [1.1.0] - 2017-03-02
34
+
8
35
  ### Added
36
+
37
+ - [#2](https://github.com/civisanalytics/tableau_api/pull/2)
38
+ - `TableauApi::Resources::Groups` added to support API calls for
39
+ adding/deleting/updating groups.
40
+ - `TableauApi::Resources::Workbook#remove_permissions` added, including
41
+ support for user and group permissions.
42
+ - `TableauApi::Resources::Workbook#add_permissions` supports group
43
+ permissions.
44
+ - [#6](https://github.com/civisanalytics/tableau_api/pull/6)
45
+ Added `Users#update_user`
46
+ - [#7](https://github.com/civisanalytics/tableau_api/pull/7)
47
+ Added `Sites#create` and `Sites#delete`
48
+
49
+ ### Changed
50
+
51
+ - [#3](https://github.com/civisanalytics/tableau_api/pull/3)
52
+ `TableauApi::Resources::Workbook#permissions` now returns existing permissions
53
+ instead of adding new permissions. New permissions can be added with
54
+ `TableauApi::Resources::Workbook#add_permissions`.
55
+
56
+ ### Fixed
57
+
58
+ - [#4](https://github.com/civisanalytics/tableau_api/pull/4)
59
+ Always parse/return workbook permissions as an array
60
+
61
+ ## [1.0.0] - 2016-06-06
62
+
9
63
  - Initial Release
10
64
 
11
- [Unreleased]: https://github.com/civisanalytics/tableau_api/compare/v1.0.0...HEAD
65
+ [Unreleased]: https://github.com/civisanalytics/tableau_api/compare/v1.1.2...HEAD
66
+ [1.1.2]: https://github.com/civisanalytics/tableau_api/compare/v1.1.1...v1.1.2
67
+ [1.1.1]: https://github.com/civisanalytics/tableau_api/compare/v1.1.0...v1.1.1
68
+ [1.1.0]: https://github.com/civisanalytics/tableau_api/compare/v1.0.0...v1.1.0
12
69
  [1.0.0]: https://github.com/civisanalytics/tableau_api/tree/v1.0.0
data/README.md CHANGED
@@ -60,6 +60,10 @@ docker exec -it CONTAINER_ID /bin/bash -c "cd /src && bundle && rake"
60
60
 
61
61
  ### Creating New VCR Cassettes
62
62
 
63
+ Cassettes should be self-contained, generated by a single spec file
64
+ run in defined order. To make changes to specs, it's best to delete a whole cassette
65
+ and rerun the whole spec file.
66
+
63
67
  Set the environment variables below to an administrator account, create a tunnel
64
68
  to your tableau server on port 2000, then run the commands below.
65
69
 
data/lib/tableau_api.rb CHANGED
@@ -10,6 +10,7 @@ require 'tableau_api/resources/auth'
10
10
  require 'tableau_api/resources/projects'
11
11
  require 'tableau_api/resources/sites'
12
12
  require 'tableau_api/resources/users'
13
+ require 'tableau_api/resources/groups'
13
14
  require 'tableau_api/resources/workbooks'
14
15
  require 'tableau_api/version'
15
16
 
@@ -27,6 +27,7 @@ module TableauApi
27
27
  projects: TableauApi::Resources::Projects,
28
28
  sites: TableauApi::Resources::Sites,
29
29
  users: TableauApi::Resources::Users,
30
+ groups: TableauApi::Resources::Groups,
30
31
  workbooks: TableauApi::Resources::Workbooks
31
32
  }
32
33
  end
@@ -39,5 +40,9 @@ module TableauApi
39
40
  super
40
41
  end
41
42
  end
43
+
44
+ def respond_to_missing?(name, include_private = false)
45
+ self.class.resources.keys.include?(name) || super
46
+ end
42
47
  end
43
48
  end
@@ -28,7 +28,7 @@ module TableauApi
28
28
  raise TableauError, res if res.code.to_s != '200'
29
29
 
30
30
  # ensure the result is an array because it will not be an array if there is only one element
31
- [collection.split('.').reduce(res['tsResponse']) { |a, e| a && a[e] }].flatten.compact.each do |obj|
31
+ [collection.split('.').reduce(res['tsResponse']) { |acc, elem| acc && acc[elem] }].flatten.compact.each do |obj|
32
32
  enum.yield obj
33
33
  end
34
34
 
@@ -52,6 +52,10 @@ module TableauApi
52
52
  api_method(:put, path, *args)
53
53
  end
54
54
 
55
+ def api_delete(path, *args)
56
+ api_method(:delete, path, *args)
57
+ end
58
+
55
59
  def api_post_multipart(path, parts, headers)
56
60
  headers = auth_headers(headers)
57
61
  headers['Content-Type'] = 'multipart/mixed'
@@ -60,7 +64,7 @@ module TableauApi
60
64
 
61
65
  req = Net::HTTP::Post::Multipart.new(uri.to_s, parts, headers)
62
66
 
63
- Net::HTTP.start(uri.host, uri.port) do |http|
67
+ Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
64
68
  http.request(req)
65
69
  end
66
70
  end
@@ -0,0 +1,43 @@
1
+ module TableauApi
2
+ module Resources
3
+ class Groups < Base
4
+ def create(name:, default_site_role: 'Viewer')
5
+ raise 'invalid default_site_role' unless Users::SITE_ROLES.include? default_site_role
6
+
7
+ request = Builder::XmlMarkup.new.tsRequest do |ts|
8
+ ts.group(name: name, defaultSiteRole: default_site_role)
9
+ end
10
+
11
+ res = @client.connection.api_post("sites/#{@client.auth.site_id}/groups", body: request)
12
+
13
+ res['tsResponse']['group'] if res.code == 201
14
+ end
15
+
16
+ def list
17
+ url = "sites/#{@client.auth.site_id}/groups"
18
+ @client.connection.api_get_collection(url, 'groups.group')
19
+ end
20
+
21
+ def users(group_id:)
22
+ url = "sites/#{@client.auth.site_id}/groups/#{group_id}/users"
23
+ @client.connection.api_get_collection(url, 'users.user')
24
+ end
25
+
26
+ def add_user(group_id:, user_id:)
27
+ request = Builder::XmlMarkup.new.tsRequest do |ts|
28
+ ts.user(id: user_id)
29
+ end
30
+
31
+ res = @client.connection.api_post("sites/#{@client.auth.site_id}/groups/#{group_id}/users", body: request)
32
+
33
+ res.code == 200
34
+ end
35
+
36
+ def remove_user(group_id:, user_id:)
37
+ res = @client.connection.api_delete("sites/#{@client.auth.site_id}/groups/#{group_id}/users/#{user_id}")
38
+
39
+ res.code == 204
40
+ end
41
+ end
42
+ end
43
+ end
@@ -4,6 +4,33 @@ module TableauApi
4
4
  def list
5
5
  @client.connection.api_get_collection('sites', 'sites.site')
6
6
  end
7
+
8
+ def create(name:, content_url:, admin_mode: nil, num_users: nil, storage_quota: nil)
9
+ # required parameters
10
+ request_hash = {
11
+ name: name,
12
+ contentUrl: content_url
13
+ }
14
+ # optional parameters
15
+ request_hash[:admin_mode] = admin_mode if admin_mode
16
+ request_hash[:num_users] = num_users if num_users
17
+ request_hash[:storage_quota] = storage_quota if storage_quota
18
+
19
+ request = Builder::XmlMarkup.new.tsRequest do |ts|
20
+ ts.site(request_hash)
21
+ end
22
+
23
+ res = @client.connection.api_post('sites', body: request)
24
+
25
+ return res['tsResponse']['site'] if res.code == 201
26
+ raise TableauError, res
27
+ end
28
+
29
+ def delete(site_id:)
30
+ res = @client.connection.api_delete("sites/#{site_id}")
31
+ return true if res.code == 204
32
+ raise TableauError, res
33
+ end
7
34
  end
8
35
  end
9
36
  end
@@ -27,6 +27,23 @@ module TableauApi
27
27
  url = "sites/#{@client.auth.site_id}/users"
28
28
  @client.connection.api_get_collection(url, 'users.user')
29
29
  end
30
+
31
+ def update_user(user_id:, site_role:)
32
+ raise 'invalid site_role' unless SITE_ROLES.include? site_role
33
+
34
+ res = @client.connection.api_get("sites/#{@client.auth.site_id}/users/#{user_id}")
35
+
36
+ raise 'failed to find user' if res.code != 200
37
+ user = res['tsResponse']['user']
38
+
39
+ request = Builder::XmlMarkup.new.tsRequest do |ts|
40
+ ts.user(name: user['name'], siteRole: site_role)
41
+ end
42
+
43
+ res = @client.connection.api_put("sites/#{@client.auth.site_id}/users/#{user_id}", body: request)
44
+
45
+ res['tsResponse']['user'] if res.code == 200
46
+ end
30
47
  end
31
48
  end
32
49
  end
@@ -53,29 +53,57 @@ module TableauApi
53
53
  Filter Read ShareView ViewComments ViewUnderlyingData WebAuthoring Write
54
54
  ).freeze
55
55
 
56
- # capabilities is a hash of symbol keys to booleans { Read: true, ChangePermissions: false }
57
- def permissions(workbook_id:, user_id:, capabilities:)
58
- request = Builder::XmlMarkup.new.tsRequest do |ts|
59
- ts.permissions do |p|
60
- p.workbook(id: workbook_id)
61
- p.granteeCapabilities do |gc|
62
- gc.user(id: user_id)
63
- gc.capabilities do |c|
64
- capabilities.each do |k, v|
65
- k = k.to_s
66
- raise "invalid capability #{k}" unless CAPABILITIES.include? k
67
- c.capability(name: k, mode: v ? 'Allow' : 'Deny')
68
- end
69
- end
70
- end
56
+ CAPABILITY_MODES = %w(ALLOW DENY).freeze
57
+
58
+ def permissions(workbook_id:)
59
+ res = @client.connection.api_get("sites/#{@client.auth.site_id}/workbooks/#{workbook_id}/permissions")
60
+
61
+ raise TableauError, res if res.code != 200
62
+ permissions = HTTParty::Parser.new(res.body, :xml).parse['tsResponse']['permissions']['granteeCapabilities']
63
+ return [] if permissions.nil?
64
+
65
+ permissions = [permissions] unless permissions.is_a? Array
66
+ permissions.map do |p|
67
+ grantee_type = p['group'].nil? ? 'user' : 'group'
68
+
69
+ capabilities = {}
70
+ capabilities_list = p['capabilities']['capability']
71
+ capabilities_list = [capabilities_list] unless capabilities_list.is_a? Array
72
+
73
+ capabilities_list.each do |c|
74
+ capabilities[c['name'].to_sym] = c['mode'] == 'Allow'
71
75
  end
76
+
77
+ {
78
+ grantee_type: grantee_type,
79
+ grantee_id: p[grantee_type]['id'],
80
+ capabilities: capabilities
81
+ }
72
82
  end
83
+ end
84
+
85
+ # capabilities is a hash of symbol keys to booleans { Read: true, ChangePermissions: false }
86
+ def add_permissions(workbook_id:, user_id: nil, group_id: nil, capabilities:)
87
+ validate_user_group_exclusivity(user_id, group_id)
73
88
 
89
+ request = permissions_request(workbook_id, user_id, group_id, capabilities)
74
90
  res = @client.connection.api_put("sites/#{@client.auth.site_id}/workbooks/#{workbook_id}/permissions", body: request)
75
91
 
76
92
  res.code == 200
77
93
  end
78
94
 
95
+ def delete_permissions(workbook_id:, user_id: nil, group_id: nil, capability:, capability_mode:)
96
+ validate_user_group_exclusivity(user_id, group_id)
97
+ raise 'invalid capability' unless CAPABILITIES.include? capability.to_s
98
+ raise 'invalid mode' unless CAPABILITY_MODES.include? capability_mode.to_s
99
+
100
+ subpath = user_id ? "users/#{user_id}" : "groups/#{group_id}"
101
+ subpath += "/#{capability}/#{capability_mode}"
102
+ res = @client.connection.api_delete("sites/#{@client.auth.site_id}/workbooks/#{workbook_id}/permissions/#{subpath}")
103
+
104
+ res.code == 204
105
+ end
106
+
79
107
  def update(workbook_id:, owner_user_id:)
80
108
  request = Builder::XmlMarkup.new.tsRequest do |ts|
81
109
  ts.workbook(id: workbook_id) do |w|
@@ -102,6 +130,32 @@ module TableauApi
102
130
  url = "sites/#{@client.auth.site_id}/users/#{@client.auth.user_id}/workbooks"
103
131
  @client.connection.api_get_collection(url, 'workbooks.workbook')
104
132
  end
133
+
134
+ private
135
+
136
+ def permissions_request(workbook_id, user_id, group_id, capabilities)
137
+ Builder::XmlMarkup.new.tsRequest do |ts|
138
+ ts.permissions do |p|
139
+ p.workbook(id: workbook_id)
140
+ p.granteeCapabilities do |gc|
141
+ gc.user(id: user_id) if user_id
142
+ gc.group(id: group_id) if group_id
143
+ gc.capabilities do |c|
144
+ capabilities.each do |k, v|
145
+ k = k.to_s
146
+ raise "invalid capability #{k}" unless CAPABILITIES.include? k
147
+ c.capability(name: k, mode: v ? 'Allow' : 'Deny')
148
+ end
149
+ end
150
+ end
151
+ end
152
+ end
153
+ end
154
+
155
+ def validate_user_group_exclusivity(user_id, group_id)
156
+ raise 'cannot specify user_id and group_id simultaneously' if user_id && group_id
157
+ raise 'must specify user_id or group_id' unless user_id || group_id
158
+ end
105
159
  end
106
160
  end
107
161
  end
@@ -1,3 +1,3 @@
1
1
  module TableauApi
2
- VERSION = '1.0.0'.freeze
2
+ VERSION = '1.1.2'.freeze
3
3
  end
data/tableau_api.gemspec CHANGED
@@ -6,7 +6,8 @@ require 'tableau_api/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = 'tableau_api'
8
8
  spec.version = TableauApi::VERSION
9
- spec.authors = ['Christopher Manning']
9
+ spec.authors = ['Christopher Manning', 'Matt Brennan',
10
+ 'Jonathan Cobian']
10
11
  spec.email = ['opensource@civisanalytics.com']
11
12
 
12
13
  spec.summary = 'Ruby interface to the Tableau 9.0 API.'
@@ -26,10 +27,10 @@ Gem::Specification.new do |spec|
26
27
 
27
28
  spec.add_development_dependency 'bundler', '~> 1.12'
28
29
  spec.add_development_dependency 'rake', '~> 11.0'
29
- spec.add_development_dependency 'rspec', '~> 3.4'
30
+ spec.add_development_dependency 'rspec', '~> 3.6'
30
31
  spec.add_development_dependency 'vcr', '~> 3.0'
31
- spec.add_development_dependency 'webmock', '~> 1.24'
32
+ spec.add_development_dependency 'webmock', '~> 3.0'
32
33
  spec.add_development_dependency 'pry', '~> 0.10'
33
34
  spec.add_development_dependency 'pry-byebug', '~> 3.4'
34
- spec.add_development_dependency 'rubocop', '~> 0.40'
35
+ spec.add_development_dependency 'rubocop', '~> 0.46.0'
35
36
  end
metadata CHANGED
@@ -1,14 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tableau_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Christopher Manning
8
+ - Matt Brennan
9
+ - Jonathan Cobian
8
10
  autorequire:
9
11
  bindir: exe
10
12
  cert_chain: []
11
- date: 2016-06-06 00:00:00.000000000 Z
13
+ date: 2017-05-24 00:00:00.000000000 Z
12
14
  dependencies:
13
15
  - !ruby/object:Gem::Dependency
14
16
  name: httparty
@@ -100,14 +102,14 @@ dependencies:
100
102
  requirements:
101
103
  - - "~>"
102
104
  - !ruby/object:Gem::Version
103
- version: '3.4'
105
+ version: '3.6'
104
106
  type: :development
105
107
  prerelease: false
106
108
  version_requirements: !ruby/object:Gem::Requirement
107
109
  requirements:
108
110
  - - "~>"
109
111
  - !ruby/object:Gem::Version
110
- version: '3.4'
112
+ version: '3.6'
111
113
  - !ruby/object:Gem::Dependency
112
114
  name: vcr
113
115
  requirement: !ruby/object:Gem::Requirement
@@ -128,14 +130,14 @@ dependencies:
128
130
  requirements:
129
131
  - - "~>"
130
132
  - !ruby/object:Gem::Version
131
- version: '1.24'
133
+ version: '3.0'
132
134
  type: :development
133
135
  prerelease: false
134
136
  version_requirements: !ruby/object:Gem::Requirement
135
137
  requirements:
136
138
  - - "~>"
137
139
  - !ruby/object:Gem::Version
138
- version: '1.24'
140
+ version: '3.0'
139
141
  - !ruby/object:Gem::Dependency
140
142
  name: pry
141
143
  requirement: !ruby/object:Gem::Requirement
@@ -170,14 +172,14 @@ dependencies:
170
172
  requirements:
171
173
  - - "~>"
172
174
  - !ruby/object:Gem::Version
173
- version: '0.40'
175
+ version: 0.46.0
174
176
  type: :development
175
177
  prerelease: false
176
178
  version_requirements: !ruby/object:Gem::Requirement
177
179
  requirements:
178
180
  - - "~>"
179
181
  - !ruby/object:Gem::Version
180
- version: '0.40'
182
+ version: 0.46.0
181
183
  description:
182
184
  email:
183
185
  - opensource@civisanalytics.com
@@ -204,6 +206,7 @@ files:
204
206
  - lib/tableau_api/error.rb
205
207
  - lib/tableau_api/resources/auth.rb
206
208
  - lib/tableau_api/resources/base.rb
209
+ - lib/tableau_api/resources/groups.rb
207
210
  - lib/tableau_api/resources/projects.rb
208
211
  - lib/tableau_api/resources/sites.rb
209
212
  - lib/tableau_api/resources/users.rb
@@ -230,7 +233,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
230
233
  version: '0'
231
234
  requirements: []
232
235
  rubyforge_project:
233
- rubygems_version: 2.4.5.1
236
+ rubygems_version: 2.6.11
234
237
  signing_key:
235
238
  specification_version: 4
236
239
  summary: Ruby interface to the Tableau 9.0 API.