Frontend first draft
This commit is contained in:
61
frontend/pshared/lib/service/account.dart
Normal file
61
frontend/pshared/lib/service/account.dart
Normal file
@@ -0,0 +1,61 @@
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
import 'package:pshared/api/requests/signup.dart';
|
||||
import 'package:pshared/api/responses/account.dart';
|
||||
import 'package:pshared/api/requests/change_password.dart';
|
||||
import 'package:pshared/data/mapper/account/account.dart';
|
||||
import 'package:pshared/models/account/account.dart';
|
||||
import 'package:pshared/service/authorization/service.dart';
|
||||
import 'package:pshared/service/files.dart';
|
||||
import 'package:pshared/service/services.dart';
|
||||
import 'package:pshared/utils/http/requests.dart';
|
||||
|
||||
|
||||
class AccountService {
|
||||
static final _logger = Logger('service.account');
|
||||
static const String _objectType = Services.account;
|
||||
|
||||
static Future<Account> login(String email, String password, String locale) async {
|
||||
_logger.fine('Logging in');
|
||||
return AuthorizationService.login(_objectType, email, password, locale);
|
||||
}
|
||||
|
||||
static Future<Account> restore() async {
|
||||
return AuthorizationService.restore();
|
||||
}
|
||||
|
||||
static Future<void> signup(SignupRequest request) async {
|
||||
await getPOSTResponse(_objectType, 'signup', request.toJson());
|
||||
}
|
||||
|
||||
static Future<void> logout() async {
|
||||
_logger.fine('Logging out');
|
||||
await AuthorizationService.logout();
|
||||
}
|
||||
|
||||
static Future<Account> _getAccount(Future<Map<String, dynamic>> future) async {
|
||||
final response = await future;
|
||||
return AccountResponse.fromJson(response).account.toDomain();
|
||||
}
|
||||
|
||||
static Future<Account> update(Account account) async {
|
||||
_logger.fine('Patching account ${account.id}');
|
||||
return _getAccount(AuthorizationService.getPUTResponse(_objectType, '', account.toDTO().toJson()));
|
||||
}
|
||||
|
||||
static Future<Account> changePassword(String oldPassword, String newPassword) async {
|
||||
_logger.fine('Changing password');
|
||||
return _getAccount(AuthorizationService.getPATCHResponse(
|
||||
_objectType,
|
||||
'password',
|
||||
ChangePassword(oldPassword: oldPassword, newPassword: newPassword).toJson(),
|
||||
));
|
||||
}
|
||||
|
||||
static Future<String> uploadAvatar(String id, XFile avatarFile) async {
|
||||
_logger.fine('Uploading avatar');
|
||||
return FilesService.uploadImage(_objectType, id, avatarFile);
|
||||
}
|
||||
}
|
||||
35
frontend/pshared/lib/service/accounts/employees.dart
Normal file
35
frontend/pshared/lib/service/accounts/employees.dart
Normal file
@@ -0,0 +1,35 @@
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'package:pshared/api/errors/unauthorized.dart';
|
||||
import 'package:pshared/api/responses/employees.dart';
|
||||
import 'package:pshared/models/organization/employee.dart';
|
||||
import 'package:pshared/data/mapper/account/account.dart';
|
||||
import 'package:pshared/service/authorization/service.dart';
|
||||
import 'package:pshared/service/services.dart';
|
||||
|
||||
|
||||
class EmployeesService {
|
||||
static final _logger = Logger('service.employees');
|
||||
static const String _objectType = Services.account;
|
||||
|
||||
static Future<List<Employee>> list(String organizationRef) async {
|
||||
_logger.fine('Loading organization employees');
|
||||
return _getEmployees(AuthorizationService.getGETResponse(_objectType, '/list/$organizationRef'));
|
||||
}
|
||||
|
||||
|
||||
static Future<List<Employee>> _getEmployees(Future<Map<String, dynamic>> future) async {
|
||||
try {
|
||||
final responseJson = await future;
|
||||
final response = EmployeesResponse.fromJson(responseJson);
|
||||
final accounts = response.accounts.map((dto) => dto.toDomain()).toList();
|
||||
|
||||
if (accounts.isEmpty) throw ErrorUnauthorized();
|
||||
_logger.fine('Fetched ${accounts.length} account(s)');
|
||||
return accounts;
|
||||
} catch (e, stackTrace) {
|
||||
_logger.severe('Failed to fetch accounts', e, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
89
frontend/pshared/lib/service/authorization/service.dart
Normal file
89
frontend/pshared/lib/service/authorization/service.dart
Normal file
@@ -0,0 +1,89 @@
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'package:pshared/api/errors/upload_failed.dart';
|
||||
import 'package:pshared/api/requests/login.dart';
|
||||
import 'package:pshared/api/responses/account.dart';
|
||||
import 'package:pshared/api/responses/login.dart';
|
||||
import 'package:pshared/config/constants.dart';
|
||||
import 'package:pshared/data/mapper/account/account.dart';
|
||||
import 'package:pshared/models/account/account.dart';
|
||||
import 'package:pshared/service/authorization/storage.dart';
|
||||
import 'package:pshared/service/authorization/token.dart';
|
||||
import 'package:pshared/service/device_id.dart';
|
||||
import 'package:pshared/utils/http/requests.dart' as httpr;
|
||||
|
||||
|
||||
class AuthorizationService {
|
||||
static final _logger = Logger('service.authorization');
|
||||
|
||||
static Future<void> _updateAccessToken(AccountResponse response) async {
|
||||
await AuthorizationStorage.updateToken(response.accessToken);
|
||||
}
|
||||
|
||||
static Future<void> _updateTokens(LoginResponse response) async {
|
||||
await _updateAccessToken(response);
|
||||
return AuthorizationStorage.updateRefreshToken(response.refreshToken);
|
||||
}
|
||||
|
||||
static Future<LoginResponse> _completeLogin(Map<String, dynamic> response) async {
|
||||
final LoginResponse lr = LoginResponse.fromJson(response);
|
||||
await _updateTokens(lr);
|
||||
return lr;
|
||||
}
|
||||
|
||||
static Future<Account> login(String service, String email, String password, String locale) async {
|
||||
_logger.fine('Logging in $email with $locale locale');
|
||||
final deviceId = await DeviceIdManager.getDeviceId();
|
||||
final response = await httpr.getPOSTResponse(
|
||||
service,
|
||||
'/login',
|
||||
LoginRequest(
|
||||
login: email.toLowerCase(),
|
||||
password: password,
|
||||
locale: locale,
|
||||
deviceId: deviceId,
|
||||
clientId: Constants.clientId,
|
||||
).toJson());
|
||||
|
||||
return (await _completeLogin(response)).account.toDomain();
|
||||
}
|
||||
|
||||
static Future<Account> restore() async {
|
||||
return (await TokenService.rotateRefreshToken()).account.toDomain();
|
||||
}
|
||||
|
||||
static Future<void> logout() async {
|
||||
return AuthorizationStorage.removeTokens();
|
||||
}
|
||||
|
||||
static Future<Map<String, dynamic>> _authenticatedRequest(
|
||||
String service,
|
||||
String url,
|
||||
Future<Map<String, dynamic>> Function(String, String, Map<String, dynamic>, {String? authToken}) requestType,
|
||||
{Map<String, dynamic>? body}) async {
|
||||
final accessToken = await TokenService.getAccessToken();
|
||||
return requestType(service, url, body ?? {}, authToken: accessToken);
|
||||
}
|
||||
|
||||
static Future<Map<String, dynamic>> getPOSTResponse(String service, String url, Map<String, dynamic> body) async => _authenticatedRequest(service, url, httpr.getPOSTResponse, body: body);
|
||||
|
||||
static Future<Map<String, dynamic>> getGETResponse(String service, String url) async {
|
||||
final accessToken = await TokenService.getAccessToken();
|
||||
return httpr.getGETResponse(service, url, authToken: accessToken);
|
||||
}
|
||||
|
||||
static Future<Map<String, dynamic>> getPUTResponse(String service, String url, Map<String, dynamic> body) async => _authenticatedRequest(service, url, httpr.getPUTResponse, body: body);
|
||||
|
||||
static Future<Map<String, dynamic>> getPATCHResponse(String service, String url, Map<String, dynamic> body) async => _authenticatedRequest(service, url, httpr.getPATCHResponse, body: body);
|
||||
|
||||
static Future<Map<String, dynamic>> getDELETEResponse(String service, String url, Map<String, dynamic> body) async => _authenticatedRequest(service, url, httpr.getDELETEResponse, body: body);
|
||||
|
||||
static Future<String> getFileUploadResponseAuth(String service, String url, String fileName, String fileType, String mediaType, List<int> bytes) async {
|
||||
final accessToken = await TokenService.getAccessToken();
|
||||
final res = await httpr.getFileUploadResponse(service, url, fileName, fileType, mediaType, bytes, authToken: accessToken);
|
||||
if (res == null) {
|
||||
throw ErrorUploadFailed();
|
||||
}
|
||||
return res.url;
|
||||
}
|
||||
}
|
||||
53
frontend/pshared/lib/service/authorization/storage.dart
Normal file
53
frontend/pshared/lib/service/authorization/storage.dart
Normal file
@@ -0,0 +1,53 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'package:pshared/api/errors/unauthorized.dart';
|
||||
import 'package:pshared/api/responses/token.dart';
|
||||
import 'package:pshared/config/constants.dart';
|
||||
import 'package:pshared/service/secure_storage.dart';
|
||||
|
||||
|
||||
class AuthorizationStorage {
|
||||
static final _logger = Logger('service.authorization.storage');
|
||||
|
||||
static Future<TokenData> _getTokenData(String tokenKey) async {
|
||||
_logger.fine('Getting token data');
|
||||
final String? tokenJson = await SecureStorageService.get(tokenKey);
|
||||
if (tokenJson == null || tokenJson.isEmpty) {
|
||||
throw ErrorUnauthorized();
|
||||
}
|
||||
return TokenData.fromJson(jsonDecode(tokenJson));
|
||||
}
|
||||
|
||||
static Future<TokenData> getAccessToken() async {
|
||||
_logger.fine('Getting access token');
|
||||
return _getTokenData(Constants.accessTokenStorageKey);
|
||||
}
|
||||
|
||||
static Future<TokenData> getRefreshToken() async {
|
||||
_logger.fine('Getting refresh token');
|
||||
return _getTokenData(Constants.refreshTokenStorageKey);
|
||||
}
|
||||
|
||||
static Future<void> updateToken(TokenData tokenData) async {
|
||||
_logger.fine('Storing access token...');
|
||||
final tokenJson = jsonEncode(tokenData.toJson());
|
||||
await SecureStorageService.set(Constants.accessTokenStorageKey, tokenJson);
|
||||
}
|
||||
|
||||
static Future<void> updateRefreshToken(TokenData tokenData) async {
|
||||
_logger.fine('Storing refresh token...');
|
||||
final refreshTokenJson = jsonEncode(tokenData.toJson());
|
||||
await SecureStorageService.set(Constants.refreshTokenStorageKey, refreshTokenJson);
|
||||
}
|
||||
|
||||
static Future<void> removeTokens() {
|
||||
return Future.wait([
|
||||
SecureStorageService.delete(Constants.refreshTokenStorageKey),
|
||||
SecureStorageService.delete(Constants.accessTokenStorageKey),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
85
frontend/pshared/lib/service/authorization/token.dart
Normal file
85
frontend/pshared/lib/service/authorization/token.dart
Normal file
@@ -0,0 +1,85 @@
|
||||
|
||||
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'package:pshared/api/errors/unauthorized.dart';
|
||||
import 'package:pshared/api/requests/tokens/access_refresh.dart';
|
||||
import 'package:pshared/api/requests/tokens/refresh_rotate.dart';
|
||||
import 'package:pshared/api/responses/account.dart';
|
||||
import 'package:pshared/api/responses/login.dart';
|
||||
import 'package:pshared/api/responses/token.dart';
|
||||
import 'package:pshared/config/constants.dart';
|
||||
import 'package:pshared/service/authorization/storage.dart';
|
||||
import 'package:pshared/service/device_id.dart';
|
||||
import 'package:pshared/service/services.dart';
|
||||
import 'package:pshared/utils/http/requests.dart';
|
||||
|
||||
|
||||
class TokenService {
|
||||
static final _logger = Logger('service.authorization.token');
|
||||
static const String _objectType = Services.account;
|
||||
|
||||
static bool _isTokenExpiringSoon(TokenData token, Duration duration) {
|
||||
return token.expiration.isBefore(DateTime.now().add(duration));
|
||||
}
|
||||
|
||||
static Future<String> getAccessToken() async {
|
||||
TokenData token = await AuthorizationStorage.getAccessToken();
|
||||
if (_isTokenExpiringSoon(token, const Duration(hours: 4))) {
|
||||
token = (await _refreshAccessToken()).accessToken;
|
||||
}
|
||||
return token.token;
|
||||
}
|
||||
|
||||
static Future<void> _updateTokens(LoginResponse response) async {
|
||||
await AuthorizationStorage.updateToken(response.accessToken);
|
||||
await AuthorizationStorage.updateRefreshToken(response.refreshToken);
|
||||
}
|
||||
|
||||
static Future<AccountResponse> _refreshAccessToken() async {
|
||||
_logger.fine('Refreshing access token...');
|
||||
final deviceId = await DeviceIdManager.getDeviceId();
|
||||
final refresh = await AuthorizationStorage.getRefreshToken();
|
||||
|
||||
if (_isTokenExpiringSoon(refresh, const Duration(days: 7))) {
|
||||
return await rotateRefreshToken();
|
||||
}
|
||||
|
||||
final response = await getPOSTResponse(
|
||||
_objectType,
|
||||
'/refresh',
|
||||
AccessTokenRefreshRequest(
|
||||
deviceId: deviceId,
|
||||
clientId: Constants.clientId,
|
||||
token: refresh.token,
|
||||
).toJson(),
|
||||
);
|
||||
|
||||
final accountResp = AccountResponse.fromJson(response);
|
||||
await AuthorizationStorage.updateToken(accountResp.accessToken);
|
||||
return accountResp;
|
||||
}
|
||||
|
||||
static Future<LoginResponse> rotateRefreshToken() async {
|
||||
_logger.fine('Rotating refresh token...');
|
||||
final refresh = await AuthorizationStorage.getRefreshToken();
|
||||
|
||||
if (refresh.expiration.isBefore(DateTime.now())) throw ErrorUnauthorized();
|
||||
|
||||
final deviceId = await DeviceIdManager.getDeviceId();
|
||||
final response = await getPOSTResponse(
|
||||
_objectType,
|
||||
'/rotate',
|
||||
RotateRefreshTokenRequest(
|
||||
token: refresh.token,
|
||||
clientId: Constants.clientId,
|
||||
deviceId: deviceId,
|
||||
).toJson(),
|
||||
);
|
||||
|
||||
final loginResponse = LoginResponse.fromJson(response);
|
||||
await _updateTokens(loginResponse);
|
||||
return loginResponse;
|
||||
}
|
||||
|
||||
}
|
||||
24
frontend/pshared/lib/service/device_id.dart
Normal file
24
frontend/pshared/lib/service/device_id.dart
Normal file
@@ -0,0 +1,24 @@
|
||||
import 'package:uuid/uuid.dart';
|
||||
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'package:pshared/config/web.dart';
|
||||
import 'package:pshared/service/secure_storage.dart';
|
||||
|
||||
|
||||
class DeviceIdManager {
|
||||
static final _logger = Logger('service.device_id');
|
||||
|
||||
static final String _key = Constants.deviceIdStorageKey;
|
||||
static Future<String> getDeviceId() async {
|
||||
String? deviceId = await SecureStorageService.get(_key);
|
||||
|
||||
if (deviceId == null) {
|
||||
_logger.fine('Device id is not set, generating new');
|
||||
deviceId = (const Uuid()).v4();
|
||||
await SecureStorageService.set(_key, deviceId);
|
||||
}
|
||||
|
||||
return deviceId;
|
||||
}
|
||||
}
|
||||
38
frontend/pshared/lib/service/files.dart
Normal file
38
frontend/pshared/lib/service/files.dart
Normal file
@@ -0,0 +1,38 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:cached_network_image/cached_network_image.dart';
|
||||
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
import 'package:pshared/service/authorization/service.dart';
|
||||
import 'package:pshared/utils/image/conversion.dart';
|
||||
import 'package:pshared/utils/image/transformed.dart';
|
||||
|
||||
|
||||
String generateRandomLatinString(int length) {
|
||||
const String chars = 'abcdefghijklmnopqrstuvwxyz';
|
||||
final Random random = Random.secure();
|
||||
return List.generate(length, (index) => chars[random.nextInt(chars.length)]).join();
|
||||
}
|
||||
|
||||
class FilesService {
|
||||
static Future<String> uploadImage(
|
||||
String objectType,
|
||||
String? id,
|
||||
XFile imageFile, {
|
||||
Future<TransformedImage> Function(XFile) fileReader = defaultTransformImage,
|
||||
}) async {
|
||||
final objRef = id ?? generateRandomLatinString(16);
|
||||
final image = await fileReader(imageFile);
|
||||
final res = await AuthorizationService.getFileUploadResponseAuth(
|
||||
objectType,
|
||||
'image/$objRef',
|
||||
'$objRef.${image.imageType.split('/').last}',
|
||||
'image',
|
||||
image.imageType,
|
||||
image.bytes
|
||||
);
|
||||
CachedNetworkImage.evictFromCache(res);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
63
frontend/pshared/lib/service/organization.dart
Normal file
63
frontend/pshared/lib/service/organization.dart
Normal file
@@ -0,0 +1,63 @@
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'package:share_plus/share_plus.dart';
|
||||
|
||||
import 'package:pshared/api/errors/unauthorized.dart';
|
||||
import 'package:pshared/api/responses/organization.dart';
|
||||
import 'package:pshared/models/organization/organization.dart';
|
||||
import 'package:pshared/data/mapper/organization.dart';
|
||||
import 'package:pshared/service/authorization/service.dart';
|
||||
import 'package:pshared/service/files.dart';
|
||||
import 'package:pshared/service/services.dart';
|
||||
import 'package:pshared/utils/http/requests.dart';
|
||||
|
||||
|
||||
class OrganizationService {
|
||||
static final _logger = Logger('service.organization');
|
||||
static const String _objectType = Services.organization;
|
||||
|
||||
static Future<List<Organization>> list() async {
|
||||
_logger.fine('Loading all organizations');
|
||||
return _getOrganizations(AuthorizationService.getGETResponse(_objectType, ''));
|
||||
}
|
||||
|
||||
static Future<Organization> load(String organizationRef) async {
|
||||
_logger.fine('Loading organization $organizationRef');
|
||||
final orgs = await _getOrganizations(AuthorizationService.getGETResponse(_objectType, organizationRef));
|
||||
return orgs.first;
|
||||
}
|
||||
|
||||
static Future<Organization> loadByInvitation(String invitationRef) async {
|
||||
_logger.fine('Loading organization by invitation ref $invitationRef');
|
||||
final orgs = await _getOrganizations(getGETResponse(_objectType, 'invitation/$invitationRef'));
|
||||
return orgs.first;
|
||||
}
|
||||
|
||||
static Future<List<Organization>> update(Organization organization) async {
|
||||
_logger.fine('Patching organization ${organization.id}');
|
||||
// Convert domain object to DTO, then to JSON
|
||||
return _getOrganizations(
|
||||
AuthorizationService.getPUTResponse(_objectType, '', organization.toDTO().toJson())
|
||||
);
|
||||
}
|
||||
|
||||
static Future<String> uploadLogo(String organizationRef, XFile logoFile) async {
|
||||
_logger.fine('Uploading logo');
|
||||
return FilesService.uploadImage(_objectType, organizationRef, logoFile);
|
||||
}
|
||||
|
||||
static Future<List<Organization>> _getOrganizations(Future<Map<String, dynamic>> future) async {
|
||||
try {
|
||||
final responseJson = await future;
|
||||
final response = OrganizationResponse.fromJson(responseJson);
|
||||
final orgs = response.organizations.map((dto) => dto.toDomain()).toList();
|
||||
|
||||
if (orgs.isEmpty) throw ErrorUnauthorized();
|
||||
_logger.fine('Fetched ${orgs.length} organization(s)');
|
||||
return orgs;
|
||||
} catch (e, stackTrace) {
|
||||
_logger.severe('Failed to fetch organizations', e, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
79
frontend/pshared/lib/service/permissions.dart
Normal file
79
frontend/pshared/lib/service/permissions.dart
Normal file
@@ -0,0 +1,79 @@
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'package:pshared/api/requests/change_role.dart';
|
||||
import 'package:pshared/api/requests/permissions/change_policies.dart';
|
||||
import 'package:pshared/api/responses/policies.dart';
|
||||
import 'package:pshared/data/mapper/permissions/data/permissions.dart';
|
||||
import 'package:pshared/data/mapper/permissions/descriptions/description.dart';
|
||||
import 'package:pshared/models/permissions/access.dart';
|
||||
import 'package:pshared/models/permissions/data/policy.dart';
|
||||
import 'package:pshared/service/authorization/service.dart';
|
||||
import 'package:pshared/service/services.dart';
|
||||
|
||||
|
||||
class PermissionsService {
|
||||
static final _logger = Logger('service.permissions');
|
||||
static const String _objectType = Services.permission;
|
||||
|
||||
static Future<UserAccess> load(String organizationRef) async {
|
||||
_logger.fine('Loading permissions...');
|
||||
return _getPolicies(AuthorizationService.getGETResponse(_objectType, organizationRef));
|
||||
}
|
||||
|
||||
static Future<UserAccess> loadAll(String organizationRef) async {
|
||||
_logger.fine('Loading permissions for all the users...');
|
||||
return _getPolicies(AuthorizationService.getGETResponse(_objectType, '/all/$organizationRef'));
|
||||
}
|
||||
|
||||
static Future<void> changeRole(String organizationRef, ChangeRole request) async {
|
||||
_logger.fine('Changing role for account ${request.accountRef} to role ${request.newRoleDescriptionRef}');
|
||||
await AuthorizationService.getPOSTResponse(_objectType, '/change_role/$organizationRef', request.toJson());
|
||||
}
|
||||
|
||||
static Future<void> deleteRoleDescription(String roleDescriptionRef) async {
|
||||
_logger.fine('Deleting role $roleDescriptionRef...');
|
||||
await AuthorizationService.getDELETEResponse(_objectType, '/role/$roleDescriptionRef', {});
|
||||
}
|
||||
|
||||
static Future<void> createPolicies(List<Policy> policies) async {
|
||||
_logger.fine('Creating ${policies.length} policies...');
|
||||
await AuthorizationService.getPOSTResponse(
|
||||
_objectType,
|
||||
'/policies',
|
||||
PoliciesChangeRequest.add(policies: policies).toJson(),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> deletePolicies(List<Policy> policies) async {
|
||||
_logger.fine('Deleting ${policies.length} policies...');
|
||||
await AuthorizationService.getDELETEResponse(
|
||||
_objectType,
|
||||
'/policies',
|
||||
PoliciesChangeRequest.remove(policies: policies).toJson(),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<void> changePolicies(List<Policy> add, List<Policy> remove) async {
|
||||
final common = add.toSet().intersection(remove.toSet());
|
||||
if (common.isNotEmpty) {
|
||||
throw ArgumentError.value(common, 'add/remove', 'These policies are in both add and remove: ${common.toString()}');
|
||||
}
|
||||
_logger.fine('Adding ${add.length} policies, removing ${remove.length} policies...');
|
||||
await AuthorizationService.getPUTResponse(
|
||||
_objectType,
|
||||
'/policies',
|
||||
PoliciesChangeRequest.change(add: add, remove: remove).toJson(),
|
||||
);
|
||||
}
|
||||
|
||||
static Future<UserAccess> _getPolicies(Future<Map<String, dynamic>> future) async {
|
||||
final resp = PoliciesResponse.fromJson(await future);
|
||||
final res = UserAccess(
|
||||
descriptions: resp.descriptions.toDomain(),
|
||||
permissions: resp.permissions.toDomain(),
|
||||
);
|
||||
_logger.fine('Loaded ${res.descriptions.roles.length} role descriptions, ${res.permissions.roles.length} role assignments, ${res.descriptions.policies.length} policy descriptions, ${res.permissions.policies.length} assigned policies, and ${res.permissions.permissions.length} assigned permissions');
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
15
frontend/pshared/lib/service/pfe/login.dart
Normal file
15
frontend/pshared/lib/service/pfe/login.dart
Normal file
@@ -0,0 +1,15 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'login.g.dart';
|
||||
|
||||
|
||||
@JsonSerializable()
|
||||
class LoginRequest {
|
||||
final String login;
|
||||
final String password;
|
||||
|
||||
const LoginRequest({required this.login, required this.password});
|
||||
|
||||
factory LoginRequest.fromJson(Map<String, dynamic> json) => _$LoginRequestFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$LoginRequestToJson(this);
|
||||
}
|
||||
29
frontend/pshared/lib/service/pfe/service.dart
Normal file
29
frontend/pshared/lib/service/pfe/service.dart
Normal file
@@ -0,0 +1,29 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'package:http/http.dart' as http;
|
||||
|
||||
import 'package:pshared/service/pfe/login.dart';
|
||||
|
||||
|
||||
class PfeService {
|
||||
static final _logger = Logger('service.pfe');
|
||||
|
||||
static Future<String> login(String email, String password) async {
|
||||
_logger.fine('Logging in');
|
||||
|
||||
try {
|
||||
final res = await http.post(
|
||||
Uri.parse('http://localhost:3000/api/v1/auth/login'),
|
||||
headers: {'Content-Type': 'application/json'},
|
||||
body: json.encode(LoginRequest(login: email, password: password).toJson()),
|
||||
);
|
||||
return res.toString();
|
||||
} catch (e) {
|
||||
_logger.warning(e.toString());
|
||||
rethrow;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
0
frontend/pshared/lib/service/pfe/services.dart
Normal file
0
frontend/pshared/lib/service/pfe/services.dart
Normal file
25
frontend/pshared/lib/service/secure_storage.dart
Normal file
25
frontend/pshared/lib/service/secure_storage.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
|
||||
class SecureStorageService {
|
||||
static Future<String?> get(String key) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
return prefs.getString(key);
|
||||
}
|
||||
|
||||
static Future<void> _setImp(SharedPreferences prefs, String key, String value) async {
|
||||
await prefs.setString(key, value);
|
||||
}
|
||||
|
||||
static Future<void> set(String key, String? value) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
if (value == null) {
|
||||
return delete(key);
|
||||
}
|
||||
return _setImp(prefs, key, value);
|
||||
}
|
||||
|
||||
static Future<void> delete(String key) async {
|
||||
final prefs = await SharedPreferences.getInstance();
|
||||
await prefs.remove(key);
|
||||
}
|
||||
}
|
||||
32
frontend/pshared/lib/service/services.dart
Normal file
32
frontend/pshared/lib/service/services.dart
Normal file
@@ -0,0 +1,32 @@
|
||||
class Services {
|
||||
static const String account = 'accounts';
|
||||
static const String authorization = 'authorization';
|
||||
static const String comments = 'comments';
|
||||
static const String device = 'device';
|
||||
static const String invitations = 'invitations';
|
||||
static const String organization = 'organizations';
|
||||
static const String permission = 'permissions';
|
||||
static const String project = 'projects';
|
||||
static const String pgroup = 'priority_groups';
|
||||
static const String priorities = 'priorities';
|
||||
static const String reactions = 'reactions';
|
||||
static const String storage = 'storage';
|
||||
static const String taskStatus = 'statuses';
|
||||
static const String tasks = 'tasks';
|
||||
|
||||
static const String amplitude = 'amplitude';
|
||||
static const String automations = 'automation';
|
||||
static const String changes = 'changes';
|
||||
static const String clients = 'clients';
|
||||
static const String invoices = 'invoices';
|
||||
static const String logo = 'logo';
|
||||
static const String notifications = 'notifications';
|
||||
static const String policies = 'policies';
|
||||
static const String properties = 'properties';
|
||||
static const String refreshTokens = 'refresh_tokens';
|
||||
static const String roles = 'roles';
|
||||
static const String steps = 'steps';
|
||||
static const String teams = 'teams';
|
||||
static const String workflows = 'workflows';
|
||||
static const String workspaces = 'workspaces';
|
||||
}
|
||||
66
frontend/pshared/lib/service/template.dart
Normal file
66
frontend/pshared/lib/service/template.dart
Normal file
@@ -0,0 +1,66 @@
|
||||
import 'package:logging/logging.dart';
|
||||
|
||||
import 'package:pshared/service/authorization/service.dart';
|
||||
|
||||
|
||||
class BasicService<T> {
|
||||
final String _objectType;
|
||||
final Logger _logger;
|
||||
final List<T> Function(Map<String, dynamic> json) fromJson;
|
||||
|
||||
Logger get logger => _logger;
|
||||
|
||||
BasicService({
|
||||
required String objectType,
|
||||
required this.fromJson,
|
||||
}) : _objectType = objectType, _logger = Logger('service.$objectType');
|
||||
|
||||
Future<List<T>> list(String organizationRef, String parentRef) async {
|
||||
_logger.fine('Loading all objects');
|
||||
return _getObjects(
|
||||
AuthorizationService.getGETResponse(_objectType, '/list/$organizationRef/$parentRef'),
|
||||
);
|
||||
}
|
||||
|
||||
Future<T> get(String objectRef) async {
|
||||
_logger.fine('Loading object $objectRef');
|
||||
final objects = await _getObjects(
|
||||
AuthorizationService.getGETResponse(_objectType, '/$objectRef'),
|
||||
);
|
||||
return objects.first;
|
||||
}
|
||||
|
||||
Future<List<T>> create(String organizationRef, Map<String, dynamic> request) async {
|
||||
_logger.fine('Creating new object...');
|
||||
return _getObjects(
|
||||
AuthorizationService.getPOSTResponse(_objectType, '/$organizationRef', request),
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<T>> update(Map<String, dynamic> request) async {
|
||||
_logger.fine('Patching object...');
|
||||
return _getObjects(
|
||||
AuthorizationService.getPUTResponse(_objectType, '/', request,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<T>> delete(String objecRef) async {
|
||||
_logger.fine('Deleting object $objecRef');
|
||||
return _getObjects(
|
||||
AuthorizationService.getDELETEResponse(_objectType, '/$objecRef', {}),
|
||||
);
|
||||
}
|
||||
|
||||
Future<List<T>> _getObjects(Future<Map<String, dynamic>> future) async {
|
||||
try {
|
||||
final responseJson = await future;
|
||||
final objects = fromJson(responseJson);
|
||||
_logger.fine('Fetched ${objects.length} object(s)');
|
||||
return objects;
|
||||
} catch (e, stackTrace) {
|
||||
_logger.severe('Failed to fetch objects', e, stackTrace);
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user