Skip to content

Commit f66d7a0

Browse files
authored
feat(amplify_auth_cognito): deleteUser API (#1236)
1 parent 856fef1 commit f66d7a0

36 files changed

+325
-87
lines changed

packages/amplify_analytics_pinpoint/ios/amplify_analytics_pinpoint.podspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ This code is the iOS part of the Amplify Flutter Pinpoint Analytics Plugin. The
1717
s.source = { :path => '.' }
1818
s.source_files = 'Classes/**/*'
1919
s.dependency 'Flutter'
20-
s.dependency 'Amplify', '1.18.3'
21-
s.dependency 'AmplifyPlugins/AWSPinpointAnalyticsPlugin', '1.18.3'
20+
s.dependency 'Amplify', '1.19.0'
21+
s.dependency 'AmplifyPlugins/AWSPinpointAnalyticsPlugin', '1.19.0'
2222
s.dependency 'amplify_core'
2323
s.dependency 'SwiftLint'
2424
s.dependency 'SwiftFormat/CLI'

packages/amplify_api/ios/amplify_api.podspec

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@ The API module for Amplify Flutter.
1717
s.source = { :git => 'https://github.com/aws-amplify/amplify-flutter.git' }
1818
s.source_files = 'Classes/**/*'
1919
s.dependency 'Flutter'
20-
s.dependency 'Amplify', '1.18.3'
21-
s.dependency 'AmplifyPlugins/AWSAPIPlugin', '1.18.3'
20+
s.dependency 'Amplify', '1.19.0'
21+
s.dependency 'AmplifyPlugins/AWSAPIPlugin', '1.19.0'
2222
s.dependency 'amplify_core'
2323
s.dependency 'SwiftLint'
2424
s.dependency 'SwiftFormat/CLI'
Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
/*
2+
* Copyright 2022 Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License").
5+
* You may not use this file except in compliance with the License.
6+
* A copy of the License is located at
7+
*
8+
* http://aws.amazon.com/apache2.0
9+
*
10+
* or in the "license" file accompanying this file. This file is distributed
11+
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12+
* express or implied. See the License for the specific language governing
13+
* permissions and limitations under the License.
14+
*/
15+
import 'dart:io' show Platform;
16+
import 'package:integration_test/integration_test.dart';
17+
import 'package:flutter_test/flutter_test.dart';
18+
import 'package:amplify_flutter/amplify_flutter.dart';
19+
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
20+
import 'package:amplify_api/amplify_api.dart';
21+
import 'package:amplify_test/amplify_test.dart';
22+
23+
import 'utils/mock_data.dart';
24+
import 'utils/setup_utils.dart';
25+
26+
void main() {
27+
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
28+
29+
group('deleteUser (iOS)', () {
30+
setUpAll(() async {
31+
await configureAuth(additionalPlugins: [
32+
AmplifyAPI(),
33+
]);
34+
await signOutUser();
35+
});
36+
37+
testWidgets('should delete a confirmed user on iOS',
38+
(WidgetTester tester) async {
39+
final username = generateUsername();
40+
final password = generatePassword();
41+
42+
// Create a confirmed user
43+
await adminCreateUser(
44+
username,
45+
password,
46+
autoConfirm: true,
47+
verifyAttributes: true,
48+
);
49+
50+
// Sign the user in
51+
SignInResult preDeleteSignIn = await Amplify.Auth.signIn(
52+
username: username,
53+
password: password,
54+
);
55+
expect(preDeleteSignIn.isSignedIn, true);
56+
57+
// Delete the user
58+
await Amplify.Auth.deleteUser();
59+
60+
// Expect subsequent sign in to fail
61+
try {
62+
await Amplify.Auth.signIn(
63+
username: username,
64+
password: password,
65+
);
66+
} catch (e) {
67+
expect(e, TypeMatcher<UserNotFoundException>());
68+
return;
69+
}
70+
fail('Expected UserNotFoundException');
71+
});
72+
73+
testWidgets(
74+
'fetchAuthSession should throw SignedOutException after user deletion',
75+
(WidgetTester tester) async {
76+
final username = generateUsername();
77+
final password = generatePassword();
78+
79+
// Create a confirmed user
80+
await adminCreateUser(
81+
username,
82+
password,
83+
autoConfirm: true,
84+
verifyAttributes: true,
85+
);
86+
87+
// Sign the user in
88+
SignInResult preDeleteSignIn = await Amplify.Auth.signIn(
89+
username: username,
90+
password: password,
91+
);
92+
expect(preDeleteSignIn.isSignedIn, true);
93+
94+
// Delete the user
95+
await Amplify.Auth.deleteUser();
96+
97+
// Expect fetchAuthSession to throw a SignedOutException (the tokens have been cleared)
98+
try {
99+
await Amplify.Auth.fetchAuthSession(
100+
options: CognitoSessionOptions(getAWSCredentials: true));
101+
} catch (e) {
102+
expect(e, TypeMatcher<SignedOutException>());
103+
return;
104+
}
105+
fail('Expected SignedOutException');
106+
});
107+
}, skip: !Platform.isIOS);
108+
109+
group('deleteUser (Android)', () {
110+
testWidgets('should throw an UnimplementedError on Android',
111+
(WidgetTester tester) async {
112+
try {
113+
await Amplify.Auth.deleteUser();
114+
} catch (e) {
115+
expect(e, TypeMatcher<UnimplementedError>());
116+
return;
117+
}
118+
fail('Expected UnimplementedError');
119+
});
120+
}, skip: !Platform.isAndroid);
121+
}

packages/amplify_auth_cognito/example/integration_test/hub_events_test.dart

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,12 @@
1313
* permissions and limitations under the License.
1414
*/
1515

16+
import 'dart:io' show Platform;
17+
import 'package:amplify_test/amplify_test.dart';
1618
import 'package:integration_test/integration_test.dart';
1719
import 'package:flutter_test/flutter_test.dart';
1820
import 'package:amplify_flutter/amplify_flutter.dart';
19-
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
21+
import 'package:amplify_api/amplify_api.dart';
2022

2123
import 'utils/mock_data.dart';
2224
import 'utils/setup_utils.dart';
@@ -29,15 +31,16 @@ void main() {
2931

3032
group('auth hub', () {
3133
setUpAll(() async {
32-
await configureAuth();
34+
await configureAuth(additionalPlugins: [
35+
AmplifyAPI(),
36+
]);
3337

34-
await Amplify.Auth.signUp(
35-
username: username,
36-
password: password,
37-
options: CognitoSignUpOptions(userAttributes: {
38-
CognitoUserAttributeKey.email: generateEmail(),
39-
CognitoUserAttributeKey.phoneNumber: mockPhoneNumber
40-
}));
38+
await adminCreateUser(
39+
username,
40+
password,
41+
autoConfirm: true,
42+
verifyAttributes: true,
43+
);
4144

4245
await signOutUser();
4346
});
@@ -56,7 +59,10 @@ void main() {
5659
nextEvent = authEventStream.first;
5760
await Amplify.Auth.signIn(username: username, password: password);
5861
event = await nextEvent;
59-
expect(event.eventName, 'SIGNED_IN');
62+
expect(
63+
event.eventName,
64+
'SIGNED_IN',
65+
);
6066

6167
// assert sign out event is broadcast
6268
nextEvent = authEventStream.first;
@@ -66,7 +72,10 @@ void main() {
6672

6773
// assert a second sign in event is broadcast
6874
nextEvent = authEventStream.first;
69-
await Amplify.Auth.signIn(username: username, password: password);
75+
await Amplify.Auth.signIn(
76+
username: username,
77+
password: password,
78+
);
7079
event = await nextEvent;
7180
expect(event.eventName, 'SIGNED_IN');
7281

@@ -80,5 +89,41 @@ void main() {
8089
expect(eventCount, 4);
8190
},
8291
);
92+
93+
testWidgets(
94+
'should broadcast events for deleteUser',
95+
(WidgetTester tester) async {
96+
// setup
97+
var nextEvent;
98+
var event;
99+
var eventCount = 0;
100+
var authEventStream = Amplify.Hub.availableStreams[HubChannel.Auth]!;
101+
authEventStream.listen((event) => eventCount++);
102+
103+
// assert sign in event is broadcast
104+
nextEvent = authEventStream.first;
105+
await Amplify.Auth.signIn(
106+
username: username,
107+
password: password,
108+
);
109+
event = await nextEvent;
110+
expect(event.eventName, 'SIGNED_IN');
111+
112+
// assert signed out event is broadcast
113+
nextEvent = authEventStream.first;
114+
await Amplify.Auth.deleteUser();
115+
event = await nextEvent;
116+
expect(event.eventName, 'SIGNED_OUT');
117+
118+
// assert delete user event is broadcast
119+
nextEvent = authEventStream.first;
120+
event = await nextEvent;
121+
expect(event.eventName, 'USER_DELETED');
122+
123+
// assert 3 total events are broadcast
124+
expect(eventCount, 3);
125+
},
126+
skip: !Platform.isIOS,
127+
);
83128
});
84129
}

packages/amplify_auth_cognito/example/integration_test/main_test.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import 'hub_events_test.dart' as hub_events_tests;
2626
import 'update_password_test.dart' as update_password_tests;
2727
import 'fetch_session_test.dart' as fetch_session_tests;
2828
import 'get_current_user_test.dart' as get_current_user_tests;
29+
import 'delete_user_test.dart' as delete_user_tests;
2930

3031
void main() async {
3132
IntegrationTestWidgetsFlutterBinding.ensureInitialized();
@@ -44,5 +45,6 @@ void main() async {
4445
update_password_tests.main();
4546
fetch_session_tests.main();
4647
get_current_user_tests.main();
48+
delete_user_tests.main();
4749
});
4850
}

packages/amplify_auth_cognito/example/integration_test/utils/setup_utils.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
1717
import 'package:amplify_auth_cognito_example/amplifyconfiguration.dart';
1818
import 'package:amplify_flutter/amplify_flutter.dart';
1919

20-
Future<void> configureAuth() async {
20+
Future<void> configureAuth({
21+
List<AmplifyPluginInterface> additionalPlugins = const [],
22+
}) async {
2123
if (!Amplify.isConfigured) {
2224
final authPlugin = AmplifyAuthCognito();
23-
await Amplify.addPlugins([authPlugin]);
25+
await Amplify.addPlugins([authPlugin, ...additionalPlugins]);
2426
await Amplify.configure(amplifyconfig);
2527
}
2628
}

packages/amplify_auth_cognito/example/lib/main.dart

Lines changed: 20 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
*/
1515

1616
import 'dart:async';
17+
import 'dart:io' show Platform;
1718

1819
import 'package:flutter/material.dart';
1920
import 'package:amplify_auth_cognito/amplify_auth_cognito.dart';
@@ -86,32 +87,13 @@ class _MyAppState extends State<MyApp> {
8687
var isSignedIn = false;
8788

8889
subscription = Amplify.Hub.listen([HubChannel.Auth], (hubEvent) {
89-
switch (hubEvent.eventName) {
90-
case 'SIGNED_IN':
91-
{
92-
setState(() {
93-
lastHubEvent = 'SIGNED_IN';
94-
});
95-
print('HUB: USER IS SIGNED IN');
96-
}
97-
break;
98-
case 'SIGNED_OUT':
99-
{
100-
setState(() {
101-
lastHubEvent = 'SIGNED_OUT';
102-
});
103-
print('HUB: USER IS SIGNED OUT');
104-
}
105-
break;
106-
case 'SESSION_EXPIRED':
107-
{
108-
setState(() {
109-
lastHubEvent = 'SESSION_EXPIRED';
110-
});
111-
print('HUB: USER SESSION HAS EXPIRED');
112-
}
113-
break;
90+
setState(() {
91+
lastHubEvent = hubEvent.eventName;
92+
});
93+
if (lastHubEvent != 'SIGNED_IN') {
94+
changeDisplay('SHOW_SIGN_IN');
11495
}
96+
print('HUB: $lastHubEvent');
11597
});
11698
try {
11799
await Amplify.configure(amplifyconfig);
@@ -137,6 +119,10 @@ class _MyAppState extends State<MyApp> {
137119
return session.isSignedIn;
138120
}
139121

122+
Future<void> _deleteUser() async {
123+
await Amplify.Auth.deleteUser();
124+
}
125+
140126
void _signOut() async {
141127
try {
142128
await Amplify.Auth.signOut();
@@ -276,6 +262,12 @@ class _MyAppState extends State<MyApp> {
276262
ElevatedButton(
277263
onPressed: _viewUserAttributes,
278264
child: const Text('View/Edit User Attributes')),
265+
const Padding(padding: EdgeInsets.all(10.0)),
266+
if (Platform.isIOS)
267+
ElevatedButton(
268+
onPressed: _deleteUser,
269+
child: const Text('Delete User'),
270+
),
279271
],
280272
),
281273
),
@@ -327,10 +319,9 @@ class _MyAppState extends State<MyApp> {
327319
if (displayState == 'SHOW_UPDATE_PASSWORD')
328320
UpdatePasswordWidget(showResult, changeDisplay,
329321
setError, _backToSignIn, _backToApp),
330-
if (displayState == 'SHOW_UPDATE_PASSWORD')
331-
if (displayState == 'SHOW_CONFIRM_RESET')
332-
ConfirmResetWidget(showResult, changeDisplay,
333-
setError, _backToSignIn),
322+
if (displayState == 'SHOW_CONFIRM_RESET')
323+
ConfirmResetWidget(
324+
showResult, changeDisplay, setError, _backToSignIn),
334325
if (this.displayState == "SIGNED_IN") showApp(),
335326
ElevatedButton(
336327
key: Key('configure-button'),

packages/amplify_auth_cognito/example/pubspec.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ dependencies:
1414
sdk: flutter
1515
amplify_flutter:
1616
path: ../../amplify_flutter
17+
amplify_api:
18+
path: ../../amplify_api
1719
amplify_auth_cognito:
1820
# When depending on this package from a real application you should use:
1921
# amplify_auth_cognito: ^x.y.z

packages/amplify_auth_cognito/ios/Classes/AuthCognitoBridge.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -270,4 +270,15 @@ class AuthCognitoBridge {
270270
}
271271
}
272272
}
273+
274+
func onDeleteUser(flutterResult: @escaping FlutterResult) {
275+
Amplify.Auth.deleteUser() { response in
276+
switch response {
277+
case .success:
278+
flutterResult(nil)
279+
case .failure(let error):
280+
self.errorHandler.handleAuthError(authError: error, flutterResult: flutterResult)
281+
}
282+
}
283+
}
273284
}

packages/amplify_auth_cognito/ios/Classes/AuthCognitoHubEventStreamHandler.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ public class AuthCognitoHubEventStreamHandler: NSObject, FlutterStreamHandler {
3737
self.sendEvent(eventName: "SESSION_EXPIRED")
3838
case HubPayload.EventName.Auth.signedOut:
3939
self.sendEvent(eventName: "SIGNED_OUT")
40+
case HubPayload.EventName.Auth.userDeleted:
41+
self.sendEvent(eventName: "USER_DELETED")
4042
case HubPayload.EventName.Amplify.configured:
4143
print("AuthPlugin successfully initialized")
4244
default:

0 commit comments

Comments
 (0)