// 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 .
// 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_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() {
return name.splitMapJoin(
RegExp('[A-Z]'),
onMatch: (m) => '_${m[0]?.toLowerCase()}',
onNonMatch: (n) => n,
);
}
factory EmailVerificationAction.fromString(String str) {
return EmailVerificationAction.values.firstWhere(
(EmailVerificationAction 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,
}) {
return VerifyCode(
email: email ?? this.email,
verificationCode: verificationCode ?? this.verificationCode,
action: action ?? this.action,
);
}
Map toMap() {
return {
'email': email,
'verification_code': verificationCode,
'action': action.toSnakeCase(),
};
}
factory VerifyCode.fromMap(Map map) {
return 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);
@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,
}) {
return Account(
email: email ?? this.email,
sessionId: sessionId ?? this.sessionId,
);
}
Map toMap() {
return {
'email': email,
'session_id': sessionId,
};
}
factory Account.fromMap(Map map) {
return 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);
@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,
}) {
return SignUp(
sessionId: sessionId ?? this.sessionId,
password: password ?? this.password,
);
}
Map toMap() {
return {
'session_id': sessionId,
'password': password,
};
}
factory SignUp.fromMap(Map map) {
return 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);
@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,
}) {
return TokenSuccess(
accessToken: accessToken ?? this.accessToken,
refreshToken: refreshToken ?? this.refreshToken,
account: account ?? this.account,
);
}
Map toMap() {
return {
'access_token': accessToken,
'refresh_token': refreshToken,
'account': account.toMap(),
};
}
factory TokenSuccess.fromMap(Map map) {
return TokenSuccess(
accessToken: map['access_token'] as String,
refreshToken: map['refresh_token'] as String,
account: Account.fromMap(map['account'] as Map),
);
}
String toJson() => json.encode(toMap());
factory TokenSuccess.fromJson(String source) =>
TokenSuccess.fromMap(json.decode(source) as Map);
@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,
}) {
return Login(
email: email ?? this.email,
password: password ?? this.password,
);
}
Map toMap() {
return {
'email': email,
'password': password,
};
}
factory Login.fromMap(Map map) {
return 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);
@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 sendSignUpCode(String email) async {
final r = await client.post(
Uri.parse('$apiPath/auth/send-sign-up-code'),
body: {
'email': email,
},
);
if (r.statusCode != 201) {
throw Exception('Invalid reponse: ${r.statusCode}');
}
}
Future 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)['account']
as Map,
);
}
}
Future 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 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 refresh() async {
// final r = await client.refresh();
// return TokenSuccess.fromJson(r?.body ?? '');
// }
Future> 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)['founds']
as List