freckle_io 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.codeclimate.yml +5 -0
- data/.env.sample +3 -0
- data/.env.test.sample +3 -0
- data/.gitignore +5 -0
- data/.rubocop.yml +67 -0
- data/.travis.yml +20 -0
- data/Gemfile +8 -0
- data/README.md +95 -0
- data/Rakefile +5 -0
- data/freckle-io.gemspec +37 -0
- data/icon.svg +192 -0
- data/lib/freckle_io/authentication.rb +26 -0
- data/lib/freckle_io/client/entries.rb +53 -0
- data/lib/freckle_io/client/project_groups.rb +36 -0
- data/lib/freckle_io/client/projects.rb +42 -0
- data/lib/freckle_io/client/tags.rb +33 -0
- data/lib/freckle_io/client/users.rb +35 -0
- data/lib/freckle_io/configuration.rb +48 -0
- data/lib/freckle_io/connection.rb +80 -0
- data/lib/freckle_io/errors/configuration.rb +5 -0
- data/lib/freckle_io/errors/connection.rb +9 -0
- data/lib/freckle_io/errors/params.rb +8 -0
- data/lib/freckle_io/paginator.rb +70 -0
- data/lib/freckle_io/params.rb +46 -0
- data/lib/freckle_io/request/multiple_pages.rb +62 -0
- data/lib/freckle_io/request/single_page.rb +73 -0
- data/lib/freckle_io/validator/entry.rb +57 -0
- data/lib/freckle_io/validator/project.rb +46 -0
- data/lib/freckle_io/validator/project_group.rb +30 -0
- data/lib/freckle_io/validator/restricted_hash.rb +11 -0
- data/lib/freckle_io/validator/tag.rb +30 -0
- data/lib/freckle_io/validator/user.rb +43 -0
- data/lib/freckle_io/validator/validation.yml +14 -0
- data/lib/freckle_io.rb +35 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Entries/with_configuration/_all/result_must_be_a_Request_MultiplePages.yml +48 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Entries/with_configuration/_all/returns_a_entry_for_each_response.yml +48 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Entries/with_configuration/with_valid_params/params_should_be_valid.yml +48 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Entries/with_configuration/with_validator/call_entry_s_validator.yml +48 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_ProjectGroups/with_configuration/_all/result_must_be_a_Request_MultiplePages.yml +99 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_ProjectGroups/with_configuration/_all/returns_a_project_group_for_each_response.yml +99 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_ProjectGroups/with_configuration/with_valid_params/params_should_be_valid.yml +48 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_ProjectGroups/with_configuration/with_validator/call_project_group_s_validator.yml +99 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Projects/with_configuration/_all/result_must_be_a_Request_MultiplePages.yml +491 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Projects/with_configuration/_all/returns_a_project_for_each_response.yml +491 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Projects/with_configuration/_show/get_a_spacific_project.yml +48 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Projects/with_configuration/_show/raw_links_should_be_a_empty_array.yml +48 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Projects/with_configuration/with_valid_params/params_should_be_valid.yml +48 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Projects/with_configuration/with_validator/call_project_s_validator.yml +491 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Tags/with_configuration/_all/result_must_be_a_Request_MultiplePages.yml +48 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Tags/with_configuration/_all/returns_a_tag_for_each_response.yml +48 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Tags/with_configuration/with_valid_params/params_should_be_valid.yml +48 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Tags/with_configuration/with_validator/call_tag_s_validator.yml +48 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Users/with_configuration/_all/result_must_be_a_Request_MultiplePages.yml +99 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Users/with_configuration/_all/returns_a_user_for_each_response.yml +99 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Users/with_configuration/_show/get_a_spacific_user.yml +48 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Users/with_configuration/_show/raw_links_should_be_a_empty_array.yml +48 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Users/with_configuration/with_valid_params/params_should_be_valid.yml +48 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Users/with_configuration/with_validator/call_user_s_validator.yml +99 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Connection/with_default_configuration/with_a_valid_response/must_be_a_json_format.yml +51 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Connection/with_default_configuration/with_freckle_token_authentication/set_X-FreckleToken.yml +51 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Connection/with_default_configuration/with_header/set_user_agent.yml +51 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Connection/with_default_configuration/with_invalid_url/raises_a_resource_not_found_error_for_invalid_resource.yml +40 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Connection/with_default_configuration/with_page_param/response_must_be_success.yml +51 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Connection/with_default_configuration/with_per_page_param/response_must_have_per_page_elements.yml +51 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Request_MultiplePages/with_configuration/_get/returns_an_array_of_faraday_response.yml +99 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Request_MultiplePages/with_configuration/_get/returns_freckle_default_per_page_elements.yml +99 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Request_MultiplePages/with_per_page/_get/return_per_page_number_elements.yml +148 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_first/next_page_should_be_a_SinglePage.yml +99 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_first/prev_page_should_be_nil.yml +51 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_first/when_get_last_page_from_the_first_page/next_should_be_nil.yml +99 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_get/returns_correct_raw_links_for_the_first_page.yml +51 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_last/next_page_should_be_nil.yml +99 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_last/returns_correct_raw_links_for_the_last_page.yml +99 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_last/when_get_prev_page_from_the_last_page/prev_should_be_nil.yml +147 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_next/previous_page_is_a_SinglePage.yml +147 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_next/previous_page_should_be_not_nil.yml +147 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_prev/next_page_is_a_SinglePage.yml +195 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_prev/when_get_prev_page_from_the_first_page/prev_should_be_nil.yml +147 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_total_page/with_first_page/returns_the_range_of_pages.yml +51 -0
- data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_total_page/with_next_page/returns_an_empty_array.yml +99 -0
- data/spec/freckle_io/client/entries_spec.rb +359 -0
- data/spec/freckle_io/client/project_groups_spec.rb +132 -0
- data/spec/freckle_io/client/projects_spec.rb +183 -0
- data/spec/freckle_io/client/tags_spec.rb +132 -0
- data/spec/freckle_io/client/users_spec.rb +150 -0
- data/spec/freckle_io/configuration_spec.rb +70 -0
- data/spec/freckle_io/connection_spec.rb +116 -0
- data/spec/freckle_io/paginator_spec.rb +105 -0
- data/spec/freckle_io/params_spec.rb +15 -0
- data/spec/freckle_io/request/multiple_pages_spec.rb +39 -0
- data/spec/freckle_io/request/single_page_spec.rb +107 -0
- data/spec/spec_helper.rb +69 -0
- data/spec/support/anonymize/entries.rb +60 -0
- data/spec/support/anonymize/project_groups.rb +55 -0
- data/spec/support/anonymize/projects.rb +60 -0
- data/spec/support/anonymize/tags.rb +47 -0
- data/spec/support/anonymize/users.rb +59 -0
- data/spec/support/anonymize_interaction.rb +60 -0
- data/spec/support/entry_info.rb +19 -0
- data/spec/support/project_group_info.rb +13 -0
- data/spec/support/project_info.rb +26 -0
- data/spec/support/shared/links/raw_links.rb +13 -0
- data/spec/support/tag_info.rb +11 -0
- data/spec/support/user_info.rb +21 -0
- metadata +382 -0
@@ -0,0 +1,107 @@
|
|
1
|
+
require_relative "../../spec_helper"
|
2
|
+
|
3
|
+
describe FreckleIO::Request::SinglePage do
|
4
|
+
context "with configuration", :vcr do
|
5
|
+
let(:users) { subject.get("/v2/users") }
|
6
|
+
|
7
|
+
describe "#get" do
|
8
|
+
let(:body_response) { users.last_response.body }
|
9
|
+
|
10
|
+
it "returns correct raw links for the first page" do
|
11
|
+
expect(users.raw_links).to eq first_page
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#next" do
|
16
|
+
let(:next_users) { users.next }
|
17
|
+
let(:body_response) { next_users.last_response.body }
|
18
|
+
|
19
|
+
it "previous page should be not nil" do
|
20
|
+
expect(next_users.prev).to_not be nil
|
21
|
+
end
|
22
|
+
|
23
|
+
it "previous page is a SinglePage" do
|
24
|
+
expect(next_users.prev).to be_a described_class
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "#prev" do
|
29
|
+
before do
|
30
|
+
users.next
|
31
|
+
end
|
32
|
+
|
33
|
+
let(:prev_users) { users.prev }
|
34
|
+
let(:body_response) { prev_users.last_response.body }
|
35
|
+
|
36
|
+
it "next page is a SinglePage" do
|
37
|
+
expect(prev_users.next).to be_a described_class
|
38
|
+
end
|
39
|
+
|
40
|
+
context "when get prev page from the first page" do
|
41
|
+
it "prev should be nil" do
|
42
|
+
expect(prev_users.prev).to be nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#last" do
|
48
|
+
before do
|
49
|
+
users.last
|
50
|
+
end
|
51
|
+
|
52
|
+
let(:last_users) { users }
|
53
|
+
let(:body_response) { last_users.last_response.body }
|
54
|
+
|
55
|
+
it "next page should be nil" do
|
56
|
+
expect(last_users.next).to be nil
|
57
|
+
end
|
58
|
+
|
59
|
+
it "returns correct raw links for the last page" do
|
60
|
+
expect(users.raw_links).to eq last_page
|
61
|
+
end
|
62
|
+
|
63
|
+
context "when get prev page from the last page" do
|
64
|
+
it "prev should be nil" do
|
65
|
+
expect(last_users.first.prev).to be nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "#first" do
|
71
|
+
let(:first_users) { users }
|
72
|
+
let(:body_response) { first_users.last_response.body }
|
73
|
+
|
74
|
+
it "prev page should be nil" do
|
75
|
+
expect(first_users.prev).to be nil
|
76
|
+
end
|
77
|
+
|
78
|
+
it "next page should be a SinglePage" do
|
79
|
+
expect(first_users.next).to be_a described_class
|
80
|
+
end
|
81
|
+
|
82
|
+
context "when get last page from the first page" do
|
83
|
+
it "next should be nil" do
|
84
|
+
expect(first_users.last.next).to be nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "#total page" do
|
90
|
+
context "with first page" do
|
91
|
+
it "returns the range of pages" do
|
92
|
+
expect(users.total_pages).to be_a Integer
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "with next page" do
|
97
|
+
before do
|
98
|
+
users.next
|
99
|
+
end
|
100
|
+
|
101
|
+
it "returns an empty array" do
|
102
|
+
expect(users.total_pages).to eq(0)
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
|
4
|
+
Dir["./spec/support/**/*.rb"].sort.each { |f| require f }
|
5
|
+
|
6
|
+
require "simplecov"
|
7
|
+
require "simplecov-console"
|
8
|
+
require "coveralls"
|
9
|
+
|
10
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
|
11
|
+
[
|
12
|
+
SimpleCov::Formatter::HTMLFormatter,
|
13
|
+
SimpleCov::Formatter::Console,
|
14
|
+
Coveralls::SimpleCov::Formatter
|
15
|
+
]
|
16
|
+
)
|
17
|
+
|
18
|
+
SimpleCov.start do
|
19
|
+
add_filter "spec/"
|
20
|
+
end
|
21
|
+
|
22
|
+
require "freckle_io"
|
23
|
+
require "rspec"
|
24
|
+
require "vcr"
|
25
|
+
require "webmock"
|
26
|
+
require "webmock/rspec"
|
27
|
+
require "dotenv"
|
28
|
+
|
29
|
+
Dotenv.load(".env.test")
|
30
|
+
|
31
|
+
RSpec.configure do |config|
|
32
|
+
config.before(:each) do
|
33
|
+
FreckleIO.configure do |c|
|
34
|
+
c.token = ENV["FRECKLE_TOKEN"]
|
35
|
+
c.auth_type = :freckle_token
|
36
|
+
c.max_concurrency = 5
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
config.after(:each) do
|
41
|
+
FreckleIO.reset
|
42
|
+
end
|
43
|
+
|
44
|
+
config.include_context "with raw links"
|
45
|
+
config.expect_with :rspec do |expectations|
|
46
|
+
expectations.syntax = :expect
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
VCR.configure do |c|
|
51
|
+
c.hook_into :webmock
|
52
|
+
c.allow_http_connections_when_no_cassette = true
|
53
|
+
c.cassette_library_dir = "spec/fixtures/vcr_cassettes"
|
54
|
+
|
55
|
+
c.configure_rspec_metadata!
|
56
|
+
c.default_cassette_options = {
|
57
|
+
match_requests_on: [:method, :query, :body]
|
58
|
+
}
|
59
|
+
|
60
|
+
c.filter_sensitive_data("<TOKEN>") { filter_api_token }
|
61
|
+
|
62
|
+
c.before_record do |interaction|
|
63
|
+
AnonymizeInteraction.new(interaction: interaction).call
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def filter_api_token
|
68
|
+
ENV.fetch "FRECKLE_TOKEN", "freckle_token"
|
69
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Anonymize
|
2
|
+
class Entries
|
3
|
+
attr_accessor :interaction
|
4
|
+
ENTRY_API_REPLACE_VALUES = {
|
5
|
+
id: /\"id\":(.*?),/i,
|
6
|
+
description: /\"description\":\"(.*?)\"/i,
|
7
|
+
name: /\"name\":\"(.*?)\"/i,
|
8
|
+
email: /\"email\":\"(.*?)\",/i,
|
9
|
+
first_name: /\"first_name\":\"(.*?)\"/i,
|
10
|
+
last_name: /\"last_name\":\"(.*?)\"/i,
|
11
|
+
profile_image_url: /\"profile_image_url\":\"(.*?)\"/i,
|
12
|
+
url: /\"url\":\"(.*?)\"/i
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
def initialize(interaction:)
|
16
|
+
@interaction = interaction
|
17
|
+
end
|
18
|
+
|
19
|
+
def call
|
20
|
+
find_and_replace
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def find_and_replace
|
26
|
+
response_body = interaction.response.body
|
27
|
+
|
28
|
+
ENTRY_API_REPLACE_VALUES.each do |key, regex|
|
29
|
+
match_texts = response_body.scan(regex).uniq
|
30
|
+
sort_texts = sort_by_word_count(match_texts)
|
31
|
+
|
32
|
+
sort_texts.each_with_index do |text, index|
|
33
|
+
replace = anonymize_response_value(key, index)
|
34
|
+
interaction.filter!(text, replace)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
interaction
|
39
|
+
end
|
40
|
+
|
41
|
+
def anonymize_response_value(key, index)
|
42
|
+
return "http://foo.com/#{index}" if key.to_s.include? "url"
|
43
|
+
|
44
|
+
case key
|
45
|
+
when :id
|
46
|
+
index.to_s
|
47
|
+
when :email
|
48
|
+
"#{key}_#{index}@domain.com"
|
49
|
+
else
|
50
|
+
"#{key}_#{index}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def sort_by_word_count(words)
|
55
|
+
words.flatten.sort do |a, b|
|
56
|
+
b.split.length <=> a.split.length
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
module Anonymize
|
2
|
+
class ProjectGroups
|
3
|
+
attr_accessor :interaction
|
4
|
+
PROJECT_GROUP_API_REPLACE_VALUES = {
|
5
|
+
id: /\"id\":(.*?),/mi,
|
6
|
+
name: /\"name\":\"(.*?)\"/mi,
|
7
|
+
url: /\"url\":\"(.*?)\"/mi
|
8
|
+
}.freeze
|
9
|
+
|
10
|
+
def initialize(interaction:)
|
11
|
+
@interaction = interaction
|
12
|
+
end
|
13
|
+
|
14
|
+
def call
|
15
|
+
find_and_replace
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def find_and_replace
|
21
|
+
response_body = interaction.response.body
|
22
|
+
|
23
|
+
PROJECT_GROUP_API_REPLACE_VALUES.each do |key, regex|
|
24
|
+
match_texts = response_body.scan(regex).uniq
|
25
|
+
sort_texts = sort_by_word_count(match_texts)
|
26
|
+
|
27
|
+
sort_texts.each_with_index do |text, index|
|
28
|
+
replace = anonymize_response_value(key, index)
|
29
|
+
interaction.filter!(text, replace)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
interaction
|
34
|
+
end
|
35
|
+
|
36
|
+
def anonymize_response_value(key, index)
|
37
|
+
return "http://foo.com/#{index}" if key.to_s.include? "url"
|
38
|
+
|
39
|
+
case key
|
40
|
+
when :id
|
41
|
+
index.to_s
|
42
|
+
when :mail
|
43
|
+
"#{key}_#{index}@domain.com"
|
44
|
+
else
|
45
|
+
"#{key}_#{index}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def sort_by_word_count(words)
|
50
|
+
words.flatten.sort do |a, b|
|
51
|
+
b.split.length <=> a.split.length
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module Anonymize
|
2
|
+
class Projects
|
3
|
+
attr_accessor :interaction
|
4
|
+
PROJECT_API_REPLACE_VALUES = {
|
5
|
+
name: /\"name\":\"(.*?)\"/i,
|
6
|
+
id: /\"id\":(.*?),/i,
|
7
|
+
url: /\"url\":\"(.*?)\"/i,
|
8
|
+
description: /\"description\":\"(.*?)\"/i,
|
9
|
+
email: /\"email\":\"(.*?)\",/i,
|
10
|
+
first_name: /\"first_name\":\"(.*?)\"/i,
|
11
|
+
last_name: /\"last_name\":\"(.*?)\"/i,
|
12
|
+
profile_image_url: /\"profile_image_url\":\"(.*?)\"/i
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
def initialize(interaction:)
|
16
|
+
@interaction = interaction
|
17
|
+
end
|
18
|
+
|
19
|
+
def call
|
20
|
+
find_and_replace
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def find_and_replace
|
26
|
+
response_body = interaction.response.body
|
27
|
+
|
28
|
+
PROJECT_API_REPLACE_VALUES.each do |key, regex|
|
29
|
+
match_texts = response_body.scan(regex).uniq
|
30
|
+
sort_texts = sort_by_word_count(match_texts)
|
31
|
+
|
32
|
+
sort_texts.each_with_index do |text, index|
|
33
|
+
replace = anonymize_response_value(key, index)
|
34
|
+
interaction.filter!(text, replace)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
interaction
|
39
|
+
end
|
40
|
+
|
41
|
+
def anonymize_response_value(key, index)
|
42
|
+
return "http://foo.com/#{index}" if key.to_s.include? "url"
|
43
|
+
|
44
|
+
case key
|
45
|
+
when :id
|
46
|
+
index.to_s
|
47
|
+
when :email
|
48
|
+
"#{key}_#{index}@domain.com"
|
49
|
+
else
|
50
|
+
"#{key}_#{index}"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def sort_by_word_count(words)
|
55
|
+
words.flatten.sort do |a, b|
|
56
|
+
b.split.length <=> a.split.length
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Anonymize
|
2
|
+
class Tags
|
3
|
+
attr_accessor :interaction
|
4
|
+
TAG_API_REPLACE_VALUES = {
|
5
|
+
id: /\"id\":(.*?),/mi,
|
6
|
+
name: /\"name\":\"(.*?)\"/mi,
|
7
|
+
formatted_name: /\"formatted_name\":\"(.*?)\"/mi,
|
8
|
+
url: /\"url\":\"(.*?)\"/mi
|
9
|
+
}.freeze
|
10
|
+
|
11
|
+
def initialize(interaction:)
|
12
|
+
@interaction = interaction
|
13
|
+
end
|
14
|
+
|
15
|
+
def call
|
16
|
+
find_and_replace
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def find_and_replace
|
22
|
+
TAG_API_REPLACE_VALUES.each do |key, regex|
|
23
|
+
match_texts = interaction.response.body.scan(regex)
|
24
|
+
|
25
|
+
match_texts.each_with_index do |text, index|
|
26
|
+
replace = anonymize_response_value(key, index)
|
27
|
+
interaction.filter!(text.first, replace)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
interaction
|
32
|
+
end
|
33
|
+
|
34
|
+
def anonymize_response_value(key, index)
|
35
|
+
return "http://foo.com/#{index}" if key.to_s.include? "url"
|
36
|
+
|
37
|
+
case key
|
38
|
+
when :id
|
39
|
+
index.to_s
|
40
|
+
when :mail
|
41
|
+
"#{key}_#{index}@domain.com"
|
42
|
+
else
|
43
|
+
"#{key}_#{index}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
module Anonymize
|
2
|
+
class Users
|
3
|
+
attr_accessor :interaction
|
4
|
+
|
5
|
+
# rubocop:disable Metrics/LineLength
|
6
|
+
USER_API_REPLACE_VALUES = {
|
7
|
+
id: /\"id\":(.*?),/mi,
|
8
|
+
mail: /\"email\":\"(.*?)\"/mi,
|
9
|
+
first_name: /\"first_name\":\"(.*?)\"/mi,
|
10
|
+
last_name: /\"last_name\":\"(.*?)\"/mi,
|
11
|
+
profile_image_url: /\"profile_image_url\":\"(.*?)\"/i,
|
12
|
+
url: /\"url\":\"(.*?)\"/mi,
|
13
|
+
entries_url: /\"entries_url\":\"(.*?)\"/mi,
|
14
|
+
expanses_url: /\"expanse_url\":\"(.*?)\"/mi,
|
15
|
+
activate_url: /\"activate_url\":\"(.*?)\"/mi,
|
16
|
+
deactivate_url: /\"deactivate_url\":\"(.*?)\"/mi,
|
17
|
+
access_projects_url: /\"give_access_to_projects_url\":\"(.*?)\"/mi,
|
18
|
+
revoke_projects_url: /\"revoke_access_to_projects_url\":\"(.*?)\"/mi,
|
19
|
+
revoke_all_projects_url: /\"revoke_access_to_all_projects_url\":\"(.*?)\"/mi
|
20
|
+
}.freeze
|
21
|
+
# rubocop:enable Metrics/LineLength
|
22
|
+
|
23
|
+
def initialize(interaction:)
|
24
|
+
@interaction = interaction
|
25
|
+
end
|
26
|
+
|
27
|
+
def call
|
28
|
+
find_and_replace
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def find_and_replace
|
34
|
+
USER_API_REPLACE_VALUES.each do |key, regex|
|
35
|
+
match_texts = interaction.response.body.scan(regex)
|
36
|
+
|
37
|
+
match_texts.each_with_index do |text, index|
|
38
|
+
replace = anonymize_response_value(key, index)
|
39
|
+
interaction.filter!(text.first, replace)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
interaction
|
44
|
+
end
|
45
|
+
|
46
|
+
def anonymize_response_value(key, index)
|
47
|
+
return "http://foo.com/#{index}" if key.to_s.include? "url"
|
48
|
+
|
49
|
+
case key
|
50
|
+
when :id
|
51
|
+
index.to_s
|
52
|
+
when :mail
|
53
|
+
"#{key}_#{index}@domain.com"
|
54
|
+
else
|
55
|
+
"#{key}_#{index}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require "cgi"
|
2
|
+
require "uri"
|
3
|
+
|
4
|
+
class AnonymizeInteraction
|
5
|
+
attr_reader :interaction
|
6
|
+
|
7
|
+
PATH_TO_CLASS = [
|
8
|
+
{
|
9
|
+
path: %r{^\/v2\/users(\/\d+)?$},
|
10
|
+
klass: "Anonymize::Users"},
|
11
|
+
{
|
12
|
+
path: %r{^\/v2\/projects(\/\d+)?$},
|
13
|
+
klass: "Anonymize::Projects"},
|
14
|
+
{
|
15
|
+
path: %r{^\/v2\/entries(\/\d+)?$},
|
16
|
+
klass: "Anonymize::Entries"},
|
17
|
+
{
|
18
|
+
path: %r{^\/v2\/tags(\/\d+)?$},
|
19
|
+
klass: "Anonymize::Tags"},
|
20
|
+
{
|
21
|
+
path: %r{^\/v2\/project_groups(\/\d+)?$},
|
22
|
+
klass: "Anonymize::ProjectGroups"
|
23
|
+
}
|
24
|
+
].freeze
|
25
|
+
|
26
|
+
def initialize(interaction:)
|
27
|
+
@interaction = interaction
|
28
|
+
end
|
29
|
+
|
30
|
+
def call
|
31
|
+
class_path = which_class
|
32
|
+
|
33
|
+
if class_path
|
34
|
+
Kernel.const_get(class_path).new(interaction: interaction).call
|
35
|
+
else
|
36
|
+
puts "Attention! Interaction #{request_url} isn't anonymize!"
|
37
|
+
end
|
38
|
+
rescue StandardError
|
39
|
+
abort("Undefined class for #{request_url} path")
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def which_class
|
45
|
+
PATH_TO_CLASS.each do |path|
|
46
|
+
return path[:klass] if path[:path].match(request_url)
|
47
|
+
end
|
48
|
+
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def request_url
|
53
|
+
@request_url ||= begin
|
54
|
+
raw_uri = interaction.request.uri
|
55
|
+
uri = URI.parse(raw_uri)
|
56
|
+
|
57
|
+
uri.path
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
ENTRY_KEYS = %w(
|
2
|
+
id
|
3
|
+
date
|
4
|
+
billable
|
5
|
+
minutes
|
6
|
+
description
|
7
|
+
created_at
|
8
|
+
updated_at
|
9
|
+
approved_at
|
10
|
+
source_url
|
11
|
+
user
|
12
|
+
approved_by
|
13
|
+
tags
|
14
|
+
project
|
15
|
+
url
|
16
|
+
invoiced_outside_of_freckle_url
|
17
|
+
approved_url
|
18
|
+
unapproved_url
|
19
|
+
).freeze
|
@@ -0,0 +1,26 @@
|
|
1
|
+
PROJECT_KEYS = %w(
|
2
|
+
id
|
3
|
+
name
|
4
|
+
description
|
5
|
+
billing_increment
|
6
|
+
enabled
|
7
|
+
billable
|
8
|
+
color
|
9
|
+
created_at
|
10
|
+
updated_at
|
11
|
+
group
|
12
|
+
minutes
|
13
|
+
billable_minutes
|
14
|
+
unbillable_minutes
|
15
|
+
invoiced_minutes
|
16
|
+
uninvoiced_minutes
|
17
|
+
remaining_minutes
|
18
|
+
budgeted_minutes
|
19
|
+
participants
|
20
|
+
entries
|
21
|
+
entries_url
|
22
|
+
url
|
23
|
+
merge_url
|
24
|
+
archive_url
|
25
|
+
unarchive_url
|
26
|
+
).freeze
|
@@ -0,0 +1,13 @@
|
|
1
|
+
RSpec.shared_context "with raw links" do
|
2
|
+
let(:first_page) do
|
3
|
+
# rubocop:disable Metrics/LineLength
|
4
|
+
"<https://api.letsfreckle.com/v2/users?page=2>; rel=\"last\", <https://api.letsfreckle.com/v2/users?page=2>; rel=\"next\""
|
5
|
+
# rubocop:enable Metrics/LineLength
|
6
|
+
end
|
7
|
+
|
8
|
+
let(:last_page) do
|
9
|
+
# rubocop:disable Metrics/LineLength
|
10
|
+
"<https://api.letsfreckle.com/v2/users?page=1>; rel=\"first\", <https://api.letsfreckle.com/v2/users?page=1>; rel=\"prev\""
|
11
|
+
# rubocop:enable Metrics/LineLength
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
USER_KEYS = %w(
|
2
|
+
id
|
3
|
+
email
|
4
|
+
first_name
|
5
|
+
last_name
|
6
|
+
profile_image_url
|
7
|
+
state
|
8
|
+
role
|
9
|
+
entries
|
10
|
+
expenses
|
11
|
+
created_at
|
12
|
+
updated_at
|
13
|
+
url
|
14
|
+
entries_url
|
15
|
+
expenses_url
|
16
|
+
activate_url
|
17
|
+
deactivate_url
|
18
|
+
give_access_to_projects_url
|
19
|
+
revoke_access_to_projects_url
|
20
|
+
revoke_access_to_all_projects_url
|
21
|
+
).freeze
|