Skip to content

Commit

Permalink
feat(Auth): Rename resendConfirmationCode API for User Attributes to …
Browse files Browse the repository at this point in the history
…sendVerificationCode (#3384)

* feat(Auth): Rename resendConfirmationCode API for User Attributes to sendVerificationCode

* fix to use correct options

* worked on review comments

* Update Amplify/Categories/Auth/AuthCategoryUserBehavior.swift

Co-authored-by: Michael Law <[email protected]>

* updated the deprecation message

---------

Co-authored-by: Michael Law <[email protected]>
  • Loading branch information
harsh62 and lawmicha authored Dec 7, 2023
1 parent def0423 commit 15c514e
Show file tree
Hide file tree
Showing 12 changed files with 278 additions and 81 deletions.
13 changes: 11 additions & 2 deletions Amplify/Categories/Auth/AuthCategory+UserBehavior.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,19 @@ extension AuthCategory: AuthCategoryUserBehavior {
try await plugin.update(userAttributes: userAttributes, options: options)
}

public func resendConfirmationCode(forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthAttributeResendConfirmationCodeRequest.Options? = nil) async throws -> AuthCodeDeliveryDetails {
@available(*, deprecated, renamed: "sendVerificationCode(forUserAttributeKey:options:)")
public func resendConfirmationCode(
forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthAttributeResendConfirmationCodeRequest.Options? = nil
) async throws -> AuthCodeDeliveryDetails {
try await plugin.resendConfirmationCode(forUserAttributeKey: userAttributeKey, options: options)
}

public func sendVerificationCode(
forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthSendUserAttributeVerificationCodeRequest.Options? = nil
) async throws -> AuthCodeDeliveryDetails {
try await plugin.sendVerificationCode(forUserAttributeKey: userAttributeKey, options: options)
}

public func confirm(userAttribute: AuthUserAttributeKey,
Expand Down
17 changes: 15 additions & 2 deletions Amplify/Categories/Auth/AuthCategoryUserBehavior.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,21 @@ public protocol AuthCategoryUserBehavior: AnyObject {
/// - Parameters:
/// - userAttributeKey: Attribute to be verified
/// - options: Parameters specific to plugin behavior
func resendConfirmationCode(forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthAttributeResendConfirmationCodeRequest.Options?) async throws -> AuthCodeDeliveryDetails
@available(*, deprecated, renamed: "sendVerificationCode(forUserAttributeKey:options:)")
func resendConfirmationCode(
forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthAttributeResendConfirmationCodeRequest.Options?
) async throws -> AuthCodeDeliveryDetails

/// Sends the verification code required to verify an attribute
///
/// - Parameters:
/// - userAttributeKey: Attribute to be verified
/// - options: Parameters specific to plugin behavior
func sendVerificationCode(
forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthSendUserAttributeVerificationCodeRequest.Options?
) async throws -> AuthCodeDeliveryDetails

/// Confirm an attribute using confirmation code
///
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

// swiftlint:disable type_name

/// Request for sending verification code that was generated for update attribute
public struct AuthSendUserAttributeVerificationCodeRequest: AmplifyOperationRequest {

/// Attribute key for which the confirmation code was sent
public let attributeKey: AuthUserAttributeKey

/// Extra request options defined in `AuthSendUserAttributeVerificationCodeRequest.Options`
public var options: Options

public init(attributeKey: AuthUserAttributeKey,
options: Options) {
self.attributeKey = attributeKey
self.options = options
}
}

public extension AuthSendUserAttributeVerificationCodeRequest {

struct Options {

/// Extra plugin specific options, only used in special circumstances when the existing options do not provide
/// a way to utilize the underlying auth plugin functionality. See plugin documentation for expected
/// key/values
public let pluginOptions: Any?

public init(pluginOptions: Any? = nil) {
self.pluginOptions = pluginOptions
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,11 @@ public extension AWSCognitoAuthPlugin {
} as! [AuthUserAttributeKey: AuthUpdateAttributeResult]
}

func resendConfirmationCode(forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthAttributeResendConfirmationCodeRequest.Options? = nil) async throws -> AuthCodeDeliveryDetails {
@available(*, deprecated, renamed: "sendVerificationCode(forUserAttributeKey:options:)")
func resendConfirmationCode(
forUserAttributeKey userAttributeKey: AuthUserAttributeKey,
options: AuthAttributeResendConfirmationCodeRequest.Options? = nil
) async throws -> AuthCodeDeliveryDetails {

let options = options ?? AuthAttributeResendConfirmationCodeRequest.Options()
let request = AuthAttributeResendConfirmationCodeRequest(
Expand All @@ -53,6 +56,22 @@ public extension AWSCognitoAuthPlugin {
} as! AuthCodeDeliveryDetails
}

func sendVerificationCode(
forUserAttributeKey userAttributeKey:
AuthUserAttributeKey,
options: AuthSendUserAttributeVerificationCodeRequest.Options? = nil
) async throws -> AuthCodeDeliveryDetails {
let options = options ?? AuthSendUserAttributeVerificationCodeRequest.Options()
let request = AuthSendUserAttributeVerificationCodeRequest(
attributeKey: userAttributeKey, options: options)
let task = AWSAuthSendUserAttributeVerificationCodeTask(
request, authStateMachine: authStateMachine,
userPoolFactory: authEnvironment.cognitoUserPoolFactory)
return try await taskQueue.sync {
return try await task.value
} as! AuthCodeDeliveryDetails
}

func confirm(userAttribute: AuthUserAttributeKey, confirmationCode: String, options: AuthConfirmUserAttributeRequest.Options? = nil) async throws {
let options = options ?? AuthConfirmUserAttributeRequest.Options()
let request = AuthConfirmUserAttributeRequest(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import Foundation

@available(*, deprecated, renamed: "AWSSendUserAttributeVerificationCodeOptions")
public struct AWSAttributeResendConfirmationCodeOptions {

/// A map of custom key-value pairs that you can provide as input for any custom workflows that this action triggers.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation

public struct AWSSendUserAttributeVerificationCodeOptions {

/// A map of custom key-value pairs that you can provide as input for any custom workflows that this action triggers.
///
/// When you use the ResendConfirmationCode API action, Amazon Cognito invokes the function that is assigned to the custom message trigger.
/// When Amazon Cognito invokes this function, it passes a JSON payload, which the function receives as input.
/// This payload contains a clientMetadata attribute, which provides the data that you assigned to the ClientMetadata parameter in your GetUserAttributeVerificationCode request.
/// In your function code in AWS Lambda, you can process the clientMetadata value to enhance your workflow for your specific needs.
///
/// For more information, see Customizing user pool Workflows with Lambda Triggers in the Amazon Cognito Developer Guide.
public let metadata: [String: String]?

public init(metadata: [String: String]? = nil) {
self.metadata = metadata
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Amplify

protocol AuthSendUserAttributeVerificationCodeTask: AmplifyAuthTask where Request == AuthSendUserAttributeVerificationCodeRequest, Success == AuthCodeDeliveryDetails, Failure == AuthError {}

public extension HubPayload.EventName.Auth {

/// eventName for HubPayloads emitted by this operation
static let sendUserAttributeVerificationCodeAPI = "Auth.sendUserAttributeVerificationCodeAPI"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
//
// Copyright Amazon.com Inc. or its affiliates.
// All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import Foundation
import Amplify
import AWSPluginsCore
import AWSCognitoIdentityProvider

class AWSAuthSendUserAttributeVerificationCodeTask: AuthSendUserAttributeVerificationCodeTask {
typealias CognitoUserPoolFactory = () throws -> CognitoUserPoolBehavior

private let request: AuthSendUserAttributeVerificationCodeRequest
private let authStateMachine: AuthStateMachine
private let userPoolFactory: CognitoUserPoolFactory
private let taskHelper: AWSAuthTaskHelper

var eventName: HubPayloadEventName {
HubPayload.EventName.Auth.sendUserAttributeVerificationCodeAPI
}

init(_ request: AuthSendUserAttributeVerificationCodeRequest,
authStateMachine: AuthStateMachine,
userPoolFactory: @escaping CognitoUserPoolFactory) {
self.request = request
self.authStateMachine = authStateMachine
self.userPoolFactory = userPoolFactory
self.taskHelper = AWSAuthTaskHelper(authStateMachine: authStateMachine)
}

func execute() async throws -> AuthCodeDeliveryDetails {
do {
await taskHelper.didStateMachineConfigured()
let accessToken = try await taskHelper.getAccessToken()
let devices = try await initiateGettingVerificationCode(with: accessToken)
return devices
} catch let error as AuthErrorConvertible {
throw error.authError
} catch {
throw AuthError.configuration(
"Unable to execute auth task",
AuthPluginErrorConstants.configurationError,
error
)
}
}

func initiateGettingVerificationCode(with accessToken: String) async throws -> AuthCodeDeliveryDetails {
let userPoolService = try userPoolFactory()
let clientMetaData = (request.options.pluginOptions as? AWSSendUserAttributeVerificationCodeOptions)?.metadata ?? [:]

let input = GetUserAttributeVerificationCodeInput(
accessToken: accessToken,
attributeName: request.attributeKey.rawValue,
clientMetadata: clientMetaData)

let result = try await userPoolService.getUserAttributeVerificationCode(input: input)
guard let deliveryDetails = result.codeDeliveryDetails?.toAuthCodeDeliveryDetails() else {
let authError = AuthError.unknown("Unable to get Auth code delivery details", nil)
throw authError
}
return deliveryDetails
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,36 +136,36 @@ class AWSCognitoAuthUserBehaviorTests: BasePluginTest {
_ = try await plugin.update(userAttributes: [emailAttribute, phoneAttribute])
}

/// Test resendConfirmationCode(for:) operation can be invoked
/// Test sendVerificationCode(for:) operation can be invoked
///
/// - Given: Given a configured auth plugin
/// - When:
/// - I call resendConfirmationCode(for:) operation
/// - I call sendVerificationCode(for:) operation
/// - Then:
/// - I should get a valid task completion
///
func testResendConfirmationCodeAttributeRequest() async throws {
func testSendVerificationCodeAttributeRequest() async throws {
mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutput: { _ in
GetUserAttributeVerificationCodeOutput(
codeDeliveryDetails: .init(
attributeName: "attributeName",
deliveryMedium: .email,
destination: "destination"))
})
let pluginOptions = AWSAttributeResendConfirmationCodeOptions(metadata: ["key": "value"])
let options = AuthAttributeResendConfirmationCodeRequest.Options(pluginOptions: pluginOptions)
_ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email, options: options)
let pluginOptions = AWSSendUserAttributeVerificationCodeOptions(metadata: ["key": "value"])
let options = AuthSendUserAttributeVerificationCodeRequest.Options(pluginOptions: pluginOptions)
_ = try await plugin.sendVerificationCode(forUserAttributeKey: .email, options: options)
}

/// Test resendConfirmationCode(for:) operation can be invoked with plugin options
/// Test sendVerificationCode(for:) operation can be invoked with plugin options
///
/// - Given: Given a configured auth plugin
/// - When:
/// - I call resendConfirmationCode(for:) operation
/// - I call sendVerificationCode(for:) operation
/// - Then:
/// - I should get a valid task completion
///
func testResendConfirmationCodeWithPluginOptions() async throws {
func testSendVerificationCodeWithPluginOptions() async throws {
mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutput: { request in

XCTAssertNotNil(request.clientMetadata)
Expand All @@ -176,28 +176,28 @@ class AWSCognitoAuthUserBehaviorTests: BasePluginTest {
deliveryMedium: .email,
destination: "destination"))
})
let pluginOptions = AWSAttributeResendConfirmationCodeOptions(metadata: ["key": "value"])
let options = AuthAttributeResendConfirmationCodeRequest.Options(pluginOptions: pluginOptions)
_ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email, options: options)
let pluginOptions = AWSSendUserAttributeVerificationCodeOptions(metadata: ["key": "value"])
let options = AuthSendUserAttributeVerificationCodeRequest.Options(pluginOptions: pluginOptions)
_ = try await plugin.sendVerificationCode(forUserAttributeKey: .email, options: options)
}

/// Test resendConfirmationCode(for:) operation can be invoked without options
/// Test sendVerificationCode(for:) operation can be invoked without options
///
/// - Given: Given a configured auth plugin
/// - When:
/// - I call resendConfirmationCode(for:) operation
/// - I call sendVerificationCode(for:) operation
/// - Then:
/// - I should get a valid task completion
///
func testResendConfirmationCodeAttributeRequestWithoutOptions() async throws {
func testSendVerificationCodeAttributeRequestWithoutOptions() async throws {
mockIdentityProvider = MockIdentityProvider(mockGetUserAttributeVerificationCodeOutput: { _ in
GetUserAttributeVerificationCodeOutput(
codeDeliveryDetails: .init(
attributeName: "attributeName",
deliveryMedium: .email,
destination: "destination"))
})
_ = try await plugin.resendConfirmationCode(forUserAttributeKey: .email)
_ = try await plugin.sendVerificationCode(forUserAttributeKey: .email)
}

/// Test confirm(userAttribute: ) operation can be invoked
Expand Down
Loading

0 comments on commit 15c514e

Please sign in to comment.