bookingsync-engine 4.0.1 → 6.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (96) hide show
  1. checksums.yaml +5 -5
  2. data/app/views/sessions/failure.html.erb +3 -1
  3. data/lib/bookingsync-engine.rb +11 -2
  4. data/lib/bookingsync/engine.rb +14 -5
  5. data/lib/bookingsync/engine/auth_helpers.rb +38 -16
  6. data/lib/bookingsync/engine/models/account.rb +9 -3
  7. data/lib/bookingsync/engine/models/base_account.rb +8 -6
  8. data/lib/bookingsync/engine/models/multi_applications_account.rb +9 -3
  9. data/lib/bookingsync/engine/retryable.rb +16 -0
  10. data/lib/bookingsync/engine/version.rb +1 -1
  11. data/spec/controllers/authenticated_controller_spec.rb +36 -12
  12. data/spec/dummy/app/assets/config/manifest.js +3 -0
  13. data/spec/dummy/config/initializers/bookingsync-engine.rb +8 -0
  14. data/spec/dummy/db/migrate/20190623220013_add_custom_booking_sync_key_id_to_accounts.rb +5 -0
  15. data/spec/dummy/db/migrate/20190623220132_add_custom_booking_sync_key_id_to_multi_applications_accounts.rb +5 -0
  16. data/spec/dummy/db/schema.rb +3 -1
  17. data/spec/dummy/log/development.log +2 -7427
  18. data/spec/dummy/log/test.log +9640 -62357
  19. data/spec/fixtures/accounts.yml +2 -0
  20. data/spec/lib/bookingsync/engine/retryable_spec.rb +81 -0
  21. data/spec/models/account_spec.rb +79 -0
  22. data/spec/models/multi_application_account_spec.rb +12 -0
  23. metadata +43 -153
  24. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/0A/0AkQ3CITU4KXnU7GsiDQLAWeLkJApWK8LSS1j7wEk2I.cache +0 -0
  25. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/1M/1MTKfLxlwDryDP9C4ksVeuOF5FekTW5EddfnaJ4ujrA.cache +0 -0
  26. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/2F/2FjAKNLL-jC6FeYfXsL0M8jItncHQcdDy239KNsTZQs.cache +0 -1
  27. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/2_/2_hJriYgvh3UGtv5NMhrnkrtfpJlyTuQ4F5jYdVf8sQ.cache +0 -1
  28. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/3J/3JfiofMyqvbHq3sZznFIDsFS81fHxyAWoCXJLrtrWP4.cache +0 -0
  29. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/3f/3fwING3B2z9NOnWMwdXFatlVw06vge46KkOWOII0KlU.cache +0 -1
  30. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/4i/4iLsjcOzC2_Y0hxnbPKuyayJABeUFDSyIh4Ed9OA8Xw.cache +0 -0
  31. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/50/502uMBbq2ELFXg5u1vtykxQ_whhsdgQnmTwNA96niD0.cache +0 -0
  32. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/5s/5sm0UHvqondwU5MMfjMuqvLW2WQ6S7ylUf9PNw2uCTc.cache +0 -1
  33. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/6F/6F2x1Bu3NKSTCTwUS6iCRFhKRT_ntZMzmPIMnVGabK4.cache +0 -1
  34. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/6g/6gkpMq6BGSOyooWUFJJQCs2k3-tT0WID6Vg4wknhJoM.cache +0 -0
  35. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/8K/8KNXqSB0siJpEjgLM64KpfTgX1FSbkYKxWso4jP9F6U.cache +0 -0
  36. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Bf/BfiLjztc-8aILuCwNaYiWOika9XKeEiGNJJJK_LCEr4.cache +0 -0
  37. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/CM/CMaRV8szi0IicAXD33YjDgWpLw468X08ycoS-ndwO5o.cache +0 -0
  38. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Cc/CcghYxY4f6VUjmyR9LJJi0rYn2LXCdBR9t8Qn4SroL8.cache +0 -0
  39. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Cj/CjEM6wfYwxY_zG--WNzelIKjC420AU9WpvQLgolQOPM.cache +0 -1
  40. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Cj/cJJ0QWQg4eJ37I13drpPfSy27rwN7iqiQYPswqRm_Po.cache +0 -0
  41. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/E2/E2tGPoiGjrMuq9vL-ndjkozskpSFwLcGQXxJf_dl4z0.cache +0 -0
  42. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/EN/ENHTZiiuQ1cqn16401VaQQBp7b0gwZOA7_I-W5CL5ig.cache +0 -1
  43. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/EV/EVkLQJ6idLBSbQnkUelhejMxSOql0wh2QbtfKpdJiak.cache +0 -1
  44. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Gg/Gg6i-z0G_WiBfMUE_gmveurGXQff5_TlQi29HwQcZ-8.cache +0 -1
  45. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Go/Gohhb2B4rJ5hYmGM-VhZxS5dB_NFtsEAdbP1kTKDUeU.cache +0 -0
  46. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/IH/IHM0sjf5lujHT6BG1cYKLB0rdqCd1KYYR5SLZkxXi1k.cache +0 -1
  47. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/NS/NSFU7p8JOb9tHDvG74s3jdRt4ONYZoCTluL3HEsrPxc.cache +0 -0
  48. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/OX/OXQFRQZ5OA2i3YtnP1fZ96aWeUC3_IIqO4fAMdR9FsM.cache +0 -2
  49. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Oi/OiV2J0lyHQgXCDgtmFPNLE59EbztPsv9MNy05s943Yw.cache +0 -2
  50. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ps/PsVVU35DPe0tSyJ1zEoiPaaJiwo6NclhO2OKuFSn76A.cache +0 -0
  51. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/R-/R-onhPbfjYnU6tM9fR0wZkXDSvCLrY5G1wyNCSVmKEs.cache +0 -1
  52. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/RR/RRXzNBrpSlU0RGhaxTSE_1GoRrV4JkWqF0ZoOf9xtzQ.cache +0 -0
  53. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Rd/Rd_ZtA5c34XyxDbTpkN8_ZfF1x78s46DbRXLu0jqMgo.cache +0 -1
  54. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Sm/SmJRxdUchUsyyMi6zvsdwrcRR1hfQ9YeSZNKNM-n5lw.cache +0 -0
  55. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Su/Sue46_TUXTlImzpNh2bkqDFL5cQ08rCAcaaJqlWI7qg.cache +0 -0
  56. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/T1/T1lVNy8C6VpxjRsI38DgOfG7yIh3OohPWTNZmJb8CPo.cache +0 -0
  57. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Z-/Z-P7NJ7vzHin8mjLSAoWJW6FZfd6xwWS3xuoCX0DE40.cache +0 -0
  58. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Z9/Z9d8_EzLy9N7tx_nHmbmBF5LzFtW_0sik4AH1IFBX0Y.cache +0 -1
  59. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Ze/ZelUAL6jLQcQiGZUfnAbvuJbU9OAqHiXV_Ccu8lToho.cache +0 -1
  60. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/Zr/Zr7RfTTM_QNQ-7MuSD-M0rF18yH25tCSI9G4H5yYjAQ.cache +0 -1
  61. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/_S/_SxbUQwhqQU8951QbOA6ZZ41F0d9D-VhhQqUE4BCryQ.cache +0 -0
  62. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/_o/_okSFa_t7W5YJBZTW7ZitTwnmAFYgJup7tpTYum0Udo.cache +0 -1
  63. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/aJ/aJ4EkukIrCHlOkA1WpQIasGGosjGkOKvRMsfcNQx1QQ.cache +0 -0
  64. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/bk/bk_rOYlFWoHkh4HHsvbxeo8rSvDWRX6cCbVlO2VCVNA.cache +0 -1
  65. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/cO/cOGLhXoKF0BumBbtviyCY1xusm_WMEMhGSWY9qFekRU.cache +0 -2
  66. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/cq/cqMX8l9XlG5jEWd0fWjA7MTlj21d6dzcnhhOq08uFHY.cache +0 -0
  67. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/cy/cyurAtFfq8D4ORO-aDATDzTKcBumJfgafhOUCbECuMw.cache +0 -0
  68. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/eO/eOY3YH36a6yvdznpQqACMiI0e1CcTwPiEjUdhRfmm9k.cache +0 -0
  69. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/f3/f3VckKo5w8mrxeqmzwLfZr7f6sj0dA8xZrFq3GMF0ig.cache +0 -1
  70. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/fS/fSn1A2ssuKdsdJ-uwH_i8bXBaWmbJd0wHd-Ob6pTPi0.cache +0 -1
  71. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/gD/gDQJ-WkVLldqzYHKOLkamKeU-sTkDscHqOQawz7a6m4.cache +0 -0
  72. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/hj/hj8Ir9wcVSy1KYrnWu9bpD24vDhCG3tvt-nKbNxb1Wg.cache +0 -0
  73. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/jH/jHvwYeln0CEBatCDHIjJMF0vIdmuDmS_eTKNxFhOmlA.cache +0 -1
  74. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/jU/jUktWNbR4V7n34UAZe7uJpmEofhflF0bVtIO2BgxyJ8.cache +0 -2
  75. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/jb/jb46fu3q3DLQ7TFyiuaXmL_CPF7cQst2RgrF0xVyGtA.cache +0 -1
  76. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/le/lekrQ_bDFewtYzH2xoA2tovuPzYdoSwnauQ4MgDwb0U.cache +0 -1
  77. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/m8/m8I0GZ1puWB4hISNebXEGDX3G5QkoSVWHP4SiRvN-3Y.cache +0 -0
  78. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/mn/mNEeM32MBaqiZ0_N_eheQR9oimoBpmcXRXr5puTAh3o.cache +0 -0
  79. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/mn/mNaj9zqaawn26kC4FL9ECzN5lkppnwTTQ93MIeJRKZg.cache +0 -1
  80. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/mn/mnJy7Ei2tJLs8tfmmUHjtWmfk2yfl1opoYG7Deg2bWQ.cache +0 -0
  81. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/oC/oCsZTGZyV4kH8Y4OeSDUdrwfkJFPzTODZjuBKZB8oGQ.cache +0 -0
  82. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/oS/oS5JF4El36MylOD0SJtv4YV-fsqNzd89t1IqlBzwYes.cache +0 -1
  83. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/oY/oYCeXuzhz0IQEBtepScpQ7HlUp5yVleUE6BOLsnhXwA.cache +0 -1
  84. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/oZ/oZDDUJWB1xgHo4uv_iiUCtutWZ6LeJykII3cNkmd_bA.cache +0 -1
  85. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/q6/q6BYa32YJF11eGVapO4ouNl6gayPIsARgMavlzZmoi0.cache +0 -0
  86. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/u-/u-Iidm4zcU2RFkiqJFQkLTBxXuEoF5gCeJM4V5-3Qyc.cache +0 -0
  87. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/uK/uKpQUG2ys9fKuyfsrw1Payh72LhuIrYJXep13nTbIIc.cache +0 -1
  88. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/uX/uXHfYanP3WS7whlKHqs0pLBkEQwj_IGbfmktFdHfZ_A.cache +0 -0
  89. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/v9/v9HWdIdg3uuXOOqxWg8Y6aWxzqbywfxecFSDm5ilUs8.cache +0 -1
  90. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/w2/w2izaLMTzGRpPOq1R_Yl-0Ma7hm7tej5kSjV9khvFSk.cache +0 -1
  91. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/x7/x7KkTV3ibfIEysLB_ug5bfmnn2VLV_BldukPR3EoPBk.cache +0 -0
  92. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/y4/y4-jRuYEQUuCPpXrCIiCC1lgXmW4pm12ZEla-d56noA.cache +0 -1
  93. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/yW/yWlGtA8E8Li2epEGqbxtvBeb5h0e52XZQ8xKiMXgDOY.cache +0 -1
  94. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/yZ/yZRcLaNBQxCgGewY_IaXZrXG1YmOhr1iSxfZ-4MMK9Y.cache +0 -0
  95. data/spec/dummy/tmp/cache/assets/sprockets/v3.0/zU/zUYxN3uLSvSCpp561lMJSJXPGanKNgxT32rw-w5jpPs.cache +0 -0
  96. data/spec/dummy/tmp/restart.txt +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 1e682837dca15bd556e399c58a64744e5779aea9
