-
Notifications
You must be signed in to change notification settings - Fork 683
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
9 changed files
with
239 additions
and
29 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
73 changes: 73 additions & 0 deletions
73
lib/shopify_app/session/user_session_storage_with_scopes_and_expiry.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
# frozen_string_literal: true | ||
|
||
module ShopifyApp | ||
module UserSessionStorageWithScopesAndExpiry | ||
extend ActiveSupport::Concern | ||
include ::ShopifyApp::UserSessionStorageWithScopes | ||
|
||
included do | ||
validates :shopify_domain, presence: true | ||
end | ||
|
||
class_methods do | ||
def store(auth_session, user) | ||
user = find_or_initialize_by(shopify_user_id: user.id) | ||
user.shopify_token = auth_session.access_token | ||
user.shopify_domain = auth_session.shop | ||
user.access_scopes = auth_session.scope.to_s | ||
user.expires_at = auth_session.expires | ||
|
||
user.save! | ||
user.id | ||
end | ||
|
||
def retrieve(id) | ||
user = find_by(id: id) | ||
construct_session(user) | ||
end | ||
|
||
def retrieve_by_shopify_user_id(user_id) | ||
user = find_by(shopify_user_id: user_id) | ||
construct_session(user) | ||
end | ||
|
||
private | ||
|
||
def construct_session(user) | ||
return unless user | ||
|
||
associated_user = ShopifyAPI::Auth::AssociatedUser.new( | ||
id: user.shopify_user_id, | ||
first_name: "", | ||
last_name: "", | ||
email: "", | ||
email_verified: false, | ||
account_owner: false, | ||
locale: "", | ||
collaborator: false, | ||
) | ||
|
||
ShopifyAPI::Auth::Session.new( | ||
shop: user.shopify_domain, | ||
access_token: user.shopify_token, | ||
scope: user.access_scopes, | ||
associated_user_scope: user.access_scopes, | ||
associated_user: associated_user, | ||
expires: user.expires_at, | ||
) | ||
end | ||
end | ||
|
||
def expires_at=(expires_at) | ||
super(expires_at) | ||
rescue NotImplementedError, NoMethodError | ||
raise NotImplementedError, "#expires_at= must be defined to handle storing the expiry date" | ||
end | ||
|
||
def expires_at | ||
super | ||
rescue NotImplementedError, NoMethodError | ||
raise NotImplementedError, "#expires_at must be defined to leverage the session expiry date" | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
156 changes: 156 additions & 0 deletions
156
test/shopify_app/session/user_session_storage_with_scopes_and_expiry_test.rb
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,156 @@ | ||
# frozen_string_literal: true | ||
|
||
require "test_helper" | ||
|
||
class UserMockSessionStoreWithScopesAndExpiry < ActiveRecord::Base | ||
include ShopifyApp::UserSessionStorageWithScopesAndExpiry | ||
end | ||
|
||
module ShopifyApp | ||
class UserSessionStorageWithScopeAndExpiryTest < ActiveSupport::TestCase | ||
TEST_SHOPIFY_USER_ID = 42 | ||
TEST_SHOPIFY_DOMAIN = "example.myshopify.com" | ||
TEST_SHOPIFY_USER_TOKEN = "some-user-token-42" | ||
TEST_MERCHANT_SCOPES = "read_orders, write_products" | ||
TEST_EXPIRES_AT = Time.now | ||
|
||
test ".retrieve returns user session by id" do | ||
UserMockSessionStoreWithScopesAndExpiry.stubs(:find_by).returns(MockUserInstance.new( | ||
shopify_user_id: TEST_SHOPIFY_USER_ID, | ||
shopify_domain: TEST_SHOPIFY_DOMAIN, | ||
shopify_token: TEST_SHOPIFY_USER_TOKEN, | ||
scopes: TEST_MERCHANT_SCOPES, | ||
expires_at: TEST_EXPIRES_AT, | ||
)) | ||
|
||
session = UserMockSessionStoreWithScopesAndExpiry.retrieve(shopify_user_id: TEST_SHOPIFY_USER_ID) | ||
|
||
assert_equal TEST_SHOPIFY_DOMAIN, session.shop | ||
assert_equal TEST_SHOPIFY_USER_TOKEN, session.access_token | ||
assert_equal ShopifyAPI::Auth::AuthScopes.new(TEST_MERCHANT_SCOPES), session.scope | ||
assert_equal TEST_EXPIRES_AT, session.expires | ||
end | ||
|
||
test ".retrieve_by_shopify_user_id returns user session by shopify_user_id" do | ||
instance = MockUserInstance.new( | ||
shopify_user_id: TEST_SHOPIFY_USER_ID, | ||
shopify_domain: TEST_SHOPIFY_DOMAIN, | ||
shopify_token: TEST_SHOPIFY_USER_TOKEN, | ||
api_version: ShopifyApp.configuration.api_version, | ||
scopes: TEST_MERCHANT_SCOPES, | ||
expires_at: TEST_EXPIRES_AT, | ||
) | ||
UserMockSessionStoreWithScopesAndExpiry.stubs(:find_by).with(shopify_user_id: TEST_SHOPIFY_USER_ID) | ||
.returns(instance) | ||
|
||
expected_session = ShopifyAPI::Auth::Session.new( | ||
shop: instance.shopify_domain, | ||
access_token: instance.shopify_token, | ||
scope: TEST_MERCHANT_SCOPES, | ||
expires: TEST_EXPIRES_AT, | ||
) | ||
|
||
user_id = TEST_SHOPIFY_USER_ID | ||
session = UserMockSessionStoreWithScopesAndExpiry.retrieve_by_shopify_user_id(user_id) | ||
assert_equal expected_session.shop, session.shop | ||
assert_equal expected_session.access_token, session.access_token | ||
assert_equal expected_session.scope, session.scope | ||
assert_equal expected_session.expires, session.expires | ||
end | ||
|
||
test ".store can store user session record" do | ||
mock_user_instance = MockUserInstance.new(shopify_user_id: 100) | ||
mock_user_instance.stubs(:save!).returns(true) | ||
|
||
UserMockSessionStoreWithScopesAndExpiry.stubs(:find_or_initialize_by).returns(mock_user_instance) | ||
|
||
saved_id = UserMockSessionStoreWithScopesAndExpiry.store( | ||
mock_session( | ||
shop: mock_user_instance.shopify_domain, | ||
scope: TEST_MERCHANT_SCOPES, | ||
), | ||
mock_associated_user, | ||
) | ||
|
||
assert_equal "a-new-user_token!", mock_user_instance.shopify_token | ||
assert_equal mock_user_instance.id, saved_id | ||
end | ||
|
||
test ".retrieve returns nil for non-existent user" do | ||
user_id = "non-existent-user" | ||
UserMockSessionStoreWithScopesAndExpiry.stubs(:find_by).with(id: user_id).returns(nil) | ||
|
||
refute UserMockSessionStoreWithScopesAndExpiry.retrieve(user_id) | ||
end | ||
|
||
test ".retrieve_by_user_id returns nil for non-existent user" do | ||
user_id = "non-existent-user" | ||
UserMockSessionStoreWithScopesAndExpiry.stubs(:find_by).with(shopify_user_id: user_id).returns(nil) | ||
|
||
refute UserMockSessionStoreWithScopesAndExpiry.retrieve_by_shopify_user_id(user_id) | ||
end | ||
|
||
test ".retrieve throws NotImplementedError when access_scopes getter is not implemented" do | ||
mock_user = MockUserInstance.new( | ||
shopify_user_id: TEST_SHOPIFY_USER_ID, | ||
shopify_domain: TEST_SHOPIFY_DOMAIN, | ||
shopify_token: TEST_SHOPIFY_USER_TOKEN, | ||
) | ||
mock_user.stubs(:access_scopes).raises(NotImplementedError) | ||
UserMockSessionStoreWithScopesAndExpiry.stubs(:find_by).returns(mock_user) | ||
|
||
assert_raises NotImplementedError do | ||
UserMockSessionStoreWithScopesAndExpiry.retrieve(1) | ||
end | ||
end | ||
|
||
test ".store throws NotImplementedError when expires_at setter is not implemented" do | ||
mock_user = MockUserInstance.new( | ||
shopify_user_id: TEST_SHOPIFY_USER_ID, | ||
shopify_domain: TEST_SHOPIFY_DOMAIN, | ||
shopify_token: TEST_SHOPIFY_USER_TOKEN, | ||
) | ||
mock_user.stubs(:expires_at=).raises(NotImplementedError) | ||
UserMockSessionStoreWithScopesAndExpiry.stubs(:find_or_initialize_by).returns(mock_user) | ||
|
||
assert_raises NotImplementedError do | ||
UserMockSessionStoreWithScopesAndExpiry.store( | ||
mock_session( | ||
shop: mock_user.shopify_domain, | ||
scope: TEST_MERCHANT_SCOPES, | ||
), | ||
mock_associated_user, | ||
) | ||
end | ||
end | ||
|
||
test ".retrieve throws NotImplementedError when expires_at getter is not implemented" do | ||
mock_user = MockUserInstance.new( | ||
shopify_user_id: TEST_SHOPIFY_USER_ID, | ||
shopify_domain: TEST_SHOPIFY_DOMAIN, | ||
shopify_token: TEST_SHOPIFY_USER_TOKEN, | ||
) | ||
mock_user.stubs(:expires_at).raises(NotImplementedError) | ||
UserMockSessionStoreWithScopesAndExpiry.stubs(:find_by).returns(mock_user) | ||
|
||
assert_raises NotImplementedError do | ||
UserMockSessionStoreWithScopesAndExpiry.retrieve(1) | ||
end | ||
end | ||
|
||
private | ||
|
||
def mock_associated_user | ||
ShopifyAPI::Auth::AssociatedUser.new( | ||
id: 100, | ||
first_name: "John", | ||
last_name: "Doe", | ||
email: "johndoe@email.com", | ||
email_verified: true, | ||
account_owner: false, | ||
locale: "en", | ||
collaborator: true, | ||
) | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters