login method
Authenticates a user with NTUT Portal credentials.
Sets the JSESSIONID cookie in the app.ntut.edu.tw domain for subsequent authenticated requests. This session cookie is shared across all services.
Returns user profile information including name, email, and avatar filename.
Throws a LoginException subtype on failure — see WrongCredentialsException, AccountLockedException, PasswordExpiredException, MobileVerificationRequiredException, UnknownLoginException.
Implementation
Future<UserDto> login(String username, String password) async {
_firebase.log('Attempting login');
final response = await _portalDio.post(
'login.do',
queryParameters: {'muid': username, 'mpassword': password},
);
final body = jsonDecode(response.data);
if (!body['success']) {
_firebase.log('Login failed');
final String? errorMsg = body['errorMsg'];
final bool resetPwd = body['resetPwd'] ?? false;
throw switch (errorMsg) {
final msg? when msg.contains('密碼錯誤') =>
const WrongCredentialsException(),
final msg? when msg.contains('已被鎖住') => const AccountLockedException(),
final msg? when msg.contains('密碼已過期') && resetPwd =>
const PasswordExpiredException(),
final msg? when msg.contains('驗證手機') =>
const MobileVerificationRequiredException(),
_ => UnknownLoginException(errorMsg),
};
}
_firebase.log('Login successful');
final String? passwordExpiredRemind = body['passwordExpiredRemind'];
// Normalize empty strings to null for consistency
String? normalizeEmpty(String? value) =>
value?.isNotEmpty == true ? value : null;
return (
name: normalizeEmpty(body['givenName']),
avatarFilename: normalizeEmpty(body['userPhoto']),
email: normalizeEmpty(body['userMail']),
passwordExpiresInDays: passwordExpiredRemind != null
? int.tryParse(passwordExpiredRemind)
: null,
);
}