4
- data.tar.gz: 8ed995c29acdda9688394ff1b74d9c7162d60b8d
2
+ SHA256:
3
+ metadata.gz: 76d677891a37b6bf242cc2ecdccac253d00e74d980c4c674f1e4e258a23c27aa
4
+ data.tar.gz: 6bbe344b51c76817b5f91e5db0196a8ff651a8ed668c15e8c24f809357fe7568
5
5
  SHA512:
6
- metadata.gz: 2011800c2f0f947f871695ed2e5c8685e6b9cf1a8086ab098fbe7b77a8aca374086a8a07481f66a39954392dba96769afe045bdd59c21801fc5604d70d18823b
7
- data.tar.gz: d9d6d2170c82c3c22e2751830af0acad3b30b347246c7ca9117506f993cbee03f37b9178010387c9b2ceff20aad070a2a39d5bfea6f6c3a3c9f1ce1f699b8276
6
+ metadata.gz: 0105eb59ada39b9121ad1aad63e72f7c8f9d1d717ef9cfa85ad5189b9aedf06aa61bc165265289ca55e783546ce2713f720fe26d900116b3cbe5f9d84a921587
7
+ data.tar.gz: 850bbffb9e6233f2c15009073a463ecfed670bb46db08a5b62afd5abdd8dcb5df0eee57f580872a1603cc84f897dcd4997d2d7e09c8361b384d63a2535b54640
@@ -2,4 +2,6 @@
2
2
 
