All checks were successful
continuous-integration/drone/push Build is passing
372 lines
10 KiB
Dart
372 lines
10 KiB
Dart
// Copyright (C) 2022 WYATT GROUP
|
|
// Please see the AUTHORS file for details.
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
// ignore_for_file: public_member_api_docs, sort_constructors_first
|
|
import 'dart:convert';
|
|
|
|
import 'package:wyatt_http_client/src/middleware_client.dart';
|
|
import 'package:wyatt_http_client/src/middlewares/body_to_json_middleware.dart';
|
|
import 'package:wyatt_http_client/src/middlewares/refresh_token_auth_middleware.dart';
|
|
import 'package:wyatt_http_client/src/middlewares/simple_logger_middleware.dart';
|
|
import 'package:wyatt_http_client/src/middlewares/uri_prefix_middleware.dart';
|
|
import 'package:wyatt_http_client/src/pipeline.dart';
|
|
import 'package:wyatt_http_client/src/utils/http_status.dart';
|
|
import 'package:wyatt_http_client/src/utils/protocols.dart';
|
|
|
|
enum EmailVerificationAction {
|
|
signUp,
|
|
resetPassword,
|
|
changeEmail;
|
|
|
|
String toSnakeCase() => name.splitMapJoin(
|
|
RegExp('[A-Z]'),
|
|
onMatch: (m) => '_${m[0]?.toLowerCase()}',
|
|
onNonMatch: (n) => n,
|
|
);
|
|
|
|
factory EmailVerificationAction.fromString(String str) =>
|
|
EmailVerificationAction.values.firstWhere(
|
|
(element) => element.toSnakeCase() == str,
|
|
);
|
|
}
|
|
|
|
class VerifyCode {
|
|
final String email;
|
|
final String verificationCode;
|
|
final EmailVerificationAction action;
|
|
VerifyCode({
|
|
required this.email,
|
|
required this.verificationCode,
|
|
required this.action,
|
|
});
|
|
|
|
VerifyCode copyWith({
|
|
String? email,
|
|
String? verificationCode,
|
|
EmailVerificationAction? action,
|
|
}) =>
|
|
VerifyCode(
|
|
email: email ?? this.email,
|
|
verificationCode: verificationCode ?? this.verificationCode,
|
|
action: action ?? this.action,
|
|
);
|
|
|
|
Map<String, dynamic> toMap() => <String, dynamic>{
|
|
'email': email,
|
|
'verification_code': verificationCode,
|
|
'action': action.toSnakeCase(),
|
|
};
|
|
|
|
factory VerifyCode.fromMap(Map<String, dynamic> map) => VerifyCode(
|
|
email: map['email'] as String,
|
|
verificationCode: map['verification_code'] as String,
|
|
action: EmailVerificationAction.fromString(map['action'] as String),
|
|
);
|
|
|
|
String toJson() => json.encode(toMap());
|
|
|
|
factory VerifyCode.fromJson(String source) =>
|
|
VerifyCode.fromMap(json.decode(source) as Map<String, dynamic>);
|
|
|
|
@override
|
|
String toString() => 'VerifyCode(email: $email, verificationCode: '
|
|
'$verificationCode, action: $action)';
|
|
}
|
|
|
|
class Account {
|
|
final String email;
|
|
final String? sessionId;
|
|
Account({
|
|
required this.email,
|
|
this.sessionId,
|
|
});
|
|
|
|
Account copyWith({
|
|
String? email,
|
|
String? sessionId,
|
|
}) =>
|
|
Account(
|
|
email: email ?? this.email,
|
|
sessionId: sessionId ?? this.sessionId,
|
|
);
|
|
|
|
Map<String, dynamic> toMap() => <String, dynamic>{
|
|
'email': email,
|
|
'session_id': sessionId,
|
|
};
|
|
|
|
factory Account.fromMap(Map<String, dynamic> map) => Account(
|
|
email: map['email'] as String,
|
|
sessionId:
|
|
map['session_id'] != null ? map['session_id'] as String : null,
|
|
);
|
|
|
|
String toJson() => json.encode(toMap());
|
|
|
|
factory Account.fromJson(String source) =>
|
|
Account.fromMap(json.decode(source) as Map<String, dynamic>);
|
|
|
|
@override
|
|
String toString() => 'Account(email: $email, sessionId: $sessionId)';
|
|
}
|
|
|
|
class SignUp {
|
|
final String sessionId;
|
|
final String password;
|
|
SignUp({
|
|
required this.sessionId,
|
|
required this.password,
|
|
});
|
|
|
|
SignUp copyWith({
|
|
String? sessionId,
|
|
String? password,
|
|
}) =>
|
|
SignUp(
|
|
sessionId: sessionId ?? this.sessionId,
|
|
password: password ?? this.password,
|
|
);
|
|
|
|
Map<String, dynamic> toMap() => <String, dynamic>{
|
|
'session_id': sessionId,
|
|
'password': password,
|
|
};
|
|
|
|
factory SignUp.fromMap(Map<String, dynamic> map) => SignUp(
|
|
sessionId: map['session_id'] as String,
|
|
password: map['password'] as String,
|
|
);
|
|
|
|
String toJson() => json.encode(toMap());
|
|
|
|
factory SignUp.fromJson(String source) =>
|
|
SignUp.fromMap(json.decode(source) as Map<String, dynamic>);
|
|
|
|
@override
|
|
String toString() => 'SignUp(sessionId: $sessionId, password: $password)';
|
|
}
|
|
|
|
class TokenSuccess {
|
|
final String accessToken;
|
|
final String refreshToken;
|
|
final Account account;
|
|
TokenSuccess({
|
|
required this.accessToken,
|
|
required this.refreshToken,
|
|
required this.account,
|
|
});
|
|
|
|
TokenSuccess copyWith({
|
|
String? accessToken,
|
|
String? refreshToken,
|
|
Account? account,
|
|
}) =>
|
|
TokenSuccess(
|
|
accessToken: accessToken ?? this.accessToken,
|
|
refreshToken: refreshToken ?? this.refreshToken,
|
|
account: account ?? this.account,
|
|
);
|
|
|
|
Map<String, dynamic> toMap() => <String, dynamic>{
|
|
'access_token': accessToken,
|
|
'refresh_token': refreshToken,
|
|
'account': account.toMap(),
|
|
};
|
|
|
|
factory TokenSuccess.fromMap(Map<String, dynamic> map) => TokenSuccess(
|
|
accessToken: map['access_token'] as String,
|
|
refreshToken: map['refresh_token'] as String,
|
|
account: Account.fromMap(map['account'] as Map<String, dynamic>),
|
|
);
|
|
|
|
String toJson() => json.encode(toMap());
|
|
|
|
factory TokenSuccess.fromJson(String source) =>
|
|
TokenSuccess.fromMap(json.decode(source) as Map<String, dynamic>);
|
|
|
|
@override
|
|
String toString() => 'TokenSuccess(accessToken: $accessToken, refreshToken: '
|
|
'$refreshToken, account: $account)';
|
|
}
|
|
|
|
class Login {
|
|
final String email;
|
|
final String password;
|
|
Login({
|
|
required this.email,
|
|
required this.password,
|
|
});
|
|
|
|
Login copyWith({
|
|
String? email,
|
|
String? password,
|
|
}) =>
|
|
Login(
|
|
email: email ?? this.email,
|
|
password: password ?? this.password,
|
|
);
|
|
|
|
Map<String, dynamic> toMap() => <String, dynamic>{
|
|
'email': email,
|
|
'password': password,
|
|
};
|
|
|
|
factory Login.fromMap(Map<String, dynamic> map) => Login(
|
|
email: map['email'] as String,
|
|
password: map['password'] as String,
|
|
);
|
|
|
|
String toJson() => json.encode(toMap());
|
|
|
|
factory Login.fromJson(String source) =>
|
|
Login.fromMap(json.decode(source) as Map<String, dynamic>);
|
|
|
|
@override
|
|
String toString() => 'Login(email: $email, password: $password)';
|
|
}
|
|
|
|
class FastAPI {
|
|
final String baseUrl;
|
|
final MiddlewareClient client;
|
|
final int apiVersion;
|
|
|
|
FastAPI({
|
|
this.baseUrl = 'localhost:80',
|
|
MiddlewareClient? client,
|
|
this.apiVersion = 1,
|
|
}) : client = client ?? MiddlewareClient();
|
|
|
|
String get apiPath => '/api/v$apiVersion';
|
|
|
|
Future<void> sendSignUpCode(String email) async {
|
|
final r = await client.post(
|
|
Uri.parse('$apiPath/auth/send-sign-up-code'),
|
|
body: <String, String>{
|
|
'email': email,
|
|
},
|
|
);
|
|
if (r.statusCode != 201) {
|
|
throw Exception('Invalid reponse: ${r.statusCode}');
|
|
}
|
|
}
|
|
|
|
Future<Account> verifyCode(VerifyCode verifyCode) async {
|
|
final r = await client.post(
|
|
Uri.parse('$apiPath/auth/verify-code'),
|
|
body: verifyCode.toMap(),
|
|
);
|
|
if (r.statusCode != 202) {
|
|
throw Exception('Invalid reponse: ${r.statusCode}');
|
|
} else {
|
|
return Account.fromMap(
|
|
(jsonDecode(r.body) as Map<String, dynamic>)['account']
|
|
as Map<String, dynamic>,
|
|
);
|
|
}
|
|
}
|
|
|
|
Future<Account> signUp(SignUp signUp) async {
|
|
final r = await client.post(
|
|
Uri.parse('$apiPath/auth/sign-up'),
|
|
body: signUp.toMap(),
|
|
);
|
|
if (r.statusCode != 201) {
|
|
throw Exception('Invalid reponse: ${r.statusCode}');
|
|
} else {
|
|
return Account.fromJson(r.body);
|
|
}
|
|
}
|
|
|
|
Future<TokenSuccess> signInWithPassword(Login login) async {
|
|
final r = await client.post(
|
|
Uri.parse('$apiPath/auth/sign-in-with-password'),
|
|
body: login.toMap(),
|
|
);
|
|
if (r.statusCode != 200) {
|
|
throw Exception('Invalid reponse: ${r.statusCode}');
|
|
} else {
|
|
return TokenSuccess.fromJson(r.body);
|
|
}
|
|
}
|
|
|
|
// Future<TokenSuccess> refresh() async {
|
|
// final r = await client.refresh();
|
|
// return TokenSuccess.fromJson(r?.body ?? '');
|
|
// }
|
|
|
|
Future<List<Account>> getAccountList() async {
|
|
final r = await client.get(
|
|
Uri.parse('$apiPath/account'),
|
|
);
|
|
if (r.statusCode != 200) {
|
|
throw Exception('Invalid reponse: ${r.statusCode}');
|
|
} else {
|
|
final list = (jsonDecode(r.body) as Map<String, dynamic>)['founds']
|
|
as List<Map<String, dynamic>>;
|
|
final result = <Account>[];
|
|
for (final element in list) {
|
|
result.add(Account.fromMap(element));
|
|
}
|
|
return result;
|
|
}
|
|
}
|
|
}
|
|
|
|
void main(List<String> args) async {
|
|
final Pipeline pipeline = Pipeline()
|
|
.addMiddleware(
|
|
UriPrefixMiddleware(
|
|
protocol: Protocols.http,
|
|
authority: 'localhost:80',
|
|
),
|
|
)
|
|
.addMiddleware(BodyToJsonMiddleware())
|
|
.addMiddleware(
|
|
RefreshTokenAuthMiddleware(
|
|
authorizationEndpoint: '/api/v1/auth/sign-in-with-password',
|
|
tokenEndpoint: '/api/v1/auth/refresh',
|
|
accessTokenParser: (body) => body['access_token']! as String,
|
|
refreshTokenParser: (body) => body['refresh_token']! as String,
|
|
unauthorized: HttpStatus.forbidden,
|
|
),
|
|
)
|
|
.addMiddleware(SimpleLoggerMiddleware());
|
|
|
|
print(pipeline);
|
|
final client = MiddlewareClient(pipeline: pipeline);
|
|
|
|
final api = FastAPI(
|
|
client: client,
|
|
);
|
|
|
|
await api.sendSignUpCode('git@pcl.ovh');
|
|
// final verifiedAccount = await api.verifyCode(
|
|
// VerifyCode(
|
|
// email: 'git@pcl.ovh',
|
|
// verificationCode: '000000000',
|
|
// action: EmailVerificationAction.signUp,
|
|
// ),
|
|
// );
|
|
// final registeredAccount = await api.signUp(
|
|
// SignUp(sessionId: verifiedAccount.sessionId ?? '', password: 'password'),
|
|
// );
|
|
// final signedInAccount = await api.signInWithPassword(
|
|
// Login(email: 'git@pcl.ovh', password: 'password'),
|
|
// );
|
|
final accountList = await api.getAccountList();
|
|
print(accountList);
|
|
}
|