tableau_api 1.0.0 → 1.1.2

Sign up to get free protection for your applications and to get access to all the features.
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.