3
3
  <p>Error: <%= @error_message %></p>
4
4
 
5
- <a href="/auth/bookingsync">Sign in again</a>
5
+ <%= form_tag("/auth/bookingsync", method: :post) do %>
6
+ <button type="submit">Sign in again</button>
7
+ <% end %>
@@ -1,5 +1,3 @@
1
- require "bookingsync"
2
-
3
1
  module BookingSyncEngine
4
2
  cattr_accessor :support_multi_applications
5
3
  self.support_multi_applications = false
@@ -10,6 +8,15 @@ module BookingSyncEngine
10
8
  cattr_accessor :multi_app_model
11
9
  self.multi_app_model = -> { ::Account }
12
10
 
11
+ cattr_accessor :oauth_client_connection_options
12
+ self.oauth_client_connection_options = { request: { timeout: 2 } }
13
+
14
+ cattr_accessor :token_refresh_timeout_retry_count
15
+ self.token_refresh_timeout_retry_count = 2
16
+
17
+ cattr_accessor :bookingsync_id_key
18
+ self.bookingsync_id_key = :synced_id
19
+
13
20
  def self.setup
14
21
  yield self
15
22
  end
@@ -22,3 +29,5 @@ module BookingSyncEngine
22
29
  support_multi_applications? ? multi_app_model.call : single_app_model.call
