lib/src/operations/version1/SessionOperationsV1.dart
import 'dart:async';
import 'dart:convert';
import 'package:pip_facade_sample_dart/pip_facade_sample_dart.dart';
import 'package:pip_clients_accounts/pip_clients_accounts.dart';
import 'package:pip_clients_passwords/pip_clients_passwords.dart';
import 'package:pip_clients_roles/pip_clients_roles.dart';
import 'package:pip_clients_sessions/pip_clients_sessions.dart';
import 'package:pip_services3_commons/pip_services3_commons.dart';
import 'package:pip_services3_rpc/pip_services3_rpc.dart';
import 'package:pip_services_accounts/pip_services_accounts.dart';
import 'package:pip_services_passwords/pip_services_passwords.dart';
import 'package:pip_services_sessions/pip_services_sessions.dart';
import 'package:shelf_router/shelf_router.dart';
import 'package:shelf/shelf.dart';
class SessionsOperationsV1 extends RestOperations {
final ConfigParams _defaultConfig1 = ConfigParams.fromTuples([
[
'options.cookie_enabled',
true,
'options.cookie',
'x-session-id',
'options.max_cookie_age',
365 * 24 * 60 * 60 * 1000
]
]);
String _cookie = 'x-session-id';
bool _cookieEnabled = true;
int _maxCookieAge = 365 * 24 * 60 * 60 * 1000;
late IAccountsClientV1 _accountsClient;
late ISessionsClientV1 _sessionsClient;
late IPasswordsClientV1 _passwordsClient;
late IRolesClientV1 _rolesClient;
SessionsOperationsV1() : super.withName('sessionsOperations') {
dependencyResolver.put('accounts',
Descriptor('pip-services-accounts', 'client', '*', '*', '1.0'));
dependencyResolver.put('passwords',
Descriptor('pip-services-passwords', 'client', '*', '*', '1.0'));
dependencyResolver.put(
'roles', Descriptor('pip-services-roles', 'client', '*', '*', '1.0'));
dependencyResolver.put('sessions',
Descriptor('pip-services-sessions', 'client', '*', '*', '1.0'));
}
@override
void configure(ConfigParams config) {
config = config.setDefaults(_defaultConfig1);
dependencyResolver.configure(config);
_cookieEnabled = config.getAsBooleanWithDefault(
'options.cookie_enabled', _cookieEnabled);
_cookie = config.getAsStringWithDefault('options.cookie', _cookie);
_maxCookieAge =
config.getAsLongWithDefault('options.max_cookie_age', _maxCookieAge);
}
@override
void setReferences(IReferences references) {
super.setReferences(references);
_sessionsClient =
dependencyResolver.getOneRequired<ISessionsClientV1>('sessions');
_accountsClient =
dependencyResolver.getOneRequired<IAccountsClientV1>('accounts');
_passwordsClient =
dependencyResolver.getOneRequired<IPasswordsClientV1>('passwords');
_rolesClient = dependencyResolver.getOneRequired<IRolesClientV1>('roles');
}
Future loadSession(Request req) async {
// Is user really cached? If yes, then we shall reinvalidate cache when connections are changed
// if (req.user) {
// callback(null, req.user);
// return;
// }
// parse headers first, and if nothing in headers get cookie
var correlationId = getCorrelationId(req);
var sessionId = req.headers['x-session-id'];
if (sessionId != null && sessionId.isNotEmpty) {
var result = await _sessionsClient.getSessionById(
correlationId ?? 'facade', sessionId);
if (result == null) {
throw UnauthorizedException('facade', 'SESSION_NOT_FOUND',
'Session invalid or already expired.')
.withDetails('session_id', sessionId)
.withStatus(440);
} else {
// Associate session user with the request
var user = {
'user': {
'user_id': result.user_id as Object,
'user_name': result.user_name as Object,
'user': result.user as Object,
'session_id': result.id as Object
}
};
req = req.change(context: user);
}
}
return req;
}
FutureOr<Response> openSession(
Request req, AccountV1 account, List<String> roles) async {
SessionV1? session;
UserPasswordInfoV1? passwordInfo;
var settings = ConfigParams();
print('open session');
try {
passwordInfo = await _passwordsClient.getPasswordInfo(null, account.id!);
// Open a new user session
var user = SessionUserV1(
id: account.id,
name: account.name,
login: account.login,
create_time: account.create_time,
time_zone: account.time_zone,
language: account.language,
theme: account.theme,
roles: roles,
settings: settings,
change_pwd_time:
passwordInfo != null ? passwordInfo.change_time : null,
custom_hdr: account.custom_hdr,
custom_dat: account.custom_dat);
var address = HttpRequestDetector.detectAddress(req);
var client = HttpRequestDetector.detectBrowser(req);
session = await _sessionsClient.openSession(
null, account.id, account.name, address, client, user, null);
return sendResult(req, null, session);
} catch (ex) {
return sendError(req, ex);
}
}
FutureOr<Response> signup(Request req) async {
try {
var signupData = jsonDecode(await req.readAsString());
AccountV1? account;
List<String> roles =
signupData['roles'] != null && signupData['roles'] is List
? signupData['roles']
: [];
// Create account
var newAccount = AccountV1(
name: signupData['name'],
login: signupData['login'] ??
signupData['email'], // Use email by default
language: signupData['language'],
theme: signupData['theme'],
time_zone: signupData['time_zone']);
account = await _accountsClient.createAccount(null, newAccount);
// Create password for the account
var password = signupData['password'];
await _passwordsClient.setPassword(null, account!.id!, password);
// Create roles for the account
if (roles.isNotEmpty) {
await _rolesClient.grantRoles(null, account.id!, roles);
}
return await openSession(req, account, roles);
} catch (ex) {
return await sendError(req, ex);
}
}
// Future signupValidate(RequestContext req, ResponseContext res) async {
// await safeInvoke(req, res, componentName + '.signupValidate', () async {
// var correlationId = getCorrelationId(req) ?? 'facade';
// var login = req.params['login'] ?? req.queryParameters['login'];
// if (login) {
// var result =
// await _accountsClient.getAccountByIdOrLogin(correlationId, login);
// if (result != null) {
// throw BadRequestException(correlationId, 'LOGIN_ALREADY_USED',
// 'Login ' + login + ' already being used')
// .withDetails('login', login);
// }
// } else {
// await sendEmptyResult(req, res, null);
// }
// }, (ex) {
// sendError(req, res, ex);
// });
// }
FutureOr<Response> signin(Request req) async {
try {
var body = await req.readAsString();
var json = body.isNotEmpty ? jsonDecode(body) : {};
var login = json['login'];
var password = json['password'];
AccountV1? account;
List<String> roles;
// Find user account
account = await _accountsClient.getAccountByIdOrLogin(null, login ?? '');
if (account == null) {
throw BadRequestException(null, 'WRONG_LOGIN',
'Account ' + login.toString() + ' was not found')
.withDetails('login', login);
}
// Authenticate user
var result =
await _passwordsClient.authenticate(null, account.id!, password!);
if (result == false) {
throw BadRequestException(null, 'WRONG_PASSWORD',
'Wrong password for account ' + login.toString())
.withDetails('login', login);
}
// Retrieve user roles
roles = await _rolesClient.getRolesById(null, account.id!) ?? [];
return await openSession(req, account, roles);
} catch (ex) {
return await sendError(req, ex);
}
}
FutureOr<Response> signout(Request req) async {
if (req.headers['session_id'] != null) {
try {
await _sessionsClient.closeSession(null, req.headers['session_id']!);
return await sendEmptyResult(req, null);
} catch (ex) {
return await sendError(req, ex);
}
}
return await sendEmptyResult(req, null);
}
}