gooddata 1.0.2-java → 1.1.0-java
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 +5 -5
- data/.gitignore +1 -0
- data/CONTRIBUTING.md +12 -0
- data/README.md +5 -2
- data/Rakefile +0 -1
- data/dev-gooddata-sso.pub.encrypted +40 -0
- data/gooddata.gemspec +3 -3
- data/lib/gooddata/connection.rb +23 -13
- data/lib/gooddata/helpers/data_helper.rb +0 -1
- data/lib/gooddata/lcm/actions/apply_custom_maql.rb +8 -1
- data/lib/gooddata/lcm/actions/associate_clients.rb +8 -1
- data/lib/gooddata/lcm/actions/base_action.rb +10 -0
- data/lib/gooddata/lcm/actions/collect_ca_metrics.rb +7 -1
- data/lib/gooddata/lcm/actions/collect_client_projects.rb +3 -0
- data/lib/gooddata/lcm/actions/collect_clients.rb +3 -1
- data/lib/gooddata/lcm/actions/collect_data_product.rb +10 -2
- data/lib/gooddata/lcm/actions/collect_dynamic_schedule_params.rb +12 -1
- data/lib/gooddata/lcm/actions/collect_ldm_objects.rb +6 -2
- data/lib/gooddata/lcm/actions/collect_meta.rb +1 -1
- data/lib/gooddata/lcm/actions/collect_segment_clients.rb +8 -1
- data/lib/gooddata/lcm/actions/collect_segments.rb +6 -5
- data/lib/gooddata/lcm/actions/collect_tagged_objects.rb +1 -1
- data/lib/gooddata/lcm/actions/collect_users_brick_users.rb +10 -4
- data/lib/gooddata/lcm/actions/create_segment_masters.rb +12 -2
- data/lib/gooddata/lcm/actions/ensure_data_product.rb +10 -0
- data/lib/gooddata/lcm/actions/ensure_technical_users_domain.rb +5 -1
- data/lib/gooddata/lcm/actions/ensure_technical_users_project.rb +3 -0
- data/lib/gooddata/lcm/actions/execute_schedules.rb +10 -0
- data/lib/gooddata/lcm/actions/import_object_collections.rb +1 -1
- data/lib/gooddata/lcm/actions/provision_clients.rb +12 -2
- data/lib/gooddata/lcm/actions/purge_clients.rb +2 -0
- data/lib/gooddata/lcm/actions/rename_existing_client_projects.rb +3 -0
- data/lib/gooddata/lcm/actions/synchronize_attribute_drillpaths.rb +4 -1
- data/lib/gooddata/lcm/actions/synchronize_cas.rb +7 -1
- data/lib/gooddata/lcm/actions/synchronize_clients.rb +11 -1
- data/lib/gooddata/lcm/actions/synchronize_color_palette.rb +7 -1
- data/lib/gooddata/lcm/actions/synchronize_etls_in_segment.rb +12 -7
- data/lib/gooddata/lcm/actions/synchronize_label_types.rb +4 -1
- data/lib/gooddata/lcm/actions/synchronize_ldm.rb +18 -7
- data/lib/gooddata/lcm/actions/synchronize_meta.rb +9 -0
- data/lib/gooddata/lcm/actions/synchronize_new_segments.rb +11 -1
- data/lib/gooddata/lcm/actions/synchronize_processes.rb +7 -1
- data/lib/gooddata/lcm/actions/synchronize_schedules.rb +4 -1
- data/lib/gooddata/lcm/actions/synchronize_tag_objects.rb +6 -0
- data/lib/gooddata/lcm/actions/synchronize_user_filters.rb +60 -15
- data/lib/gooddata/lcm/actions/synchronize_user_groups.rb +7 -1
- data/lib/gooddata/lcm/actions/synchronize_users.rb +106 -3
- data/lib/gooddata/lcm/actions/update_release_table.rb +19 -0
- data/lib/gooddata/lcm/helpers/check_helper.rb +21 -6
- data/lib/gooddata/lcm/lcm2.rb +35 -22
- data/lib/gooddata/lcm/types/class/gd_logger.rb +23 -0
- data/lib/gooddata/lcm/types/class/gd_product.rb +23 -0
- data/lib/gooddata/lcm/types/class/gd_project.rb +23 -0
- data/lib/gooddata/lcm/types/class/smart_hash.rb +23 -0
- data/lib/gooddata/lcm/types/complex/segment.rb +1 -1
- data/lib/gooddata/lcm/types/scalar/integer.rb +2 -2
- data/lib/gooddata/lcm/types/special/any.rb +18 -0
- data/lib/gooddata/models/blueprint/dataset_blueprint.rb +1 -1
- data/lib/gooddata/models/blueprint/to_manifest.rb +1 -3
- data/lib/gooddata/models/blueprint/to_wire.rb +2 -1
- data/lib/gooddata/models/from_wire.rb +13 -1
- data/lib/gooddata/models/metadata/folder.rb +22 -0
- data/lib/gooddata/models/metadata/metric.rb +5 -8
- data/lib/gooddata/models/model.rb +1 -1
- data/lib/gooddata/models/process.rb +42 -32
- data/lib/gooddata/models/project.rb +19 -36
- data/lib/gooddata/models/project_creator.rb +3 -1
- data/lib/gooddata/models/project_role.rb +3 -4
- data/lib/gooddata/models/schedule.rb +0 -2
- data/lib/gooddata/models/user_filters/mandatory_user_filter.rb +9 -1
- data/lib/gooddata/models/user_filters/user_filter.rb +1 -2
- data/lib/gooddata/models/user_filters/user_filter_builder.rb +18 -6
- data/lib/gooddata/rest/client.rb +1 -2
- data/lib/gooddata/rest/connection.rb +12 -46
- data/lib/gooddata/rest/phmap.rb +101 -56
- data/lib/gooddata/version.rb +1 -1
- data/rubydev_public.gpg.encrypted +51 -0
- data/rubydev_secret_keys.gpg.encrypted +109 -0
- data/spec/data/user_filters.csv +2 -0
- data/spec/environment/default.rb +2 -2
- data/spec/environment/development.rb +1 -1
- data/spec/environment/staging.rb +2 -3
- data/spec/environment/testing.rb +4 -4
- data/spec/integration/connection_spec.rb +37 -0
- data/spec/integration/core/connection_spec.rb +1 -1
- data/spec/integration/core/logging_spec.rb +8 -6
- data/spec/integration/core/project_spec.rb +1 -1
- data/spec/integration/mandatory_user_filter_spec.rb +53 -0
- data/spec/integration/mixins/id_to_uri_spec.rb +17 -5
- data/spec/integration/models/label_spec.rb +9 -0
- data/spec/integration/models/metric_spec.rb +24 -0
- data/spec/integration/models/process_spec.rb +35 -0
- data/spec/integration/models/project_role_spec.rb +1 -1
- data/spec/integration/models/schedule_spec.rb +0 -8
- data/spec/integration/schedule_spec.rb +4 -6
- data/spec/integration/user_filters_spec.rb +20 -16
- data/spec/integration/user_group_spec.rb +1 -1
- data/spec/integration/vcr_cassettes/GoodData_-_logging/_logger/can_assign_a_custom_logger.yml +2287 -0
- data/spec/integration/vcr_cassettes/GoodData_-_logging/_logger/client_logs_when_given_custom_message.yml +2287 -0
- data/spec/integration/vcr_cassettes/GoodData_-_logging/_logger/has_the_request_id_logged_when_I_passed_it.yml +2287 -0
- data/spec/integration/vcr_cassettes/GoodData_-_logging/_logging_off/Disables_logging.yml +2287 -0
- data/spec/integration/vcr_cassettes/GoodData_-_logging/_logging_on/Enables_logging.yml +2287 -0
- data/spec/integration/vcr_cassettes/GoodData_-_project/_project/Returns_project_assigned.yml +354 -0
- data/spec/integration/vcr_cassettes/GoodData_-_project/_project_/Assigns_nil.yml +299 -0
- data/spec/integration/vcr_cassettes/GoodData_-_project/_project_/Assigns_project_directly.yml +354 -0
- data/spec/integration/vcr_cassettes/GoodData_-_project/_project_/Assigns_project_using_project_ID.yml +354 -0
- data/spec/integration/vcr_cassettes/GoodData_-_project/_project_/Assigns_project_using_project_URL.yml +354 -0
- data/spec/integration/vcr_cassettes/GoodData_-_project/_with_project/Uses_project_specified.yml +354 -0
- data/spec/integration/vcr_cassettes/GoodData_Metric/all.yml +2065 -0
- data/spec/integration/vcr_cassettes/GoodData_Metric/should_be_able_to_update_folders.yml +119 -0
- data/spec/integration/vcr_cassettes/GoodData_Mixin_MdIdToUri/all.yml +9812 -0
- data/spec/integration/vcr_cassettes/GoodData_Mixin_MdIdToUri/should_get_json_containing_correct_id.yml +174 -0
- data/spec/integration/vcr_cassettes/GoodData_Mixin_MdIdToUri/should_return_nil_for_unknown_id.yml +58 -0
- data/spec/integration/vcr_cassettes/GoodData_Mixin_MdIdToUri/should_throw_BadRequest_for_-1.yml +63 -0
- data/spec/integration/vcr_cassettes/GoodData_Rest_Connection/_connect/Connects_using_username_and_password.yml +299 -0
- data/spec/integration/vcr_cassettes/GoodData_Rest_Connection/_disconnect/Connects_using_username_and_password.yml +299 -0
- data/spec/integration/vcr_cassettes/GoodData_Rest_Connection/_generate_request_id/Generates_a_non-empty_string.yml +2287 -0
- data/spec/integration/vcr_cassettes/GoodData_UserGroup/_/Should_list_user_groups_as_Array.yml +56 -0
- data/spec/integration/vcr_cassettes/GoodData_UserGroup/_add_members/Should_add_member.yml +315 -0
- data/spec/integration/vcr_cassettes/GoodData_UserGroup/_members/Should_return_members_as_array.yml +54 -0
- data/spec/integration/vcr_cassettes/GoodData_UserGroup/_remove_members/Should_remove_existing_members.yml +258 -0
- data/spec/integration/vcr_cassettes/GoodData_UserGroup/_save/updates_existing_group.yml +159 -0
- data/spec/integration/vcr_cassettes/GoodData_UserGroup/_set_members/Should_set_new_members.yml +158 -0
- data/spec/integration/vcr_cassettes/GoodData_UserGroup/all.yml +809 -0
- data/spec/spec_helper.rb +46 -2
- data/spec/unit/actions/associate_clients_spec.rb +2 -1
- data/spec/unit/actions/collect_data_product_spec.rb +3 -1
- data/spec/unit/actions/collect_segment_clients_spec.rb +1 -0
- data/spec/unit/actions/create_segment_masters_spec.rb +1 -0
- data/spec/unit/actions/ensure_data_product_spec.rb +1 -0
- data/spec/unit/actions/ensure_technical_users_domain_spec.rb +2 -0
- data/spec/unit/actions/ensure_technical_users_project_spec.rb +4 -0
- data/spec/unit/actions/provision_clients_spec.rb +2 -1
- data/spec/unit/actions/synchronize_etls_in_segment_spec.rb +0 -6
- data/spec/unit/actions/synchronize_ldm_spec.rb +20 -7
- data/spec/unit/actions/synchronize_user_filters_spec.rb +21 -0
- data/spec/unit/helpers/check_helper_production_spec.rb +34 -0
- data/spec/unit/helpers/check_helper_spec.rb +97 -9
- data/spec/unit/lcm/lcm2_spec.rb +67 -3
- data/spec/unit/models/blueprint/to_wire_spec.rb +1 -0
- data/spec/unit/models/dataset_blueprint.rb +14 -0
- data/spec/unit/models/from_wire_spec.rb +20 -0
- data/spec/unit/models/model_spec.rb +10 -0
- data/spec/unit/models/to_manifest_spec.rb +29 -0
- data/spec/unit/models/user_filters/user_filter_builder_spec.rb +44 -6
- data/spec/unit/rest/phmap_spec.rb +117 -0
- data/spec/vcr_configurer.rb +63 -0
- metadata +283 -24
- data/lib/gooddata/lcm/actions/ensure_segments.rb +0 -32
|
@@ -264,6 +264,9 @@ module GoodData
|
|
|
264
264
|
to_process = if process.path
|
|
265
265
|
to_process.delete if to_process
|
|
266
266
|
GoodData::Process.deploy_from_appstore(process.path, name: process.name, client: to_project.client, project: to_project)
|
|
267
|
+
elsif process.component
|
|
268
|
+
to_process.delete if to_process
|
|
269
|
+
GoodData::Process.deploy_component(GoodData::Helpers.symbolize_keys(process.to_hash), project: to_project, client: to_project.client)
|
|
267
270
|
else
|
|
268
271
|
Dir.mktmpdir('etl_transfer') do |dir|
|
|
269
272
|
dir = Pathname(dir)
|
|
@@ -1172,22 +1175,15 @@ module GoodData
|
|
|
1172
1175
|
# @return [String] Returns token that you can use as input for object_import
|
|
1173
1176
|
def objects_export(objs, options = {})
|
|
1174
1177
|
fail 'Nothing to migrate. You have to pass list of objects, ids or uris that you would like to migrate' if objs.nil?
|
|
1175
|
-
objs = Array(objs)
|
|
1178
|
+
objs = Array(objs).map { |o| o.respond_to?(:uri) ? o.uri : o }
|
|
1176
1179
|
if objs.empty?
|
|
1177
1180
|
GoodData.logger.warn 'Nothing to migrate.'
|
|
1178
1181
|
return
|
|
1179
1182
|
end
|
|
1180
1183
|
|
|
1181
|
-
objs = objs.pmap { |obj| [obj, objects(obj)] }
|
|
1182
|
-
if objs.any? { |_, obj| obj.nil? }
|
|
1183
|
-
object = objs.select { |_, obj| obj.nil? }.map { |o, _| o }.join(', ')
|
|
1184
|
-
error_message = "Exporting objects failed with messages. " \
|
|
1185
|
-
"Object #{object} could not be found."
|
|
1186
|
-
fail ObjectsExportError, error_message
|
|
1187
|
-
end
|
|
1188
1184
|
export_payload = {
|
|
1189
1185
|
:partialMDExport => {
|
|
1190
|
-
:uris => objs
|
|
1186
|
+
:uris => objs,
|
|
1191
1187
|
:exportAttributeProperties => '1',
|
|
1192
1188
|
:crossDataCenterExport => '1'
|
|
1193
1189
|
}
|
|
@@ -1259,32 +1255,21 @@ module GoodData
|
|
|
1259
1255
|
if projects.is_a?(Array)
|
|
1260
1256
|
projects.each_slice(batch_size).flat_map do |batch|
|
|
1261
1257
|
batch.pmap do |proj|
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
}
|
|
1269
|
-
rescue RestClient::Exception => e
|
|
1270
|
-
{
|
|
1271
|
-
project: proj,
|
|
1272
|
-
exception: e,
|
|
1273
|
-
result: false,
|
|
1274
|
-
reason: GoodData::Helpers.interpolate_error_message(MultiJson.load(e.response))
|
|
1275
|
-
}
|
|
1276
|
-
rescue GoodData::ObjectsImportError => e
|
|
1277
|
-
{
|
|
1278
|
-
project: target_project,
|
|
1279
|
-
result: false,
|
|
1280
|
-
reason: e.message
|
|
1281
|
-
}
|
|
1282
|
-
end
|
|
1258
|
+
target_project = client.projects(proj)
|
|
1259
|
+
target_project.objects_import(token, options)
|
|
1260
|
+
{
|
|
1261
|
+
project: target_project,
|
|
1262
|
+
result: true
|
|
1263
|
+
}
|
|
1283
1264
|
end
|
|
1284
1265
|
end
|
|
1285
1266
|
else
|
|
1286
1267
|
target_project = client.projects(projects)
|
|
1287
1268
|
target_project.objects_import(token, options)
|
|
1269
|
+
[{
|
|
1270
|
+
project: target_project,
|
|
1271
|
+
result: true
|
|
1272
|
+
}]
|
|
1288
1273
|
end
|
|
1289
1274
|
end
|
|
1290
1275
|
|
|
@@ -1464,12 +1449,10 @@ module GoodData
|
|
|
1464
1449
|
#
|
|
1465
1450
|
# @return [Array<GoodData::ProjectRole>] List of roles
|
|
1466
1451
|
def roles
|
|
1467
|
-
url = "/gdc/projects/#{pid}/roles"
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
json = client.get role_url
|
|
1472
|
-
client.create(GoodData::ProjectRole, json, project: self)
|
|
1452
|
+
url = "/gdc/internal/projects/#{pid}/roles"
|
|
1453
|
+
res = client.get url
|
|
1454
|
+
res['internalProjectRoles']['roles'].map do |r|
|
|
1455
|
+
client.create(GoodData::ProjectRole, r, project: self)
|
|
1473
1456
|
end
|
|
1474
1457
|
end
|
|
1475
1458
|
|
|
@@ -42,7 +42,9 @@ module GoodData
|
|
|
42
42
|
_, project = GoodData.get_client_and_project(opts)
|
|
43
43
|
|
|
44
44
|
bp = ProjectBlueprint.new(spec)
|
|
45
|
-
|
|
45
|
+
maql_diff_params = [:includeGrain]
|
|
46
|
+
maql_diff_params << :excludeFactRule if opts[:exclude_fact_rule]
|
|
47
|
+
response = project.maql_diff(blueprint: bp, params: maql_diff_params)
|
|
46
48
|
|
|
47
49
|
GoodData.logger.debug("projectModelDiff") { response.pretty_inspect }
|
|
48
50
|
chunks = response['projectModelDiff']['updateScripts']
|
|
@@ -33,6 +33,7 @@ module GoodData
|
|
|
33
33
|
d[:updated] = data[:updated] || d[:created] || Time.now
|
|
34
34
|
d[:title] = data[:title]
|
|
35
35
|
d[:summary] = data[:summary]
|
|
36
|
+
d[:uri] = data[:uri]
|
|
36
37
|
end
|
|
37
38
|
new_data = GoodData::Helpers.deep_dup(EMPTY_OBJECT).tap do |d|
|
|
38
39
|
d['projectRole']['links']['self'] = data[:uri] if data[:uri]
|
|
@@ -54,7 +55,7 @@ module GoodData
|
|
|
54
55
|
#
|
|
55
56
|
# @return [Array<GoodData::Profile>] List of users
|
|
56
57
|
def users
|
|
57
|
-
url =
|
|
58
|
+
url = uri + '/users'
|
|
58
59
|
tmp = client.get url
|
|
59
60
|
tmp['associatedUsers']['users'].pmap do |user_url|
|
|
60
61
|
url = user_url
|
|
@@ -67,9 +68,7 @@ module GoodData
|
|
|
67
68
|
#
|
|
68
69
|
# @return [string] URI of this project role
|
|
69
70
|
def uri
|
|
70
|
-
|
|
71
|
-
return nil unless @json['projectRole']['links']['roleUsers']
|
|
72
|
-
@json['projectRole']['links']['roleUsers'].split('/')[0...-1].join('/')
|
|
71
|
+
@json['projectRole']['meta']['uri']
|
|
73
72
|
end
|
|
74
73
|
|
|
75
74
|
def ==(other)
|
|
@@ -77,7 +77,6 @@ module GoodData
|
|
|
77
77
|
else
|
|
78
78
|
fail 'Executable has to be provided' if executable.blank?
|
|
79
79
|
end
|
|
80
|
-
fail 'Trigger schedule has to be provided' if trigger.blank?
|
|
81
80
|
|
|
82
81
|
schedule = c.create(GoodData::Schedule, GoodData::Helpers.stringify_keys(GoodData::Helpers.deep_dup(SCHEDULE_TEMPLATE)), client: c, project: project)
|
|
83
82
|
|
|
@@ -403,7 +402,6 @@ module GoodData
|
|
|
403
402
|
#
|
|
404
403
|
# @return [Boolean] True if saved
|
|
405
404
|
def save
|
|
406
|
-
fail 'trigger schedule has to be provided' if cron.blank? && trigger_id.blank?
|
|
407
405
|
fail 'A timezone has to be provided' if timezone.blank?
|
|
408
406
|
fail 'Schedule type has to be provided' if schedule_type.blank?
|
|
409
407
|
rewrite_deprecated_params
|
|
@@ -28,7 +28,7 @@ module GoodData
|
|
|
28
28
|
result = c.get("/gdc/md/#{project.pid}/userfilters?count=#{count}&offset=#{offset}")
|
|
29
29
|
result['userFilters']['items'].each do |item|
|
|
30
30
|
item['userFilters'].each do |f|
|
|
31
|
-
user_lookup[f] = item['user']
|
|
31
|
+
user_lookup[f] = user_lookup[f] ? Array(user_lookup[f]).concat([item['user']]) : item['user']
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
break if result['userFilters']['length'] < offset
|
|
@@ -72,5 +72,13 @@ module GoodData
|
|
|
72
72
|
res = client.post(project.md['obj'], data)
|
|
73
73
|
@json[:uri] = res['uri']
|
|
74
74
|
end
|
|
75
|
+
|
|
76
|
+
def related
|
|
77
|
+
if related_uri.is_a? Array
|
|
78
|
+
related_uri.map { |u| super u }
|
|
79
|
+
else
|
|
80
|
+
super
|
|
81
|
+
end
|
|
82
|
+
end
|
|
75
83
|
end
|
|
76
84
|
end
|
|
@@ -30,8 +30,7 @@ module GoodData
|
|
|
30
30
|
# Returns the the object of this filter is related to. It can be either project or a user
|
|
31
31
|
#
|
|
32
32
|
# @return [GoodData::Project | GoodData::Profile] Related object
|
|
33
|
-
def related
|
|
34
|
-
uri = related_uri
|
|
33
|
+
def related(uri = related_uri)
|
|
35
34
|
return unless uri
|
|
36
35
|
level == :project ? client.projects(uri) : client.create(GoodData::Profile, client.get(uri))
|
|
37
36
|
end
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
# LICENSE file in the root directory of this source tree.
|
|
6
6
|
|
|
7
7
|
require_relative '../project_log_formatter'
|
|
8
|
+
require 'active_support/core_ext/hash/indifferent_access'
|
|
8
9
|
|
|
9
10
|
module GoodData
|
|
10
11
|
module UserFilterBuilder
|
|
@@ -270,10 +271,10 @@ module GoodData
|
|
|
270
271
|
attrs_cache = create_attrs_cache(filters, options)
|
|
271
272
|
create_filter_proc = proc do |login, f|
|
|
272
273
|
expression, errors = create_expression(f, labels_cache, lookups_cache, attrs_cache, options)
|
|
274
|
+
safe_login = login.downcase
|
|
273
275
|
profiles_uri = if options[:type] == :muf
|
|
274
276
|
project_user = project_users.find { |u| u.login == login }
|
|
275
|
-
|
|
276
|
-
project_user.nil? ? ('/gdc/account/profile/' + login) : project_user.profile_url
|
|
277
|
+
project_user.nil? ? ('/gdc/account/profile/' + safe_login) : project_user.profile_url
|
|
277
278
|
elsif options[:type] == :variable
|
|
278
279
|
(users_cache[login] && users_cache[login].uri)
|
|
279
280
|
else
|
|
@@ -384,7 +385,14 @@ module GoodData
|
|
|
384
385
|
else
|
|
385
386
|
GoodData.logger.warn("Data permissions computed: #{to_create.count} to create and #{to_delete.count} to delete")
|
|
386
387
|
end
|
|
387
|
-
|
|
388
|
+
|
|
389
|
+
if dry_run
|
|
390
|
+
create_results = to_create.map { |x| { status: 'dry_run', user: x.first, type: 'create' } }
|
|
391
|
+
delete_results = to_delete.map { |x| { status: 'dry_run', user: x.first, type: 'delete' } }
|
|
392
|
+
return { created: {},
|
|
393
|
+
deleted: {},
|
|
394
|
+
results: create_results + delete_results }
|
|
395
|
+
end
|
|
388
396
|
|
|
389
397
|
create_results = to_create.each_slice(100).flat_map do |batch|
|
|
390
398
|
batch.pmapcat do |related_uri, group|
|
|
@@ -414,6 +422,8 @@ module GoodData
|
|
|
414
422
|
end
|
|
415
423
|
|
|
416
424
|
project_log_formatter.log_user_filter_results(create_results, to_create)
|
|
425
|
+
create_errors = create_results.select { |r| r[:status] == :failed }
|
|
426
|
+
fail "Creating MUFs resulted in errors: #{create_errors}" if create_errors.any?
|
|
417
427
|
|
|
418
428
|
delete_results = unless options[:do_not_touch_filters_that_are_not_mentioned]
|
|
419
429
|
to_delete.each_slice(100).flat_map do |batch|
|
|
@@ -444,6 +454,8 @@ module GoodData
|
|
|
444
454
|
end
|
|
445
455
|
|
|
446
456
|
project_log_formatter.log_user_filter_results(delete_results, to_delete)
|
|
457
|
+
delete_errors = delete_results.select { |r| r[:status] == :failed } if delete_results
|
|
458
|
+
fail "Deleting MUFs resulted in errors: #{delete_errors}" if delete_errors && delete_errors.any?
|
|
447
459
|
|
|
448
460
|
{ created: to_create, deleted: to_delete, results: create_results + (delete_results || []) }
|
|
449
461
|
end
|
|
@@ -541,13 +553,13 @@ module GoodData
|
|
|
541
553
|
# if this does not happen, users that are about to be deleted by users_brick
|
|
542
554
|
# would have all their filters removed now, which is not desirable
|
|
543
555
|
def self.sanitize_filters_to_delete(to_delete, users_brick_input, project_users)
|
|
544
|
-
return
|
|
556
|
+
return [] unless users_brick_input && users_brick_input.any?
|
|
545
557
|
user_profiles = users_brick_input.map do |user|
|
|
546
|
-
result = project_users.find { |u| u.login == user['login'] }
|
|
558
|
+
result = project_users.find { |u| u.login == user.with_indifferent_access['login'] }
|
|
547
559
|
next unless result
|
|
548
560
|
result.profile_url
|
|
549
561
|
end.compact
|
|
550
|
-
return
|
|
562
|
+
return [] unless user_profiles.any?
|
|
551
563
|
to_delete.reject do |_, value|
|
|
552
564
|
user_profiles.none? { |profile| profile == value.first.json[:related] }
|
|
553
565
|
end
|
data/lib/gooddata/rest/client.rb
CHANGED
|
@@ -17,48 +17,6 @@ require_relative '../helpers/global_helpers'
|
|
|
17
17
|
|
|
18
18
|
require_relative 'phmap'
|
|
19
19
|
|
|
20
|
-
module RestClient
|
|
21
|
-
module AbstractResponse
|
|
22
|
-
alias_method :old_follow_redirection, :follow_redirection
|
|
23
|
-
def follow_redirection(request = nil, result = nil, &block)
|
|
24
|
-
if RestClient::VERSION != '1.8.0'
|
|
25
|
-
fail 'Using monkey patched version of RestClient::AbstractResponse#' \
|
|
26
|
-
'follow_redirection which is guaranteed to be compatible only ' \
|
|
27
|
-
'with RestClient 1.8.0'
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
new_args = @args.dup
|
|
31
|
-
|
|
32
|
-
url = headers[:location]
|
|
33
|
-
url = URI.parse(request.url).merge(url).to_s if url !~ /^http/
|
|
34
|
-
|
|
35
|
-
new_args[:url] = url
|
|
36
|
-
if request
|
|
37
|
-
fail MaxRedirectsReached if request.max_redirects.zero?
|
|
38
|
-
new_args[:password] = request.password
|
|
39
|
-
new_args[:user] = request.user
|
|
40
|
-
new_args[:headers] = request.headers
|
|
41
|
-
new_args[:max_redirects] = request.max_redirects - 1
|
|
42
|
-
|
|
43
|
-
# TODO: figure out what to do with original :cookie, :cookies values
|
|
44
|
-
new_args[:cookies] = get_redirection_cookies(request, result, new_args)
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
Request.execute(new_args, &block)
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
# Returns cookies which should be passed when following redirect
|
|
51
|
-
#
|
|
52
|
-
# @param request [RestClient::Request] Original request
|
|
53
|
-
# @param result [Net::HTTPResponse] Response
|
|
54
|
-
# @param args [Hash] Original arguments
|
|
55
|
-
# @return [Hash] Cookies to be passsed when following redirect
|
|
56
|
-
def get_redirection_cookies(request, _result, _args)
|
|
57
|
-
request.cookies
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
end
|
|
61
|
-
|
|
62
20
|
module GoodData
|
|
63
21
|
module Rest
|
|
64
22
|
class RestRetryError < StandardError
|
|
@@ -210,13 +168,23 @@ module GoodData
|
|
|
210
168
|
|
|
211
169
|
# Reset old cookies first
|
|
212
170
|
if options[:sst_token]
|
|
213
|
-
|
|
171
|
+
headers = {
|
|
172
|
+
:x_gdc_authsst => options[:sst_token],
|
|
173
|
+
:x_gdc_authtt => options[:tt_token]
|
|
174
|
+
}
|
|
175
|
+
merge_headers!(headers)
|
|
214
176
|
get('/gdc/account/token', @request_params)
|
|
215
177
|
|
|
216
178
|
@user = get(get('/gdc/app/account/bootstrap')['bootstrapResource']['accountSetting']['links']['self'])
|
|
217
179
|
GoodData.logger.info("Connected using SST to server #{@server.url} to profile \"#{@user['accountSetting']['login']}\"")
|
|
218
180
|
@auth = {}
|
|
219
181
|
refresh_token :dont_reauth => true
|
|
182
|
+
elsif options[:headers][:x_gdc_authsst]
|
|
183
|
+
@request_params = options[:headers]
|
|
184
|
+
@user = get('/gdc/app/account/bootstrap')['bootstrapResource']
|
|
185
|
+
GoodData.logger.info("Connected using SST to server #{@server.url} to profile \"#{@user['accountSetting']['login']}\"")
|
|
186
|
+
@auth = {}
|
|
187
|
+
refresh_token :dont_reauth => true
|
|
220
188
|
else
|
|
221
189
|
GoodData.logger.info("Connected using username \"#{username}\" to server #{@server.url}")
|
|
222
190
|
credentials = Connection.construct_login_payload(username, password)
|
|
@@ -656,9 +624,7 @@ ERR
|
|
|
656
624
|
placeholders = true
|
|
657
625
|
|
|
658
626
|
if placeholders
|
|
659
|
-
|
|
660
|
-
break if title.gsub!(pm[1], pm[0])
|
|
661
|
-
end
|
|
627
|
+
title = self.class.map_placeholders(title)
|
|
662
628
|
end
|
|
663
629
|
|
|
664
630
|
stat = stats[title]
|
data/lib/gooddata/rest/phmap.rb
CHANGED
|
@@ -7,74 +7,119 @@
|
|
|
7
7
|
module GoodData
|
|
8
8
|
module Rest
|
|
9
9
|
class Connection
|
|
10
|
+
def self.map_placeholders(title)
|
|
11
|
+
PH_MAP.each do |pm|
|
|
12
|
+
break if title.gsub!(pm[1], pm[0])
|
|
13
|
+
end
|
|
14
|
+
title
|
|
15
|
+
end
|
|
16
|
+
|
|
10
17
|
# PH_MAP for wildcarding of URLs in reports
|
|
11
18
|
PH_MAP = [
|
|
12
|
-
['/gdc/
|
|
13
|
-
|
|
14
|
-
['/gdc/
|
|
15
|
-
|
|
19
|
+
['/gdc/projects/{id}/execute', %r{/gdc/projects/[^\/]+/execute}],
|
|
20
|
+
|
|
21
|
+
['/gdc/dataload/projects/{id}/outputStage', %r{/gdc/dataload/projects/[^\/]+/outputStage}],
|
|
22
|
+
|
|
23
|
+
['/gdc/datawarehouse/instances/{id}', %r{/gdc/datawarehouse/instances/[^\/]+}],
|
|
24
|
+
['/gdc/datawarehouse/executions/{id}', %r{/gdc/datawarehouse/executions/[^\/]+}],
|
|
16
25
|
|
|
17
|
-
|
|
26
|
+
# domain dataproducts' clients
|
|
27
|
+
['/gdc/domains/{id}/dataproducts/{data_product}/clients?segment={segment}',
|
|
28
|
+
%r{\/gdc\/domains\/[^\/]+\/dataproducts\/[^\/]+\/clients\?.*segment=[^\/]+}],
|
|
29
|
+
['/gdc/domains/{id}/dataproducts/{data_product}/clients/{client}', %r{/gdc/domains/[^\/]+/dataproducts/[^\/]+/clients/[^\/]+}],
|
|
30
|
+
['/gdc/domains/{id}/dataproducts/{data_product}/clients', %r{/gdc/domains/[^\/]+/dataproducts/[^\/]+/clients}],
|
|
18
31
|
|
|
19
|
-
|
|
20
|
-
['/gdc/
|
|
32
|
+
# domain dataproducts' segments
|
|
33
|
+
['/gdc/domains/{id}/dataproducts/{data_product}/segments/{segment}/synchronizeClients/results/{result}/details?offset={offset}&limit={limit}',
|
|
34
|
+
%r{/gdc/domains/[^\/]+/dataproducts/[^\/]+/segments/[^\/]+/synchronizeClients/results/[^\/]+/details\?offset=[\d]+&limit=[\d]+}],
|
|
35
|
+
['/gdc/domains/{id}/dataproducts/{data_product}/segments/{segment}/synchronizeClients/results/{result}',
|
|
36
|
+
%r{/gdc/domains/[^\/]+/dataproducts/[^\/]+/segments/[^\/]+/synchronizeClients/results/[^\/]+}],
|
|
37
|
+
['/gdc/domains/{id}/dataproducts/{data_product}/segments/{segment}', %r{/gdc/domains/[^\/]+/dataproducts/[^\/]+/segments/[^\/]+}],
|
|
38
|
+
['/gdc/domains/{id}/dataproducts/{data_product}/segments', %r{/gdc/domains/[^\/]+/dataproducts/[^\/]+/segments}],
|
|
21
39
|
|
|
40
|
+
# domain dataproducts' provision & update
|
|
41
|
+
['/gdc/domains/{id}/dataproducts/{data_product}/provisionClientProjects/results/{result}/details?offset={offset}&limit={limit}',
|
|
42
|
+
%r{/gdc/domains/[^\/]+/dataproducts/[^\/]+/provisionClientProjects/results/[^\/]+/details\?offset=[\d]+&limit=[\d]+}],
|
|
43
|
+
['/gdc/domains/{id}/dataproducts/{data_product}/provisionClientProjects/results/{result}',
|
|
44
|
+
%r{/gdc/domains/[^\/]+/dataproducts/[^\/]+/provisionClientProjects/results/[^\/]+}],
|
|
45
|
+
['/gdc/domains/{id}/dataproducts/{data_product}/provisionClientProjects',
|
|
46
|
+
%r{/gdc/domains/[^\/]+/dataproducts/[^\/]+/provisionClientProjects}],
|
|
47
|
+
['/gdc/domains/{id}/dataproducts/{data_product}/updateClients?deleteExtraInSegments={segments}',
|
|
48
|
+
%r{/gdc/domains/[^\/]+/dataproducts/[^\/]+/updateClients\?deleteExtraInSegments=[^\/]+}],
|
|
49
|
+
['/gdc/domains/{id}/dataproducts/{data_product}/updateClients',
|
|
50
|
+
%r{/gdc/domains/[^\/]+/dataproducts/[^\/]+/updateClients}],
|
|
51
|
+
|
|
52
|
+
# domain dataproduct
|
|
53
|
+
['/gdc/domains/{id}/dataproducts/{data_product}', %r{/gdc/domains/[^\/]+/dataproducts/[^\/]+}],
|
|
54
|
+
['/gdc/domains/{id}/dataproducts', %r{/gdc/domains/[^\/]+/dataproducts}],
|
|
55
|
+
|
|
56
|
+
# domain segments
|
|
22
57
|
['/gdc/domains/{id}/segments/{segment}/synchronizeClients/results/{result}/details?offset={offset}&limit={limit}',
|
|
23
|
-
%r{/gdc/domains/[
|
|
58
|
+
%r{/gdc/domains/[^\/]+/segments/[^\/]+/synchronizeClients/results/[^\/]+/details\?offset=[\d]+&limit=[\d]+}],
|
|
24
59
|
['/gdc/domains/{id}/segments/{segment}/synchronizeClients/results/{result}',
|
|
25
|
-
%r{/gdc/domains/[
|
|
26
|
-
['/gdc/domains/{id}/segments/{segment}/', %r{/gdc/domains/[
|
|
27
|
-
['/gdc/domains/{id}/segments/{segment}', %r{/gdc/domains/[
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
['/gdc/domains/{id}/clients
|
|
31
|
-
['/gdc/domains/{id}/clients/{client_id}', %r{/gdc/domains/[
|
|
60
|
+
%r{/gdc/domains/[^\/]+/segments/[^\/]+/synchronizeClients/results/[^\/]+}],
|
|
61
|
+
['/gdc/domains/{id}/segments/{segment}/', %r{/gdc/domains/[^\/]+/segments/[^\/]+/}],
|
|
62
|
+
['/gdc/domains/{id}/segments/{segment}', %r{/gdc/domains/[^\/]+/segments/[^\/]+}],
|
|
63
|
+
|
|
64
|
+
# domain clients
|
|
65
|
+
['/gdc/domains/{id}/clients?segment={segment}', %r{/gdc/domains/[^\/]+/clients\?segment=[^\/]+}],
|
|
66
|
+
['/gdc/domains/{id}/clients/{client_id}/settings/lcm.title', %r{/gdc/domains/[^\/]+/clients/[^\/]+/settings/lcm.title}],
|
|
67
|
+
['/gdc/domains/{id}/clients/{client_id}/settings/lcm.token', %r{/gdc/domains/[^\/]+/clients/[^\/]+/settings/lcm.token}],
|
|
68
|
+
['/gdc/domains/{id}/clients/{client_id}', %r{/gdc/domains/[^\/]+/clients/[^\/]+}],
|
|
32
69
|
['/gdc/domains/{id}/provisionClientProjects/results/{result}/details?offset={offset}&limit={limit}',
|
|
33
|
-
%r{/gdc/domains/[
|
|
34
|
-
['/gdc/domains/{id}/provisionClientProjects/results/{result}', %r{/gdc/domains/[
|
|
35
|
-
['/gdc/domains/{id}/provisionClientProjects', %r{/gdc/domains/[
|
|
36
|
-
['/gdc/domains/{id}/updateClients', %r{/gdc/domains/[
|
|
37
|
-
['/gdc/domains/{id}/', %r{/gdc/domains/[
|
|
70
|
+
%r{/gdc/domains/[^\/]+/provisionClientProjects/results/[^\/]+/details\?offset=[\d]+&limit=[\d]+}],
|
|
71
|
+
['/gdc/domains/{id}/provisionClientProjects/results/{result}', %r{/gdc/domains/[^\/]+/provisionClientProjects/results/[^\/]+}],
|
|
72
|
+
['/gdc/domains/{id}/provisionClientProjects', %r{/gdc/domains/[^\/]+/provisionClientProjects}],
|
|
73
|
+
['/gdc/domains/{id}/updateClients', %r{/gdc/domains/[^\/]+/updateClients}],
|
|
74
|
+
['/gdc/domains/{id}/', %r{/gdc/domains/[^\/]+/}],
|
|
38
75
|
|
|
39
|
-
['/gdc/exporter/result/{id}/{id}', %r{/gdc/exporter/result/[
|
|
76
|
+
['/gdc/exporter/result/{id}/{id}', %r{/gdc/exporter/result/[^\/]+/[^\/]+}],
|
|
40
77
|
|
|
41
78
|
['/gdc/internal/lcm/domains/{id}/dataproducts/{data_product}/segments/{segment}/syncProcesses/{process}',
|
|
42
|
-
%r{/gdc/internal/lcm/domains/[
|
|
79
|
+
%r{/gdc/internal/lcm/domains/[^\/]+/dataproducts/[^\/]+/segments/[^\/]+/syncProcesses/[^\/]+}],
|
|
43
80
|
['/gdc/internal/lcm/domains/{id}/dataproducts/{data_product}/segments/{segment}/syncProcesses',
|
|
44
|
-
%r{/gdc/internal/lcm/domains/[
|
|
45
|
-
|
|
46
|
-
['/gdc/internal/projects/{id}/objects/setPermissions', %r{/gdc/internal/projects/[
|
|
47
|
-
|
|
48
|
-
['/gdc/md/{id}/variables/item/{id}', %r{/gdc/md/[
|
|
49
|
-
['/gdc/md/{id}/validate/task/{id}', %r{/gdc/md/[
|
|
50
|
-
['/gdc/md/{id}/using2/{id}/{id}', %r{/gdc/md/[
|
|
51
|
-
['/gdc/md/{id}/using2/{id}', %r{/gdc/md/[
|
|
52
|
-
['/gdc/md/{id}/userfilters?users={users}', %r{
|
|
53
|
-
['/gdc/md/{id}/userfilters?count={count}&offset={offset}', %r{/gdc/md/[
|
|
54
|
-
['/gdc/md/{id}/usedby2/{id}/{id}', %r{/gdc/md/[
|
|
55
|
-
['/gdc/md/{id}/usedby2/{id}', %r{/gdc/md/[
|
|
56
|
-
['/gdc/md/{id}/tasks/{id}/status', %r{/gdc/md/[
|
|
57
|
-
['/gdc/md/{id}/obj/{id}/validElements', %r{/gdc/md/[
|
|
58
|
-
['/gdc/md/{id}/obj/{id}/elements', %r{/gdc/md/[
|
|
59
|
-
['/gdc/md/{id}/obj/{id}', %r{/gdc/md/[
|
|
60
|
-
['/gdc/md/{id}/etltask/{id}', %r{/gdc/md/[
|
|
61
|
-
['/gdc/md/{id}/dataResult/{id}', %r{/gdc/md/[
|
|
62
|
-
['/gdc/md/{id}', %r{/gdc/md/[
|
|
63
|
-
|
|
64
|
-
['/gdc/projects/{id}/users/{id}/roles', %r{/gdc/projects/[
|
|
65
|
-
['/gdc/projects/{id}/users/{id}/permissions', %r{/gdc/projects/[
|
|
66
|
-
['/gdc/projects/{id}/users', %r{/gdc/projects/[
|
|
67
|
-
['/gdc/projects/{id}/schedules/{id}/executions/{id}', %r{/gdc/projects/[
|
|
68
|
-
['/gdc/projects/{id}/schedules/{id}', %r{/gdc/projects/[
|
|
69
|
-
['/gdc/projects/{id}/roles/{id}', %r{/gdc/projects/[
|
|
70
|
-
['/gdc/projects/{id}/model/view/{id}', %r{/gdc/projects/[
|
|
71
|
-
['/gdc/projects/{id}/model/view', %r{/gdc/projects/[
|
|
72
|
-
['/gdc/projects/{id}/model/diff/{id}', %r{/gdc/projects/[
|
|
73
|
-
['/gdc/projects/{id}/model/diff', %r{/gdc/projects/[
|
|
74
|
-
['/gdc/projects/{id}/dataload/
|
|
75
|
-
['/gdc/projects/{id}/dataload/processes/{id}', %r{/gdc/projects/[
|
|
76
|
-
['/gdc/projects/{id}/', %r{/gdc/projects/[
|
|
77
|
-
['/gdc/projects/{id}', %r{/gdc/projects/[
|
|
81
|
+
%r{/gdc/internal/lcm/domains/[^\/]+/dataproducts/[^\/]+/segments/[^\/]+/syncProcesses}],
|
|
82
|
+
|
|
83
|
+
['/gdc/internal/projects/{id}/objects/setPermissions', %r{/gdc/internal/projects/[^\/]+/objects/setPermissions}],
|
|
84
|
+
|
|
85
|
+
['/gdc/md/{id}/variables/item/{id}', %r{/gdc/md/[^\/]+/variables/item/[\d]+}],
|
|
86
|
+
['/gdc/md/{id}/validate/task/{id}', %r{/gdc/md/[^\/]+/validate/task/[^\/]+}],
|
|
87
|
+
['/gdc/md/{id}/using2/{id}/{id}', %r{/gdc/md/[^\/]+/using2/[\d]+/[\d]+}],
|
|
88
|
+
['/gdc/md/{id}/using2/{id}', %r{/gdc/md/[^\/]+/using2/[\d]+}],
|
|
89
|
+
['/gdc/md/{id}/userfilters?users={users}', %r{\/gdc\/md\/[^\/]+\/userfilters\?users=[\/\w+@.]+}],
|
|
90
|
+
['/gdc/md/{id}/userfilters?count={count}&offset={offset}', %r{/gdc/md/[^\/]+/userfilters\?count=[\d]+&offset=[\d]+}],
|
|
91
|
+
['/gdc/md/{id}/usedby2/{id}/{id}', %r{/gdc/md/[^\/]+/usedby2/[\d]+/[\d]+}],
|
|
92
|
+
['/gdc/md/{id}/usedby2/{id}', %r{/gdc/md/[^\/]+/usedby2/[\d]+}],
|
|
93
|
+
['/gdc/md/{id}/tasks/{id}/status', %r{/gdc/md/[^\/]+/tasks/[^\/]+/status}],
|
|
94
|
+
['/gdc/md/{id}/obj/{id}/validElements', %r{/gdc/md/[^\/]+/obj/[\d]+/validElements(/)?(\?.*)?}],
|
|
95
|
+
['/gdc/md/{id}/obj/{id}/elements', %r{/gdc/md/[^\/]+/obj/[\d]+/elements(/)?(\?.*)?}],
|
|
96
|
+
['/gdc/md/{id}/obj/{id}', %r{/gdc/md/[^\/]+/obj/[\d]+}],
|
|
97
|
+
['/gdc/md/{id}/etltask/{id}', %r{/gdc/md/[^\/]+/etltask/[^\/]+}],
|
|
98
|
+
['/gdc/md/{id}/dataResult/{id}', %r{/gdc/md/[^\/]+/dataResult/[\d]+}],
|
|
99
|
+
['/gdc/md/{id}', %r{/gdc/md/[^\/]+}],
|
|
100
|
+
|
|
101
|
+
['/gdc/projects/{id}/users/{id}/roles', %r{/gdc/projects/[^\/]+/users/[^\/]+/roles}],
|
|
102
|
+
['/gdc/projects/{id}/users/{id}/permissions', %r{/gdc/projects/[^\/]+/users/[^\/]+/permissions}],
|
|
103
|
+
['/gdc/projects/{id}/users', %r{/gdc/projects/[^\/]+/users}],
|
|
104
|
+
['/gdc/projects/{id}/schedules/{id}/executions/{id}', %r{/gdc/projects/[^\/]+/schedules/[^\/]+/executions/[^\/]+}],
|
|
105
|
+
['/gdc/projects/{id}/schedules/{id}', %r{/gdc/projects/[^\/]+/schedules/[^\/]+}],
|
|
106
|
+
['/gdc/projects/{id}/roles/{id}', %r{/gdc/projects/[^\/]+/roles/[\d]+}],
|
|
107
|
+
['/gdc/projects/{id}/model/view/{id}', %r{/gdc/projects/[^\/]+/model/view/[^\/]+}],
|
|
108
|
+
['/gdc/projects/{id}/model/view', %r{/gdc/projects/[^\/]+/model/view}],
|
|
109
|
+
['/gdc/projects/{id}/model/diff/{id}', %r{/gdc/projects/[^\/]+/model/diff/[^\/]+}],
|
|
110
|
+
['/gdc/projects/{id}/model/diff', %r{/gdc/projects/[^\/]+/model/diff}],
|
|
111
|
+
['/gdc/projects/{id}/dataload/metadata/{project}', %r{/gdc/projects/[^\/]+/dataload/metadata/[^\/]+}],
|
|
112
|
+
['/gdc/projects/{id}/dataload/processes/{id}/executions/{id}', %r{/gdc/projects/[^\/]+/dataload/processes/[^\/]+/executions/[^\/]+}],
|
|
113
|
+
['/gdc/projects/{id}/dataload/processes/{id}', %r{/gdc/projects/[^\/]+/dataload/processes/[^\/]+}],
|
|
114
|
+
['/gdc/projects/{id}/', %r{/gdc/projects/[^\/]+/}],
|
|
115
|
+
['/gdc/projects/{id}', %r{/gdc/projects/[^\/]+}],
|
|
116
|
+
|
|
117
|
+
['/gdc/userGroups/{id}', %r{/gdc/userGroups/[^\/]+}],
|
|
118
|
+
|
|
119
|
+
['/gdc/account/profile/{id}', %r{/gdc/account/profile/[^\/]+}],
|
|
120
|
+
['/gdc/account/login/{id}', %r{/gdc/account/login/[^\/]+}],
|
|
121
|
+
['/gdc/account/domains/{id}/users?login={login}', %r{/gdc/account/domains/[^\/]+/users\?login=[^&$]+}],
|
|
122
|
+
['/gdc/account/domains/{id}', %r{/gdc/account/domains/[^\/]+}]
|
|
78
123
|
]
|
|
79
124
|
end
|
|
80
125
|
end
|