23
30
  end
24
31
  end
32
+
33
+ require "bookingsync"
@@ -7,8 +7,8 @@ module BookingSync
7
7
  initializer "bookingsync.add_omniauth" do |app|
8
8
  app.middleware.use OmniAuth::Builder do
9
9
  provider :bookingsync,
10
- BookingSyncEngine.support_multi_applications? ? nil : ENV["BOOKINGSYNC_APP_ID"],
11
- BookingSyncEngine.support_multi_applications? ? nil : ENV["BOOKINGSYNC_APP_SECRET"],
10
+ ::BookingSyncEngine.support_multi_applications? ? nil : ENV["BOOKINGSYNC_APP_ID"],
11
+ ::BookingSyncEngine.support_multi_applications? ? nil : ENV["BOOKINGSYNC_APP_SECRET"],
12
12
  scope: ENV["BOOKINGSYNC_SCOPE"],
13
13
  setup: -> (env) {
14
14
  if url = ENV["BOOKINGSYNC_URL"]
@@ -18,7 +18,7 @@ module BookingSync
18
18
  verify: ENV["BOOKINGSYNC_VERIFY_SSL"] != "false"
19
19
  }
20
20
 
21
- if BookingSyncEngine.support_multi_applications?
21
+ if ::BookingSyncEngine.support_multi_applications?
22
22
  credentials = BookingSync::Engine::CredentialsResolver.new(env["HTTP_HOST"]).call
23
23
  if credentials.valid?
24
24
  env["omniauth.strategy"].options[:client_id] = credentials.client_id
@@ -76,16 +76,24 @@ module BookingSync
76
76
  #
77
77
  # @return [OAuth2::Client] configured OAuth client
78
78
  def self.oauth_client(client_id: ENV["BOOKINGSYNC_APP_ID"], client_secret: ENV["BOOKINGSYNC_APP_SECRET"])
79
+ connection_options = {
80
+ headers: { accept: "application/vnd.api+json" }
81
+ }.merge(::BookingSyncEngine.oauth_client_connection_options)
82
+
79
83
  client_options = {
80
84
  site: ENV["BOOKINGSYNC_URL"] || 'https://www.bookingsync.com',
81
- connection_opts: { headers: { accept: "application/vnd.api+json" } }
85
+ connection_opts: connection_options
82
86
  }
