freckle_io 0.0.3

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.
Files changed (106) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +5 -0
  3. data/.env.sample +3 -0
  4. data/.env.test.sample +3 -0
  5. data/.gitignore +5 -0
  6. data/.rubocop.yml +67 -0
  7. data/.travis.yml +20 -0
  8. data/Gemfile +8 -0
  9. data/README.md +95 -0
  10. data/Rakefile +5 -0
  11. data/freckle-io.gemspec +37 -0
  12. data/icon.svg +192 -0
  13. data/lib/freckle_io/authentication.rb +26 -0
  14. data/lib/freckle_io/client/entries.rb +53 -0
  15. data/lib/freckle_io/client/project_groups.rb +36 -0
  16. data/lib/freckle_io/client/projects.rb +42 -0
  17. data/lib/freckle_io/client/tags.rb +33 -0
  18. data/lib/freckle_io/client/users.rb +35 -0
  19. data/lib/freckle_io/configuration.rb +48 -0
  20. data/lib/freckle_io/connection.rb +80 -0
  21. data/lib/freckle_io/errors/configuration.rb +5 -0
  22. data/lib/freckle_io/errors/connection.rb +9 -0
  23. data/lib/freckle_io/errors/params.rb +8 -0
  24. data/lib/freckle_io/paginator.rb +70 -0
  25. data/lib/freckle_io/params.rb +46 -0
  26. data/lib/freckle_io/request/multiple_pages.rb +62 -0
  27. data/lib/freckle_io/request/single_page.rb +73 -0
  28. data/lib/freckle_io/validator/entry.rb +57 -0
  29. data/lib/freckle_io/validator/project.rb +46 -0
  30. data/lib/freckle_io/validator/project_group.rb +30 -0
  31. data/lib/freckle_io/validator/restricted_hash.rb +11 -0
  32. data/lib/freckle_io/validator/tag.rb +30 -0
  33. data/lib/freckle_io/validator/user.rb +43 -0
  34. data/lib/freckle_io/validator/validation.yml +14 -0
  35. data/lib/freckle_io.rb +35 -0
  36. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Entries/with_configuration/_all/result_must_be_a_Request_MultiplePages.yml +48 -0
  37. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Entries/with_configuration/_all/returns_a_entry_for_each_response.yml +48 -0
  38. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Entries/with_configuration/with_valid_params/params_should_be_valid.yml +48 -0
  39. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Entries/with_configuration/with_validator/call_entry_s_validator.yml +48 -0
  40. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_ProjectGroups/with_configuration/_all/result_must_be_a_Request_MultiplePages.yml +99 -0
  41. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_ProjectGroups/with_configuration/_all/returns_a_project_group_for_each_response.yml +99 -0
  42. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_ProjectGroups/with_configuration/with_valid_params/params_should_be_valid.yml +48 -0
  43. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_ProjectGroups/with_configuration/with_validator/call_project_group_s_validator.yml +99 -0
  44. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Projects/with_configuration/_all/result_must_be_a_Request_MultiplePages.yml +491 -0
  45. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Projects/with_configuration/_all/returns_a_project_for_each_response.yml +491 -0
  46. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Projects/with_configuration/_show/get_a_spacific_project.yml +48 -0
  47. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Projects/with_configuration/_show/raw_links_should_be_a_empty_array.yml +48 -0
  48. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Projects/with_configuration/with_valid_params/params_should_be_valid.yml +48 -0
  49. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Projects/with_configuration/with_validator/call_project_s_validator.yml +491 -0
  50. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Tags/with_configuration/_all/result_must_be_a_Request_MultiplePages.yml +48 -0
  51. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Tags/with_configuration/_all/returns_a_tag_for_each_response.yml +48 -0
  52. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Tags/with_configuration/with_valid_params/params_should_be_valid.yml +48 -0
  53. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Tags/with_configuration/with_validator/call_tag_s_validator.yml +48 -0
  54. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Users/with_configuration/_all/result_must_be_a_Request_MultiplePages.yml +99 -0
  55. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Users/with_configuration/_all/returns_a_user_for_each_response.yml +99 -0
  56. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Users/with_configuration/_show/get_a_spacific_user.yml +48 -0
  57. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Users/with_configuration/_show/raw_links_should_be_a_empty_array.yml +48 -0
  58. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Users/with_configuration/with_valid_params/params_should_be_valid.yml +48 -0
  59. data/spec/fixtures/vcr_cassettes/FreckleIO_Client_Users/with_configuration/with_validator/call_user_s_validator.yml +99 -0
  60. data/spec/fixtures/vcr_cassettes/FreckleIO_Connection/with_default_configuration/with_a_valid_response/must_be_a_json_format.yml +51 -0
  61. data/spec/fixtures/vcr_cassettes/FreckleIO_Connection/with_default_configuration/with_freckle_token_authentication/set_X-FreckleToken.yml +51 -0
  62. data/spec/fixtures/vcr_cassettes/FreckleIO_Connection/with_default_configuration/with_header/set_user_agent.yml +51 -0
  63. 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
  64. data/spec/fixtures/vcr_cassettes/FreckleIO_Connection/with_default_configuration/with_page_param/response_must_be_success.yml +51 -0
  65. data/spec/fixtures/vcr_cassettes/FreckleIO_Connection/with_default_configuration/with_per_page_param/response_must_have_per_page_elements.yml +51 -0
  66. data/spec/fixtures/vcr_cassettes/FreckleIO_Request_MultiplePages/with_configuration/_get/returns_an_array_of_faraday_response.yml +99 -0
  67. data/spec/fixtures/vcr_cassettes/FreckleIO_Request_MultiplePages/with_configuration/_get/returns_freckle_default_per_page_elements.yml +99 -0
  68. data/spec/fixtures/vcr_cassettes/FreckleIO_Request_MultiplePages/with_per_page/_get/return_per_page_number_elements.yml +148 -0
  69. data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_first/next_page_should_be_a_SinglePage.yml +99 -0
  70. data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_first/prev_page_should_be_nil.yml +51 -0
  71. 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
  72. data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_get/returns_correct_raw_links_for_the_first_page.yml +51 -0
  73. data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_last/next_page_should_be_nil.yml +99 -0
  74. data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_last/returns_correct_raw_links_for_the_last_page.yml +99 -0
  75. 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
  76. data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_next/previous_page_is_a_SinglePage.yml +147 -0
  77. data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_next/previous_page_should_be_not_nil.yml +147 -0
  78. data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_prev/next_page_is_a_SinglePage.yml +195 -0
  79. 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
  80. data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_total_page/with_first_page/returns_the_range_of_pages.yml +51 -0
  81. data/spec/fixtures/vcr_cassettes/FreckleIO_Request_SinglePage/with_configuration/_total_page/with_next_page/returns_an_empty_array.yml +99 -0
  82. data/spec/freckle_io/client/entries_spec.rb +359 -0
  83. data/spec/freckle_io/client/project_groups_spec.rb +132 -0
  84. data/spec/freckle_io/client/projects_spec.rb +183 -0
  85. data/spec/freckle_io/client/tags_spec.rb +132 -0
  86. data/spec/freckle_io/client/users_spec.rb +150 -0
  87. data/spec/freckle_io/configuration_spec.rb +70 -0
  88. data/spec/freckle_io/connection_spec.rb +116 -0
  89. data/spec/freckle_io/paginator_spec.rb +105 -0
  90. data/spec/freckle_io/params_spec.rb +15 -0
  91. data/spec/freckle_io/request/multiple_pages_spec.rb +39 -0
  92. data/spec/freckle_io/request/single_page_spec.rb +107 -0
  93. data/spec/spec_helper.rb +69 -0
  94. data/spec/support/anonymize/entries.rb +60 -0
  95. data/spec/support/anonymize/project_groups.rb +55 -0
  96. data/spec/support/anonymize/projects.rb +60 -0
  97. data/spec/support/anonymize/tags.rb +47 -0
  98. data/spec/support/anonymize/users.rb +59 -0
  99. data/spec/support/anonymize_interaction.rb +60 -0
  100. data/spec/support/entry_info.rb +19 -0
  101. data/spec/support/project_group_info.rb +13 -0
  102. data/spec/support/project_info.rb +26 -0
  103. data/spec/support/shared/links/raw_links.rb +13 -0
  104. data/spec/support/tag_info.rb +11 -0
  105. data/spec/support/user_info.rb +21 -0
  106. 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
@@ -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,13 @@
1
+ PROJECT_GROUP_KEYS = %w(
2
+ id
3
+ name
4
+ created_at
5
+ updated_at
6
+ projects
7
+ url
8
+ entries_url
9
+ projects_url
10
+ add_projects_url
11
+ remove_projects_url
12
+ remove_all_projects_url
13
+ ).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,11 @@
1
+ TAG_KEYS = %w(
2
+ id
3
+ name
4
+ billable
5
+ formatted_name
6
+ entries
7
+ entries_url
8
+ url
9
+ created_at
10
+ updated_at
11
+ ).freeze
@@ -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