Added account permissions and ui for recipient
This commit is contained in:
105
frontend/pweb/lib/services/accounts.dart
Normal file
105
frontend/pweb/lib/services/accounts.dart
Normal file
@@ -0,0 +1,105 @@
|
||||
import 'package:collection/collection.dart';
|
||||
|
||||
import 'package:pshared/api/requests/login_data.dart';
|
||||
import 'package:pshared/models/account/account.dart';
|
||||
import 'package:pshared/models/describable.dart';
|
||||
import 'package:pshared/models/storable.dart';
|
||||
|
||||
import 'mock_ids.dart';
|
||||
|
||||
class InvalidCredentialsException implements Exception {
|
||||
@override
|
||||
String toString() => 'InvalidCredentialsException';
|
||||
}
|
||||
|
||||
class DuplicateAccountException implements Exception {
|
||||
@override
|
||||
String toString() => 'DuplicateAccountException';
|
||||
}
|
||||
|
||||
class AccountLoginResult {
|
||||
final Account account;
|
||||
final String roleId;
|
||||
|
||||
const AccountLoginResult({
|
||||
required this.account,
|
||||
required this.roleId,
|
||||
});
|
||||
}
|
||||
|
||||
class _AccountRecord {
|
||||
final Account account;
|
||||
final String password;
|
||||
final String roleId;
|
||||
|
||||
const _AccountRecord({
|
||||
required this.account,
|
||||
required this.password,
|
||||
required this.roleId,
|
||||
});
|
||||
}
|
||||
|
||||
class AccountsService {
|
||||
final List<_AccountRecord> _accounts = [
|
||||
_AccountRecord(
|
||||
account: Account(
|
||||
storable: newStorable(id: companyAccountRef),
|
||||
describable: newDescribable(name: 'Sendico Company'),
|
||||
avatarUrl: null,
|
||||
lastName: 'Owner',
|
||||
login: 'company@sendico.com',
|
||||
locale: 'ru',
|
||||
),
|
||||
password: 'password123A',
|
||||
roleId: companyRoleId,
|
||||
),
|
||||
_AccountRecord(
|
||||
account: Account(
|
||||
storable: newStorable(id: recipientAccountRef),
|
||||
describable: newDescribable(name: 'John Recipient'),
|
||||
avatarUrl: null,
|
||||
lastName: 'Doe',
|
||||
login: 'recipient@sendico.com',
|
||||
locale: 'ru',
|
||||
),
|
||||
password: 'password123A',
|
||||
roleId: recipientRoleId,
|
||||
),
|
||||
];
|
||||
|
||||
Future<AccountLoginResult> login(String email, String password, {String? locale}) async {
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
|
||||
final normalized = email.trim().toLowerCase();
|
||||
final record = _accounts.where((acc) => acc.account.login.toLowerCase() == normalized).singleOrNull;
|
||||
|
||||
if (record == null || record.password != password) {
|
||||
throw InvalidCredentialsException();
|
||||
}
|
||||
|
||||
return AccountLoginResult(account: record.account, roleId: record.roleId);
|
||||
}
|
||||
|
||||
Future<AccountLoginResult> signup(AccountData data, {String roleId = recipientRoleId}) async {
|
||||
await Future.delayed(const Duration(milliseconds: 300));
|
||||
|
||||
final normalized = data.login.trim().toLowerCase();
|
||||
if (_accounts.any((acc) => acc.account.login.toLowerCase() == normalized)) {
|
||||
throw DuplicateAccountException();
|
||||
}
|
||||
|
||||
final account = Account(
|
||||
storable: newStorable(id: 'account-${_accounts.length + 1}'),
|
||||
describable: newDescribable(name: data.name),
|
||||
avatarUrl: null,
|
||||
lastName: data.lastName,
|
||||
login: normalized,
|
||||
locale: data.locale,
|
||||
);
|
||||
|
||||
_accounts.add(_AccountRecord(account: account, password: data.password, roleId: roleId));
|
||||
return AccountLoginResult(account: account, roleId: roleId);
|
||||
}
|
||||
|
||||
Account? getByRef(String accountRef) => _accounts.where((acc) => acc.account.id == accountRef).singleOrNull?.account;
|
||||
}
|
||||
12
frontend/pweb/lib/services/mock_ids.dart
Normal file
12
frontend/pweb/lib/services/mock_ids.dart
Normal file
@@ -0,0 +1,12 @@
|
||||
// Centralized identifiers for mock auth/permission data to keep the
|
||||
// mock services in sync and make it easy to swap in a real API later.
|
||||
const String mockOrganizationRef = 'org-sendico';
|
||||
|
||||
const String companyRoleId = 'role-company';
|
||||
const String recipientRoleId = 'role-recipient';
|
||||
|
||||
const String companyAccountRef = 'account-company';
|
||||
const String recipientAccountRef = 'account-recipient';
|
||||
|
||||
const String accountsPolicyDescriptionId = 'policy-accounts';
|
||||
const String rolesPolicyDescriptionId = 'policy-roles';
|
||||
117
frontend/pweb/lib/services/permissions.dart
Normal file
117
frontend/pweb/lib/services/permissions.dart
Normal file
@@ -0,0 +1,117 @@
|
||||
import 'package:pshared/models/describable.dart';
|
||||
import 'package:pshared/models/permissions/access.dart';
|
||||
import 'package:pshared/models/permissions/action.dart';
|
||||
import 'package:pshared/models/permissions/action_effect.dart';
|
||||
import 'package:pshared/models/permissions/data/permission.dart';
|
||||
import 'package:pshared/models/permissions/data/permissions.dart';
|
||||
import 'package:pshared/models/permissions/data/policy.dart';
|
||||
import 'package:pshared/models/permissions/data/role.dart';
|
||||
import 'package:pshared/models/permissions/descriptions/permissions.dart';
|
||||
import 'package:pshared/models/permissions/descriptions/policy.dart';
|
||||
import 'package:pshared/models/permissions/descriptions/role.dart';
|
||||
import 'package:pshared/models/permissions/effect.dart';
|
||||
import 'package:pshared/models/resources.dart';
|
||||
import 'package:pshared/models/storable.dart';
|
||||
|
||||
import 'mock_ids.dart';
|
||||
|
||||
class PermissionsService {
|
||||
static const String _objectType = 'permissions';
|
||||
|
||||
Future<UserAccess> loadForAccount(String accountRef) async {
|
||||
await Future.delayed(const Duration(milliseconds: 200));
|
||||
final baseAccess = _buildMockUserAccess();
|
||||
|
||||
final roles = [...baseAccess.permissions.roles];
|
||||
final permissions = [...baseAccess.permissions.permissions];
|
||||
final policies = [...baseAccess.permissions.policies];
|
||||
|
||||
final hasAccount = roles.any((r) => r.accountRef == accountRef);
|
||||
if (!hasAccount) {
|
||||
roles.add(Role(accountRef: accountRef, descriptionRef: recipientRoleId, organizationRef: mockOrganizationRef));
|
||||
}
|
||||
|
||||
final relevantRoleRefs = roles
|
||||
.where((r) => r.accountRef == accountRef)
|
||||
.map((r) => r.descriptionRef)
|
||||
.toSet();
|
||||
|
||||
final filteredPolicies = permissions
|
||||
.where((p) => p.accountRef == accountRef && relevantRoleRefs.contains(p.policy.roleDescriptionRef))
|
||||
.toList();
|
||||
|
||||
return UserAccess(
|
||||
descriptions: baseAccess.descriptions,
|
||||
permissions: PermissionsData(
|
||||
roles: roles.where((r) => r.accountRef == accountRef).toList(),
|
||||
policies: policies.where((p) => relevantRoleRefs.contains(p.roleDescriptionRef)).toList(),
|
||||
permissions: filteredPolicies,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
UserAccess _buildMockUserAccess() {
|
||||
final roleDescriptions = [
|
||||
RoleDescription(
|
||||
storable: newStorable(id: companyRoleId),
|
||||
describable: newDescribable(name: 'Компания'),
|
||||
organizationRef: mockOrganizationRef,
|
||||
),
|
||||
RoleDescription(
|
||||
storable: newStorable(id: recipientRoleId),
|
||||
describable: newDescribable(name: 'Получатель'),
|
||||
organizationRef: mockOrganizationRef,
|
||||
),
|
||||
];
|
||||
|
||||
final policyDescriptions = [
|
||||
PolicyDescription(
|
||||
storable: newStorable(id: accountsPolicyDescriptionId),
|
||||
describable: newDescribable(name: 'Управление аккаунтами'),
|
||||
resourceTypes: const [ResourceType.accounts],
|
||||
organizationRef: mockOrganizationRef,
|
||||
),
|
||||
PolicyDescription(
|
||||
storable: newStorable(id: rolesPolicyDescriptionId),
|
||||
describable: newDescribable(name: 'Управление ролями'),
|
||||
resourceTypes: const [ResourceType.roles],
|
||||
organizationRef: mockOrganizationRef,
|
||||
),
|
||||
];
|
||||
|
||||
final companyAccountsPolicy = Policy(
|
||||
roleDescriptionRef: companyRoleId,
|
||||
organizationRef: mockOrganizationRef,
|
||||
descriptionRef: accountsPolicyDescriptionId,
|
||||
objectRef: null,
|
||||
effect: const ActionEffect(action: Action.read, effect: Effect.allow),
|
||||
);
|
||||
|
||||
final companyRolesPolicy = Policy(
|
||||
roleDescriptionRef: companyRoleId,
|
||||
organizationRef: mockOrganizationRef,
|
||||
descriptionRef: rolesPolicyDescriptionId,
|
||||
objectRef: null,
|
||||
effect: const ActionEffect(action: Action.read, effect: Effect.allow),
|
||||
);
|
||||
|
||||
final roles = [
|
||||
Role(accountRef: companyAccountRef, descriptionRef: companyRoleId, organizationRef: mockOrganizationRef),
|
||||
Role(accountRef: recipientAccountRef, descriptionRef: recipientRoleId, organizationRef: mockOrganizationRef),
|
||||
];
|
||||
|
||||
final permissions = [
|
||||
Permission(policy: companyAccountsPolicy, accountRef: companyAccountRef),
|
||||
Permission(policy: companyRolesPolicy, accountRef: companyAccountRef),
|
||||
];
|
||||
|
||||
return UserAccess(
|
||||
descriptions: PermissionsDescription(roles: roleDescriptions, policies: policyDescriptions),
|
||||
permissions: PermissionsData(
|
||||
roles: roles,
|
||||
policies: [companyAccountsPolicy, companyRolesPolicy],
|
||||
permissions: permissions,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user