83
87
  client_options[:ssl] = { verify: ENV['BOOKINGSYNC_VERIFY_SSL'] != 'false' }
84
88
  OAuth2::Client.new(client_id, client_secret, client_options)
85
89
  end
86
90
 
87
91
  def self.application_token(client_id: ENV["BOOKINGSYNC_APP_ID"], client_secret: ENV["BOOKINGSYNC_APP_SECRET"])
88
- oauth_client(client_id: client_id, client_secret: client_secret).client_credentials.get_token
92
+ token_refresh_timeout_attempts_allowed = ::BookingSyncEngine.token_refresh_timeout_retry_count + 1
93
+
94
+ BookingSync::Engine::Retryable.perform(times: token_refresh_timeout_attempts_allowed, errors: [Faraday::TimeoutError]) do
95
+ oauth_client(client_id: client_id, client_secret: client_secret).client_credentials.get_token
96
+ end
89
97
  end
90
98
  end
91
99
  end
@@ -94,3 +102,4 @@ require "bookingsync/engine/application_credentials"
94
102
  require "bookingsync/engine/credentials_resolver"
95
103
  require "bookingsync/engine/api_client"
96
104
  require "bookingsync/engine/models"
105
+ require "bookingsync/engine/retryable"
@@ -1,3 +1,5 @@
1
+ require "repost"
2
+
1
3
  module BookingSync::Engine::AuthHelpers
2
4
  extend ActiveSupport::Concern
3
5
 
@@ -16,7 +18,7 @@ module BookingSync::Engine::AuthHelpers
16
18
  return if session[:account_id].nil?
17
19
 
18
20
  @current_account ||=
19
- BookingSyncEngine.account_model.find_by_host_and_synced_id(request.host, session[:account_id])
21
+ ::BookingSyncEngine.account_model.find_by_host_and_bookingsync_id_key(request.host, session[:account_id])
20
22
  end
21
23
 
22
24
  # Callback after account is authorized.
@@ -25,7 +27,7 @@ module BookingSync::Engine::AuthHelpers
25
27
  #
26
28
  # @param account [Account] the just authorized account
27
29
  def account_authorized(account)
28
- session[:account_id] = account.synced_id.to_s
30
+ session[:account_id] = account.public_send(BookingSyncEngine.bookingsync_id_key).to_s
29
31
  end
30
32
 
31
33
  # Clear authorization if the account passed from the BookingSync app store
@@ -58,20 +60,32 @@ module BookingSync::Engine::AuthHelpers
58
60
 
59
61
  # Request a new authorization.
60
62
  def request_authorization!
61
- if request.xhr?
62
- request_authorization_for_xhr!
63
- elsif BookingSync::Engine.embedded
64
- request_authorization_for_embedded!
65
- else
66
- request_authorization_for_standalone!
63
+ respond_to do |format|
64
+ format.html do
65
+ if request.xhr?
66
+ request_authorization_for_xhr!
67
+ elsif BookingSync::Engine.embedded
68
+ request_authorization_for_embedded!
69
+ else
70
+ request_authorization_for_standalone!
71
+ end
72
+ end
73
+
74
+ format.json do
75
+ head :unauthorized
76
+ end
77
+
78
+ format.api_json do
79
+ head :unauthorized
80
+ end
67
81
  end
68
82
  end
69
83
 
70
84
  # Request a new authorization for Ajax requests.
71
85
  #
72
- # Renders the new authorization path with 401 Unauthorized status by default.
86
+ # Renders the new auto submit form with 401 Unauthorized status by default.
73
87
  def request_authorization_for_xhr!
74
- render plain: new_authorization_url, status: :unauthorized
88
+ render html: auto_submit_form_html, status: :unauthorized
75
89
  end
76
90
 
77
91
  # Request a new authorization for Embedded Apps.
@@ -79,23 +93,23 @@ module BookingSync::Engine::AuthHelpers
79
93
  # Load the new authorization path using Javascript by default.
80
94
  def request_authorization_for_embedded!
81
95
  allow_bookingsync_iframe
82
- render html: ("<script type='text/javascript'>top.location.href = " +
83
- "'#{new_authorization_path}';</script>").html_safe
96
+ render html: auto_submit_form_html
84
97
  end
85
98
 
86
99
  # Request a new authorization for Standalone Apps.
87
100
  #
88
101
  # Redirects to new authorization path by default.
89
102
  def request_authorization_for_standalone!
