power-bi 2.3.0 → 2.4.0

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
  SHA256:
3
- metadata.gz: c120eeef2ac35b02afcfff32690f003efad7fbfd59c7f2bd714a6d0659b1ed44
4
- data.tar.gz: ee077e4fa8f6faae52ad5c1107fd96f9cb8bae5e7c8f0ef47a83009e7c80ce0d
3
+ metadata.gz: 90d415a89ed5860c82824f7e152e4c58d42054bc293f5534f6669774682a1ffe
4
+ data.tar.gz: 536d4c7cea48c859c7b780db751da15375b060a45c59946a2335887d8e948494
5
5
  SHA512:
6
- metadata.gz: c9c742362808fb3fa08ad663ebbdaf34d916f932fa5bed8f66d657caf769c230a7694d82cd05555a642d41098ccb9fcf6eed9b6f89233ca344ff3f1c3d02b6fb
7
- data.tar.gz: dc28a5e89d26365b7b48d5f6538bd1e8c12a9fe45c81b4f216ae63074ced3b728f31395c98751ee571a9e7234315693af5f6a7cffe4d86c398f6ec6683cfeafe
6
+ metadata.gz: d31db71feb4b03d7810d5805b3d48016e89ead1782bfae66269aa2a0c55340e6cf21031525ffa6d5b917cdc36041670ef52c1ccff499ebdfc7d0051d8005b6a8
7
+ data.tar.gz: 1ea49ae1a15e45b16c21b9da86c8ac20abb9e96a6eb63e6a0ed9a7dfcbca25dfff8431896703f2d55736a148668cf4b85ac591eb20c68bf1b2d9f6baee455e3a
data/README.md CHANGED
@@ -62,7 +62,9 @@ Once authenticated, you can set profiles like this:
62
62
  pbi.profile = profile
