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 +4 -4
- data/README.md +8 -1
- data/lib/power-bi/gateway.rb +2 -2
- data/lib/power-bi/gateway_datasource.rb +7 -6
- data/lib/power-bi/gateway_datasource_user.rb +51 -0
- data/lib/power-bi/profile.rb +4 -4
- data/lib/power-bi/tenant.rb +31 -21
- data/lib/power-bi.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 90d415a89ed5860c82824f7e152e4c58d42054bc293f5534f6669774682a1ffe
|
|
4
|
+
data.tar.gz: 536d4c7cea48c859c7b780db751da15375b060a45c59946a2335887d8e948494
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
|
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.
|
data/lib/power-bi/gateway.rb
CHANGED
|
@@ -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
|
data/lib/power-bi/profile.rb
CHANGED
|
@@ -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
|
data/lib/power-bi/tenant.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
module PowerBI
|
|
2
2
|
class Tenant
|
|
3
|
-
attr_reader :workspaces, :gateways, :capacities, :profiles, :
|
|
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
|
-
@
|
|
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
|
-
@
|
|
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
|
|
62
|
-
req
|
|
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
|
|
87
|
-
req
|
|
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
|
|
109
|
-
req
|
|
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
|
|
133
|
-
req
|
|
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
|
|
156
|
-
req
|
|
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
|
|
184
|
-
req
|
|
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.
|
|
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:
|
|
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
|