90
- redirect_to new_authorization_path
103
+ render html: auto_submit_form_html
91
104
  end
92
105
 
93
- # Path to which the user should be redirected to start a new
106
+ # Path which will be used in POST request to start a new
94
107
  # Authorization process.
95
108
  #
96
- # Default to /auth/bookingsync/?account_id=SESSION_BOOKINGSYNC_ACCOUNT_ID
109
+ # Default to /auth/bookingsync
110
+ NEW_AUTHORIZATION_URL = "/auth/bookingsync".freeze
97
111
  def new_authorization_path
98
- "/auth/bookingsync/?account_id=#{session[:_bookingsync_account_id]}"
112
+ NEW_AUTHORIZATION_URL
99
113
  end
100
114
 
101
115
  def new_authorization_url
@@ -141,4 +155,12 @@ module BookingSync::Engine::AuthHelpers
141
155
  def store_bookingsync_account_id # :nodoc:
142
156
  session[:_bookingsync_account_id] = params.delete(:_bookingsync_account_id)
143
157
  end
158
+
159
+ def auto_submit_form_html
160
+ Repost::Senpai.perform(
161
+ new_authorization_path,
162
+ params: { account_id: session[:_bookingsync_account_id] },
163
+ options: { authenticity_token: Rack::Protection::AuthenticityToken.token(session) }
164
+ ).html_safe
165
+ end
144
166
  end
@@ -3,12 +3,12 @@ module BookingSync::Engine::Models::Account
3
3
  include BookingSync::Engine::Models::BaseAccount
4
4
 
5
5
  included do
6
- validates :synced_id, uniqueness: true
6
+ validates BookingSyncEngine.bookingsync_id_key, uniqueness: true
7
7
  end
8
8
 
9
9
  module ClassMethods
10
10
  def from_omniauth(auth, _host)
11
- account = find_or_initialize_by(synced_id: auth.uid, provider: auth.provider)
11
+ account = find_or_initialize_by(BookingSyncEngine.bookingsync_id_key => auth.uid, provider: auth.provider)
12
12
 
13
13
  account.tap do |account|
14
14
  account.name = auth.info.business_name
@@ -17,8 +17,14 @@ module BookingSync::Engine::Models::Account
17
17
  end
18
18
  end
19
19
 
20
+ def find_by_host_and_bookingsync_id_key(_host, bookingsync_id)
21
+ find_by(BookingSyncEngine.bookingsync_id_key => bookingsync_id)
22
+ end
23
+
24
+ # DEPRECATED: Please use find_by_host_and_bookingsync_id_key instead.
20
25
  def find_by_host_and_synced_id(_host, synced_id)
21
- find_by(synced_id: synced_id)
26
+ warn("DEPRECATED: find_by_host_and_synced_id is deprecated, use #find_by_host_and_bookingsync_id_key instead. It will be removed with the release of version 6 of this gem. Called from #{Gem.location_of_caller.join(":")}")
27
+ find_by_host_and_bookingsync_id_key(nil, synced_id)
22
28
  end
23
29
  end
24
30
 
@@ -10,7 +10,7 @@ module BookingSync::Engine::Models::BaseAccount
10
10
  token_options = {}
11
11
  if oauth_refresh_token
12
12
  token_options[:refresh_token] = oauth_refresh_token
13
- token_options[:expires_at] = oauth_expires_at
13
+ token_options[:expires_at] = oauth_expires_at && oauth_expires_at.to_i
14
14
  end
15
15
 
16
16
  token = OAuth2::AccessToken.new(oauth_client, oauth_access_token, token_options)
@@ -40,12 +40,14 @@ module BookingSync::Engine::Models::BaseAccount
40
40
  self.oauth_expires_at = token.expires_at
41
41
  end
42
42
 
43
- private
44
-
45
43
  def refresh_token!(current_token = token)
46
- @token = current_token.refresh!.tap do |new_token|
47
- update_token(new_token)
48
- save!
44
+ token_refresh_timeout_attempts_allowed = ::BookingSyncEngine.token_refresh_timeout_retry_count + 1
45
+
46
+ BookingSync::Engine::Retryable.perform(times: token_refresh_timeout_attempts_allowed, errors: [Faraday::TimeoutError]) do
47
+ @token = current_token.refresh!.tap do |new_token|
48
+ update_token(new_token)
49
+ save!
50
+ end
49
51
  end
50
52
  end
51
53
  end
