Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes for issues found in QA #124

Merged
merged 3 commits into from
Sep 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .env-example
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,8 @@ CLOUD_FUNCTIONS_URL=
SA_EMAIL=
SA_SECRET_KEY=

#Development Environment
ENVIRONMENT=development

# Places API
PLACES_API_KEY=
1 change: 1 addition & 0 deletions .github/workflows/firebase-hosting-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ jobs:
echo CLOUD_FUNCTIONS_URL=${{ secrets.CLOUD_FUNCTIONS_URL }} >> .env
echo SA_EMAIL=${{ secrets.SA_EMAIL }} >> .env
echo SA_SECRET_KEY="${{ secrets.SA_SECRET_KEY }}" >> .env
echo ENVIRONMENT="${{ secrets.ENVIRONMENT }}" >> .env
- run: flutter build web --dart-define-from-file=.env
- name: Update .firebaserc
run: |
Expand Down
1 change: 1 addition & 0 deletions .github/workflows/firebase-hosting-pull-request.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ jobs:
echo CLOUD_FUNCTIONS_URL=${{ secrets.CLOUD_FUNCTIONS_URL }} >> .env
echo SA_EMAIL=${{ secrets.SA_EMAIL }} >> .env
echo SA_SECRET_KEY="${{ secrets.SA_SECRET_KEY }}" >> .env
echo ENVIRONMENT="${{ secrets.ENVIRONMENT }}" >> .env
- run: flutter build web --dart-define-from-file=.env
- name: Update .firebaserc
run: |
Expand Down
71 changes: 36 additions & 35 deletions functions/auth0/api/auth0.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const updateUser = onRequest(async (req, res) => {

if (user.lastName) {
updatedUserObject['family_name'] = user.lastName;
updatedUserObject['name'] += ` ${user.lastName}`;
}

const primaryAddress = {};
Expand Down Expand Up @@ -354,6 +355,40 @@ export const unenrollMFA = onRequest(async (req, res) => {
}
});

export const removeConnection = onRequest(async (req, res) => {
try {
const {
connectionId
} = req.body;

if (!connectionId) {
res.status(400).send('Invalid request - missing required fields.');
return;
}

const config = {
method: 'delete',
maxBodyLength: Infinity,
url: `https://${auth0Domain}/api/v2/grants/${connectionId}`,
headers: {
'Authorization': `Bearer ${await getAccessToken()}`
}
};

await axios.request(config)
res.status(200).send();
} catch (error) {
console.log(error);

const {
status = 500,
message = '',
} = error.response;

return res.status(status).send(message);
};
});

const getConnectedServices = async (userId) => {

if (!userId) {
Expand Down Expand Up @@ -427,38 +462,4 @@ const getConnectedServices = async (userId) => {

return res.status(status).send(message);
}
};

export const removeConnection = onRequest(async (req, res) => {
try {
const {
connectionId
} = req.body;

if (!connectionId) {
res.status(400).send('Invalid request - missing required fields.');
return;
}

const config = {
method: 'delete',
maxBodyLength: Infinity,
url: `https://${auth0Domain}/api/v2/grants/${connectionId}`,
headers: {
'Authorization': `Bearer ${await getAccessToken()}`
}
};

await axios.request(config)
res.status(200).send();
} catch (error) {
console.log(error);

const {
status = 500,
message = '',
} = error.response;

return res.status(status).send(message);
};
});
};
2 changes: 2 additions & 0 deletions lib/controllers/auth0_user_api.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,6 @@ abstract class Api {
void confirmMFA(final Map<String, String> body);

void unenrollMFA(final Map<String, String> body);

void removeConnection(final String connectionId);
}
1 change: 1 addition & 0 deletions lib/controllers/auth0_user_api_implementation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,7 @@
}
}

@override

Check warning on line 305 in lib/controllers/auth0_user_api_implementation.dart

View check run for this annotation

Codecov / codecov/patch

lib/controllers/auth0_user_api_implementation.dart#L305

