Add an API to reset the password
This commit is contained in:
parent
20b2f7df0a
commit
469381f595
1
.env
Normal file
1
.env
Normal file
@ -0,0 +1 @@
|
||||
SOFTPLAYER_BACKEND_URL=https://softplayer-backend.badhouseplants.net:8080
|
@ -1,7 +1,4 @@
|
||||
# Environemnt to install flutter and build web
|
||||
FROM debian:latest AS build-env
|
||||
|
||||
# install all needed stuff
|
||||
RUN apt-get update
|
||||
RUN apt-get install -y curl tar xz-utils git
|
||||
|
||||
@ -13,12 +10,11 @@ ARG APP=/app/
|
||||
|
||||
RUN curl -l -o /tmp/flutter.tar.xz https://storage.googleapis.com/flutter_infra_release/releases/stable/linux/flutter_linux_${FLUTTER_VERSION}-stable.tar.xz
|
||||
RUN tar -xf /tmp/flutter.tar.xz -C /usr/local
|
||||
|
||||
ENV PATH="$FLUTTER_SDK/bin:$FLUTTER_SDK/bin/cache/dart-sdk/bin:${PATH}"
|
||||
|
||||
RUN mkdir $APP
|
||||
COPY . $APP
|
||||
WORKDIR $APP
|
||||
COPY . $APP
|
||||
|
||||
RUN flutter build web --release
|
||||
|
||||
# once heare the app will be compiled and ready to deploy
|
||||
|
@ -1,5 +1,4 @@
|
||||
import 'package:grpc/grpc_web.dart';
|
||||
import 'package:softplayer_dart_proto/accounts/accounts_v1.pbgrpc.dart';
|
||||
import 'package:softplayer_dart_proto/main.dart';
|
||||
|
||||
class AccountLocalData {
|
||||
@ -57,4 +56,33 @@ class AccountsGrpc {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<Empty> resetPassword(String username, String email) async {
|
||||
final request = AccountData(
|
||||
name: username,
|
||||
email: email,
|
||||
);
|
||||
try {
|
||||
final response = await accountsStub.resetPassword(request);
|
||||
return response;
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<Empty> newPassword(
|
||||
String username, String code, String newPassword) async {
|
||||
final request = AccountWithPasswordAndCode(
|
||||
data: AccountData(
|
||||
name: username,
|
||||
),
|
||||
code: code,
|
||||
password: AccountPassword(password: newPassword));
|
||||
try {
|
||||
final response = await accountsStub.newPassword(request);
|
||||
return response;
|
||||
} catch (e) {
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -53,8 +53,8 @@ class _EnvirnomentCardState extends State<EnvirnomentCard> {
|
||||
position: RelativeRect.fromSize(Rect.largest, Size.infinite),
|
||||
context: context,
|
||||
items: [
|
||||
PopupMenuItem(child: Text("test")),
|
||||
PopupMenuItem(child: Text("text")),
|
||||
const PopupMenuItem(child: Text("test")),
|
||||
const PopupMenuItem(child: Text("text")),
|
||||
],
|
||||
),
|
||||
onTap: () => showDialog(
|
||||
|
@ -1,5 +1,4 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:softplayer_web/api/grpc/environments.dart';
|
||||
import 'package:softplayer_web/helpers/providers/common.dart';
|
||||
|
||||
@ -61,7 +60,7 @@ class _EnvirnomentPreviewState extends State<EnvirnomentPreiview> {
|
||||
]),
|
||||
],
|
||||
),
|
||||
Divider(),
|
||||
const Divider(),
|
||||
Table(
|
||||
border: const TableBorder(
|
||||
bottom: BorderSide.none,
|
||||
@ -69,13 +68,13 @@ class _EnvirnomentPreviewState extends State<EnvirnomentPreiview> {
|
||||
right: BorderSide.none,
|
||||
top: BorderSide.none,
|
||||
),
|
||||
children: [
|
||||
children: const [
|
||||
TableRow(children: [
|
||||
const Text("Price per hour"),
|
||||
Text("Price per hour"),
|
||||
Text("0.52"),
|
||||
]),
|
||||
TableRow(children: [
|
||||
const Text("Current usage"),
|
||||
Text("Current usage"),
|
||||
Text("10.5"),
|
||||
]),
|
||||
],
|
||||
@ -84,8 +83,8 @@ class _EnvirnomentPreviewState extends State<EnvirnomentPreiview> {
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
TextButton(onPressed: () => print("lala"), child: Text("test")),
|
||||
TextButton(onPressed: () => print("lala"), child: Text("test")),
|
||||
TextButton(onPressed: () => print("lala"), child: const Text("test")),
|
||||
TextButton(onPressed: () => print("lala"), child: const Text("test")),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ class LoginForm extends StatefulWidget {
|
||||
State<StatefulWidget> createState() => _LoginFormState();
|
||||
}
|
||||
|
||||
enum Action { singIn, signUp }
|
||||
enum Action { singIn, signUp, resetPassword }
|
||||
|
||||
class _LoginFormState extends State<LoginForm> {
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
@ -25,9 +25,11 @@ class _LoginFormState extends State<LoginForm> {
|
||||
final passwordCtrl = TextEditingController();
|
||||
final passwordVerifyCtrl = TextEditingController();
|
||||
final emailCtrl = TextEditingController();
|
||||
final codeCtrl = TextEditingController();
|
||||
|
||||
late AccountsGrpc accountsGrpc;
|
||||
Action action = Action.singIn;
|
||||
bool codeEnabled = false;
|
||||
static const dialogName = "Login";
|
||||
|
||||
void submitSignUp() {
|
||||
@ -71,7 +73,6 @@ class _LoginFormState extends State<LoginForm> {
|
||||
widget.notifyParent();
|
||||
// Navigator.of(context, rootNavigator: true).pop();
|
||||
}).catchError((e) {
|
||||
print(e);
|
||||
GrpcError error = e;
|
||||
String msg;
|
||||
if (error.message != null) {
|
||||
@ -90,6 +91,61 @@ class _LoginFormState extends State<LoginForm> {
|
||||
}
|
||||
}
|
||||
|
||||
void subminResetPassword() {
|
||||
// Validate returns true if the form is valid, or false otherwise.
|
||||
if (_formKey.currentState!.validate()) {
|
||||
final username = usernameCtrl.text;
|
||||
final password = passwordCtrl.text;
|
||||
final code = codeCtrl.text;
|
||||
accountsGrpc.newPassword(username, code, password).then((rs) {
|
||||
action = Action.singIn;
|
||||
// Navigator.of(context, rootNavigator: true).pop();
|
||||
}).catchError((e) {
|
||||
GrpcError error = e;
|
||||
String msg;
|
||||
if (error.message != null) {
|
||||
msg = error.message!;
|
||||
} else {
|
||||
msg = error.toString();
|
||||
}
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content: Text(msg),
|
||||
backgroundColor: Colors.red,
|
||||
showCloseIcon: true,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
));
|
||||
passwordCtrl.clear();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void sendCode() {
|
||||
if (_formKey.currentState!.validate()) {
|
||||
final username = usernameCtrl.text;
|
||||
final email = emailCtrl.text;
|
||||
accountsGrpc
|
||||
.resetPassword(username, email)
|
||||
.then((_) => setState(() {
|
||||
codeEnabled = true;
|
||||
}))
|
||||
.catchError((e) {
|
||||
GrpcError error = e;
|
||||
String msg;
|
||||
if (error.message != null) {
|
||||
msg = error.message!;
|
||||
} else {
|
||||
msg = error.toString();
|
||||
}
|
||||
ScaffoldMessenger.of(context).showSnackBar(SnackBar(
|
||||
content: Text(msg),
|
||||
backgroundColor: Colors.red,
|
||||
showCloseIcon: true,
|
||||
behavior: SnackBarBehavior.floating,
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Widget signInForm() => SizedBox(
|
||||
width: 420,
|
||||
height: 280,
|
||||
@ -122,6 +178,11 @@ class _LoginFormState extends State<LoginForm> {
|
||||
cursorHeight: 18,
|
||||
cursorRadius: const Radius.circular(10),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => setState(() {
|
||||
action = Action.resetPassword;
|
||||
}),
|
||||
child: const Text("reset yomakeur password")),
|
||||
]))));
|
||||
|
||||
List<Widget> signInActions() => [
|
||||
@ -142,13 +203,33 @@ class _LoginFormState extends State<LoginForm> {
|
||||
onPressed: () => setState(() {
|
||||
action = Action.singIn;
|
||||
}),
|
||||
child: const Text('Sing In'),
|
||||
child: const Text('Sign In'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: submitSignUp,
|
||||
child: const Text('OK'),
|
||||
),
|
||||
];
|
||||
|
||||
List<Widget> resetPasswordActions() => [
|
||||
TextButton(
|
||||
onPressed: () => setState(() {
|
||||
action = Action.singIn;
|
||||
}),
|
||||
child: const Text('Sign In'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => setState(() {
|
||||
action = Action.signUp;
|
||||
}),
|
||||
child: const Text('Sing Up'),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: subminResetPassword,
|
||||
child: const Text('OK'),
|
||||
),
|
||||
];
|
||||
|
||||
Widget signUpForm() => SizedBox(
|
||||
width: 420,
|
||||
height: 280,
|
||||
@ -207,6 +288,86 @@ class _LoginFormState extends State<LoginForm> {
|
||||
cursorRadius: const Radius.circular(10),
|
||||
),
|
||||
]))));
|
||||
Widget resetPasswordForm() => SizedBox(
|
||||
width: 420,
|
||||
height: 420,
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Center(
|
||||
child: Column(children: [
|
||||
TextFormField(
|
||||
// onFieldSubmitted: (value) => submitSignUp(),
|
||||
autofocus: true,
|
||||
controller: usernameCtrl,
|
||||
decoration: const InputDecoration(
|
||||
hintText: "Enter your username",
|
||||
icon: Icon(Icons.account_circle),
|
||||
label: Text("Username"),
|
||||
),
|
||||
cursorWidth: 1,
|
||||
cursorHeight: 18,
|
||||
cursorRadius: const Radius.circular(10),
|
||||
),
|
||||
TextFormField(
|
||||
// onFieldSubmitted: (value) => submitSignUp(),
|
||||
controller: emailCtrl,
|
||||
autofocus: true,
|
||||
decoration: const InputDecoration(
|
||||
hintText: "Enter your email",
|
||||
icon: Icon(Icons.email),
|
||||
label: Text("Email"),
|
||||
),
|
||||
cursorWidth: 1,
|
||||
cursorHeight: 18,
|
||||
cursorRadius: const Radius.circular(10),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () => sendCode(), child: const Text("send code to email")),
|
||||
TextFormField(
|
||||
// onFieldSubmitted: (value) => submitSignUp(),
|
||||
controller: codeCtrl,
|
||||
autofocus: false,
|
||||
enabled: codeEnabled,
|
||||
decoration: const InputDecoration(
|
||||
hintText: "Enter code that you've received via the email",
|
||||
icon: Icon(Icons.numbers),
|
||||
label: Text("Code"),
|
||||
),
|
||||
cursorWidth: 1,
|
||||
cursorHeight: 18,
|
||||
cursorRadius: const Radius.circular(10),
|
||||
),
|
||||
TextFormField(
|
||||
// onFieldSubmitted: (value) => submitSignUp(),
|
||||
controller: passwordCtrl,
|
||||
autofocus: false,
|
||||
enabled: codeEnabled,
|
||||
obscureText: true,
|
||||
decoration: const InputDecoration(
|
||||
hintText: "Enter a new password",
|
||||
icon: Icon(Icons.password),
|
||||
label: Text("Password"),
|
||||
),
|
||||
cursorWidth: 1,
|
||||
cursorHeight: 18,
|
||||
cursorRadius: const Radius.circular(10),
|
||||
),
|
||||
TextFormField(
|
||||
// onFieldSubmitted: (value) => submitSignUp(),
|
||||
controller: passwordVerifyCtrl,
|
||||
autofocus: false,
|
||||
enabled: codeEnabled,
|
||||
obscureText: true,
|
||||
decoration: const InputDecoration(
|
||||
hintText: "Enter a new password",
|
||||
icon: Icon(Icons.password),
|
||||
label: Text("Password"),
|
||||
),
|
||||
cursorWidth: 1,
|
||||
cursorHeight: 18,
|
||||
cursorRadius: const Radius.circular(10),
|
||||
),
|
||||
]))));
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -217,8 +378,26 @@ class _LoginFormState extends State<LoginForm> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => AlertDialog(
|
||||
title: const Text(dialogName),
|
||||
content: action == Action.singIn ? signInForm() : signUpForm(),
|
||||
actions: action == Action.singIn ? signInActions() : signUpActions(),
|
||||
);
|
||||
title: const Text(dialogName),
|
||||
// content: action == Action.singIn ? signInForm() : signUpForm(),
|
||||
content: () {
|
||||
switch (action) {
|
||||
case Action.signUp:
|
||||
return signUpForm();
|
||||
case Action.resetPassword:
|
||||
return resetPasswordForm();
|
||||
default:
|
||||
return signInForm();
|
||||
}
|
||||
}(),
|
||||
actions: () {
|
||||
switch (action) {
|
||||
case Action.signUp:
|
||||
return signUpActions();
|
||||
case Action.resetPassword:
|
||||
return resetPasswordActions();
|
||||
default:
|
||||
return signInActions();
|
||||
}
|
||||
}());
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'dart:html';
|
||||
|
||||
import 'package:flutter_dotenv/flutter_dotenv.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:grpc/grpc_web.dart';
|
||||
import 'package:softplayer_web/api/grpc/accounts.dart';
|
||||
@ -9,10 +10,8 @@ import 'package:softplayer_web/components/environments.dart';
|
||||
import 'package:softplayer_web/components/login_form.dart';
|
||||
|
||||
void main() async {
|
||||
const String backendURL = String.fromEnvironment(
|
||||
'SOFTPLAYER_BACKEND_URL',
|
||||
defaultValue: 'https://softplayer-backend.badhouseplants.net:8080',
|
||||
);
|
||||
await dotenv.load(fileName: ".env");
|
||||
String backendURL = dotenv.env['SOFTPLAYER_BACKEND_URL']!;
|
||||
GrpcWebClientChannel grpcChannel =
|
||||
GrpcWebClientChannel.xhr(Uri.parse(backendURL));
|
||||
|
||||
|
14
pubspec.lock
14
pubspec.lock
@ -5,10 +5,10 @@ packages:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: archive
|
||||
sha256: "0763b45fa9294197a2885c8567927e2830ade852e5c896fd4ab7e0e348d0f373"
|
||||
sha256: ecf4273855368121b1caed0d10d4513c7241dfc813f7d3c8933b36622ae9b265
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "3.5.0"
|
||||
version: "3.5.1"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
@ -102,6 +102,14 @@ packages:
|
||||
description: flutter
|
||||
source: sdk
|
||||
version: "0.0.0"
|
||||
flutter_dotenv:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: flutter_dotenv
|
||||
sha256: "9357883bdd153ab78cbf9ffa07656e336b8bbb2b5a3ca596b0b27e119f7c7d77"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "5.1.0"
|
||||
flutter_lints:
|
||||
dependency: "direct dev"
|
||||
description:
|
||||
@ -245,7 +253,7 @@ packages:
|
||||
description:
|
||||
path: "."
|
||||
ref: main
|
||||
resolved-ref: "3bf6e1bef80350848f0f0407685e4eaf868d4c7e"
|
||||
resolved-ref: "5ee911c92eee4ee7db58a2da0407da4f7db2f994"
|
||||
url: "https://git.badhouseplants.net/softplayer/softplayer-dart-proto.git"
|
||||
source: git
|
||||
version: "1.0.0+1"
|
||||
|
@ -18,6 +18,7 @@ dependencies:
|
||||
grpc: ^3.2.4
|
||||
http: ^1.2.1
|
||||
dio: ^5.4.2
|
||||
flutter_dotenv: ^5.1.0
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
@ -28,3 +29,4 @@ flutter:
|
||||
uses-material-design: true
|
||||
assets:
|
||||
- assets/
|
||||
- .env
|
Loading…
Reference in New Issue
Block a user