mirror of
				https://gitlab.com/comunic/comunicmobile
				synced 2025-11-04 12:14:11 +00:00 
			
		
		
		
	Show security questions
This commit is contained in:
		@@ -130,10 +130,20 @@ class AccountHelper {
 | 
			
		||||
  /// Throws in case of failure
 | 
			
		||||
  static Future<bool> hasSecurityQuestions(String email) async =>
 | 
			
		||||
      (await APIRequest.withoutLogin("account/has_security_questions")
 | 
			
		||||
          .addString("email", email)
 | 
			
		||||
          .execWithThrow())
 | 
			
		||||
              .addString("email", email)
 | 
			
		||||
              .execWithThrow())
 | 
			
		||||
          .getObject()["defined"];
 | 
			
		||||
 | 
			
		||||
  /// Get the security questions of the user
 | 
			
		||||
  ///
 | 
			
		||||
  /// Throws in case of failure
 | 
			
		||||
  static Future<List<String>> getSecurityQuestions(String email) async =>
 | 
			
		||||
      ((await APIRequest.withoutLogin("account/get_security_questions")
 | 
			
		||||
                  .addString("email", email)
 | 
			
		||||
                  .execWithThrow())
 | 
			
		||||
              .getObject()["questions"])
 | 
			
		||||
          .cast<String>();
 | 
			
		||||
 | 
			
		||||
  /// Get current user ID from the server
 | 
			
		||||
  Future<int> _downloadCurrentUserID() async {
 | 
			
		||||
    final response = await APIRequest(
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import 'package:comunic/utils/intl_utils.dart';
 | 
			
		||||
import 'package:comunic/utils/ui_utils.dart';
 | 
			
		||||
import 'package:flutter/cupertino.dart';
 | 
			
		||||
import 'package:flutter/material.dart';
 | 
			
		||||
import 'package:flutter/rendering.dart';
 | 
			
		||||
 | 
			
		||||
/// Reset password route
 | 
			
		||||
///
 | 
			
		||||
@@ -21,14 +22,14 @@ class ResetPasswordRoute extends StatelessWidget {
 | 
			
		||||
      body: Center(
 | 
			
		||||
        child: ConstrainedBox(
 | 
			
		||||
          constraints: BoxConstraints(maxWidth: 300),
 | 
			
		||||
          child: _ResetPasswordBody(),
 | 
			
		||||
          child: SingleChildScrollView(child: _ResetPasswordBody()),
 | 
			
		||||
        ),
 | 
			
		||||
      ),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
enum _SelectedOption { NONE }
 | 
			
		||||
enum _SelectedOption { NONE, SECURITY_QUESTIONS }
 | 
			
		||||
 | 
			
		||||
class _ResetPasswordBody extends StatefulWidget {
 | 
			
		||||
  @override
 | 
			
		||||
@@ -54,6 +55,10 @@ class _ResetPasswordBodyState extends SafeState<_ResetPasswordBody> {
 | 
			
		||||
 | 
			
		||||
  void _setLoading(bool loading) => setState(() => _loading = loading);
 | 
			
		||||
 | 
			
		||||
  /// Step 3b - Answer security questions
 | 
			
		||||
  List<String> _questions;
 | 
			
		||||
  var _questionsControllers = List<TextEditingController>();
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    if (_loading) return buildCenteredProgressBar();
 | 
			
		||||
@@ -63,6 +68,9 @@ class _ResetPasswordBodyState extends SafeState<_ResetPasswordBody> {
 | 
			
		||||
    switch (_selectedOption) {
 | 
			
		||||
      case _SelectedOption.NONE:
 | 
			
		||||
        return _buildOptionsScreen();
 | 
			
		||||
 | 
			
		||||
      case _SelectedOption.SECURITY_QUESTIONS:
 | 
			
		||||
        return _buildSecurityQuestionsScreen();
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -126,13 +134,20 @@ class _ResetPasswordBodyState extends SafeState<_ResetPasswordBody> {
 | 
			
		||||
        crossAxisAlignment: CrossAxisAlignment.stretch,
 | 
			
		||||
        children: <Widget>[
 | 
			
		||||
          Text(tr("Here are your options to reset your account:")),
 | 
			
		||||
          Container(height: 15),
 | 
			
		||||
          _Spacer(),
 | 
			
		||||
          OutlineButton.icon(
 | 
			
		||||
            onPressed: _openSendEmailDialog,
 | 
			
		||||
            icon: Icon(Icons.email),
 | 
			
		||||
            label: Text(tr("Send us an email to ask for help")),
 | 
			
		||||
          ),
 | 
			
		||||
          Container(height: 15),
 | 
			
		||||
          _Spacer(visible: _hasSecurityQuestions),
 | 
			
		||||
          _hasSecurityQuestions
 | 
			
		||||
              ? OutlineButton.icon(
 | 
			
		||||
                  onPressed: _loadSecurityQuestions,
 | 
			
		||||
                  icon: Icon(Icons.help_outline),
 | 
			
		||||
                  label: Text(tr("Answer your security questions")),
 | 
			
		||||
                )
 | 
			
		||||
              : Container(),
 | 
			
		||||
        ],
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
@@ -146,4 +161,60 @@ class _ResetPasswordBodyState extends SafeState<_ResetPasswordBody> {
 | 
			
		||||
              actions: <Widget>[CancelDialogButton()],
 | 
			
		||||
            ));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Load security questions
 | 
			
		||||
  void _loadSecurityQuestions() async {
 | 
			
		||||
    _setLoading(true);
 | 
			
		||||
    try {
 | 
			
		||||
      _questions = await AccountHelper.getSecurityQuestions(_emailAddress);
 | 
			
		||||
 | 
			
		||||
      _questionsControllers =
 | 
			
		||||
          List.generate(_questions.length, (i) => TextEditingController());
 | 
			
		||||
      _selectedOption = _SelectedOption.SECURITY_QUESTIONS;
 | 
			
		||||
    } catch (e, s) {
 | 
			
		||||
      print("Could not load security questions! $e\n$s");
 | 
			
		||||
      showSimpleSnack(context, tr("Could not load your security questions!"));
 | 
			
		||||
    }
 | 
			
		||||
    _setLoading(false);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /// Show a screen to prompt security questions of the user
 | 
			
		||||
  Widget _buildSecurityQuestionsScreen() {
 | 
			
		||||
    return Column(
 | 
			
		||||
      mainAxisSize: MainAxisSize.min,
 | 
			
		||||
      crossAxisAlignment: CrossAxisAlignment.stretch,
 | 
			
		||||
      children: <Widget>[]
 | 
			
		||||
        ..add(Text(tr("Please answer now your security questions:")))
 | 
			
		||||
        ..add(_Spacer())
 | 
			
		||||
        ..addAll(List.generate(_questions.length, _buildSecurityQuestionField))
 | 
			
		||||
        ..add(_Spacer())
 | 
			
		||||
        ..add(OutlineButton(
 | 
			
		||||
          onPressed: null,
 | 
			
		||||
          child: Text(tr("Submit")),
 | 
			
		||||
        )),
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  Widget _buildSecurityQuestionField(int id) => TextField(
 | 
			
		||||
        controller: _questionsControllers[id],
 | 
			
		||||
        decoration: InputDecoration(
 | 
			
		||||
          alignLabelWithHint: true,
 | 
			
		||||
          labelText: _questions[id],
 | 
			
		||||
        ),
 | 
			
		||||
      );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class _Spacer extends StatelessWidget {
 | 
			
		||||
  final bool visible;
 | 
			
		||||
 | 
			
		||||
  const _Spacer({Key key, this.visible = true})
 | 
			
		||||
      : assert(visible != null),
 | 
			
		||||
        super(key: key);
 | 
			
		||||
 | 
			
		||||
  @override
 | 
			
		||||
  Widget build(BuildContext context) {
 | 
			
		||||
    return Container(
 | 
			
		||||
      height: visible ? 35 : null,
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user