63
63
  ```
64
64
 
65
- Every action executed after setting the profile, will be executed _through the eyes of the profile_. This way, you can create an isolated multi-tenant setup. Using profiles, simplifies the internal organization of Power BI and allows faster interaction with Power BI. This also lifts the 1000-workspaces limit that is imposed on Master Userss and Service Principals
65
+ Every action executed after setting the profile, will be executed _through the eyes of the profile_. This way, you can create an isolated multi-tenant setup. Using profiles, simplifies the internal organization of Power BI and allows faster interaction with Power BI. This also lifts the 1000-workspaces limit that is imposed on Master Users and Service Principals
66
+
67
+ Note: when working with Service principal profiles (SPP), you need to add the SPP to the gateway datasource before binding the gateway datasource to the dataset.
66
68
 
67
69
  # Supported endpoints
68
70
 
@@ -122,6 +124,11 @@ Note 2: to limit the number of API calls, it is best to directly use the _getter
122
124
  * Create a new gateway datasource: `gateway.gateway_datasource.create(name, credentials, db_server, db_name)`
123
125
  * Delete a new gateway datasource: `gateway_datasource.delete`
124
126
 
127
+ ## Gateway datasource users
128
+
129
+ * List datasource users in a gateway datasource: `gateway_datasource.gateway_datasource_users`
130
+ * Add a Service principal profile to a gateway datasource: `gateway_datasource.add_service_principal_profile_user(profile_id, principal_object_id)`
131
+
125
132
  ## Capacities
126
133
 
127
134
  Note: Capacities are Azure creatures, you can't create them in Power BI.
@@ -8,7 +8,7 @@ module PowerBI
8
8
  end
9
9
 
10
10
  def get_data(id)
11
- @tenant.get("/gateways/#{id}")
11
+ @tenant.get("/gateways/#{id}", use_profile: false)
12
12
  end
13
13
 
14
14
  def data_to_attributes(data)
@@ -32,7 +32,7 @@ module PowerBI
32
32
  end
33
33
 
34
34
  def get_data
35
- @tenant.get("/gateways")[:value]
35
+ @tenant.get("/gateways", use_profile: false)[:value]
36
36
  end
37
37
  end
38
38
  end
@@ -1,14 +1,15 @@
1
1
  module PowerBI
2
2
  class GatewayDatasource < Object
3
- attr_reader :gateway
3
+ attr_reader :gateway, :gateway_datasource_users
4
4
 
5
5
  def initialize(tenant, parent, id = nil)
6
6
  super(tenant, id)
7
7
  @gateway = parent
8
+ @gateway_datasource_users = GatewayDatasourceUserArray.new(@tenant, self)
8
9
  end
9
10
 
10
11
  def get_data(id)
11
- @tenant.get("/gateways/#{@gateway.id}/datasources/#{id}")
12
+ @tenant.get("/gateways/#{@gateway.id}/datasources/#{id}", use_profile: false)
12
13
  end
13
14
 
14
15
  def data_to_attributes(data)
@@ -24,7 +25,7 @@ module PowerBI
24
25
  end
25
26
 
26
27
  def update_credentials(encrypted_credentials)
27
- @tenant.patch("/gateways/#{gateway.id}/datasources/#{id}") do |req|
28
+ @tenant.patch("/gateways/#{gateway.id}/datasources/#{id}", use_profile: false) do |req|
28
29
  req.body = {
29
30
  credentialDetails: {
30
31
  credentialType: "Basic",
@@ -41,7 +42,7 @@ module PowerBI
41
42
  end
42
43
 
43
44
  def delete
44
- @tenant.delete("/gateways/#{gateway.id}/datasources/#{id}")
45
+ @tenant.delete("/gateways/#{gateway.id}/datasources/#{id}", use_profile: false)
45
46
  @gateway.gateway_datasources.reload
46
47
  true
47
48
  end
@@ -61,7 +62,7 @@ module PowerBI
61
62
 
62
63
  # only MySQL type is currently supported
63
64
  def create(name, encrypted_credentials, db_server, db_name)
64
- data = @tenant.post("/gateways/#{@gateway.id}/datasources",) do |req|
65
+ data = @tenant.post("/gateways/#{@gateway.id}/datasources", use_profile: false) do |req|
65
66
  req.body = {
66
67
  connectionDetails: {server: db_server, database: db_name}.to_json,
67
68
  credentialDetails: {
@@ -82,7 +83,7 @@ module PowerBI
82
83
  end
83
84
 
84
85
  def get_data
85
- @tenant.get("/gateways/#{@gateway.id}/datasources")[:value]
86
+ @tenant.get("/gateways/#{@gateway.id}/datasources", use_profile: false)[:value]
86
87
  end
87
88
  end
88
89
  end
@@ -0,0 +1,51 @@
1
+ module PowerBI
2
+ class GatewayDatasourceUser < Object
3
+ attr_reader :gateway_datasource
4
+
5
+ def initialize(tenant, parent, id = nil)
6
+ super(tenant, id)
7
+ @gateway_datasource = parent
8
+ end
9
+
10
+ def data_to_attributes(data)
11
+ {
12
+ datasource_access_right: data[:datasourceAccessRight],
13
+ display_name: data[:displayName],
14
+ email_address: data[:emailAddress],
15
+ identifier: data[:identifier],
16
+ principal_type: data[:principalType],
17
+ profile: data[:profile],
18
+ }
19
+ end
20
+
21
+ end
22
+
23
+ class GatewayDatasourceUserArray < Array
24
+
25
+ def initialize(tenant, gateway_datasource)
26
+ super(tenant, gateway_datasource)
27
+ @gateway_datasource = gateway_datasource
28
+ end
29
+
30
+ def self.get_class
31
+ GatewayDatasourceUser
32
+ end
33
+
34
+ # service principal object ID: https://learn.microsoft.com/en-us/power-bi/developer/embedded/embedded-troubleshoot#what-is-the-difference-between-application-object-id-and-principal-object-id
35
+ def add_service_principal_profile_user(profile_id, principal_object_id, datasource_access_right: "Read")
36
+ @tenant.post("/gateways/#{@gateway_datasource.gateway.id}/datasources/#{@gateway_datasource.id}/users", use_profile: false) do |req|
37
+ req.body = {
38
+ datasourceAccessRight: datasource_access_right,
39
+ identifier: principal_object_id,
40
+ principalType: "App",
41
+ profile: {id: profile_id},
42
+ }.to_json
43
+ end
44
+ self.reload
45
+ end
46
+
47
+ def get_data
48
+ @tenant.get("/gateways/#{@gateway_datasource.gateway.id}/datasources/#{@gateway_datasource.id}/users", use_profile: false)[:value]
49
+ end
50
+ end
51
+ end
@@ -6,7 +6,7 @@ module PowerBI
6
6
  end
7
7
 
8
8
  def get_data(id)
9
- @tenant.get("/profiles/#{id}")
9
+ @tenant.get("/profiles/#{id}", use_profile: false)
10
10
  end
11
11
 
12
12
  def data_to_attributes(data)
@@ -17,7 +17,7 @@ module PowerBI
17
17
  end
18
18
 
19
19
  def delete
20
- @tenant.delete("/profiles/#{@id}")
20
+ @tenant.delete("/profiles/#{@id}", use_profile: false)
21
21
  @tenant.profiles.reload
22
22
  true
23
23
  end
@@ -30,7 +30,7 @@ module PowerBI
30
30
  end
31
31
 
32
32
  def create(name)
33
- data = @tenant.post("/profiles") do |req|
33
+ data = @tenant.post("/profiles", use_profile: false) do |req|
34
34
  req.body = {displayName: name}.to_json
35
35
  end
36
36
  self.reload
@@ -38,7 +38,7 @@ module PowerBI
38
38
  end
39
39
 
40
40
  def get_data
41
- @tenant.get("/profiles")[:value]
41
+ @tenant.get("/profiles", use_profile: false)[:value]
42
42
  end
43
43
  end
44
44
  end
@@ -1,6 +1,6 @@
1
1
  module PowerBI
2
2
  class Tenant
3
- attr_reader :workspaces, :gateways, :capacities, :profiles, :profile
3
+ attr_reader :workspaces, :gateways, :capacities, :profiles, :profile_id
4
4
 
5
5
  def initialize(token_generator, retries: 5, logger: nil)
6
6
  @token_generator = token_generator
@@ -9,7 +9,7 @@ module PowerBI
9
9
  @capacities = CapacityArray.new(self)
10
10
  @profiles = ProfileArray.new(self)
11
11
  @logger = logger
12
- @profile = nil
12
+ @profile_id = nil
13
13
 
14
14
  ## WHY RETRIES? ##
15
15
  # It is noticed that once in a while (~0.1% API calls), the Power BI server returns a 500 (internal server error) without apparent reason, just retrying works :-)
@@ -44,12 +44,16 @@ module PowerBI
44
44
  Capacity.new(self, nil, id)
45
45
  end
46
46
 
47
+ def profile(id)
48
+ Profile.new(self, nil, id)
49
+ end
50
+
47
51
  def profile=(profile)
48
- @profile = profile
52
+ @profile_id = profile.is_a?(String) ? profile : profile&.id
49
53
  @workspaces.reload # we need to reload the workspaces because we look through the eyes of the profile
50
54
  end
51
55
 
52
- def get(url, params = {})
56
+ def get(url, params = {}, use_profile: true)
53
57
  t0 = Time.now
54
58
  conn = Faraday.new do |f|
55
59
  f.request :retry, @retry_options
@@ -58,8 +62,8 @@ module PowerBI
58
62
  req.params = params
59
63
  req.headers['Accept'] = 'application/json'
60
64
  req.headers['authorization'] = "Bearer #{token}"
61
- if @profile
62
- req.headers['X-PowerBI-Profile-Id'] = @profile.id
65
+ if use_profile
66
+ add_spp_header(req)
63
67
  end
64
68
  yield req if block_given?
65
69
  end
@@ -75,7 +79,7 @@ module PowerBI
75
79
  end
76
80
  end
77
81
 
78
- def get_raw(url, params = {})
82
+ def get_raw(url, params = {}, use_profile: true)
79
83
  t0 = Time.now
80
84
  conn = Faraday.new do |f|
81
85
  f.request :retry, @retry_options
@@ -83,8 +87,8 @@ module PowerBI
83
87
  response = conn.get(PowerBI::BASE_URL + url) do |req|
84
88
  req.params = params
85
89
  req.headers['authorization'] = "Bearer #{token}"
86
- if @profile
87
- req.headers['X-PowerBI-Profile-Id'] = @profile.id
90
+ if use_profile
91
+ add_spp_header(req)
88
92
  end
89
93
  yield req if block_given?
90
94
  end
@@ -95,7 +99,7 @@ module PowerBI
95
99
  response.body
96
100
  end
97
101
 
98
- def post(url, params = {})
102
+ def post(url, params = {}, use_profile: true)
99
103
  t0 = Time.now
100
104
  conn = Faraday.new do |f|
101
105
  f.request :retry, @retry_options
@@ -105,8 +109,8 @@ module PowerBI
105
109
  req.headers['Accept'] = 'application/json'
106
110
  req.headers['Content-Type'] = 'application/json'
107
111
  req.headers['authorization'] = "Bearer #{token}"
108
- if @profile
109
- req.headers['X-PowerBI-Profile-Id'] = @profile.id
112
+ if use_profile
113
+ add_spp_header(req)
110
114
  end
111
115
  yield req if block_given?
112
116
  end
@@ -119,7 +123,7 @@ module PowerBI
119
123
  end
120
124
  end
121
125
 
122
- def patch(url, params = {})
126
+ def patch(url, params = {}, use_profile: true)
123
127
  t0 = Time.now
124
128
  conn = Faraday.new do |f|
125
129
  f.request :retry, @retry_options
@@ -129,8 +133,8 @@ module PowerBI
129
133
  req.headers['Accept'] = 'application/json'
130
134
  req.headers['Content-Type'] = 'application/json'
131
135
  req.headers['authorization'] = "Bearer #{token}"
132
- if @profile
133
- req.headers['X-PowerBI-Profile-Id'] = @profile.id
136
+ if use_profile
137
+ add_spp_header(req)
134
138
  end
135
139
  yield req if block_given?
136
140
  end
@@ -143,7 +147,7 @@ module PowerBI
143
147
  end
144
148
  end
145
149
 
146
- def delete(url, params = {})
150
+ def delete(url, params = {}, use_profile: true)
147
151
  t0 = Time.now
148
152
  conn = Faraday.new do |f|
149
153
  f.request :retry, @retry_options
@@ -152,8 +156,8 @@ module PowerBI
152
156
  req.params = params
153
157
  req.headers['Accept'] = 'application/json'
154
158
  req.headers['authorization'] = "Bearer #{token}"
155
- if @profile
156
- req.headers['X-PowerBI-Profile-Id'] = @profile.id
159
+ if use_profile
160
+ add_spp_header(req)
157
161
  end
158
162
  yield req if block_given?
159
163
  end
@@ -169,7 +173,7 @@ module PowerBI
169
173
  end
170
174
  end
171
175
 
172
- def post_file(url, file, params = {})
176
+ def post_file(url, file, params = {}, use_profile: true)
173
177
  t0 = Time.now
174
178
  conn = Faraday.new do |f|
175
179
  f.request :multipart
@@ -180,8 +184,8 @@ module PowerBI
180
184
  req.headers['Accept'] = 'application/json'
181
185
  req.headers['Content-Type'] = 'multipart/form-data'
182
186
  req.headers['authorization'] = "Bearer #{token}"
183
- if @profile
184
- req.headers['X-PowerBI-Profile-Id'] = @profile.id
187
+ if use_profile
188
+ add_spp_header(req)
185
189
  end
186
190
  req.body = {value: Faraday::UploadIO.new(file, 'application/octet-stream')}
187
191
  req.options.timeout = 120 # default is 60 seconds Net::ReadTimeout
@@ -195,6 +199,12 @@ module PowerBI
195
199
 
196
200
  private
197
201
 
202
+ def add_spp_header(req)
203
+ if @profile_id
204
+ req.headers['X-PowerBI-Profile-Id'] = @profile_id
205
+ end
206
+ end
207
+
198
208
  def token
199
209
  @token_generator.call
200
210
  end
data/lib/power-bi.rb CHANGED
@@ -22,6 +22,7 @@ require_relative "power-bi/parameter"
22
22
  require_relative "power-bi/refresh"
23
23
  require_relative "power-bi/gateway"
24
24
  require_relative "power-bi/gateway_datasource"
25
+ require_relative "power-bi/gateway_datasource_user"
25
26
  require_relative "power-bi/page"
26
27
  require_relative "power-bi/user"
27
28
  require_relative "power-bi/capacity"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: power-bi
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lode Cools
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-08-04 00:00:00.000000000 Z
11
+ date: 2024-05-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
@@ -95,6 +95,7 @@ files:
95
95
  - lib/power-bi/datasource.rb
96
96
  - lib/power-bi/gateway.rb
97
97
  - lib/power-bi/gateway_datasource.rb
98
+ - lib/power-bi/gateway_datasource_user.rb
98
99
  - lib/power-bi/object.rb
99
100
  - lib/power-bi/page.rb
100
101
  - lib/power-bi/parameter.rb