Added line #L305 was not covered by tests
Future<ApiResponse> removeConnection(final String connectionId) async {

final token = await getOAuthToken();
Expand Down
2 changes: 1 addition & 1 deletion lib/controllers/user_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class UserProvider extends ChangeNotifier {

Future<void> logout() => auth0Web.logout(
federated: false,
returnToUrl: 'https://angeleno.lacity.org/'
returnToUrl: 'https://sandbox.account.lacity.gov/'
);

User? get user => _user;
Expand Down
3 changes: 2 additions & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ class MyApp extends StatelessWidget {

@override
Widget build(final BuildContext context) => MaterialApp(
title: 'Angeleno - Account',
title: 'Angeleno - My Account '
'${environment == 'prod' ? '' : ' - $environment'}',
debugShowCheckedModeBanner: false,
theme: ThemeData(
useMaterial3: true,
Expand Down
1 change: 1 addition & 0 deletions lib/utils/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const cloudFunctionURL =
String.fromEnvironment('CLOUD_FUNCTIONS_URL');
const serviceAccountSecret = String.fromEnvironment('SA_SECRET_KEY');
const serviceAccountEmail = String.fromEnvironment('SA_EMAIL');
const environment = String.fromEnvironment('ENVIRONMENT');

/* Regex */
final RegExp nameRegEx = RegExp(r"^[a-zA-ZÀ-ÿ\s'\-\d]*$");
Expand Down
29 changes: 16 additions & 13 deletions lib/views/dialogs/authenticator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class _AuthenticatorDialogState extends State<AuthenticatorDialog> {
String qrCodeAltString = '';
String mfaToken = '';

String userPassword = '';
bool obscurePassword = true;

@override
Expand All @@ -45,6 +44,10 @@ class _AuthenticatorDialogState extends State<AuthenticatorDialog> {

userProvider = widget.userProvider;
auth0UserApi = widget.auth0UserApi;

passwordField.addListener(() {
setState(() {});
});
}

@override
Expand Down Expand Up @@ -151,7 +154,7 @@ class _AuthenticatorDialogState extends State<AuthenticatorDialog> {
children: [
dialogClose,
TextButton(
onPressed: () {
onPressed: passwordField.text.isEmpty ? null : () {
enrollTOTP();
},
child: const Text('Continue'),
Expand Down Expand Up @@ -183,7 +186,7 @@ class _AuthenticatorDialogState extends State<AuthenticatorDialog> {
obscureText: obscurePassword,
enableSuggestions: false,
autocorrect: false,
autovalidateMode: AutovalidateMode.always,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (final value) {
if (value == null || value.trim().isEmpty) {
return 'Password is required';
Expand Down Expand Up @@ -251,14 +254,14 @@ class _AuthenticatorDialogState extends State<AuthenticatorDialog> {
const SizedBox(height: 20),
const Text('If unable to scan, please enter the code below:'),
const SizedBox(height: 15),
Text(
qrCodeAltString,
style: const TextStyle(
decoration: TextDecoration.none,
color: Colors.black,
fontSize: 14.0,
fontWeight: FontWeight.normal
)
SelectableText(
qrCodeAltString,
style: const TextStyle(
decoration: TextDecoration.none,
color: Colors.black,
fontSize: 14.0,
fontWeight: FontWeight.normal
)
)
],
),
Expand All @@ -275,7 +278,7 @@ class _AuthenticatorDialogState extends State<AuthenticatorDialog> {
children: [
dialogClose,
TextButton(
onPressed: () {
onPressed: totpCode.isEmpty ? null : () {
confirmTOTP();
},
child: const Text('Finish'),
Expand All @@ -296,7 +299,7 @@ class _AuthenticatorDialogState extends State<AuthenticatorDialog> {
child: TextFormField(
key: const Key('totpCode'),
autofocus: true,
autovalidateMode: AutovalidateMode.always,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (final value) {
if (value == null || value.trim().isEmpty) {
return 'Code is required';
Expand Down
87 changes: 45 additions & 42 deletions lib/views/dialogs/mobile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -42,16 +42,13 @@

String errMsg = '';
String phoneNumber = '';
String userPassword = '';
String mfaToken = '';
String oobCode = '';
String codeProvided = '';
bool obscurePassword = true;
bool validPhoneNumber = false;
int _pageIndex = 0;

late List<Widget> dialogNext;

@override
void initState() {
super.initState();
Expand All @@ -60,31 +57,9 @@
api = widget.userApi;
channel = widget.channel;

dialogNext = [
TextButton(
onPressed: () {
try {
if (!validPhoneNumber && isNotTestMode) {
return;
}
_navigateToNextPage();
} catch (e) {}
},
child: const Text('Continue'),
),
TextButton(
onPressed: () {
enrollMobile();
},
child: const Text('Continue'),
),
TextButton(
onPressed: () {
confirmCode();
},
child: const Text('Continue')
)
];
passwordField.addListener(() {
setState(() {});
});
}

@override
Expand All @@ -94,6 +69,32 @@
super.dispose();
}

List<Widget> get dialogNext => [
TextButton(
onPressed: !validPhoneNumber && isNotTestMode ? null : () {
try {
if (!validPhoneNumber && isNotTestMode) {
return;
}
_navigateToNextPage();
} catch (e) {}
},
child: const Text('Continue'),
),
TextButton(
onPressed: passwordField.text.isEmpty ? null : () {
enrollMobile();
},
child: const Text('Continue'),
),
TextButton(
onPressed: codeProvided.isEmpty ? null : () {
confirmCode();
},
child: const Text('Continue')
)
];

Widget get dialogClose => IconButton(
alignment: Alignment.centerLeft,
onPressed: () {
Expand Down Expand Up @@ -216,7 +217,9 @@
phoneNumber = number.phoneNumber!;
},
onInputValidated: (final bool value) {
validPhoneNumber = value;
setState(() {
validPhoneNumber = value;

Check warning on line 221 in lib/views/dialogs/mobile.dart

View check run for this annotation

Codecov / codecov/patch

lib/views/dialogs/mobile.dart#L220-L221

Added lines #L220 - L221 were not covered by tests
});
},
autoValidateMode: isNotTestMode ?
AutovalidateMode.onUserInteraction
Expand Down Expand Up @@ -256,25 +259,25 @@
obscureText: obscurePassword,
enableSuggestions: false,
autocorrect: false,
autovalidateMode: AutovalidateMode.always,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (final value) {
if (value == null || value.trim().isEmpty) {
return 'Password is required';
}
return null;
},
decoration: InputDecoration(
suffixIcon: IconButton(
key: const Key('toggle_password'),
onPressed: () {
setState(() {
obscurePassword = !obscurePassword;
});
},
icon: Icon(
obscurePassword ? Icons.visibility : Icons.visibility_off
),
)
suffixIcon: IconButton(
key: const Key('toggle_password'),
onPressed: () {
setState(() {
obscurePassword = !obscurePassword;
});
},
icon: Icon(
obscurePassword ? Icons.visibility : Icons.visibility_off
),
)
),
),
),
Expand All @@ -296,7 +299,7 @@
child: TextFormField(
key: const Key('phoneCode'),
autofocus: true,
autovalidateMode: AutovalidateMode.always,
autovalidateMode: AutovalidateMode.onUserInteraction,
validator: (final value) {
if (value == null || value.trim().isEmpty) {
return 'Code is required';
Expand Down
Loading
Loading