freckle_io 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
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