From f1abdad54d633403640830746b64cbf608f3c483 Mon Sep 17 00:00:00 2001 From: LittleSheep Date: Sun, 30 Jun 2024 18:03:02 +0800 Subject: [PATCH] :sparkles: Password reset --- lib/exts.dart | 17 ++++++++++ lib/screens/auth/signin.dart | 62 +++++++++++++++++++++++++++++------- lib/translations.dart | 8 +++++ 3 files changed, 75 insertions(+), 12 deletions(-) diff --git a/lib/exts.dart b/lib/exts.dart index 8bf713c..9a679c6 100644 --- a/lib/exts.dart +++ b/lib/exts.dart @@ -12,6 +12,23 @@ extension SolianExtenions on BuildContext { ScaffoldMessenger.of(this).clearSnackBars(); } + Future showModalDialog(String title, desc) { + return showDialog( + useRootNavigator: true, + context: this, + builder: (ctx) => AlertDialog( + title: Text(title), + content: Text(desc), + actions: [ + TextButton( + onPressed: () => Navigator.pop(ctx), + child: Text('okay'.tr), + ) + ], + ), + ); + } + Future showErrorDialog(dynamic exception) { return showDialog( useRootNavigator: true, diff --git a/lib/screens/auth/signin.dart b/lib/screens/auth/signin.dart index 9c1dff4..864430b 100644 --- a/lib/screens/auth/signin.dart +++ b/lib/screens/auth/signin.dart @@ -19,6 +19,36 @@ class _SignInPopupState extends State { final _usernameController = TextEditingController(); final _passwordController = TextEditingController(); + void requestResetPassword(BuildContext context) async { + final username = _usernameController.value.text; + if (username.isEmpty) { + context.showErrorDialog('signinResetPasswordHint'.tr); + return; + } + + setState(() => _isBusy = true); + + final client = ServiceFinder.configureClient('passport'); + final lookupResp = await client.get('/api/users/lookup?probe=$username'); + if (lookupResp.statusCode != 200) { + context.showErrorDialog(lookupResp.bodyString); + setState(() => _isBusy = false); + return; + } + + final resp = await client.post('/api/users/me/password-reset', { + 'user_id': lookupResp.body['id'], + }); + if (resp.statusCode != 200) { + context.showErrorDialog(resp.bodyString); + setState(() => _isBusy = false); + return; + } + + setState(() => _isBusy = false); + context.showModalDialog('done'.tr, 'signinResetPasswordSent'.tr); + } + void performAction(BuildContext context) async { final AuthProvider provider = Get.find(); @@ -117,19 +147,27 @@ class _SignInPopupState extends State { onSubmitted: (_) => performAction(context), ), const SizedBox(height: 12), - Align( - alignment: Alignment.centerRight, - child: TextButton( - onPressed: _isBusy ? null : () => performAction(context), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Text('next'.tr), - const Icon(Icons.chevron_right), - ], + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + TextButton( + onPressed: + _isBusy ? null : () => requestResetPassword(context), + style: TextButton.styleFrom(foregroundColor: Colors.grey), + child: Text('forgotPassword'.tr), ), - ), - ) + TextButton( + onPressed: _isBusy ? null : () => performAction(context), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Text('next'.tr), + const Icon(Icons.chevron_right), + ], + ), + ), + ], + ), ], ), ), diff --git a/lib/translations.dart b/lib/translations.dart index d5c9bcc..b44eb40 100644 --- a/lib/translations.dart +++ b/lib/translations.dart @@ -4,6 +4,7 @@ class SolianMessages extends Translations { @override Map> get keys => { 'en_US': { + 'done': 'Done', 'hide': 'Hide', 'okay': 'Okay', 'next': 'Next', @@ -25,6 +26,7 @@ class SolianMessages extends Translations { 'openInBrowser': 'Open in browser', 'notification': 'Notification', 'errorHappened': 'An error occurred', + 'forgotPassword': 'Forgot password', 'email': 'Email', 'username': 'Username', 'nickname': 'Nickname', @@ -56,6 +58,8 @@ class SolianMessages extends Translations { 'Sign in to create post, start a realm, message your friend and more!', 'signinRiskDetected': 'Risk detected, click Next to open a webpage and signin through it to pass security check.', + 'signinResetPasswordHint': 'Please enter username to request reset password.', + 'signinResetPasswordSent': 'Reset password request sent, check your inbox!', 'signup': 'Sign up', 'signupGreeting': 'Welcome onboard', 'signupCaption': @@ -241,6 +245,7 @@ class SolianMessages extends Translations { 'accountStatusPositive': 'Positive', }, 'zh_CN': { + 'done': '完成', 'hide': '隐藏', 'okay': '确认', 'next': '下一步', @@ -262,6 +267,7 @@ class SolianMessages extends Translations { 'openInBrowser': '在浏览器中打开', 'notification': '通知', 'errorHappened': '发生错误了', + 'forgotPassword': '忘记密码', 'email': '邮件地址', 'username': '用户名', 'nickname': '显示名', @@ -289,6 +295,8 @@ class SolianMessages extends Translations { 'signinGreeting': '欢迎回来\nSolar Network', 'signinCaption': '登录以发表帖子、文章、创建领域、和你的朋友聊天,以及获取更多功能!', 'signinRiskDetected': '检测到风险,点击下一步按钮来打开一个网页,并通过在其上面登录来通过安全检查。', + 'signinResetPasswordHint': '请先填写用户名以发送重置密码请求。', + 'signinResetPasswordSent': '重置密码请求已发送,在绑定邮件收件箱可收取一份包含重置密码链接的邮件。', 'signup': '注册', 'signupGreeting': '欢迎加入\nSolar Network', 'signupCaption': '在 Solarpass 注册一个账号以获得整个 Solar Network 的存取权!',