fix
This commit is contained in:
@@ -359,6 +359,8 @@ MigrationBackup/
|
||||
# Ionide (cross platform F# VS Code tools) working folder
|
||||
.ionide/
|
||||
|
||||
.vscode/
|
||||
|
||||
/MyOffice.SPA/.vscode
|
||||
/MyOffice.SPA/dist/
|
||||
/MyOffice.SPA/src/environments/environment.ts
|
||||
@@ -382,3 +384,4 @@ package-lock.json
|
||||
/MyOffice.Shared/appsettings.shared.Production.json
|
||||
/linux_deploy_mybank.bat
|
||||
/linux_deploy_office.bat
|
||||
linux_deploy_office_public.bat
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace MyOffice.Core;
|
||||
|
||||
public interface IDataModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace MyOffice.Core;
|
||||
|
||||
public interface IDataModelDto<TSource> where TSource : IDataModel
|
||||
{
|
||||
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
namespace MyOffice.Data.Models.Accounts;
|
||||
|
||||
using Currencies;
|
||||
using MyOffice.Core;
|
||||
using MyOffice.Data.Models.Users;
|
||||
|
||||
public class Account
|
||||
public class Account: IDataModel
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string CurrencyGlobalId { get; set; } = null!;
|
||||
@@ -17,7 +18,7 @@ public class Account
|
||||
public IEnumerable<AccountAccessInvite>? Invites { get; set; }
|
||||
}
|
||||
|
||||
public class AccountDetailed
|
||||
public class AccountDetailed: IDataModel
|
||||
{
|
||||
public Account Account { get; set; } = null!;
|
||||
public decimal TotalPlus { get; set; }
|
||||
|
||||
@@ -21,11 +21,15 @@ public class AccountRepository : AppRepository<Account>, IAccountRepository
|
||||
{
|
||||
return _context.Accounts!
|
||||
.Include(x => x.CurrencyGlobal)
|
||||
.Include(x => x.Categories!.Where(x => x.Category.UserId == userId))!
|
||||
// categories created with current user
|
||||
.Include(x => x.Categories!.Where(c => c.Category.UserId == userId))!
|
||||
.ThenInclude(x => x.Category)
|
||||
.Include(x => x.AccessRights)!
|
||||
// access rights created with current user
|
||||
.Include(x => x.AccessRights!.Where(a => a.OwnerId == userId))!
|
||||
.ThenInclude(x => x.User)
|
||||
.Include(x => x.Motions)!
|
||||
// require only one motions to check if can to delete account
|
||||
.Include(x => x.Motions!.Take(1))!
|
||||
// only accounts with access to current user
|
||||
.Where(x => x.AccessRights!.Any(a => a.UserId == userId))
|
||||
.ToList();
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ export interface AccountModel {
|
||||
currencyId?: string,
|
||||
currencyName?: string,
|
||||
type?: string,
|
||||
allowWrite: boolean,
|
||||
allowDelete: boolean,
|
||||
allowManage: boolean,
|
||||
categories?: AccountCategoryModel[],
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
<td>{{account.currencyId}}</td>
|
||||
<td>{{account.type}}</td>
|
||||
<td>
|
||||
<button class="btn-space" (click)="edit(account)" mat-raised-button color="primary">
|
||||
<button class="btn-space" *ngIf="account.allowWrite" (click)="edit(account)" mat-raised-button color="primary">
|
||||
Edit
|
||||
</button>
|
||||
<button class="btn-space" *ngIf="account.allowManage" (click)="access(account)" mat-raised-button color="primary">
|
||||
|
||||
@@ -25,6 +25,15 @@
|
||||
<a href="javascript:;" (click)="selectCategory(category)" title="{{category.name}}">{{category.name}}</a>
|
||||
</li>
|
||||
</ul>
|
||||
<ul *ngIf="categoryAddShow">
|
||||
<mat-form-field class="example-full-width">
|
||||
<mat-label>Code</mat-label>
|
||||
<input matInput [(ngModel)]="categoryAddName">
|
||||
</mat-form-field>
|
||||
</ul>
|
||||
<ul *ngIf="!categoryAddShow">
|
||||
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -24,6 +24,8 @@ export class SettingsItemComponent {
|
||||
public selectedCategory?: ItemCategoryModel;
|
||||
public selectedCount: number = 0;
|
||||
public category?: ItemCategoryModel;
|
||||
public categoryAddShow: boolean = false;
|
||||
public categoryAddName?: string;
|
||||
|
||||
constructor(
|
||||
private dialogModel: MatDialog,
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
namespace MyOffice.Services.Account;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Core;
|
||||
using Core.Extensions;
|
||||
using Data.Models.Accounts;
|
||||
using Domain;
|
||||
|
||||
public partial class AccountService
|
||||
{
|
||||
public Exec<AccountAccessInviteDto, AccessInviteStatus> AccessInvite(Guid userId, Guid accountId, string email, bool isAllowWrite)
|
||||
{
|
||||
if (email == null)
|
||||
throw new ArgumentNullException(nameof(email));
|
||||
|
||||
var result = new Exec<AccountAccessInviteDto, AccessInviteStatus>(AccessInviteStatus.success);
|
||||
|
||||
var account = _accountRepository.Get(userId, accountId);
|
||||
if (account == null)
|
||||
{
|
||||
return result.Set(AccessInviteStatus.account_not_found);
|
||||
}
|
||||
|
||||
if (account.AccessRights!.Any(x => x.User!.Email.EqualsIgnoreCase(email)))
|
||||
{
|
||||
return result.Set(AccessInviteStatus.access_exists);
|
||||
}
|
||||
|
||||
var access = _accountAccessInviteRepository.Get(userId, email);
|
||||
if (access != null)
|
||||
{
|
||||
return result.Set(AccessInviteStatus.invite_exists);
|
||||
}
|
||||
|
||||
var invite = new AccountAccessInvite
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
CreatedOn = DateTime.UtcNow,
|
||||
UserId = userId,
|
||||
AccountId = account.Id,
|
||||
Email = email.SafeTrim()!,
|
||||
IsAllowWrite = isAllowWrite,
|
||||
};
|
||||
|
||||
_accountAccessInviteRepository.Add(invite);
|
||||
|
||||
return result.Set(_mapper.Map<AccountAccessInviteDto>(invite));
|
||||
}
|
||||
|
||||
public Exec<AccountDto, GeneralExecStatus> AccessUpdate(Guid userId, Guid accountId, List<AccountAccessDto> accesses)
|
||||
{
|
||||
if (accesses == null)
|
||||
throw new ArgumentNullException(nameof(accesses));
|
||||
|
||||
var result = new Exec<AccountDto, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var account = _accountRepository.Get(userId, accountId);
|
||||
if (account == null)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
foreach (var access in account.AccessRights!)
|
||||
{
|
||||
var newAccess = accesses.FirstOrDefault(x => x.UserId == access.UserId);
|
||||
if (newAccess != null && newAccess.IsAllowWrite != access.IsAllowWrite)
|
||||
{
|
||||
access.IsAllowWrite = newAccess.IsAllowWrite;
|
||||
_accountAccessRepository.Update(access);
|
||||
}
|
||||
}
|
||||
|
||||
account = _accountRepository.Get(userId, accountId);
|
||||
|
||||
return result.Set(_mapper.Map<AccountDto>(account));
|
||||
}
|
||||
|
||||
public Exec<AccountDto, GeneralExecStatus> AccessDelete(Guid userId, Guid accountId, Guid accessUserId)
|
||||
{
|
||||
var result = new Exec<AccountDto, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var account = _accountRepository.Get(userId, accountId);
|
||||
if (account == null || !account.AccessRights!.Any() || account.AccessRights!.Count() == 1)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
var access = account.AccessRights!.FirstOrDefault(x => x.UserId == accessUserId);
|
||||
if (access == null)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
if (access.OwnerId == access.UserId)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
_accountAccessRepository.Delete(access);
|
||||
|
||||
account = _accountRepository.Get(userId, accountId);
|
||||
|
||||
return result.Set(_mapper.Map<AccountDto>(account));
|
||||
|
||||
}
|
||||
|
||||
public List<AccountAccessInviteDto> InvitesGet(string email)
|
||||
{
|
||||
return _mapper.Map<List<AccountAccessInviteDto>>(_accountAccessInviteRepository.GetActive(email).ToList());
|
||||
}
|
||||
|
||||
public Exec<AccountDto, InviteAcceptStatus> InviteAccept(Guid userId, Guid id, string name)
|
||||
{
|
||||
var result = new Exec<AccountDto, InviteAcceptStatus>(InviteAcceptStatus.success);
|
||||
|
||||
var invite = _accountAccessInviteRepository.Get(id);
|
||||
if (invite == null
|
||||
|| !invite.Email.EqualsIgnoreCase(_contextProvider.User.Email)
|
||||
|| invite.AcceptedOn.HasValue
|
||||
|| invite.RejectedOn.HasValue
|
||||
)
|
||||
{
|
||||
return result.Set(InviteAcceptStatus.invite_not_found);
|
||||
}
|
||||
|
||||
var account = _accountRepository.Get(invite.UserId, invite.AccountId);
|
||||
if (account == null)
|
||||
{
|
||||
return result.Set(InviteAcceptStatus.account_not_found);
|
||||
}
|
||||
|
||||
if (account.AccessRights!.Any(x => x.UserId == userId))
|
||||
{
|
||||
result.Set(InviteAcceptStatus.already_accepted);
|
||||
}
|
||||
else
|
||||
{
|
||||
_accountAccessRepository.Add(new AccountAccess
|
||||
{
|
||||
UserId = userId,
|
||||
AccountId = account.Id,
|
||||
OwnerId = invite.UserId,
|
||||
Name = name,
|
||||
IsAllowWrite = invite.IsAllowWrite,
|
||||
Type = AccountAccessTypeEnum.external,
|
||||
});
|
||||
}
|
||||
|
||||
invite.AcceptedOn = DateTime.UtcNow;
|
||||
_accountAccessInviteRepository.Update(invite);
|
||||
|
||||
account = _accountRepository.Get(userId, account.Id);
|
||||
|
||||
return result.Set(_mapper.Map<AccountDto>(account));
|
||||
}
|
||||
|
||||
public Exec<AccountAccessInviteDto, GeneralExecStatus> InviteReject(Guid id)
|
||||
{
|
||||
var result = new Exec<AccountAccessInviteDto, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var invite = _accountAccessInviteRepository.Get(id);
|
||||
if (invite == null
|
||||
|| !invite.Email.EqualsIgnoreCase(_contextProvider.User.Email)
|
||||
|| invite.AcceptedOn.HasValue
|
||||
|| invite.RejectedOn.HasValue
|
||||
)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
invite.RejectedOn = DateTime.UtcNow;
|
||||
_accountAccessInviteRepository.Update(invite);
|
||||
|
||||
return result.Set(_mapper.Map<AccountAccessInviteDto>(invite));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,209 @@
|
||||
namespace MyOffice.Services.Account;
|
||||
|
||||
using MyOffice.Core;
|
||||
using MyOffice.Core.Extensions;
|
||||
using MyOffice.Data.Models.Accounts;
|
||||
using MyOffice.Services.Account.Domain;
|
||||
|
||||
public partial class AccountService
|
||||
{
|
||||
public List<AccountDto> GetAllAccounts(Guid userId)
|
||||
{
|
||||
return _accountRepository
|
||||
.GetAll(userId)
|
||||
.ToDto<AccountDto>(_mapper);
|
||||
}
|
||||
|
||||
public List<AccountDto> GetByCategory(Guid userId, Guid categoryId)
|
||||
{
|
||||
return _accountRepository
|
||||
.GetByCategory(userId, categoryId)
|
||||
.ToDto<AccountDto>(_mapper);
|
||||
}
|
||||
|
||||
public List<AccountDto> FindAccounts(Guid userId, string term)
|
||||
{
|
||||
return _accountRepository
|
||||
.FindAccounts(userId, term)
|
||||
.ToDto<AccountDto>(_mapper);
|
||||
}
|
||||
|
||||
public List<AccountDetailedDto> GetByCategoryDetailed(Guid userId, Guid categoryId)
|
||||
{
|
||||
return _accountRepository
|
||||
.GetByCategoryDetailed(userId, categoryId)
|
||||
.ToDto<AccountDetailedDto>(_mapper);
|
||||
}
|
||||
|
||||
public Exec<AccountDetailedDto, GeneralExecStatus> GetByIdDetailed(Guid userId, Guid id)
|
||||
{
|
||||
var result = new Exec<AccountDetailedDto, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var account = _accountRepository.GetByIdDetailed(userId, id);
|
||||
if (account == null)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
return result.Set(account.ToDto<AccountDetailedDto>(_mapper));;
|
||||
}
|
||||
|
||||
public Exec<AccountDto, AccountAddStatus> AccountAdd(Guid userId, AccountAdd input)
|
||||
{
|
||||
if (input == null)
|
||||
throw new ArgumentNullException(nameof(input));
|
||||
|
||||
var result = new Exec<AccountDto, AccountAddStatus>(AccountAddStatus.success);
|
||||
|
||||
var category = _accountCategoryRepository.Get(userId, input.CategoryId);
|
||||
if (category == null)
|
||||
{
|
||||
return result.Set(AccountAddStatus.category_not_found);
|
||||
}
|
||||
var currency = _currencyRepository.GetByGlobalCurrency(userId, input.CurrencyId);
|
||||
if (currency == null)
|
||||
{
|
||||
return result.Set(AccountAddStatus.currency_not_found);
|
||||
}
|
||||
|
||||
var account = new Account
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Name = input.Name,
|
||||
CurrencyGlobalId = currency.CurrencyGlobalId,
|
||||
OwnerId = userId,
|
||||
};
|
||||
|
||||
account.Categories = new List<AccountAccountCategory>
|
||||
{
|
||||
new()
|
||||
{
|
||||
AccountId = account.Id,
|
||||
CategoryId = category.Id,
|
||||
}
|
||||
};
|
||||
account.AccessRights = new List<AccountAccess>
|
||||
{
|
||||
new()
|
||||
{
|
||||
AccountId = account.Id,
|
||||
UserId = userId,
|
||||
OwnerId = userId,
|
||||
IsAllowManage = true,
|
||||
IsAllowRead = true,
|
||||
IsAllowWrite = true,
|
||||
}
|
||||
};
|
||||
|
||||
if (!_accountRepository.Add(account))
|
||||
{
|
||||
return result.Set(AccountAddStatus.failure);
|
||||
}
|
||||
// TODO: Add category refactoring
|
||||
if (!_accountAccountCategoryRepository.Add(account.Categories.FirstOrDefault()!))
|
||||
{
|
||||
return result.Set(AccountAddStatus.failure);
|
||||
}
|
||||
// TODO: Add access refactoring
|
||||
if (!_accountAccessRepository.Add(account.AccessRights.FirstOrDefault()!))
|
||||
{
|
||||
return result.Set(AccountAddStatus.failure);
|
||||
}
|
||||
|
||||
// TODO: Add account update AccessRights ???
|
||||
var access = account.AccessRights!.FirstOrDefault(x => x.UserId == userId);
|
||||
if (access != null && access.Type.ToString() != input.Type)
|
||||
{
|
||||
if (Enum.TryParse<AccountAccessTypeEnum>(input.Type, out var enumType))
|
||||
{
|
||||
access.Type = enumType;
|
||||
_accountAccessRepository.Update(access);
|
||||
}
|
||||
}
|
||||
|
||||
return result.Set(account.ToDto<AccountDto>(_mapper));
|
||||
}
|
||||
|
||||
public Exec<AccountDto, GeneralExecStatus> AccountDelete(Guid userId, string id)
|
||||
{
|
||||
var result = new Exec<AccountDto, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var account = _accountRepository.Get(userId, id.AsGuid());
|
||||
if (account == null)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
if (account.Motions!.Any())
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
_accountRepository.Delete(account);
|
||||
result.Set(account.ToDto<AccountDto>(_mapper));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Exec<AccountDto, AccountEditStatus> AccountUpdate(Guid userId, Guid accountId, AccountEdit input)
|
||||
{
|
||||
if (input == null)
|
||||
throw new ArgumentNullException(nameof(input));
|
||||
|
||||
var result = new Exec<AccountDto, AccountEditStatus>(AccountEditStatus.success);
|
||||
|
||||
AccountCategory? category = null;
|
||||
if (input.CategoryId.HasValue)
|
||||
{
|
||||
category = _accountCategoryRepository.Get(userId, input.CategoryId.Value);
|
||||
if (category == null)
|
||||
{
|
||||
return result.Set(AccountEditStatus.category_not_found);
|
||||
}
|
||||
}
|
||||
|
||||
var currency = _currencyRepository.GetByGlobalCurrency(userId, input.CurrencyId);
|
||||
if (currency == null)
|
||||
{
|
||||
return result.Set(AccountEditStatus.currency_not_found);
|
||||
}
|
||||
|
||||
var account = _accountRepository.Get(userId, accountId);
|
||||
if (account == null)
|
||||
{
|
||||
return result.Set(AccountEditStatus.not_found);
|
||||
}
|
||||
|
||||
account.Name = input.Name;
|
||||
if (account.CurrencyGlobalId != currency.CurrencyGlobalId)
|
||||
{
|
||||
account.CurrencyGlobalId = currency.CurrencyGlobalId;
|
||||
}
|
||||
|
||||
if (category != null && account.Categories!.All(x => x.CategoryId != category.Id))
|
||||
{
|
||||
_accountAccountCategoryRepository.Add(new AccountAccountCategory
|
||||
{
|
||||
AccountId = account.Id,
|
||||
CategoryId = category.Id,
|
||||
});
|
||||
}
|
||||
|
||||
if (!_accountRepository.Update(account))
|
||||
{
|
||||
return result.Set(AccountEditStatus.failure);
|
||||
}
|
||||
|
||||
var access = account.AccessRights!.FirstOrDefault(x => x.UserId == userId);
|
||||
if (access != null && access.Type.ToString() != input.Type)
|
||||
{
|
||||
if (Enum.TryParse<AccountAccessTypeEnum>(input.Type, out var enumType))
|
||||
{
|
||||
access.Type = enumType;
|
||||
_accountAccessRepository.Update(access);
|
||||
}
|
||||
}
|
||||
|
||||
return result.Set(account.ToDto<AccountDto>(_mapper));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
namespace MyOffice.Services.Account;
|
||||
|
||||
using MyOffice.Core;
|
||||
using MyOffice.Data.Models.Accounts;
|
||||
using MyOffice.Services.Account.Domain;
|
||||
|
||||
public partial class AccountService
|
||||
{
|
||||
public List<AccountCategoryDto> GetAllCategories(Guid userId)
|
||||
{
|
||||
var categories = _accountCategoryRepository.GetAll(userId);
|
||||
|
||||
return _mapper.Map<List<AccountCategoryDto>>(categories);
|
||||
}
|
||||
|
||||
public Exec<AccountCategoryDto, GeneralExecStatus> GetCategory(Guid userId, Guid id)
|
||||
{
|
||||
var result = new Exec<AccountCategoryDto, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var category = _accountCategoryRepository.Get(userId, id);
|
||||
|
||||
if (category == null)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
return result.Set(_mapper.Map<AccountCategoryDto>(category));
|
||||
}
|
||||
|
||||
public Exec<AccountCategoryDto, GeneralExecStatus> CategoryAdd(Guid userId, AccountCategoryDto input)
|
||||
{
|
||||
if (input == null)
|
||||
throw new ArgumentNullException(nameof(input));
|
||||
|
||||
var result = new Exec<AccountCategoryDto, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var category = new AccountCategory
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
UserId = userId,
|
||||
Name = input.Name,
|
||||
};
|
||||
|
||||
if (!_accountCategoryRepository.Add(category))
|
||||
{
|
||||
return result.Set(GeneralExecStatus.failure);
|
||||
}
|
||||
|
||||
return result.Set(_mapper.Map<AccountCategoryDto>(category));
|
||||
}
|
||||
|
||||
public Exec<AccountCategoryDto, GeneralExecStatus> CategoryUpdate(Guid userId, Guid id, AccountCategoryDto input)
|
||||
{
|
||||
if (input == null)
|
||||
throw new ArgumentNullException(nameof(input));
|
||||
|
||||
var result = new Exec<AccountCategoryDto, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var exists = _accountCategoryRepository.Get(userId, id);
|
||||
if (exists == null)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
exists.Name = input.Name;
|
||||
|
||||
if (!_accountCategoryRepository.Update(exists))
|
||||
{
|
||||
return result.Set(GeneralExecStatus.failure);
|
||||
}
|
||||
|
||||
return result.Set(_mapper.Map<AccountCategoryDto>(exists));
|
||||
}
|
||||
|
||||
public Exec<AccountCategoryDto, AccountCategoryRemoveResult> CategoryRemove(Guid userId, Guid id)
|
||||
{
|
||||
var result = new Exec<AccountCategoryDto, AccountCategoryRemoveResult>(AccountCategoryRemoveResult.success);
|
||||
|
||||
var exists = _accountCategoryRepository.Get(userId, id);
|
||||
if (exists == null)
|
||||
{
|
||||
return result.Set(AccountCategoryRemoveResult.not_found);
|
||||
}
|
||||
|
||||
if (exists.Accounts?.Any() == true)
|
||||
{
|
||||
return result.Set(AccountCategoryRemoveResult.accounts_exists);
|
||||
}
|
||||
if (!_accountCategoryRepository.Remove(exists))
|
||||
{
|
||||
return result.Set(AccountCategoryRemoveResult.failure);
|
||||
}
|
||||
|
||||
return result.Set(_mapper.Map<AccountCategoryDto>(exists));
|
||||
}
|
||||
|
||||
public Exec<List<AccountAccountCategoryDto>, GeneralExecStatus> AccountCategoryRemove(Guid userId, Guid accountId, Guid categoryId)
|
||||
{
|
||||
var result = new Exec<List<AccountAccountCategoryDto>, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var categories = _accountAccountCategoryRepository.Get(userId, accountId, categoryId);
|
||||
if (categories.Count == 0)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
foreach (var category in categories)
|
||||
{
|
||||
_accountAccountCategoryRepository.Remove(category);
|
||||
}
|
||||
|
||||
return result.Set(_mapper.Map<List<AccountAccountCategoryDto>>(categories));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
namespace MyOffice.Services.Account;
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Core;
|
||||
using Core.Extensions;
|
||||
using Data.Models.Accounts;
|
||||
using Domain;
|
||||
using Item.Domain;
|
||||
|
||||
public partial class AccountService
|
||||
{
|
||||
public Exec<List<MotionDto>, MotionAddStatus> MotionAdd(
|
||||
Guid userId,
|
||||
Guid accountId,
|
||||
MotionAddUpdate motion
|
||||
)
|
||||
{
|
||||
if (motion == null)
|
||||
throw new ArgumentNullException(nameof(motion));
|
||||
if (motion.Item == null)
|
||||
throw new ArgumentNullException(nameof(motion.Item));
|
||||
|
||||
var result = new Exec<List<MotionDto>, MotionAddStatus>(MotionAddStatus.success);
|
||||
|
||||
var account = _accountRepository.Get(userId, accountId);
|
||||
if (account == null)
|
||||
{
|
||||
return result.Set(MotionAddStatus.account_not_found);
|
||||
}
|
||||
|
||||
var itemExec = _itemService.GetOrCreate(userId, motion.Item);
|
||||
if (itemExec.Status != ItemGetOrAddResult.success)
|
||||
{
|
||||
return result.Set(MotionAddStatus.failure);
|
||||
}
|
||||
|
||||
var motionDb = new Motion
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
CreatedOn = DateTime.UtcNow,
|
||||
DateTime = motion.Date,
|
||||
AccountId = account.Id,
|
||||
ItemId = itemExec.Result!.Id,
|
||||
Description = motion.Description,
|
||||
AmountPlus = motion.Plus,
|
||||
AmountMinus = motion.Minus,
|
||||
};
|
||||
|
||||
if (!_motionRepository.Add(motionDb))
|
||||
{
|
||||
return result.Set(MotionAddStatus.failure);
|
||||
}
|
||||
|
||||
result.Set(new List<MotionDto>());
|
||||
result.Result!.Add(_mapper.Map<MotionDto>(motionDb));
|
||||
|
||||
if (motion.AccountId.IsPresent() && motion.AmountBalancing != 0)
|
||||
{
|
||||
var accountBalancing = _accountRepository.Get(userId, motion.AccountId!.AsGuid());
|
||||
if (accountBalancing != null)
|
||||
{
|
||||
var balancingName = $"+{account.Name}";
|
||||
var itemBalancingExec = _itemService.GetOrCreate(userId, balancingName);
|
||||
var plus = motion.AmountBalancing;
|
||||
var minus = 0m;
|
||||
if (motion.Plus != 0)
|
||||
{
|
||||
plus = 0;
|
||||
minus = motion.AmountBalancing;
|
||||
}
|
||||
var motionBalancing = new Motion
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
CreatedOn = DateTime.UtcNow,
|
||||
DateTime = motion.Date,
|
||||
AccountId = accountBalancing.Id,
|
||||
ItemId = itemBalancingExec.Result!.Id,
|
||||
Description = motion.Description,
|
||||
AmountPlus = plus,
|
||||
AmountMinus = minus,
|
||||
};
|
||||
|
||||
if (_motionRepository.Add(motionBalancing))
|
||||
{
|
||||
result.Result!.Add(_mapper.Map<MotionDto>(motionBalancing));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
motionDb.Item = itemExec.Result!;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Exec<MotionDto, MotionUpdateStatus> MotionUpdate(
|
||||
Guid userId,
|
||||
Guid accountId,
|
||||
Guid motionId,
|
||||
MotionAddUpdate motion
|
||||
)
|
||||
{
|
||||
if (motion == null)
|
||||
throw new ArgumentNullException(nameof(motion));
|
||||
if (motion.Item == null)
|
||||
throw new ArgumentNullException(nameof(motion.Item));
|
||||
|
||||
var result = new Exec<MotionDto, MotionUpdateStatus>(MotionUpdateStatus.success);
|
||||
|
||||
var exists = _motionRepository.Get(userId, motionId);
|
||||
if (exists == null || exists.AccountId != accountId)
|
||||
{
|
||||
return result.Set(MotionUpdateStatus.not_found);
|
||||
}
|
||||
|
||||
var itemExec = _itemService.GetOrCreate(userId, motion.Item);
|
||||
if (itemExec.Status != ItemGetOrAddResult.success)
|
||||
{
|
||||
return result.Set(MotionUpdateStatus.failure);
|
||||
}
|
||||
|
||||
exists.Item.Id = itemExec.Result!.Id;
|
||||
exists.DateTime = motion.Date;
|
||||
exists.Description = motion.Description;
|
||||
exists.AmountPlus = motion.Plus;
|
||||
exists.AmountMinus = motion.Minus;
|
||||
|
||||
if (!_motionRepository.Update(exists))
|
||||
{
|
||||
return result.Set(MotionUpdateStatus.failure);
|
||||
|
||||
}
|
||||
|
||||
return result.Set(_mapper.Map<MotionDto>(exists));
|
||||
}
|
||||
|
||||
public Exec<List<MotionDto>, GeneralExecStatus> GetMotions(
|
||||
Guid userId,
|
||||
Guid accountId,
|
||||
DateTime dateFrom,
|
||||
DateTime dateTo
|
||||
)
|
||||
{
|
||||
var result = new Exec<List<MotionDto>, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var account = _accountRepository.Get(userId, accountId);
|
||||
if (account == null)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
var motions = _motionRepository.GetByAccount(accountId, dateFrom.ToUtc(), dateTo.ToUtc());
|
||||
|
||||
return result.Set(_mapper.Map<List<MotionDto>>(motions));
|
||||
}
|
||||
|
||||
public Exec<MotionDto, MotionDeleteStatus> MotionRemove(
|
||||
Guid userId,
|
||||
Guid accountId,
|
||||
Guid motionId
|
||||
)
|
||||
{
|
||||
var result = new Exec<MotionDto, MotionDeleteStatus>(MotionDeleteStatus.success);
|
||||
|
||||
var exists = _motionRepository.Get(userId, motionId);
|
||||
if (exists == null || exists.AccountId != accountId)
|
||||
{
|
||||
return result.Set(MotionDeleteStatus.not_found);
|
||||
}
|
||||
|
||||
if (!_motionRepository.Remove(exists))
|
||||
{
|
||||
return result.Set(MotionDeleteStatus.failure);
|
||||
}
|
||||
|
||||
return result.Set(_mapper.Map<MotionDto>(exists));
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,16 @@
|
||||
namespace MyOffice.Services.Account
|
||||
namespace MyOffice.Services.Account;
|
||||
|
||||
using AutoMapper;
|
||||
using Microsoft.Extensions.Logging;
|
||||
|
||||
using Identity;
|
||||
using Data.Repositories.Account;
|
||||
using Data.Repositories.Currency;
|
||||
using Data.Repositories.Item;
|
||||
using Item;
|
||||
|
||||
public partial class AccountService
|
||||
{
|
||||
using AutoMapper;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Identity;
|
||||
using Core;
|
||||
using Core.Extensions;
|
||||
using Data.Models.Accounts;
|
||||
using Data.Repositories.Account;
|
||||
using Data.Repositories.Currency;
|
||||
using Data.Repositories.Item;
|
||||
using Domain;
|
||||
using Item;
|
||||
using Item.Domain;
|
||||
|
||||
public class AccountService
|
||||
{
|
||||
private ILogger<AccountService> _logger;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly IAccountCategoryRepository _accountCategoryRepository;
|
||||
@@ -61,625 +55,4 @@
|
||||
_itemService = itemService;
|
||||
_contextProvider = contextProvider;
|
||||
}
|
||||
|
||||
public List<AccountCategoryDto> GetAllCategories(Guid userId)
|
||||
{
|
||||
var categories = _accountCategoryRepository.GetAll(userId);
|
||||
|
||||
return _mapper.Map<List<AccountCategoryDto>>(categories);
|
||||
}
|
||||
|
||||
public Exec<AccountCategoryDto, GeneralExecStatus> GetCategory(Guid userId, Guid id)
|
||||
{
|
||||
var result = new Exec<AccountCategoryDto, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var category = _accountCategoryRepository.Get(userId, id);
|
||||
|
||||
if (category == null)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
return result.Set(_mapper.Map<AccountCategoryDto>(category));
|
||||
}
|
||||
|
||||
public Exec<AccountCategoryDto, GeneralExecStatus> CategoryAdd(Guid userId, AccountCategoryDto input)
|
||||
{
|
||||
if (input == null)
|
||||
throw new ArgumentNullException(nameof(input));
|
||||
|
||||
var result = new Exec<AccountCategoryDto, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var category = new AccountCategory
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
UserId = userId,
|
||||
Name = input.Name,
|
||||
};
|
||||
|
||||
if (!_accountCategoryRepository.Add(category))
|
||||
{
|
||||
return result.Set(GeneralExecStatus.failure);
|
||||
}
|
||||
|
||||
return result.Set(_mapper.Map<AccountCategoryDto>(category));
|
||||
}
|
||||
|
||||
public Exec<AccountCategoryDto, GeneralExecStatus> CategoryUpdate(Guid userId, Guid id, AccountCategoryDto input)
|
||||
{
|
||||
if (input == null)
|
||||
throw new ArgumentNullException(nameof(input));
|
||||
|
||||
var result = new Exec<AccountCategoryDto, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var exists = _accountCategoryRepository.Get(userId, id);
|
||||
if (exists == null)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
exists.Name = input.Name;
|
||||
|
||||
if (!_accountCategoryRepository.Update(exists))
|
||||
{
|
||||
return result.Set(GeneralExecStatus.failure);
|
||||
}
|
||||
|
||||
return result.Set(_mapper.Map<AccountCategoryDto>(exists));
|
||||
}
|
||||
|
||||
public Exec<AccountCategoryDto, AccountCategoryRemoveResult> CategoryRemove(Guid userId, Guid id)
|
||||
{
|
||||
var result = new Exec<AccountCategoryDto, AccountCategoryRemoveResult>(AccountCategoryRemoveResult.success);
|
||||
|
||||
var exists = _accountCategoryRepository.Get(userId, id);
|
||||
if (exists == null)
|
||||
{
|
||||
return result.Set(AccountCategoryRemoveResult.not_found);
|
||||
}
|
||||
|
||||
if (exists.Accounts?.Any() == true)
|
||||
{
|
||||
return result.Set(AccountCategoryRemoveResult.accounts_exists);
|
||||
}
|
||||
if (!_accountCategoryRepository.Remove(exists))
|
||||
{
|
||||
return result.Set(AccountCategoryRemoveResult.failure);
|
||||
}
|
||||
|
||||
return result.Set(_mapper.Map<AccountCategoryDto>(exists));
|
||||
}
|
||||
|
||||
public List<AccountDto> GetAllAccounts(Guid userId)
|
||||
{
|
||||
var accounts = _accountRepository.GetAll(userId);
|
||||
|
||||
return _mapper.Map<List<AccountDto>>(accounts, o => o.Items.Add("UserId", userId));
|
||||
}
|
||||
|
||||
public List<AccountDto> GetByCategory(Guid userId, Guid categoryId)
|
||||
{
|
||||
return _mapper.Map<List<AccountDto>>(_accountRepository.GetByCategory(userId, categoryId));
|
||||
}
|
||||
|
||||
public List<AccountDetailedDto> GetByCategoryDetailed(Guid userId, Guid categoryId)
|
||||
{
|
||||
return _mapper.Map<List<AccountDetailedDto>>(_accountRepository.GetByCategoryDetailed(userId, categoryId));
|
||||
}
|
||||
|
||||
public Exec<AccountDetailedDto, GeneralExecStatus> GetByIdDetailed(Guid userId, Guid id)
|
||||
{
|
||||
var result = new Exec<AccountDetailedDto, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var account = _accountRepository.GetByIdDetailed(userId, id);
|
||||
if (account == null)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
return result.Set(_mapper.Map<AccountDetailedDto>(account));
|
||||
}
|
||||
|
||||
public Exec<Account, AccountAddStatus> AccountAdd(Guid userId, AccountAdd input)
|
||||
{
|
||||
if (input == null)
|
||||
throw new ArgumentNullException(nameof(input));
|
||||
|
||||
var result = new Exec<Account, AccountAddStatus>(AccountAddStatus.success);
|
||||
|
||||
var category = _accountCategoryRepository.Get(userId, input.CategoryId);
|
||||
if (category == null)
|
||||
{
|
||||
return result.Set(AccountAddStatus.category_not_found);
|
||||
}
|
||||
var currency = _currencyRepository.GetByGlobalCurrency(userId, input.CurrencyId);
|
||||
if (currency == null)
|
||||
{
|
||||
return result.Set(AccountAddStatus.currency_not_found);
|
||||
}
|
||||
|
||||
var account = new Account
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
Name = input.Name,
|
||||
CurrencyGlobalId = currency.CurrencyGlobalId,
|
||||
OwnerId = userId,
|
||||
};
|
||||
|
||||
account.Categories = new List<AccountAccountCategory>
|
||||
{
|
||||
new()
|
||||
{
|
||||
AccountId = account.Id,
|
||||
CategoryId = category.Id,
|
||||
}
|
||||
};
|
||||
account.AccessRights = new List<AccountAccess>
|
||||
{
|
||||
new()
|
||||
{
|
||||
AccountId = account.Id,
|
||||
UserId = userId,
|
||||
OwnerId = userId,
|
||||
IsAllowManage = true,
|
||||
IsAllowRead = true,
|
||||
IsAllowWrite = true,
|
||||
}
|
||||
};
|
||||
|
||||
if (!_accountRepository.Add(account))
|
||||
{
|
||||
return result.Set(AccountAddStatus.failure);
|
||||
}
|
||||
|
||||
var access = account.AccessRights!.FirstOrDefault(x => x.UserId == userId);
|
||||
if (access != null && access.Type.ToString() != input.Type)
|
||||
{
|
||||
if (Enum.TryParse<AccountAccessTypeEnum>(input.Type, out var enumType))
|
||||
{
|
||||
access.Type = enumType;
|
||||
_accountAccessRepository.Update(access);
|
||||
}
|
||||
}
|
||||
|
||||
return result.Set(account);
|
||||
}
|
||||
|
||||
public Exec<Account, GeneralExecStatus> AccountDelete(Guid userId, string id)
|
||||
{
|
||||
var result = new Exec<Account, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var account = _accountRepository.Get(userId, id.AsGuid());
|
||||
if (account == null)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
if (account.Motions!.Any())
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
_accountRepository.Delete(account);
|
||||
result.Set(account);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Exec<Account, AccountEditStatus> AccountUpdate(Guid userId, Guid accountId, AccountEdit input)
|
||||
{
|
||||
if (input == null)
|
||||
throw new ArgumentNullException(nameof(input));
|
||||
|
||||
var result = new Exec<Account, AccountEditStatus>(AccountEditStatus.success);
|
||||
|
||||
AccountCategory? category = null;
|
||||
if (input.CategoryId.HasValue)
|
||||
{
|
||||
category = _accountCategoryRepository.Get(userId, input.CategoryId.Value);
|
||||
if (category == null)
|
||||
{
|
||||
return result.Set(AccountEditStatus.category_not_found);
|
||||
}
|
||||
}
|
||||
|
||||
var currency = _currencyRepository.GetByGlobalCurrency(userId, input.CurrencyId);
|
||||
if (currency == null)
|
||||
{
|
||||
return result.Set(AccountEditStatus.currency_not_found);
|
||||
}
|
||||
|
||||
var account = _accountRepository.Get(userId, accountId);
|
||||
if (account == null)
|
||||
{
|
||||
return result.Set(AccountEditStatus.not_found);
|
||||
}
|
||||
|
||||
account.Name = input.Name;
|
||||
if (account.CurrencyGlobalId != currency.CurrencyGlobalId)
|
||||
{
|
||||
account.CurrencyGlobalId = currency.CurrencyGlobalId;
|
||||
}
|
||||
|
||||
if (category != null && account.Categories!.All(x => x.CategoryId != category.Id))
|
||||
{
|
||||
_accountAccountCategoryRepository.Add(new AccountAccountCategory
|
||||
{
|
||||
AccountId = account.Id,
|
||||
CategoryId = category.Id,
|
||||
});
|
||||
}
|
||||
|
||||
if (!_accountRepository.Update(account))
|
||||
{
|
||||
return result.Set(AccountEditStatus.failure);
|
||||
}
|
||||
|
||||
var access = account.AccessRights!.FirstOrDefault(x => x.UserId == userId);
|
||||
if (access != null && access.Type.ToString() != input.Type)
|
||||
{
|
||||
if (Enum.TryParse<AccountAccessTypeEnum>(input.Type, out var enumType))
|
||||
{
|
||||
access.Type = enumType;
|
||||
_accountAccessRepository.Update(access);
|
||||
}
|
||||
}
|
||||
|
||||
return result.Set(account);
|
||||
}
|
||||
|
||||
public Exec<List<AccountAccountCategory>, GeneralExecStatus> AccountCategoryRemove(Guid userId, Guid accountId, Guid categoryId)
|
||||
{
|
||||
var result = new Exec<List<AccountAccountCategory>, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var categories = _accountAccountCategoryRepository.Get(userId, accountId, categoryId);
|
||||
if (categories.Count == 0)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
foreach (var category in categories)
|
||||
{
|
||||
_accountAccountCategoryRepository.Remove(category);
|
||||
}
|
||||
|
||||
return result.Set(categories);
|
||||
}
|
||||
|
||||
public Exec<List<MotionDto>, MotionAddStatus> MotionAdd(
|
||||
Guid userId,
|
||||
Guid accountId,
|
||||
MotionAddUpdate motion
|
||||
)
|
||||
{
|
||||
if (motion == null)
|
||||
throw new ArgumentNullException(nameof(motion));
|
||||
if (motion.Item == null)
|
||||
throw new ArgumentNullException(nameof(motion.Item));
|
||||
|
||||
var result = new Exec<List<MotionDto>, MotionAddStatus>(MotionAddStatus.success);
|
||||
|
||||
var account = _accountRepository.Get(userId, accountId);
|
||||
if (account == null)
|
||||
{
|
||||
return result.Set(MotionAddStatus.account_not_found);
|
||||
}
|
||||
|
||||
var itemExec = _itemService.GetOrCreate(userId, motion.Item);
|
||||
if (itemExec.Status != ItemGetOrAddResult.success)
|
||||
{
|
||||
return result.Set(MotionAddStatus.failure);
|
||||
}
|
||||
|
||||
var motionDb = new Motion
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
CreatedOn = DateTime.UtcNow,
|
||||
DateTime = motion.Date,
|
||||
AccountId = account.Id,
|
||||
ItemId = itemExec.Result!.Id,
|
||||
Description = motion.Description,
|
||||
AmountPlus = motion.Plus,
|
||||
AmountMinus = motion.Minus,
|
||||
};
|
||||
|
||||
if (!_motionRepository.Add(motionDb))
|
||||
{
|
||||
return result.Set(MotionAddStatus.failure);
|
||||
}
|
||||
|
||||
result.Set(new List<MotionDto>());
|
||||
result.Result!.Add(_mapper.Map<MotionDto>(motionDb));
|
||||
|
||||
if (motion.AccountId.IsPresent() && motion.AmountBalancing != 0)
|
||||
{
|
||||
var accountBalancing = _accountRepository.Get(userId, motion.AccountId!.AsGuid());
|
||||
if (accountBalancing != null)
|
||||
{
|
||||
var balancingName = $"+{account.Name}";
|
||||
var itemBalancingExec = _itemService.GetOrCreate(userId, balancingName);
|
||||
var plus = motion.AmountBalancing;
|
||||
var minus = 0m;
|
||||
if (motion.Plus != 0)
|
||||
{
|
||||
plus = 0;
|
||||
minus = motion.AmountBalancing;
|
||||
}
|
||||
var motionBalancing = new Motion
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
CreatedOn = DateTime.UtcNow,
|
||||
DateTime = motion.Date,
|
||||
AccountId = accountBalancing.Id,
|
||||
ItemId = itemBalancingExec.Result!.Id,
|
||||
Description = motion.Description,
|
||||
AmountPlus = plus,
|
||||
AmountMinus = minus,
|
||||
};
|
||||
|
||||
if (_motionRepository.Add(motionBalancing))
|
||||
{
|
||||
result.Result!.Add(_mapper.Map<MotionDto>(motionBalancing));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
motionDb.Item = itemExec.Result!;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public Exec<MotionDto, MotionUpdateStatus> MotionUpdate(
|
||||
Guid userId,
|
||||
Guid accountId,
|
||||
Guid motionId,
|
||||
MotionAddUpdate motion
|
||||
)
|
||||
{
|
||||
if (motion == null)
|
||||
throw new ArgumentNullException(nameof(motion));
|
||||
if (motion.Item == null)
|
||||
throw new ArgumentNullException(nameof(motion.Item));
|
||||
|
||||
var result = new Exec<MotionDto, MotionUpdateStatus>(MotionUpdateStatus.success);
|
||||
|
||||
var exists = _motionRepository.Get(userId, motionId);
|
||||
if (exists == null || exists.AccountId != accountId)
|
||||
{
|
||||
return result.Set(MotionUpdateStatus.not_found);
|
||||
}
|
||||
|
||||
var itemExec = _itemService.GetOrCreate(userId, motion.Item);
|
||||
if (itemExec.Status != ItemGetOrAddResult.success)
|
||||
{
|
||||
return result.Set(MotionUpdateStatus.failure);
|
||||
}
|
||||
|
||||
exists.Item.Id = itemExec.Result!.Id;
|
||||
exists.DateTime = motion.Date;
|
||||
exists.Description = motion.Description;
|
||||
exists.AmountPlus = motion.Plus;
|
||||
exists.AmountMinus = motion.Minus;
|
||||
|
||||
if (!_motionRepository.Update(exists))
|
||||
{
|
||||
return result.Set(MotionUpdateStatus.failure);
|
||||
|
||||
}
|
||||
|
||||
return result.Set(_mapper.Map<MotionDto>(exists));
|
||||
}
|
||||
|
||||
public Exec<List<Motion>, GeneralExecStatus> GetMotions(
|
||||
Guid userId,
|
||||
Guid accountId,
|
||||
DateTime dateFrom,
|
||||
DateTime dateTo
|
||||
)
|
||||
{
|
||||
var result = new Exec<List<Motion>, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var account = _accountRepository.Get(userId, accountId);
|
||||
if (account == null)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
var motions = _motionRepository.GetByAccount(accountId, dateFrom.ToUtc(), dateTo.ToUtc());
|
||||
|
||||
return result.Set(motions);
|
||||
}
|
||||
|
||||
public Exec<Motion, MotionDeleteStatus> MotionRemove(
|
||||
Guid userId,
|
||||
Guid accountId,
|
||||
Guid motionId
|
||||
)
|
||||
{
|
||||
var result = new Exec<Motion, MotionDeleteStatus>(MotionDeleteStatus.success);
|
||||
|
||||
var exists = _motionRepository.Get(userId, motionId);
|
||||
if (exists == null || exists.AccountId != accountId)
|
||||
{
|
||||
return result.Set(MotionDeleteStatus.not_found);
|
||||
}
|
||||
|
||||
if (!_motionRepository.Remove(exists))
|
||||
{
|
||||
return result.Set(MotionDeleteStatus.failure);
|
||||
}
|
||||
|
||||
return result.Set(exists);
|
||||
}
|
||||
|
||||
public List<Account> FindAccounts(Guid userId, string term)
|
||||
{
|
||||
return _accountRepository.FindAccounts(userId, term);
|
||||
}
|
||||
|
||||
public Exec<AccountAccessInvite, AccessInviteStatus> AccessInvite(Guid userId, Guid accountId, string email, bool isAllowWrite)
|
||||
{
|
||||
if (email == null)
|
||||
throw new ArgumentNullException(nameof(email));
|
||||
|
||||
var result = new Exec<AccountAccessInvite, AccessInviteStatus>(AccessInviteStatus.success);
|
||||
|
||||
var account = _accountRepository.Get(userId, accountId);
|
||||
if (account == null)
|
||||
{
|
||||
return result.Set(AccessInviteStatus.account_not_found);
|
||||
}
|
||||
|
||||
if (account.AccessRights!.Any(x => x.User!.Email.EqualsIgnoreCase(email)))
|
||||
{
|
||||
return result.Set(AccessInviteStatus.access_exists);
|
||||
}
|
||||
|
||||
var access = _accountAccessInviteRepository.Get(userId, email);
|
||||
if (access != null)
|
||||
{
|
||||
return result.Set(AccessInviteStatus.invite_exists);
|
||||
}
|
||||
|
||||
var invite = new AccountAccessInvite
|
||||
{
|
||||
Id = Guid.NewGuid(),
|
||||
CreatedOn = DateTime.UtcNow,
|
||||
UserId = userId,
|
||||
AccountId = account.Id,
|
||||
Email = email.SafeTrim()!,
|
||||
IsAllowWrite = isAllowWrite,
|
||||
};
|
||||
|
||||
_accountAccessInviteRepository.Add(invite);
|
||||
|
||||
return result.Set(invite);
|
||||
}
|
||||
|
||||
public Exec<AccountDto, GeneralExecStatus> AccessUpdate(Guid userId, Guid accountId, List<AccountAccessDto> accesses)
|
||||
{
|
||||
if (accesses == null)
|
||||
throw new ArgumentNullException(nameof(accesses));
|
||||
|
||||
var result = new Exec<AccountDto, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var account = _accountRepository.Get(userId, accountId);
|
||||
if (account == null)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
foreach (var access in account.AccessRights!)
|
||||
{
|
||||
var newAccess = accesses.FirstOrDefault(x => x.UserId == access.UserId);
|
||||
if (newAccess != null && newAccess.IsAllowWrite != access.IsAllowWrite)
|
||||
{
|
||||
access.IsAllowWrite = newAccess.IsAllowWrite;
|
||||
_accountAccessRepository.Update(access);
|
||||
}
|
||||
}
|
||||
|
||||
account = _accountRepository.Get(userId, accountId);
|
||||
|
||||
return result.Set(_mapper.Map<AccountDto>(account));
|
||||
}
|
||||
|
||||
public Exec<AccountDto, GeneralExecStatus> AccessDelete(Guid userId, Guid accountId, Guid accessUserId)
|
||||
{
|
||||
var result = new Exec<AccountDto, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var account = _accountRepository.Get(userId, accountId);
|
||||
if (account == null || !account.AccessRights!.Any() || account.AccessRights!.Count() == 1)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
var access = account.AccessRights!.FirstOrDefault(x => x.UserId == accessUserId);
|
||||
if (access == null)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
if (access.OwnerId == access.UserId)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
_accountAccessRepository.Delete(access);
|
||||
|
||||
account = _accountRepository.Get(userId, accountId);
|
||||
|
||||
return result.Set(_mapper.Map<AccountDto>(account));
|
||||
|
||||
}
|
||||
|
||||
public List<AccountAccessInviteDto> InvitesGet(string email)
|
||||
{
|
||||
return _mapper.Map<List<AccountAccessInviteDto>>(_accountAccessInviteRepository.GetActive(email).ToList());
|
||||
}
|
||||
|
||||
public Exec<AccountDto, InviteAcceptStatus> InviteAccept(Guid userId, Guid id, string name)
|
||||
{
|
||||
var result = new Exec<AccountDto, InviteAcceptStatus>(InviteAcceptStatus.success);
|
||||
|
||||
var invite = _accountAccessInviteRepository.Get(id);
|
||||
if (invite == null
|
||||
|| !invite.Email.EqualsIgnoreCase(_contextProvider.User.Email)
|
||||
|| invite.AcceptedOn.HasValue
|
||||
|| invite.RejectedOn.HasValue
|
||||
)
|
||||
{
|
||||
return result.Set(InviteAcceptStatus.invite_not_found);
|
||||
}
|
||||
|
||||
var account = _accountRepository.Get(invite.UserId, invite.AccountId);
|
||||
if (account == null)
|
||||
{
|
||||
return result.Set(InviteAcceptStatus.account_not_found);
|
||||
}
|
||||
|
||||
if (account.AccessRights!.Any(x => x.UserId == userId))
|
||||
{
|
||||
result.Set(InviteAcceptStatus.already_accepted);
|
||||
}
|
||||
else
|
||||
{
|
||||
_accountAccessRepository.Add(new AccountAccess
|
||||
{
|
||||
UserId = userId,
|
||||
AccountId = account.Id,
|
||||
OwnerId = invite.UserId,
|
||||
Name = name,
|
||||
IsAllowWrite = invite.IsAllowWrite,
|
||||
Type = AccountAccessTypeEnum.external,
|
||||
});
|
||||
}
|
||||
|
||||
invite.AcceptedOn = DateTime.UtcNow;
|
||||
_accountAccessInviteRepository.Update(invite);
|
||||
|
||||
account = _accountRepository.Get(userId, account.Id);
|
||||
|
||||
return result.Set(_mapper.Map<AccountDto>(account));
|
||||
}
|
||||
|
||||
public Exec<AccountAccessInviteDto, GeneralExecStatus> InviteReject(Guid id)
|
||||
{
|
||||
var result = new Exec<AccountAccessInviteDto, GeneralExecStatus>(GeneralExecStatus.success);
|
||||
|
||||
var invite = _accountAccessInviteRepository.Get(id);
|
||||
if (invite == null
|
||||
|| !invite.Email.EqualsIgnoreCase(_contextProvider.User.Email)
|
||||
|| invite.AcceptedOn.HasValue
|
||||
|| invite.RejectedOn.HasValue
|
||||
)
|
||||
{
|
||||
return result.Set(GeneralExecStatus.not_found);
|
||||
}
|
||||
|
||||
invite.RejectedOn = DateTime.UtcNow;
|
||||
_accountAccessInviteRepository.Update(invite);
|
||||
|
||||
return result.Set(_mapper.Map<AccountAccessInviteDto>(invite));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
namespace MyOffice.Services.Account.Domain;
|
||||
|
||||
using AutoMapper;
|
||||
using Core.Attributes;
|
||||
using Data.Models.Accounts;
|
||||
using Data.Models.Users;
|
||||
using Mapper;
|
||||
using MyOffice.Services.Identity;
|
||||
|
||||
[Link(typeof(AccountAccess))]
|
||||
[Link(typeof(AccountServiceProfile))]
|
||||
public class AccountAccessDto
|
||||
{
|
||||
/// <summary>
|
||||
/// Current user
|
||||
/// </summary>
|
||||
public Guid CurrenUserId { get; set; }
|
||||
|
||||
public Guid AccountId { get; set; }
|
||||
public AccountDto? Account { get; set; }
|
||||
|
||||
@@ -21,15 +18,41 @@ public class AccountAccessDto
|
||||
/// User can access to account
|
||||
/// </summary>
|
||||
public Guid UserId { get; set; }
|
||||
public User? User { get; set; }
|
||||
/// <summary>
|
||||
/// Who add access
|
||||
/// </summary>
|
||||
public Guid OwnerId { get; set; }
|
||||
public User? Owner { get; set; }
|
||||
public UserDto? User { get; set; }
|
||||
|
||||
public bool IsAllowRead { get; set; }
|
||||
public bool IsAllowWrite { get; set; }
|
||||
public bool IsAllowManage { get; set; }
|
||||
public bool IsOwner { get; set; }
|
||||
public AccountAccessTypeEnum Type { get; set; }
|
||||
/// <summary>
|
||||
/// Who add access
|
||||
/// </summary>
|
||||
public Guid OwnerId { get; set; }
|
||||
public UserDto? Owner { get; set; }
|
||||
public string? Name { get; set; }
|
||||
}
|
||||
|
||||
public class AccountAccessDtoProfile: Profile
|
||||
{
|
||||
public AccountAccessDtoProfile()
|
||||
{
|
||||
CreateMap<AccountAccess, AccountAccessDto>()
|
||||
.AfterMap<AccountAccessDtoMappingAction>()
|
||||
;
|
||||
}
|
||||
}
|
||||
|
||||
public class AccountAccessDtoMappingAction: IMappingAction<AccountAccess, AccountAccessDto>
|
||||
{
|
||||
private readonly IContextProvider _contextProvider;
|
||||
public AccountAccessDtoMappingAction(IContextProvider contextProvider)
|
||||
{
|
||||
_contextProvider = contextProvider;
|
||||
}
|
||||
|
||||
public void Process(AccountAccess source, AccountAccessDto destination, ResolutionContext context)
|
||||
{
|
||||
destination.IsOwner = destination.OwnerId == _contextProvider.UserId;
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,21 @@
|
||||
namespace MyOffice.Services.Account.Domain;
|
||||
using AutoMapper;
|
||||
using MyOffice.Core;
|
||||
using MyOffice.Data.Models.Accounts;
|
||||
|
||||
public class AccountDetailedDto
|
||||
namespace MyOffice.Services.Account.Domain;
|
||||
|
||||
public class AccountDetailedDto: IDataModelDto<AccountDetailed>
|
||||
{
|
||||
public AccountDto Account { get; set; } = null!;
|
||||
public decimal TotalPlus { get; set; }
|
||||
public decimal TotalMinus { get; set; }
|
||||
public decimal Rest => TotalPlus - TotalMinus;
|
||||
}
|
||||
|
||||
public class AccountDetailedDtoProfile: Profile
|
||||
{
|
||||
public AccountDetailedDtoProfile()
|
||||
{
|
||||
CreateMap<AccountDetailed, AccountDetailedDto>();
|
||||
}
|
||||
}
|
||||
@@ -1,27 +1,79 @@
|
||||
namespace MyOffice.Services.Account.Domain;
|
||||
|
||||
using MyOffice.Data.Models.Currencies;
|
||||
using System;
|
||||
using Data.Models.Accounts;
|
||||
using MyOffice.Services.Currency.Domain;
|
||||
using AutoMapper;
|
||||
using MyOffice.Services.Identity;
|
||||
using MyOffice.Core;
|
||||
using MyOffice.Services.Mapper;
|
||||
|
||||
public class AccountDto
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false)]
|
||||
public class GenerateMappedDtoAttribute: Attribute
|
||||
{
|
||||
public GenerateMappedDtoAttribute()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
[GenerateMappedDto]
|
||||
public class AccountDto : IDataModelDto<Account>
|
||||
{
|
||||
#region Account properties
|
||||
|
||||
public Guid Id { get; set; }
|
||||
public string CurrencyGlobalId { get; set; } = null!;
|
||||
public CurrencyGlobal? CurrencyGlobal { get; set; }
|
||||
public Guid CurrencyId { get; set; }
|
||||
public Currency? Currency { get; set; }
|
||||
public Guid UserId { get; set; }
|
||||
public UserDto? User { get; set; }
|
||||
public CurrencyGlobalDto? CurrencyGlobal { get; set; }
|
||||
public string Name { get; set; } = null!;
|
||||
public Guid OwnerId { get; set; }
|
||||
public UserDto? Owner { get; set; }
|
||||
public string Name { get; set; } = null!;
|
||||
public bool HasMotions { get; set; }
|
||||
|
||||
#endregion Account properties
|
||||
|
||||
#region Dto properties
|
||||
|
||||
public Guid CurrencyId { get; set; }
|
||||
public CurrencyDto? Currency { get; set; }
|
||||
public string Type { get; set; } = null!;
|
||||
public List<AccountAccessDto>? AccessRights { get; set; }
|
||||
public List<AccountAccountCategoryDto>? Categories { get; set; }
|
||||
|
||||
public bool HasMotions { get; set; }
|
||||
|
||||
public Guid CurrentUserId { get; set; }
|
||||
public AccountAccess? AccountAccess { get; set; }
|
||||
#endregion Dto properties
|
||||
|
||||
#region Permissions
|
||||
|
||||
public List<AccountAccessDto>? AccessRights { get; set; }
|
||||
public bool AllowRead { get; set; }
|
||||
public bool AllowWrite { get; set; }
|
||||
public bool AllowDelete { get; set; }
|
||||
public bool AllowManage { get; set; }
|
||||
|
||||
#endregion Permissions
|
||||
}
|
||||
|
||||
public class AccountDtoProfile : BaseProfile<Account, AccountDto>
|
||||
{
|
||||
public AccountDtoProfile()
|
||||
{
|
||||
Mapping
|
||||
.ForMember(x => x.HasMotions, o => o.MapFrom(x => x.Motions!.Any()))
|
||||
.AfterMap<AccountDtoMappingAction>();
|
||||
}
|
||||
}
|
||||
|
||||
public class AccountDtoMappingAction : BaseMappingAction, IMappingAction<Account, AccountDto>
|
||||
{
|
||||
public AccountDtoMappingAction(IContextProvider contextProvider) : base(contextProvider) { }
|
||||
|
||||
public void Process(Account source, AccountDto destination, ResolutionContext context)
|
||||
{
|
||||
var accessRight = destination.AccessRights?.FirstOrDefault(x => x.UserId == ContextProvider.UserId);
|
||||
destination.AllowRead = accessRight?.IsAllowRead ?? false;
|
||||
destination.AllowWrite = accessRight?.IsAllowWrite ?? false;
|
||||
destination.AllowManage = accessRight?.IsAllowManage ?? false;
|
||||
destination.AllowDelete = (accessRight?.IsOwner ?? false) && !destination.HasMotions;
|
||||
destination.Name = accessRight?.Name ?? destination.Name;
|
||||
destination.Type = accessRight?.Name ?? destination.Type;
|
||||
}
|
||||
}
|
||||
@@ -1,14 +1,13 @@
|
||||
namespace MyOffice.Services.Account.Domain;
|
||||
|
||||
using MyOffice.Data.Models.Users;
|
||||
using MyOffice.Data.Models.Items;
|
||||
|
||||
public class ItemCategoryDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public Guid UserId { get; set; }
|
||||
public User User { get; set; } = null!;
|
||||
public UserDto User { get; set; } = null!;
|
||||
public string Name { get; set; } = null!;
|
||||
public List<ItemDto> Items { get; set; } = null!;
|
||||
public bool IsInternal { get; set; }
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace MyOffice.Services.Account.Domain;
|
||||
|
||||
using Data.Models.Currencies;
|
||||
using MyOffice.Services.Currency.Domain;
|
||||
|
||||
public class UserDto
|
||||
{
|
||||
@@ -13,5 +13,5 @@ public class UserDto
|
||||
public string? Phone { get; set; }
|
||||
|
||||
public string CurrencyId { get; set; } = null!;
|
||||
public CurrencyGlobal? Currency { get; set; }
|
||||
public CurrencyGlobalDto? Currency { get; set; }
|
||||
}
|
||||
@@ -2,21 +2,22 @@
|
||||
|
||||
using MyOffice.Data.Models.Currencies;
|
||||
using MyOffice.Data.Models.Users;
|
||||
using MyOffice.Services.Account.Domain;
|
||||
|
||||
public class CurrencyDto
|
||||
{
|
||||
public Guid Id { get; set; }
|
||||
public string CurrencyGlobalId { get; set; } = null!;
|
||||
public CurrencyGlobal? CurrencyGlobal { get; set; }
|
||||
public CurrencyGlobalDto? CurrencyGlobal { get; set; }
|
||||
public Guid UserId { get; set; }
|
||||
public User? User { get; set; }
|
||||
public UserDto? User { get; set; }
|
||||
|
||||
public string Name { get; set; } = null!;
|
||||
public string ShortName { get; set; } = null!;
|
||||
public IEnumerable<CurrencyRate>? Rates { get; set; }
|
||||
public List<CurrencyRateDto>? Rates { get; set; }
|
||||
|
||||
public int? CurrentRateId { get; set; }
|
||||
public CurrencyRate? CurrentRate { get; set; }
|
||||
public CurrencyRateDto? CurrentRate { get; set; }
|
||||
|
||||
public bool IsPrimary { get; set; }
|
||||
}
|
||||
@@ -8,5 +8,5 @@ public class CurrencyRateDto
|
||||
public DateTime DateTime { get; set; }
|
||||
public int Quantity { get; set; }
|
||||
public decimal Rate { get; set; }
|
||||
public IEnumerable<CurrencyDto>? Currencies { get; set; }
|
||||
public List<CurrencyDto>? Currencies { get; set; }
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
namespace MyOffice.Services.Currency.Domain;
|
||||
|
||||
using MyOffice.Data.Models.Currencies;
|
||||
|
||||
public class CurrencyWithRateDto
|
||||
{
|
||||
public CurrencyDto Currency { get; set; } = null!;
|
||||
|
||||
@@ -30,7 +30,6 @@ public class ItemService
|
||||
_itemRepository = itemRepository;
|
||||
_itemGlobalRepository = itemGlobalRepository;
|
||||
_mapper = mapper;
|
||||
|
||||
}
|
||||
|
||||
public List<ItemCategoryDto> GetAllCategories(Guid userId)
|
||||
|
||||
@@ -30,29 +30,8 @@ public class AccountServiceProfile : Profile
|
||||
|
||||
private void MapAccount()
|
||||
{
|
||||
CreateMap<Account, AccountDto>()
|
||||
.ForMember(x => x.HasMotions, o => o.MapFrom(x => x.Motions!.Any()))
|
||||
.ForMember(x => x.CurrentUserId, o => o.MapFrom<UserIdResolver>())
|
||||
.ForMember(x => x.AccountAccess, o =>
|
||||
{
|
||||
o.MapFrom((src, dst) => src.AccessRights!.FirstOrDefault(x => x.UserId == dst.CurrentUserId));
|
||||
})
|
||||
.ForMember(x => x.Type, o =>
|
||||
{
|
||||
o.SetMappingOrder(1);
|
||||
o.MapFrom((src, dst) => dst.AccountAccess?.Type.ToString());
|
||||
})
|
||||
.ForMember(x => x.Name, o =>
|
||||
{
|
||||
o.SetMappingOrder(1);
|
||||
o.MapFrom((src, dst) => dst.AccountAccess?.Name ?? src.Name);
|
||||
})
|
||||
;
|
||||
|
||||
CreateMap<AccountDetailed, AccountDetailedDto>();
|
||||
|
||||
CreateMap<AccountAccess, AccountAccessDto>();
|
||||
|
||||
CreateMap<AccountAccountCategory, AccountAccountCategoryDto>();
|
||||
|
||||
CreateMap<AccountCategory, AccountCategoryDto>()
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
using AutoMapper;
|
||||
using MyOffice.Core;
|
||||
|
||||
namespace MyOffice.Services;
|
||||
|
||||
public static class AutomapperExtensions
|
||||
{
|
||||
public static List<TTo> ToDto<TTo>(this IEnumerable<IDataModel> list, IMapper mapper)
|
||||
{
|
||||
return mapper.Map<List<TTo>>(list);
|
||||
}
|
||||
|
||||
public static TTo ToDto<TTo>(this IDataModel item, IMapper mapper)
|
||||
{
|
||||
return mapper.Map<TTo>(item);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
using MyOffice.Services.Identity;
|
||||
|
||||
namespace MyOffice.Services.Mapper;
|
||||
|
||||
public class BaseMappingAction
|
||||
{
|
||||
protected readonly IContextProvider ContextProvider;
|
||||
public BaseMappingAction(IContextProvider contextProvider)
|
||||
{
|
||||
ContextProvider = contextProvider;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
using AutoMapper;
|
||||
|
||||
namespace MyOffice.Services.Mapper;
|
||||
|
||||
public class BaseProfile<TSource, TDestination> : Profile
|
||||
{
|
||||
protected IMappingExpression<TSource, TDestination> Mapping;
|
||||
|
||||
public BaseProfile()
|
||||
{
|
||||
Mapping = CreateMap<TSource, TDestination>();
|
||||
}
|
||||
}
|
||||
@@ -14,5 +14,4 @@
|
||||
<ProjectReference Include="..\MyOffice.Core\MyOffice.Core.csproj" />
|
||||
<ProjectReference Include="..\MyOffice.Data.Repositories\MyOffice.Data.Repositories.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
||||
@@ -5,7 +5,6 @@ using Core.Extensions;
|
||||
using IdentityModel;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using MyOffice.Web.Models;
|
||||
using static IdentityServer4.Models.IdentityResources;
|
||||
|
||||
public class BaseApiController : ControllerBase
|
||||
{
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
namespace MyOffice.Web.Controllers;
|
||||
|
||||
using AutoMapper;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
|
||||
using Core;
|
||||
using Core.Extensions;
|
||||
using Models.Account;
|
||||
using Services.Account;
|
||||
using Services.Account.Domain;
|
||||
using Infrastructure.Attributes;
|
||||
using Services.Identity;
|
||||
|
||||
[Authorize]
|
||||
[ApiController]
|
||||
[Route("api/[controller]")]
|
||||
public class SettingsAccountCategoryController : BaseApiController
|
||||
{
|
||||
private readonly ILogger<SettingsAccountController> _logger;
|
||||
private readonly IMapper _mapper;
|
||||
private readonly AccountService _accountService;
|
||||
private readonly IContextProvider _contextProvider;
|
||||
|
||||
public SettingsAccountCategoryController(
|
||||
ILogger<SettingsAccountController> logger,
|
||||
IMapper mapper,
|
||||
AccountService accountService,
|
||||
IContextProvider contextProvider
|
||||
)
|
||||
{
|
||||
_logger = logger;
|
||||
_mapper = mapper;
|
||||
_accountService = accountService;
|
||||
_contextProvider = contextProvider;
|
||||
}
|
||||
|
||||
[HttpGet("~/api/settings/account-categories")]
|
||||
public object AccountCategories()
|
||||
{
|
||||
var list = _accountService.GetAllCategories(UserId);
|
||||
|
||||
return OkResponse(_mapper.Map<List<AccountCategoryViewModel>>(list).OrderBy(x => x.Name));
|
||||
}
|
||||
|
||||
[HttpGet("~/api/settings/account-categories/{id}")]
|
||||
public object AccountCategory([AsGuid] string id)
|
||||
{
|
||||
var exec = _accountService.GetCategory(UserId, id.AsGuid());
|
||||
|
||||
switch (exec.Status)
|
||||
{
|
||||
case GeneralExecStatus.not_found:
|
||||
case GeneralExecStatus.failure:
|
||||
return ProblemBadResponse("Account category not found.");
|
||||
|
||||
case GeneralExecStatus.success:
|
||||
return _mapper.Map<AccountCategoryViewModel>(exec.Result!);
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(exec.Status.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("~/api/settings/account-categories")]
|
||||
public object AccountCategoriesAdd(AccountCategoryViewModel request)
|
||||
{
|
||||
var exec = _accountService.CategoryAdd(UserId, new AccountCategoryDto { Name = request.Name! });
|
||||
switch (exec.Status)
|
||||
{
|
||||
case GeneralExecStatus.success:
|
||||
return exec.Result!;
|
||||
|
||||
case GeneralExecStatus.failure:
|
||||
case GeneralExecStatus.not_found:
|
||||
return ProblemBadResponse("Adding account category failed.");
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(exec.Status.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPut("~/api/settings/account-categories/{id}")]
|
||||
public object AccountCategoriesEdit([AsGuid] string id, AccountCategoryViewModel request)
|
||||
{
|
||||
var exec = _accountService.CategoryUpdate(UserId, id.AsGuid(), new AccountCategoryDto { Name = request.Name! });
|
||||
switch (exec.Status)
|
||||
{
|
||||
case GeneralExecStatus.success:
|
||||
return exec.Result!;
|
||||
|
||||
case GeneralExecStatus.failure:
|
||||
case GeneralExecStatus.not_found:
|
||||
return ProblemBadResponse("Update account category failed.");
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(exec.Status.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[HttpDelete("~/api/settings/account-categories/{id}")]
|
||||
public object AccountCategoriesDelete([AsGuid] string id)
|
||||
{
|
||||
var exec = _accountService.CategoryRemove(UserId, id.AsGuid());
|
||||
switch (exec.Status)
|
||||
{
|
||||
case AccountCategoryRemoveResult.success:
|
||||
return exec.Result!;
|
||||
|
||||
case AccountCategoryRemoveResult.failure:
|
||||
return ProblemBadResponse("Remove account category failed.");
|
||||
case AccountCategoryRemoveResult.not_found:
|
||||
return ProblemBadResponse("Account category not found.");
|
||||
case AccountCategoryRemoveResult.accounts_exists:
|
||||
return ProblemBadResponse("Account category have accounts.");
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(exec.Status.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,101 +35,17 @@ public class SettingsAccountController : BaseApiController
|
||||
_contextProvider = contextProvider;
|
||||
}
|
||||
|
||||
[HttpGet("~/api/settings/account-categories")]
|
||||
public object AccountCategories()
|
||||
{
|
||||
var list = _accountService.GetAllCategories(UserId);
|
||||
|
||||
return _mapper.Map<AccountCategoryViewModel[]>(list).OrderBy(x => x.Name);
|
||||
}
|
||||
|
||||
[HttpGet("~/api/settings/account-categories/{id}")]
|
||||
public object AccountCategory([AsGuid] string id)
|
||||
{
|
||||
var exec = _accountService.GetCategory(UserId, id.AsGuid());
|
||||
|
||||
switch (exec.Status)
|
||||
{
|
||||
case GeneralExecStatus.not_found:
|
||||
case GeneralExecStatus.failure:
|
||||
return ProblemBadResponse("Account category not found.");
|
||||
|
||||
case GeneralExecStatus.success:
|
||||
return _mapper.Map<AccountCategoryViewModel>(exec.Result!);
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(exec.Status.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPost("~/api/settings/account-categories")]
|
||||
public object AccountCategoriesAdd(AccountCategoryViewModel request)
|
||||
{
|
||||
var exec = _accountService.CategoryAdd(UserId, new AccountCategoryDto { Name = request.Name! });
|
||||
switch (exec.Status)
|
||||
{
|
||||
case GeneralExecStatus.success:
|
||||
return exec.Result!;
|
||||
|
||||
case GeneralExecStatus.failure:
|
||||
case GeneralExecStatus.not_found:
|
||||
return ProblemBadResponse("Adding account category failed.");
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(exec.Status.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[HttpPut("~/api/settings/account-categories/{id}")]
|
||||
public object AccountCategoriesEdit([AsGuid] string id, AccountCategoryViewModel request)
|
||||
{
|
||||
var exec = _accountService.CategoryUpdate(UserId, id.AsGuid(), new AccountCategoryDto { Name = request.Name! });
|
||||
switch (exec.Status)
|
||||
{
|
||||
case GeneralExecStatus.success:
|
||||
return exec.Result!;
|
||||
|
||||
case GeneralExecStatus.failure:
|
||||
case GeneralExecStatus.not_found:
|
||||
return ProblemBadResponse("Update account category failed.");
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(exec.Status.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[HttpDelete("~/api/settings/account-categories/{id}")]
|
||||
public object AccountCategoriesDelete([AsGuid] string id)
|
||||
{
|
||||
var exec = _accountService.CategoryRemove(UserId, id.AsGuid());
|
||||
switch (exec.Status)
|
||||
{
|
||||
case AccountCategoryRemoveResult.success:
|
||||
return exec.Result!;
|
||||
|
||||
case AccountCategoryRemoveResult.failure:
|
||||
return ProblemBadResponse("Remove account category failed.");
|
||||
case AccountCategoryRemoveResult.not_found:
|
||||
return ProblemBadResponse("Account category not found.");
|
||||
case AccountCategoryRemoveResult.accounts_exists:
|
||||
return ProblemBadResponse("Account category have accounts.");
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(exec.Status.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("~/api/settings/accounts")]
|
||||
public List<AccountViewModel> AccountsGet([AsGuid(true)] string? category)
|
||||
public ObjectResult AccountsGet([AsGuid(true)] string? category)
|
||||
{
|
||||
var list = category.IsPresent()
|
||||
? _accountService.GetByCategory(UserId, category!.AsGuid())
|
||||
: _accountService.GetAllAccounts(UserId);
|
||||
|
||||
return _mapper.Map<List<AccountViewModel>>(list.OrderBy(x => x.Name));
|
||||
return OkResponse(list.ToViewModel(_mapper));
|
||||
}
|
||||
|
||||
[HttpPost("~/api/settings/accounts")]
|
||||
//[HttpPost("~/api/settings/accounts")]
|
||||
public object AccountsAdd(AccountViewModel request)
|
||||
{
|
||||
var exec = _accountService.AccountAdd(UserId, new AccountAdd
|
||||
@@ -149,7 +65,7 @@ public class SettingsAccountController : BaseApiController
|
||||
case AccountAddStatus.failure:
|
||||
return ProblemBadResponse("Adding account failed.");
|
||||
case AccountAddStatus.success:
|
||||
return exec.Result!;
|
||||
return _mapper.Map<AccountViewModel>(exec.Result!);
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(exec.Status.ToString());
|
||||
@@ -180,7 +96,7 @@ public class SettingsAccountController : BaseApiController
|
||||
case AccountEditStatus.failure:
|
||||
return ProblemBadResponse("Adding account failed.");
|
||||
case AccountEditStatus.success:
|
||||
return exec.Result!;
|
||||
return _mapper.Map<AccountViewModel>(exec.Result!);
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(exec.Status.ToString());
|
||||
@@ -196,7 +112,7 @@ public class SettingsAccountController : BaseApiController
|
||||
case GeneralExecStatus.not_found:
|
||||
return ProblemBadResponse("Account not found.");
|
||||
case GeneralExecStatus.success:
|
||||
return exec.Result!;
|
||||
return _mapper.Map<AccountViewModel>(exec.Result!);
|
||||
|
||||
default:
|
||||
throw new NotSupportedException(exec.Status.ToString());
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
namespace MyOffice.Web.Infrastructure;
|
||||
|
||||
using System.Linq.Expressions;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
public static class RouteHelperExtensions
|
||||
{
|
||||
public static void Bind<T>(this IRouteBuilder routeBuilder, Expression<Func<T, ObjectResult>> expression)
|
||||
{
|
||||
System.Console.WriteLine("Bind");
|
||||
System.Console.WriteLine(expression.Name);
|
||||
System.Console.WriteLine(expression.Body.ToString());
|
||||
routeBuilder.MapRoute("SettingsAccountAccountsGet", "api/settings/accounts", new { controller = "SettingsAccount", action = "AccountsGet" });
|
||||
}
|
||||
}
|
||||
|
||||
public class CustomRouter : IRouter
|
||||
{
|
||||
private readonly IRouter _defaultRouter;
|
||||
private readonly string _controller;
|
||||
private readonly string _action;
|
||||
|
||||
public CustomRouter(IRouter defaultRouter, string controller, string action)
|
||||
{
|
||||
_defaultRouter = defaultRouter;
|
||||
_controller = controller;
|
||||
_action = action;
|
||||
}
|
||||
|
||||
public VirtualPathData? GetVirtualPath(VirtualPathContext context)
|
||||
{
|
||||
Console.WriteLine($"1:{context.RouteName}");
|
||||
return null;
|
||||
}
|
||||
|
||||
public async Task RouteAsync(RouteContext context)
|
||||
{
|
||||
var headers = context.HttpContext.Request.Headers;
|
||||
var path = context.HttpContext.Request.Path.Value!.Split('/');
|
||||
|
||||
Console.WriteLine($"CustomRouter:{context.HttpContext.Request.Path.Value}");
|
||||
|
||||
context.RouteData.Values["controller"] = _controller;
|
||||
context.RouteData.Values["action"] = _action;
|
||||
|
||||
await _defaultRouter.RouteAsync(context);
|
||||
}
|
||||
}
|
||||
@@ -1,24 +1,13 @@
|
||||
namespace MyOffice.Web.Models.Account
|
||||
namespace MyOffice.Web.Models.Account;
|
||||
|
||||
using User;
|
||||
|
||||
public class AccessRightsViewModel
|
||||
{
|
||||
using Newtonsoft.Json;
|
||||
using User;
|
||||
|
||||
public class AccessRightsViewModel
|
||||
{
|
||||
public UserViewModel User { get; set; } = null!;
|
||||
public bool IsAllowRead { get; set; }
|
||||
public bool IsAllowWrite { get; set; }
|
||||
public bool IsAllowManage { get; set; }
|
||||
public bool IsAllowDelete { get; set; }
|
||||
public UserViewModel? User { get; set; } = null!;
|
||||
public bool AllowRead { get; set; }
|
||||
public bool AllowWrite { get; set; }
|
||||
public bool AllowManage { get; set; }
|
||||
public bool AllowDelete { get; set; }
|
||||
public bool IsOwner { get; set; }
|
||||
|
||||
#region DEBUG
|
||||
|
||||
[JsonIgnore]
|
||||
public Guid UserId { get; set; }
|
||||
[JsonIgnore]
|
||||
public Guid OwnerId { get; set; }
|
||||
|
||||
#endregion DEBUG
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ using MyOffice.Services.Account.Domain;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
[Link(typeof(AccountCategoryDto))]
|
||||
public class AccountCategoryViewModel
|
||||
public class AccountCategoryViewModel: IResponseModel
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
|
||||
|
||||
@@ -1,10 +1,13 @@
|
||||
namespace MyOffice.Web.Models.Account
|
||||
{
|
||||
using Newtonsoft.Json;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
namespace MyOffice.Web.Models.Account;
|
||||
|
||||
public class AccountViewModel
|
||||
{
|
||||
using AutoMapper;
|
||||
using MyOffice.Services.Account.Domain;
|
||||
using MyOffice.Services.Identity;
|
||||
using Newtonsoft.Json;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
public class AccountViewModel: IResponseModel
|
||||
{
|
||||
public string? Id { get; set; }
|
||||
|
||||
[Required]
|
||||
@@ -14,21 +17,33 @@
|
||||
[Required]
|
||||
public string CurrencyId { get; set; } = null!;
|
||||
public string? CurrencyName { get; set; }
|
||||
public bool AllowDelete { get; set; }
|
||||
public bool AllowManage { get; set; }
|
||||
|
||||
public List<AccountCategoryViewModel>? Categories { get; set; }
|
||||
|
||||
[Required]
|
||||
public string CategoryId { get; set; } = null!;
|
||||
|
||||
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
|
||||
#region Permissions
|
||||
|
||||
public List<AccessRightsViewModel>? AccessRights { get; set; }
|
||||
}
|
||||
public bool AllowRead { get; set; }
|
||||
public bool AllowWrite { get; set; }
|
||||
public bool AllowDelete { get; set; }
|
||||
public bool AllowManage { get; set; }
|
||||
|
||||
#endregion Permissions
|
||||
}
|
||||
|
||||
public class AccountAccessViewModel
|
||||
public static class AccountViewModelExtensions
|
||||
{
|
||||
public static List<AccountViewModel> ToViewModel(this List<AccountDto> accounts, IMapper mapper)
|
||||
{
|
||||
return mapper.Map<List<AccountViewModel>>(accounts.OrderBy(x => x.Name));
|
||||
}
|
||||
}
|
||||
|
||||
public class AccountAccessViewModel
|
||||
{
|
||||
public class AccountAccessItemViewModel
|
||||
{
|
||||
public string UserId { get; set; } = null!;
|
||||
@@ -38,5 +53,42 @@
|
||||
public string? Email { get; set; }
|
||||
public bool AllowWrite { get; set; }
|
||||
public List<AccountAccessItemViewModel> Accesses { get; set; } = null!;
|
||||
}
|
||||
|
||||
public class AccountViewModelProfile : Profile
|
||||
{
|
||||
public AccountViewModelProfile()
|
||||
{
|
||||
CreateMap<AccountDto, AccountViewModel>()
|
||||
.ForMember(x => x.CurrencyId, o => o.MapFrom(x => x.CurrencyGlobalId))
|
||||
.ForMember(x => x.CurrencyName, o => o.MapFrom(x => x.Currency!.Name))
|
||||
.AfterMap<AccountViewModelMappingAction>()
|
||||
;
|
||||
|
||||
CreateMap<AccountAccessDto, AccessRightsViewModel>()
|
||||
.AfterMap<AccessRightsViewModelMappingAction>()
|
||||
;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public class AccountViewModelMappingAction : IMappingAction<AccountDto, AccountViewModel>
|
||||
{
|
||||
public void Process(AccountDto source, AccountViewModel destination, ResolutionContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class AccessRightsViewModelMappingAction : IMappingAction<AccountAccessDto, AccessRightsViewModel>
|
||||
{
|
||||
private readonly IContextProvider _contextProvider;
|
||||
|
||||
public AccessRightsViewModelMappingAction(IContextProvider contextProvider)
|
||||
{
|
||||
_contextProvider = contextProvider;
|
||||
}
|
||||
|
||||
public void Process(AccountAccessDto source, AccessRightsViewModel destination, ResolutionContext context)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -3,14 +3,14 @@
|
||||
using AutoMapper;
|
||||
|
||||
using MyOffice.Services.Currency.Domain;
|
||||
using MyOffice.Services.Identity;
|
||||
using Currency;
|
||||
using Item;
|
||||
using Motion;
|
||||
using Services.Account.Domain;
|
||||
using User;
|
||||
using MyOffice.Services.Identity;
|
||||
|
||||
public class CustomResolver : IValueResolver<AccountAccessDto, AccessRightsViewModel, bool>
|
||||
/*public class CustomResolver : IValueResolver<AccountAccessDto, AccessRightsViewModel, bool>
|
||||
{
|
||||
private readonly ILogger<CustomResolver> _logger;
|
||||
private readonly IContextProvider _contextProvider;
|
||||
@@ -28,11 +28,28 @@ public class CustomResolver : IValueResolver<AccountAccessDto, AccessRightsViewM
|
||||
{
|
||||
return source.OwnerId == _contextProvider.UserId;
|
||||
}
|
||||
}*/
|
||||
|
||||
public class PublicationSystemResolver : IMemberValueResolver<object, object, string, bool>
|
||||
{
|
||||
private readonly IContextProvider _contextProvider;
|
||||
|
||||
public PublicationSystemResolver(
|
||||
IContextProvider contextProvider
|
||||
)
|
||||
{
|
||||
this._contextProvider = contextProvider;
|
||||
}
|
||||
|
||||
public bool Resolve(object source, object destination, string sourceMember, bool destMember, ResolutionContext context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public class AccountViewModelProfile : Profile
|
||||
public class AccountViewModelGeneralProfile : Profile
|
||||
{
|
||||
public AccountViewModelProfile()
|
||||
public AccountViewModelGeneralProfile()
|
||||
{
|
||||
CreateMap<AccountDetailedDto, AccountDetailedViewModel>()
|
||||
.ForMember(x => x.Account, o => o.MapFrom(x => x.Account))
|
||||
@@ -42,26 +59,11 @@ public class AccountViewModelProfile : Profile
|
||||
|
||||
CreateMap<MyOffice.Data.Models.Users.User, UserViewModel>();
|
||||
|
||||
CreateMap<AccountDto, AccountViewModel>()
|
||||
.ForMember(x => x.CurrencyId, o => o.MapFrom(x => x.CurrencyGlobalId))
|
||||
.ForMember(x => x.CurrencyName, o => o.MapFrom(x => x.Currency!.Name))
|
||||
.ForMember(x => x.AllowDelete, o => o.MapFrom(x => !x.HasMotions))
|
||||
.ForMember(x => x.AllowManage, o => o.MapFrom(x => x.AccessRights!.Any(a => a.OwnerId == x.CurrentUserId)))
|
||||
.ForMember(x => x.AccessRights, o => o.MapFrom((s, d) => s.OwnerId != s.CurrentUserId ? null : s.AccessRights))
|
||||
;
|
||||
|
||||
CreateMap<AccountAccountCategoryDto, AccountCategoryViewModel>()
|
||||
.ForMember(x => x.Id, o => o.MapFrom(x => x.CategoryId))
|
||||
.ForMember(x => x.Name, o => o.MapFrom(x => x.Category!.Name))
|
||||
;
|
||||
|
||||
CreateMap<AccountAccessDto, AccessRightsViewModel>()
|
||||
.ForMember(x => x.IsAllowDelete, o => o.MapFrom(
|
||||
(src, dst) => src.Account!.OwnerId == src.Account.CurrentUserId && src.UserId != src.Account.CurrentUserId))
|
||||
.ForMember(x => x.IsOwner, o => o.MapFrom(
|
||||
(src, dst) => src.OwnerId == src.UserId))
|
||||
;
|
||||
|
||||
CreateMap<AccountAccessViewModel.AccountAccessItemViewModel, AccountAccessDto>()
|
||||
.ForMember(x => x.IsAllowWrite, o => o.MapFrom(x => x.AllowWrite))
|
||||
;
|
||||
|
||||
@@ -1,25 +1,11 @@
|
||||
namespace MyOffice.Web.Models.User
|
||||
{
|
||||
using Core.Extensions;
|
||||
using MyOffice.Data.Models.Users;
|
||||
namespace MyOffice.Web.Models.User;
|
||||
|
||||
public class UserViewModel
|
||||
{
|
||||
using Core.Extensions;
|
||||
using MyOffice.Data.Models.Users;
|
||||
|
||||
public class UserViewModel
|
||||
{
|
||||
public string Id { get; set; } = null!;
|
||||
public string UserName { get; set; } = null!;
|
||||
public string Email { get; set; } = null!;
|
||||
}
|
||||
|
||||
public static class UserViewModelExtensions
|
||||
{
|
||||
public static UserViewModel ToModel(this User user)
|
||||
{
|
||||
return new UserViewModel
|
||||
{
|
||||
Id = user.Id.ToShort(),
|
||||
UserName = user.UserName,
|
||||
Email = user.Email,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ using Services.Item;
|
||||
using MyOffice.Services.Dashboard;
|
||||
using MyOffice.Services.Identity;
|
||||
using MyOffice.Services.Mapper;
|
||||
using MyOffice.Services.Account.Domain;
|
||||
|
||||
//TODO: Data.Model only Repository and Service, response <-> mapper <-> web <-> mapper <-> service <-> repository
|
||||
//TODO: Project management
|
||||
@@ -252,8 +253,8 @@ public class Program
|
||||
c.AllowNullCollections = true;
|
||||
c.AllowNullDestinationValues = true;
|
||||
},
|
||||
typeof(AccountViewModelProfile),
|
||||
typeof(AccountServiceProfile)
|
||||
typeof(AccountDto).Assembly,
|
||||
typeof(AccountViewModel).Assembly
|
||||
);
|
||||
}
|
||||
|
||||
@@ -421,6 +422,7 @@ public class Program
|
||||
.AllowAnyMethod());
|
||||
|
||||
app.UseIdentityServer();
|
||||
//app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
|
||||
app.MapControllers();
|
||||
|
||||
Reference in New Issue
Block a user