gooddata 0.6.15 → 0.6.16
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/gooddata/bricks/middleware/fs_download_middleware.rb +42 -0
- data/lib/gooddata/bricks/middleware/fs_upload_middleware.rb +8 -12
- data/lib/gooddata/bricks/middleware/gooddata_middleware.rb +10 -13
- data/lib/gooddata/bricks/middleware/logger_middleware.rb +7 -2
- data/lib/gooddata/core/rest.rb +7 -8
- data/lib/gooddata/helpers/data_helper.rb +81 -0
- data/lib/gooddata/helpers/global_helpers.rb +1 -1
- data/lib/gooddata/models/domain.rb +22 -48
- data/lib/gooddata/models/membership.rb +2 -0
- data/lib/gooddata/models/metadata/attribute.rb +1 -1
- data/lib/gooddata/models/metadata/dataset.rb +1 -1
- data/lib/gooddata/models/process.rb +3 -2
- data/lib/gooddata/models/profile.rb +8 -4
- data/lib/gooddata/models/project.rb +128 -80
- data/lib/gooddata/models/project_role.rb +26 -0
- data/lib/gooddata/models/user_filters/user_filter_builder.rb +10 -9
- data/lib/gooddata/rest/client.rb +2 -4
- data/lib/gooddata/rest/connection.rb +3 -2
- data/lib/gooddata/version.rb +1 -1
- data/spec/helpers/project_helper.rb +1 -1
- data/spec/integration/project_spec.rb +10 -5
- data/spec/integration/rest_spec.rb +4 -4
- data/spec/integration/user_filters_spec.rb +2 -1
- data/spec/unit/models/metric_spec.rb +9 -9
- data/spec/unit/models/project_spec.rb +0 -272
- data/spec/unit/models/unit_project.rb +122 -0
- metadata +4 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 40814e8c9d7deee9ac0eca814a3ac3c635f1ede3
|
4
|
+
data.tar.gz: fe14bb4f38e410de2e7abc9624e5f3aba6c39e6f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f4128f12fab224bc8a5814fe0dcee35c385c2652defe34afb331562a65332b7f4fdd9199b7bb4c653eebdff39d6dd21950482e10fb1b51c5e81664072c490035
|
7
|
+
data.tar.gz: 731f9c3dab1e859777931f44362e4e50c2bc79fa562a4172ad2d53c658d9b3f309ff2000fb36a9090bdecd09be5240d76d3344316d60b281803bcc3d4e90373e
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
require_relative 'base_middleware'
|
3
|
+
|
4
|
+
module GoodData
|
5
|
+
module Bricks
|
6
|
+
class FsProjectDownloadMiddleware < Bricks::Middleware
|
7
|
+
def call(params)
|
8
|
+
(params['gdc_files_to_download'] || []).each do |source|
|
9
|
+
case source[:type].to_s
|
10
|
+
when 'ads'
|
11
|
+
CSV.open(source[:to], 'w') do |csv|
|
12
|
+
header_written = false
|
13
|
+
header = nil
|
14
|
+
dwh = params['ads_client']
|
15
|
+
dwh.execute_select(source[:query]) do |row|
|
16
|
+
unless header_written
|
17
|
+
header_written = true
|
18
|
+
header = row.keys
|
19
|
+
csv << header
|
20
|
+
end
|
21
|
+
csv << row.values_at(*header)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
when 'staging'
|
25
|
+
webdav_uri = GoodData.project_webdav_path
|
26
|
+
dav = Net::DAV.new(webdav_uri, :curl => false)
|
27
|
+
dav.verify_server = false
|
28
|
+
dav.credentials(params['GDC_USERNAME'], params['GDC_PASSWORD'])
|
29
|
+
dav.find(path, recursive: true, suppress_errors: true) do |item|
|
30
|
+
puts 'Checking: ' + item.url.to_s
|
31
|
+
name = (item.uri - webdav_uri).to_s
|
32
|
+
File.open(name, 'w') do |f|
|
33
|
+
f << item.content
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
@app.call(params)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -1,9 +1,4 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
|
3
|
-
require 'uri'
|
4
|
-
require 'net/http'
|
5
|
-
require 'pathname'
|
6
|
-
|
7
2
|
require_relative 'base_middleware'
|
8
3
|
|
9
4
|
module GoodData
|
@@ -15,20 +10,21 @@ module GoodData
|
|
15
10
|
end
|
16
11
|
|
17
12
|
def call(params)
|
18
|
-
returning(@app.call(params)) do |
|
13
|
+
returning(@app.call(params)) do |_|
|
19
14
|
destination = @destination
|
20
15
|
(params['gdc_files_to_upload'] || []).each do |f|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
path = f[:path]
|
17
|
+
case destination.to_sym
|
18
|
+
when :staging
|
19
|
+
GoodData.client.get '/gdc/account/token', :dont_reauth => true
|
20
|
+
url = GoodData.project_webdav_path
|
21
|
+
GoodData.upload_to_project_webdav(path)
|
22
|
+
puts "Uploaded local file \"#{path}\" to url \"#{url + path}\""
|
25
23
|
end
|
26
24
|
end
|
27
25
|
end
|
28
26
|
end
|
29
27
|
end
|
30
|
-
|
31
|
-
# Alias to make it backwards compatible
|
32
28
|
FsUploadMiddleware = FsProjectUploadMiddleware
|
33
29
|
end
|
34
30
|
end
|
@@ -1,8 +1,4 @@
|
|
1
1
|
# encoding: UTF-8
|
2
|
-
|
3
|
-
# TODO: REmove this
|
4
|
-
# require 'gooddata'
|
5
|
-
|
6
2
|
require_relative 'base_middleware'
|
7
3
|
|
8
4
|
module GoodData
|
@@ -11,25 +7,26 @@ module GoodData
|
|
11
7
|
def call(params)
|
12
8
|
logger = params['GDC_LOGGER']
|
13
9
|
token_name = 'GDC_SST'
|
14
|
-
protocol_name = '
|
15
|
-
server_name = '
|
10
|
+
protocol_name = 'CLIENT_GDC_PROTOCOL'
|
11
|
+
server_name = 'CLIENT_GDC_HOSTNAME'
|
16
12
|
project_id = params['GDC_PROJECT_ID']
|
17
13
|
|
18
|
-
|
19
|
-
|
20
|
-
server = if !params[protocol_name].empty? && !params[server_name].empty?
|
14
|
+
server = if params[protocol_name] && params[server_name]
|
21
15
|
"#{params[protocol_name]}://#{params[server_name]}"
|
22
16
|
end
|
23
17
|
|
24
18
|
client = if params['GDC_USERNAME'].nil? || params['GDC_PASSWORD'].nil?
|
25
|
-
|
19
|
+
puts "Connecting with SST to server #{server}"
|
20
|
+
fail 'SST (SuperSecureToken) not present in params' if params[token_name].nil?
|
21
|
+
GoodData.connect(sst_token: params[token_name], server: server)
|
26
22
|
else
|
23
|
+
puts "Connecting as #{params['GDC_USERNAME']} to server #{server}"
|
27
24
|
GoodData.connect(params['GDC_USERNAME'], params['GDC_PASSWORD'], server: server)
|
28
25
|
end
|
26
|
+
project = client.projects(project_id)
|
27
|
+
GoodData.project = project
|
29
28
|
GoodData.logger = logger
|
30
|
-
|
31
|
-
@app.call(params)
|
32
|
-
end
|
29
|
+
@app.call(params.merge('GDC_GD_CLIENT' => client, 'gdc_project' => project))
|
33
30
|
end
|
34
31
|
end
|
35
32
|
end
|
@@ -8,8 +8,13 @@ module GoodData
|
|
8
8
|
module Bricks
|
9
9
|
class LoggerMiddleware < Bricks::Middleware
|
10
10
|
def call(params)
|
11
|
-
logger =
|
12
|
-
|
11
|
+
logger = nil
|
12
|
+
if params['GDC_LOGGING_OFF']
|
13
|
+
logger = NilLogger.new
|
14
|
+
else
|
15
|
+
logger = params['GDC_LOGGER'] = params[:GDC_LOGGER_FILE].nil? ? Logger.new(STDOUT) : Logger.new(params[:GDC_LOGGER_FILE])
|
16
|
+
logger.info('Pipeline starts')
|
17
|
+
end
|
13
18
|
returning(@app.call(params)) do |_result|
|
14
19
|
logger.info('Pipeline ending')
|
15
20
|
end
|
data/lib/gooddata/core/rest.rb
CHANGED
@@ -77,39 +77,38 @@ module GoodData
|
|
77
77
|
|
78
78
|
# Get WebDav directory for project data
|
79
79
|
# @return [String]
|
80
|
-
def
|
80
|
+
def project_webdav_path(options = { :project => GoodData.project })
|
81
81
|
options = merge_options(options)
|
82
82
|
project = options[:project]
|
83
|
-
project.
|
83
|
+
project.project_webdav_path
|
84
84
|
end
|
85
85
|
|
86
86
|
# Upload to project directory
|
87
87
|
def upload_to_project_webdav(file, options = { :project => GoodData.project })
|
88
88
|
options = merge_options(options)
|
89
|
-
|
90
|
-
url = get_project_webdav_path(webdav_filename, options)
|
89
|
+
url = project_webdav_path(options)
|
91
90
|
connection.upload(file, options.merge(:staging_url => url))
|
92
91
|
end
|
93
92
|
|
94
93
|
# Download from project directory
|
95
94
|
def download_from_project_webdav(file, where, options = { :project => GoodData.project })
|
96
95
|
options = merge_options(options)
|
97
|
-
url =
|
96
|
+
url = project_webdav_path(options)
|
98
97
|
connection.download(file, where, options.merge(:staging_url => url))
|
99
98
|
end
|
100
99
|
|
101
100
|
# Get WebDav directory for user data
|
102
101
|
# @return [String]
|
103
|
-
def
|
102
|
+
def user_webdav_path(options = { :project => GoodData.project })
|
104
103
|
options = merge_options(options)
|
105
104
|
project = options[:project]
|
106
|
-
project.
|
105
|
+
project.user_webdav_path
|
107
106
|
end
|
108
107
|
|
109
108
|
# Download from user directory
|
110
109
|
def download_from_user_webdav(file, where, options = { :project => GoodData.project })
|
111
110
|
options = merge_options(options)
|
112
|
-
url =
|
111
|
+
url = user_webdav_path(options)
|
113
112
|
connection.download(file, where, options.merge(:staging_url => url))
|
114
113
|
end
|
115
114
|
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# encoding: UTF-8
|
2
|
+
|
3
|
+
require 'csv'
|
4
|
+
require 'digest'
|
5
|
+
require 'open-uri'
|
6
|
+
|
7
|
+
module GoodData
|
8
|
+
module Helpers
|
9
|
+
class DataSource
|
10
|
+
attr_reader :realized
|
11
|
+
|
12
|
+
def initialize(opts = {})
|
13
|
+
opts = opts.is_a?(String) ? { type: :staging, path: opts } : opts
|
14
|
+
opts = opts.symbolize_keys
|
15
|
+
@source = opts[:type]
|
16
|
+
@options = opts
|
17
|
+
@realized = false
|
18
|
+
end
|
19
|
+
|
20
|
+
def realize_query(params)
|
21
|
+
query = @options[:query]
|
22
|
+
dwh = params['ads_client']
|
23
|
+
fail "Data Source needs a client to ads to be able to query the storage but 'ads_client' is empty." unless dwh
|
24
|
+
filename = Digest::SHA256.new.hexdigest(query)
|
25
|
+
measure = Benchmark.measure do
|
26
|
+
CSV.open(filename, 'w') do |csv|
|
27
|
+
header_written = false
|
28
|
+
header = nil
|
29
|
+
|
30
|
+
dwh.execute_select(query) do |row|
|
31
|
+
unless header_written
|
32
|
+
header_written = true
|
33
|
+
header = row.keys
|
34
|
+
csv << header
|
35
|
+
end
|
36
|
+
csv << row.values_at(*header)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
puts "Realizing SQL query \"#{query}\" took #{measure.real}"
|
41
|
+
filename
|
42
|
+
end
|
43
|
+
|
44
|
+
def realize_staging(params)
|
45
|
+
path = @options[:path]
|
46
|
+
url = URI.parse(path)
|
47
|
+
filename = Digest::SHA256.new.hexdigest(path)
|
48
|
+
if url.relative?
|
49
|
+
params['gdc_project'].download_file(path, filename)
|
50
|
+
else
|
51
|
+
params['GDC_GD_CLIENT'].download_file(path, filename)
|
52
|
+
end
|
53
|
+
filename
|
54
|
+
end
|
55
|
+
|
56
|
+
def realize_link
|
57
|
+
link = @options[:url]
|
58
|
+
filename = Digest::SHA256.new.hexdigest(link)
|
59
|
+
measure = Benchmark.measure do
|
60
|
+
File.open(filename, 'w') do |f|
|
61
|
+
open(link) { |rf| f.write(rf.read) }
|
62
|
+
end
|
63
|
+
end
|
64
|
+
puts "Realizing web download from \"#{link}\" took #{measure.real}"
|
65
|
+
filename
|
66
|
+
end
|
67
|
+
|
68
|
+
def realize(params = {})
|
69
|
+
@realized = true
|
70
|
+
case @source.to_s
|
71
|
+
when 'ads'
|
72
|
+
realize_query(params)
|
73
|
+
when 'staging'
|
74
|
+
realize_staging(params)
|
75
|
+
when 'web'
|
76
|
+
realize_link
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -10,8 +10,6 @@ module GoodData
|
|
10
10
|
class Domain < GoodData::Rest::Object
|
11
11
|
attr_reader :name
|
12
12
|
|
13
|
-
USERS_OPTIONS = { :offset => 0, :limit => 10_000 }
|
14
|
-
|
15
13
|
class << self
|
16
14
|
# Looks for domain
|
17
15
|
#
|
@@ -182,21 +180,22 @@ module GoodData
|
|
182
180
|
# @option opts [Number] :offset The subject
|
183
181
|
# @option opts [Number] :limit From address
|
184
182
|
# TODO: Review opts[:limit] functionality
|
185
|
-
def users(domain, opts =
|
183
|
+
def users(domain, opts = {})
|
186
184
|
result = []
|
187
|
-
|
188
|
-
|
189
|
-
|
185
|
+
page_limit = opts[:page_limit] || 1000
|
186
|
+
limit = opts[:limit] || Float::INFINITY
|
187
|
+
offset = opts[:offset]
|
188
|
+
uri = "/gdc/account/domains/#{domain}/users?offset=#{offset}&limit=#{page_limit}"
|
190
189
|
loop do
|
191
|
-
break unless uri
|
192
190
|
tmp = client(opts).get(uri)
|
193
191
|
tmp['accountSettings']['items'].each do |account|
|
194
192
|
result << client(opts).create(GoodData::Profile, account)
|
195
193
|
end
|
196
|
-
break if
|
194
|
+
break if result.length >= limit
|
195
|
+
|
197
196
|
uri = tmp['accountSettings']['paging']['next']
|
197
|
+
break unless uri
|
198
198
|
end
|
199
|
-
|
200
199
|
result
|
201
200
|
end
|
202
201
|
|
@@ -205,51 +204,26 @@ module GoodData
|
|
205
204
|
# @param [String] default_domain_name Default domain name used when no specified in user
|
206
205
|
# @return [Array<GoodData::User>] List of users created
|
207
206
|
def create_users(list, default_domain = nil, opts = { :client => GoodData.connection, :project => GoodData.project })
|
208
|
-
client = client(opts)
|
209
207
|
default_domain_name = default_domain.respond_to?(:name) ? default_domain.name : default_domain
|
210
|
-
|
211
|
-
|
212
|
-
|
208
|
+
domain = client.domain(default_domain_name)
|
209
|
+
|
210
|
+
domain_users_cache = Hash[domain.users.map { |u| [u.login, u] }]
|
211
|
+
list.pmapcat do |user|
|
213
212
|
begin
|
214
213
|
user_data = user.to_hash
|
215
|
-
|
216
|
-
domain_name = user_data[:domain] || default_domain_name
|
217
|
-
|
218
|
-
# Lookup for domain in cache'
|
219
|
-
domain = domains[domain_name]
|
220
|
-
|
221
|
-
# Get domain info from REST, add to cache
|
222
|
-
if domain.nil?
|
223
|
-
domain = {
|
224
|
-
:domain => domain_obj,
|
225
|
-
:users => domain_obj.users
|
226
|
-
}
|
227
|
-
|
228
|
-
domain[:users_map] = Hash[domain[:users].map { |u| [u.login, u] }]
|
229
|
-
domains[domain_name] = domain
|
230
|
-
end
|
231
|
-
|
232
|
-
# Check if user exists in domain
|
233
|
-
domain_user = domain[:users_map][user_data[:login]]
|
234
|
-
|
235
|
-
# Create domain user if needed
|
214
|
+
domain_user = domain_users_cache[user_data[:login]]
|
236
215
|
if !domain_user
|
237
|
-
|
238
|
-
|
239
|
-
domain[:users] << domain_user
|
240
|
-
domain[:users_map][domain_user.login] = domain_user
|
241
|
-
{ type: :user_added_to_domain, user: domain_user }
|
216
|
+
added_user = domain.add_user(user_data, opts)
|
217
|
+
[{ type: :user_added_to_domain, user: added_user }]
|
242
218
|
else
|
243
|
-
|
244
|
-
diff = GoodData::Helpers.diff([domain_user.to_hash], [user_data], key: :login)
|
245
|
-
next if diff[:changed].empty?
|
246
|
-
|
247
|
-
|
248
|
-
domain[:users_map][domain_user.login] = domain_user
|
249
|
-
{ type: :user_changed_in_domain, user: domain_user }
|
219
|
+
fields_to_check = opts[:fields_to_check] || user_data.keys
|
220
|
+
diff = GoodData::Helpers.diff([domain_user.to_hash], [user_data], key: :login, fields: fields_to_check)
|
221
|
+
next [] if diff[:changed].empty?
|
222
|
+
updated_user = domain.update_user(domain_user.to_hash.merge(user_data.compact), opts)
|
223
|
+
[{ type: :user_changed_in_domain, user: updated_user }]
|
250
224
|
end
|
251
225
|
rescue RuntimeError => e
|
252
|
-
{ type: :error, reason: e }
|
226
|
+
[{ type: :error, reason: e }]
|
253
227
|
end
|
254
228
|
end
|
255
229
|
end
|
@@ -358,7 +332,7 @@ module GoodData
|
|
358
332
|
# domain = GoodData::Domain['gooddata-tomas-korcak']
|
359
333
|
# pp domain.users
|
360
334
|
#
|
361
|
-
def users(opts =
|
335
|
+
def users(opts = {})
|
362
336
|
GoodData::Domain.users(name, opts.merge(client: client))
|
363
337
|
end
|
364
338
|
|
@@ -50,9 +50,11 @@ module GoodData
|
|
50
50
|
# And following lines are even much more ugly hack
|
51
51
|
# 'authentication_modes' => ['sso', 'password']
|
52
52
|
},
|
53
|
+
'links' => {},
|
53
54
|
'meta' => {}
|
54
55
|
}
|
55
56
|
}
|
57
|
+
json['user']['links']['self'] = data[:uri] if data[:uri]
|
56
58
|
c.create(self, json)
|
57
59
|
end
|
58
60
|
|
@@ -123,7 +123,7 @@ module GoodData
|
|
123
123
|
# @param name [String] name used as a basis for regular expression
|
124
124
|
# @return [GoodData::Label]
|
125
125
|
def label_by_name(name)
|
126
|
-
labels.find { |label| label.title
|
126
|
+
labels.find { |label| label.title =~ /#{name}/ || label.identifier =~ /#{name}/ }
|
127
127
|
end
|
128
128
|
end
|
129
129
|
end
|
@@ -167,9 +167,10 @@ module GoodData
|
|
167
167
|
path
|
168
168
|
else
|
169
169
|
with_zip(opts) do |zipfile|
|
170
|
-
Dir[File.join(path, '**', '**')].reject { |f| files_to_exclude.include?(Pathname(path) + f) }
|
170
|
+
files_to_upload = Dir[File.join(path, '**', '**')].reject { |f| files_to_exclude.include?(Pathname(path) + f) }
|
171
|
+
puts "Uploading #{files_to_upload.count} files."
|
172
|
+
files_to_upload.each do |file|
|
171
173
|
file_pathname = Pathname.new(file)
|
172
|
-
puts "Including item #{file_pathname}"
|
173
174
|
file_relative_pathname = file_pathname.relative_path_from(Pathname.new(path))
|
174
175
|
zipfile.add(file_relative_pathname, file)
|
175
176
|
end
|