@@ -3,7 +3,7 @@ module BookingSync::Engine::Models::MultiApplicationsAccount
3
3
  include BookingSync::Engine::Models::BaseAccount
4
4
 
5
5
  included do
6
- validates :synced_id, uniqueness: { scope: :host }
6
+ validates BookingSyncEngine.bookingsync_id_key, uniqueness: { scope: :host }
7
7
  end
8
8
 
9
9
  module ClassMethods
@@ -13,7 +13,7 @@ module BookingSync::Engine::Models::MultiApplicationsAccount
13
13
  "multi application support"
14
14
  end
15
15
 
16
- account = find_or_initialize_by(host: host, synced_id: auth.uid, provider: auth.provider)
16
+ account = find_or_initialize_by(host: host, provider: auth.provider, BookingSyncEngine.bookingsync_id_key => auth.uid)
17
17
 
18
18
  account.tap do |account|
19
19
  account.name = auth.info.business_name
@@ -22,8 +22,14 @@ module BookingSync::Engine::Models::MultiApplicationsAccount
22
22
  end
23
23
  end
24
24
 
25
+ def find_by_host_and_bookingsync_id_key(host, bookingsync_id)
26
+ find_by(host: host, BookingSyncEngine.bookingsync_id_key => bookingsync_id)
27
+ end
28
+
29
+ # DEPRECATED: Please use find_by_host_and_bookingsync_id_key instead.
25
30
  def find_by_host_and_synced_id(host, synced_id)
26
- find_by(host: host, synced_id: synced_id)
31
+ warn("DEPRECATED: find_by_host_and_synced_id is deprecated, use #find_by_host_and_bookingsync_id_key instead. It will be removed with the release of version 5 of this gem. Called from #{Gem.location_of_caller.join(":")}")
32
+ find_by_host_and_bookingsync_id_key(host, synced_id)
27
33
  end
28
34
  end
29
35
 
@@ -0,0 +1,16 @@
1
+ class BookingSync::Engine::Retryable
2
+ def self.perform(times:, errors:, before_retry: ->(_error) {})
3
+ executed = 0
4
+ begin
5
+ executed += 1
6
+ yield
7
+ rescue *errors => error
8
+ if executed < times
9
+ before_retry.call(error)
10
+ retry
11
+ else
12
+ raise error
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,3 +1,3 @@
1
1
  module BookingSync
2
- ENGINE_VERSION = "4.0.1"
2
+ ENGINE_VERSION = "6.0.0"
3
3
  end
@@ -1,15 +1,19 @@
1
1
  require "spec_helper"
2
2
 
3
3
  RSpec.describe AuthenticatedController, type: :controller do
4
+ before do
5
+ Mime::Type.register "application/vnd.api+json", :api_json
6
+ end
7
+
4
8
  describe "GET index" do
5
9
  context "when engine is embedded" do
6
10
  before { BookingSync::Engine.embedded! }
7
11
 
8
- it "redirects to auth using js" do
12
+ it "renders autosubmitted form" do
9
13
  get :index
10
14
  expect(response.status).to eq(200)
11
- expect(response.body).to eq(
12
- "<script type='text/javascript'>top.location.href = '/auth/bookingsync/?account_id=';</script>")
15
+ expect(response.body).to include("action='/auth/bookingsync' method='post'")
16
+ expect(response.body).to include("<input type='hidden' name='account_id' value=''>")
13
17
  expect(response.header["Content-Type"]).to include("text/html")
14
18
  end
15
19
  end
@@ -17,12 +21,11 @@ RSpec.describe AuthenticatedController, type: :controller do
17
21
  context "when engine is standalone" do
18
22
  before { BookingSync::Engine.standalone! }
19
23
 
20
- it "redirects to auth using 302 redirect" do
24
+ it "renders autosubmitted form" do
21
25
  get :index
22
- expect(response.status).to eq(302)
23
- expect(response.redirect_url).to eq("http://test.host/auth/bookingsync/?account_id=")
24
- expect(response.body).to eq(
25
- "<html><body>You are being <a href=\"http://test.host/auth/bookingsync/?account_id=\">redirected</a>.</body></html>")
26
+ expect(response.status).to eq(200)
27
+ expect(response.body).to include("action='/auth/bookingsync' method='post'")
28
+ expect(response.body).to include("<input type='hidden' name='account_id' value=''>")
26
29
  end
27
30
  end
28
31
  end
