feat: check for correct version
This commit is contained in:
parent
b751d93be6
commit
8e379241ee
6 changed files with 169 additions and 92 deletions
|
|
@ -1 +1,2 @@
|
||||||
const apiBasePath = "bal.ueauvergne.fr/api";
|
const apiBasePath = "bal.ueauvergne.fr/api";
|
||||||
|
const apiVersion = 1;
|
||||||
|
|
|
||||||
|
|
@ -39,4 +39,8 @@ class AuthRepository extends ChangeNotifier {
|
||||||
return Result.error(Exception(e));
|
return Result.error(Exception(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Result<int>> getRemoteApiVersion() async {
|
||||||
|
return await _authClient.getRemoteApiVersion();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -66,4 +66,23 @@ class AuthClient {
|
||||||
client.close();
|
client.close();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<Result<int>> getRemoteApiVersion() async {
|
||||||
|
final client = http.Client();
|
||||||
|
try {
|
||||||
|
final response = await client.get(
|
||||||
|
Uri.parse("https://$apiBasePath/version"),
|
||||||
|
);
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final json = jsonDecode(response.body) as int;
|
||||||
|
return Result.ok(json);
|
||||||
|
} else {
|
||||||
|
throw "Something wrong happened";
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return Result.error(Exception(e));
|
||||||
|
} finally {
|
||||||
|
client.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
import 'package:seshat/config/constants.dart';
|
||||||
import 'package:seshat/data/repositories/auth_repository.dart';
|
import 'package:seshat/data/repositories/auth_repository.dart';
|
||||||
import 'package:seshat/routing/routes.dart';
|
import 'package:seshat/routing/routes.dart';
|
||||||
import 'package:seshat/ui/add_page/view_model/add_view_model.dart';
|
import 'package:seshat/ui/add_page/view_model/add_view_model.dart';
|
||||||
|
|
@ -12,14 +13,24 @@ import 'package:seshat/ui/home_page/view_model/home_view_model.dart';
|
||||||
import 'package:seshat/ui/home_page/widgets/home_page.dart';
|
import 'package:seshat/ui/home_page/widgets/home_page.dart';
|
||||||
import 'package:seshat/ui/sell_page/view_model/sell_view_model.dart';
|
import 'package:seshat/ui/sell_page/view_model/sell_view_model.dart';
|
||||||
import 'package:seshat/ui/sell_page/widgets/sell_page.dart';
|
import 'package:seshat/ui/sell_page/widgets/sell_page.dart';
|
||||||
|
import 'package:seshat/utils/result.dart';
|
||||||
|
|
||||||
GoRouter router(AuthRepository authRepository) => GoRouter(
|
GoRouter router(AuthRepository authRepository) => GoRouter(
|
||||||
initialLocation: Routes.add,
|
initialLocation: Routes.add,
|
||||||
redirect: (context, state) async {
|
redirect: (context, state) async {
|
||||||
final loggedIn = await context.read<AuthRepository>().isLoggedIn;
|
final loggedIn = await context.read<AuthRepository>().isLoggedIn;
|
||||||
|
final result = await context.read<AuthRepository>().getRemoteApiVersion();
|
||||||
|
bool isUpToDate = false;
|
||||||
|
switch (result) {
|
||||||
|
case Ok():
|
||||||
|
isUpToDate = result.value == apiVersion;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
final logginIn = state.matchedLocation == Routes.login;
|
final logginIn = state.matchedLocation == Routes.login;
|
||||||
|
|
||||||
if (!loggedIn) {
|
if (!loggedIn || !isUpToDate) {
|
||||||
return Routes.login;
|
return Routes.login;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:seshat/config/constants.dart';
|
||||||
import 'package:seshat/data/repositories/auth_repository.dart';
|
import 'package:seshat/data/repositories/auth_repository.dart';
|
||||||
import 'package:seshat/utils/command.dart';
|
import 'package:seshat/utils/command.dart';
|
||||||
import 'package:seshat/utils/result.dart';
|
import 'package:seshat/utils/result.dart';
|
||||||
|
|
@ -7,6 +8,7 @@ class LoginViewModel extends ChangeNotifier {
|
||||||
LoginViewModel({required AuthRepository authRepository})
|
LoginViewModel({required AuthRepository authRepository})
|
||||||
: _authRepository = authRepository {
|
: _authRepository = authRepository {
|
||||||
login = Command1<void, (String username, String password)>(_login);
|
login = Command1<void, (String username, String password)>(_login);
|
||||||
|
load = Command0(_load)..execute();
|
||||||
}
|
}
|
||||||
|
|
||||||
final AuthRepository _authRepository;
|
final AuthRepository _authRepository;
|
||||||
|
|
@ -18,4 +20,39 @@ class LoginViewModel extends ChangeNotifier {
|
||||||
final result = await _authRepository.login(username, password);
|
final result = await _authRepository.login(username, password);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* =================================
|
||||||
|
* =====[ COMMAND AND LOADING ]=====
|
||||||
|
* =================================
|
||||||
|
*/
|
||||||
|
|
||||||
|
late final Command0 load;
|
||||||
|
bool isLoaded = false;
|
||||||
|
bool isUpToDate = false;
|
||||||
|
|
||||||
|
Future<Result<void>> _load() async {
|
||||||
|
final result1 = await _loadApiVersion();
|
||||||
|
switch (result1) {
|
||||||
|
case Ok():
|
||||||
|
isLoaded = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
notifyListeners();
|
||||||
|
return result1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<Result<void>> _loadApiVersion() async {
|
||||||
|
final result = await _authRepository.getRemoteApiVersion();
|
||||||
|
switch (result) {
|
||||||
|
case Ok():
|
||||||
|
isUpToDate = result.value == apiVersion;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
||||||
import 'package:go_router/go_router.dart';
|
import 'package:go_router/go_router.dart';
|
||||||
import 'package:seshat/routing/routes.dart';
|
import 'package:seshat/routing/routes.dart';
|
||||||
import 'package:seshat/ui/auth/viewmodel/login_view_model.dart';
|
import 'package:seshat/ui/auth/viewmodel/login_view_model.dart';
|
||||||
|
import 'package:seshat/ui/core/ui/await_loading.dart';
|
||||||
|
|
||||||
class LoginPage extends StatefulWidget {
|
class LoginPage extends StatefulWidget {
|
||||||
const LoginPage({super.key, required this.viewModel});
|
const LoginPage({super.key, required this.viewModel});
|
||||||
|
|
@ -40,100 +41,104 @@ class _LoginPageState extends State<LoginPage> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
body: Center(
|
body: ListenableBuilder(
|
||||||
child: ListenableBuilder(
|
listenable: widget.viewModel,
|
||||||
listenable: widget.viewModel.login,
|
builder: (context, child) => switch (widget.viewModel.isLoaded) {
|
||||||
builder: (context, child) {
|
false => AwaitLoading(),
|
||||||
return Form(
|
true => switch (widget.viewModel.isUpToDate) {
|
||||||
key: _formKey,
|
false => Center(
|
||||||
child: SingleChildScrollView(
|
child: SizedBox(
|
||||||
child: SizedBox(
|
width: 300,
|
||||||
width: 300,
|
child: Text(
|
||||||
child: Column(
|
"L'application que vous utilisez n'est pas à jour. Si aucune mise à jour n'est disponible, contactez dev@ueauvergne.fr",
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Text("Bienvenue", style: TextStyle(fontSize: 40)),
|
|
||||||
SizedBox(height: 50),
|
|
||||||
TextFormField(
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: "Identifiant de section",
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
),
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return "Veuillez entrer un identifiant";
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
onSaved: (newValue) {
|
|
||||||
username = newValue!;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
SizedBox(height: 10),
|
|
||||||
TextFormField(
|
|
||||||
decoration: InputDecoration(
|
|
||||||
labelText: "Mot de passe",
|
|
||||||
border: OutlineInputBorder(),
|
|
||||||
suffixIcon: IconButton(
|
|
||||||
onPressed: () {
|
|
||||||
setState(() {
|
|
||||||
hidePassword = !hidePassword;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
icon: Icon(
|
|
||||||
(hidePassword)
|
|
||||||
? Icons.visibility
|
|
||||||
: Icons.visibility_off,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
obscureText: hidePassword,
|
|
||||||
enableSuggestions: false,
|
|
||||||
autocorrect: false,
|
|
||||||
validator: (value) {
|
|
||||||
if (value == null || value.isEmpty) {
|
|
||||||
return "Veuillez entrer un mot de passe";
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
onSaved: (newValue) {
|
|
||||||
password = newValue!;
|
|
||||||
},
|
|
||||||
),
|
|
||||||
SizedBox(height: 10),
|
|
||||||
ElevatedButton(
|
|
||||||
onPressed: () {
|
|
||||||
_formKey.currentState!.validate();
|
|
||||||
_formKey.currentState!.save();
|
|
||||||
widget.viewModel.login.execute((username, password));
|
|
||||||
},
|
|
||||||
child: Text("Valider"),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
),
|
||||||
|
true => Center(
|
||||||
|
child: ListenableBuilder(
|
||||||
|
listenable: widget.viewModel.login,
|
||||||
|
builder: (context, child) {
|
||||||
|
return Form(
|
||||||
|
key: _formKey,
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
child: SizedBox(
|
||||||
|
width: 300,
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text("Bienvenue", style: TextStyle(fontSize: 40)),
|
||||||
|
SizedBox(height: 50),
|
||||||
|
TextFormField(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: "Identifiant de section",
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
),
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return "Veuillez entrer un identifiant";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
onSaved: (newValue) {
|
||||||
|
username = newValue!;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
TextFormField(
|
||||||
|
decoration: InputDecoration(
|
||||||
|
labelText: "Mot de passe",
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
suffixIcon: IconButton(
|
||||||
|
onPressed: () {
|
||||||
|
setState(() {
|
||||||
|
hidePassword = !hidePassword;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
icon: Icon(
|
||||||
|
(hidePassword)
|
||||||
|
? Icons.visibility
|
||||||
|
: Icons.visibility_off,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
obscureText: hidePassword,
|
||||||
|
enableSuggestions: false,
|
||||||
|
autocorrect: false,
|
||||||
|
validator: (value) {
|
||||||
|
if (value == null || value.isEmpty) {
|
||||||
|
return "Veuillez entrer un mot de passe";
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
onSaved: (newValue) {
|
||||||
|
password = newValue!;
|
||||||
|
},
|
||||||
|
),
|
||||||
|
SizedBox(height: 10),
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: () {
|
||||||
|
if (_formKey.currentState!.validate()) {
|
||||||
|
_formKey.currentState!.save();
|
||||||
|
widget.viewModel.login.execute((
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
child: Text("Valider"),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
},
|
},
|
||||||
),
|
},
|
||||||
// TextField(controller: _username),
|
|
||||||
// TextField(controller: _password),
|
|
||||||
// ListenableBuilder(
|
|
||||||
// listenable: widget.viewModel.login,
|
|
||||||
// builder: (context, child) {
|
|
||||||
// return FilledButton(
|
|
||||||
// onPressed: () {
|
|
||||||
// widget.viewModel.login.execute((
|
|
||||||
// _username.value.text,
|
|
||||||
// _password.value.text,
|
|
||||||
// ));
|
|
||||||
// },
|
|
||||||
// child: Text("Connexion"),
|
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Reference in a new issue