@@ -31,20 +34,41 @@ RSpec.describe AuthenticatedController, type: :controller do
31
34
  context "when engine is embedded" do
32
35
  before { BookingSync::Engine.embedded! }
33
36
 
34
- it "renders the target url in response" do
37
+ it "renders autosubmitted form" do
35
38
  get :index, xhr: true
36
39
  expect(response.status).to eq(401)
37
- expect(response.body).to eq("http://test.host/auth/bookingsync/?account_id=")
40
+ expect(response.body).to include("action='/auth/bookingsync' method='post'")
41
+ expect(response.body).to include("<input type='hidden' name='account_id' value=''>")
38
42
  end
39
43
  end
40
44
 
41
45
  context "when engine is standalone" do
42
46
  before { BookingSync::Engine.standalone! }
43
47
 
44
- it "renders the target url in response" do
48
+ it "renders autosubmitted form" do
45
49
  get :index, xhr: true
46
50
  expect(response.status).to eq(401)
47
- expect(response.body).to eq("http://test.host/auth/bookingsync/?account_id=")
51
+ expect(response.body).to include("action='/auth/bookingsync' method='post'")
52
+ expect(response.body).to include("<input type='hidden' name='account_id' value=''>")
53
+ end
54
+ end
55
+ end
56
+
57
+ describe "API request" do
58
+ it "returns 401 without response body" do
59
+ get :index, format: :json
60
+ expect(response.status).to eq(401)
61
+ expect(response.body).to eq("")
62
+ end
63
+
64
+ context "with vnd.api+json content type" do
65
+ it "returns 401 without response body" do
66
+ request.headers["CONTENT_TYPE"] = "application/vnd.api+json"
67
+ request.headers["ACCEPT"] = "application/vnd.api+json"
68
+
69
+ get :index
70
+ expect(response.status).to eq(401)
71
+ expect(response.body).to eq("")
48
72
  end
49
73
  end
50
74
  end
@@ -0,0 +1,3 @@
1
+ //= link_tree ../images
2
+ //= link_directory ../javascripts .js
3
+ //= link_directory ../stylesheets .css
@@ -1,3 +1,11 @@
1
+ # temporarily change default to make sure initializer override works great
2
+ BookingSyncEngine.module_eval do
3
+ self.bookingsync_id_key = :customized_key
4
+ end
5
+
6
+ # and now override to fix breaking specs
1
7
  BookingSyncEngine.setup do |setup|
2
8
  setup.multi_app_model = -> { ::MultiApplicationsAccount }
9
+
10
+ setup.bookingsync_id_key = :synced_id
3
11
  end
@@ -0,0 +1,5 @@
1
+ class AddCustomBookingSyncKeyIdToAccounts < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_column :accounts, :customized_key, :integer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddCustomBookingSyncKeyIdToMultiApplicationsAccounts < ActiveRecord::Migration[5.2]
2
+ def change
3
+ add_column :multi_applications_accounts, :customized_key, :integer
4
+ end
5
+ end
@@ -10,7 +10,7 @@
10
10
  #
11
11
  # It's strongly recommended that you check this file into your version control system.
12
12
 
13
- ActiveRecord::Schema.define(version: 2018_11_30_063104) do
13
+ ActiveRecord::Schema.define(version: 2019_06_23_220132) do
14
14
 
15
15
  # These are extensions that must be enabled in order to support this database
16
16
  enable_extension "plpgsql"
@@ -24,6 +24,7 @@ ActiveRecord::Schema.define(version: 2018_11_30_063104) do
24
24
  t.string "oauth_access_token"
25
25
  t.string "oauth_refresh_token"
26
26
  t.string "oauth_expires_at"
27
+ t.integer "customized_key"
27
28
  t.index ["synced_id"], name: "index_accounts_on_synced_id"
28
29
  end
29
30
 
@@ -48,6 +49,7 @@ ActiveRecord::Schema.define(version: 2018_11_30_063104) do
48
49
  t.string "oauth_refresh_token"
49
50
  t.string "oauth_expires_at"
50
51
  t.string "host", null: false
52
+ t.integer "customized_key"
51
53
  t.index ["host", "synced_id"], name: "index_multi_applications_accounts_on_host_and_synced_id", unique: true
52
54
  t.index ["host"], name: "index_multi_applications_accounts_on_host"
53
55
  t.index ["synced_id"], name: "index_multi_applications_accounts_on_synced_id"