This commit is contained in:
2023-12-01 20:47:42 +02:00
parent a09fc7ece3
commit 045f60e373
39 changed files with 1252 additions and 945 deletions
+3
View File
@@ -359,6 +359,8 @@ MigrationBackup/
# Ionide (cross platform F# VS Code tools) working folder # Ionide (cross platform F# VS Code tools) working folder
.ionide/ .ionide/
.vscode/
/MyOffice.SPA/.vscode /MyOffice.SPA/.vscode
/MyOffice.SPA/dist/ /MyOffice.SPA/dist/
/MyOffice.SPA/src/environments/environment.ts /MyOffice.SPA/src/environments/environment.ts
@@ -382,3 +384,4 @@ package-lock.json
/MyOffice.Shared/appsettings.shared.Production.json /MyOffice.Shared/appsettings.shared.Production.json
/linux_deploy_mybank.bat /linux_deploy_mybank.bat
/linux_deploy_office.bat /linux_deploy_office.bat
linux_deploy_office_public.bat
+6
View File
@@ -0,0 +1,6 @@
namespace MyOffice.Core;
public interface IDataModel
{
}
@@ -0,0 +1,6 @@
namespace MyOffice.Core;
public interface IDataModelDto<TSource> where TSource : IDataModel
{
}
+3 -2
View File
@@ -1,9 +1,10 @@
namespace MyOffice.Data.Models.Accounts; namespace MyOffice.Data.Models.Accounts;
using Currencies; using Currencies;
using MyOffice.Core;
using MyOffice.Data.Models.Users; using MyOffice.Data.Models.Users;
public class Account public class Account: IDataModel
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public string CurrencyGlobalId { get; set; } = null!; public string CurrencyGlobalId { get; set; } = null!;
@@ -17,7 +18,7 @@ public class Account
public IEnumerable<AccountAccessInvite>? Invites { get; set; } public IEnumerable<AccountAccessInvite>? Invites { get; set; }
} }
public class AccountDetailed public class AccountDetailed: IDataModel
{ {
public Account Account { get; set; } = null!; public Account Account { get; set; } = null!;
public decimal TotalPlus { get; set; } public decimal TotalPlus { get; set; }
@@ -21,11 +21,15 @@ public class AccountRepository : AppRepository<Account>, IAccountRepository
{ {
return _context.Accounts! return _context.Accounts!
.Include(x => x.CurrencyGlobal) .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) .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) .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)) .Where(x => x.AccessRights!.Any(a => a.UserId == userId))
.ToList(); .ToList();
} }
@@ -7,6 +7,7 @@ export interface AccountModel {
currencyId?: string, currencyId?: string,
currencyName?: string, currencyName?: string,
type?: string, type?: string,
allowWrite: boolean,
allowDelete: boolean, allowDelete: boolean,
allowManage: boolean, allowManage: boolean,
categories?: AccountCategoryModel[], categories?: AccountCategoryModel[],
@@ -38,7 +38,7 @@
<td>{{account.currencyId}}</td> <td>{{account.currencyId}}</td>
<td>{{account.type}}</td> <td>{{account.type}}</td>
<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 Edit
</button> </button>
<button class="btn-space" *ngIf="account.allowManage" (click)="access(account)" mat-raised-button color="primary"> <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> <a href="javascript:;" (click)="selectCategory(category)" title="{{category.name}}">{{category.name}}</a>
</li> </li>
</ul> </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> </div>
</div> </div>
@@ -24,6 +24,8 @@ export class SettingsItemComponent {
public selectedCategory?: ItemCategoryModel; public selectedCategory?: ItemCategoryModel;
public selectedCount: number = 0; public selectedCount: number = 0;
public category?: ItemCategoryModel; public category?: ItemCategoryModel;
public categoryAddShow: boolean = false;
public categoryAddName?: string;
constructor( constructor(
private dialogModel: MatDialog, 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));
}
}
+12 -639
View File
@@ -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 ILogger<AccountService> _logger;
private readonly IMapper _mapper; private readonly IMapper _mapper;
private readonly IAccountCategoryRepository _accountCategoryRepository; private readonly IAccountCategoryRepository _accountCategoryRepository;
@@ -61,625 +55,4 @@
_itemService = itemService; _itemService = itemService;
_contextProvider = contextProvider; _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; namespace MyOffice.Services.Account.Domain;
using AutoMapper;
using Core.Attributes; using Core.Attributes;
using Data.Models.Accounts; using Data.Models.Accounts;
using Data.Models.Users; using Data.Models.Users;
using Mapper; using Mapper;
using MyOffice.Services.Identity;
[Link(typeof(AccountAccess))] [Link(typeof(AccountAccess))]
[Link(typeof(AccountServiceProfile))] [Link(typeof(AccountServiceProfile))]
public class AccountAccessDto public class AccountAccessDto
{ {
/// <summary>
/// Current user
/// </summary>
public Guid CurrenUserId { get; set; }
public Guid AccountId { get; set; } public Guid AccountId { get; set; }
public AccountDto? Account { get; set; } public AccountDto? Account { get; set; }
@@ -21,15 +18,41 @@ public class AccountAccessDto
/// User can access to account /// User can access to account
/// </summary> /// </summary>
public Guid UserId { get; set; } public Guid UserId { get; set; }
public User? User { get; set; } public UserDto? User { get; set; }
/// <summary>
/// Who add access
/// </summary>
public Guid OwnerId { get; set; }
public User? Owner { get; set; }
public bool IsAllowRead { get; set; } public bool IsAllowRead { get; set; }
public bool IsAllowWrite { get; set; } public bool IsAllowWrite { get; set; }
public bool IsAllowManage { get; set; } public bool IsAllowManage { get; set; }
public bool IsOwner { get; set; }
public AccountAccessTypeEnum Type { 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 AccountDto Account { get; set; } = null!;
public decimal TotalPlus { get; set; } public decimal TotalPlus { get; set; }
public decimal TotalMinus { get; set; } public decimal TotalMinus { get; set; }
public decimal Rest => TotalPlus - TotalMinus; public decimal Rest => TotalPlus - TotalMinus;
} }
public class AccountDetailedDtoProfile: Profile
{
public AccountDetailedDtoProfile()
{
CreateMap<AccountDetailed, AccountDetailedDto>();
}
}
+64 -12
View File
@@ -1,27 +1,79 @@
namespace MyOffice.Services.Account.Domain; namespace MyOffice.Services.Account.Domain;
using MyOffice.Data.Models.Currencies;
using System; using System;
using Data.Models.Accounts; 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 Guid Id { get; set; }
public string CurrencyGlobalId { get; set; } = null!; public string CurrencyGlobalId { get; set; } = null!;
public CurrencyGlobal? CurrencyGlobal { get; set; } public CurrencyGlobalDto? CurrencyGlobal { get; set; }
public Guid CurrencyId { get; set; } public string Name { get; set; } = null!;
public Currency? Currency { get; set; }
public Guid UserId { get; set; }
public UserDto? User { get; set; }
public Guid OwnerId { get; set; } public Guid OwnerId { get; set; }
public UserDto? Owner { 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 string Type { get; set; } = null!;
public List<AccountAccessDto>? AccessRights { get; set; }
public List<AccountAccountCategoryDto>? Categories { get; set; } public List<AccountAccountCategoryDto>? Categories { get; set; }
public bool HasMotions { get; set; }
public Guid CurrentUserId { get; set; } #endregion Dto properties
public AccountAccess? AccountAccess { get; set; }
#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; namespace MyOffice.Services.Account.Domain;
using MyOffice.Data.Models.Users; using MyOffice.Data.Models.Items;
public class ItemCategoryDto public class ItemCategoryDto
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public Guid UserId { 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 string Name { get; set; } = null!;
public List<ItemDto> Items { get; set; } = null!; public List<ItemDto> Items { get; set; } = null!;
public bool IsInternal { get; set; } public bool IsInternal { get; set; }
} }
+2 -2
View File
@@ -1,6 +1,6 @@
namespace MyOffice.Services.Account.Domain; namespace MyOffice.Services.Account.Domain;
using Data.Models.Currencies; using MyOffice.Services.Currency.Domain;
public class UserDto public class UserDto
{ {
@@ -13,5 +13,5 @@ public class UserDto
public string? Phone { get; set; } public string? Phone { get; set; }
public string CurrencyId { get; set; } = null!; 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.Currencies;
using MyOffice.Data.Models.Users; using MyOffice.Data.Models.Users;
using MyOffice.Services.Account.Domain;
public class CurrencyDto public class CurrencyDto
{ {
public Guid Id { get; set; } public Guid Id { get; set; }
public string CurrencyGlobalId { get; set; } = null!; public string CurrencyGlobalId { get; set; } = null!;
public CurrencyGlobal? CurrencyGlobal { get; set; } public CurrencyGlobalDto? CurrencyGlobal { get; set; }
public Guid UserId { 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 Name { get; set; } = null!;
public string ShortName { 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 int? CurrentRateId { get; set; }
public CurrencyRate? CurrentRate { get; set; } public CurrencyRateDto? CurrentRate { get; set; }
public bool IsPrimary { get; set; } public bool IsPrimary { get; set; }
} }
@@ -8,5 +8,5 @@ public class CurrencyRateDto
public DateTime DateTime { get; set; } public DateTime DateTime { get; set; }
public int Quantity { get; set; } public int Quantity { get; set; }
public decimal Rate { 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; namespace MyOffice.Services.Currency.Domain;
using MyOffice.Data.Models.Currencies;
public class CurrencyWithRateDto public class CurrencyWithRateDto
{ {
public CurrencyDto Currency { get; set; } = null!; public CurrencyDto Currency { get; set; } = null!;
-1
View File
@@ -30,7 +30,6 @@ public class ItemService
_itemRepository = itemRepository; _itemRepository = itemRepository;
_itemGlobalRepository = itemGlobalRepository; _itemGlobalRepository = itemGlobalRepository;
_mapper = mapper; _mapper = mapper;
} }
public List<ItemCategoryDto> GetAllCategories(Guid userId) public List<ItemCategoryDto> GetAllCategories(Guid userId)
@@ -30,29 +30,8 @@ public class AccountServiceProfile : Profile
private void MapAccount() 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<AccountDetailed, AccountDetailedDto>();
CreateMap<AccountAccess, AccountAccessDto>();
CreateMap<AccountAccountCategory, AccountAccountCategoryDto>(); CreateMap<AccountAccountCategory, AccountAccountCategoryDto>();
CreateMap<AccountCategory, AccountCategoryDto>() 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;
}
}
+13
View File
@@ -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.Core\MyOffice.Core.csproj" />
<ProjectReference Include="..\MyOffice.Data.Repositories\MyOffice.Data.Repositories.csproj" /> <ProjectReference Include="..\MyOffice.Data.Repositories\MyOffice.Data.Repositories.csproj" />
</ItemGroup> </ItemGroup>
</Project> </Project>
@@ -5,7 +5,6 @@ using Core.Extensions;
using IdentityModel; using IdentityModel;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using MyOffice.Web.Models; using MyOffice.Web.Models;
using static IdentityServer4.Models.IdentityResources;
public class BaseApiController : ControllerBase 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; _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")] [HttpGet("~/api/settings/accounts")]
public List<AccountViewModel> AccountsGet([AsGuid(true)] string? category) public ObjectResult AccountsGet([AsGuid(true)] string? category)
{ {
var list = category.IsPresent() var list = category.IsPresent()
? _accountService.GetByCategory(UserId, category!.AsGuid()) ? _accountService.GetByCategory(UserId, category!.AsGuid())
: _accountService.GetAllAccounts(UserId); : _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) public object AccountsAdd(AccountViewModel request)
{ {
var exec = _accountService.AccountAdd(UserId, new AccountAdd var exec = _accountService.AccountAdd(UserId, new AccountAdd
@@ -149,7 +65,7 @@ public class SettingsAccountController : BaseApiController
case AccountAddStatus.failure: case AccountAddStatus.failure:
return ProblemBadResponse("Adding account failed."); return ProblemBadResponse("Adding account failed.");
case AccountAddStatus.success: case AccountAddStatus.success:
return exec.Result!; return _mapper.Map<AccountViewModel>(exec.Result!);
default: default:
throw new NotSupportedException(exec.Status.ToString()); throw new NotSupportedException(exec.Status.ToString());
@@ -180,7 +96,7 @@ public class SettingsAccountController : BaseApiController
case AccountEditStatus.failure: case AccountEditStatus.failure:
return ProblemBadResponse("Adding account failed."); return ProblemBadResponse("Adding account failed.");
case AccountEditStatus.success: case AccountEditStatus.success:
return exec.Result!; return _mapper.Map<AccountViewModel>(exec.Result!);
default: default:
throw new NotSupportedException(exec.Status.ToString()); throw new NotSupportedException(exec.Status.ToString());
@@ -196,7 +112,7 @@ public class SettingsAccountController : BaseApiController
case GeneralExecStatus.not_found: case GeneralExecStatus.not_found:
return ProblemBadResponse("Account not found."); return ProblemBadResponse("Account not found.");
case GeneralExecStatus.success: case GeneralExecStatus.success:
return exec.Result!; return _mapper.Map<AccountViewModel>(exec.Result!);
default: default:
throw new NotSupportedException(exec.Status.ToString()); 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; public UserViewModel? User { get; set; } = null!;
using User; public bool AllowRead { get; set; }
public bool AllowWrite { get; set; }
public class AccessRightsViewModel public bool AllowManage { get; set; }
{ public bool AllowDelete { get; set; }
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 bool IsOwner { 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; using System.ComponentModel.DataAnnotations;
[Link(typeof(AccountCategoryDto))] [Link(typeof(AccountCategoryDto))]
public class AccountCategoryViewModel public class AccountCategoryViewModel: IResponseModel
{ {
public string? Id { get; set; } public string? Id { get; set; }
+63 -11
View File
@@ -1,10 +1,13 @@
namespace MyOffice.Web.Models.Account namespace MyOffice.Web.Models.Account;
{
using Newtonsoft.Json;
using System.ComponentModel.DataAnnotations;
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; } public string? Id { get; set; }
[Required] [Required]
@@ -14,21 +17,33 @@
[Required] [Required]
public string CurrencyId { get; set; } = null!; public string CurrencyId { get; set; } = null!;
public string? CurrencyName { get; set; } public string? CurrencyName { get; set; }
public bool AllowDelete { get; set; }
public bool AllowManage { get; set; }
public List<AccountCategoryViewModel>? Categories { get; set; } public List<AccountCategoryViewModel>? Categories { get; set; }
[Required] [Required]
public string CategoryId { get; set; } = null!; public string CategoryId { get; set; } = null!;
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)] #region Permissions
public List<AccessRightsViewModel>? AccessRights { get; set; } 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 class AccountAccessItemViewModel
{ {
public string UserId { get; set; } = null!; public string UserId { get; set; } = null!;
@@ -38,5 +53,42 @@
public string? Email { get; set; } public string? Email { get; set; }
public bool AllowWrite { get; set; } public bool AllowWrite { get; set; }
public List<AccountAccessItemViewModel> Accesses { get; set; } = null!; 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 AutoMapper;
using MyOffice.Services.Currency.Domain; using MyOffice.Services.Currency.Domain;
using MyOffice.Services.Identity;
using Currency; using Currency;
using Item; using Item;
using Motion; using Motion;
using Services.Account.Domain; using Services.Account.Domain;
using User; 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 ILogger<CustomResolver> _logger;
private readonly IContextProvider _contextProvider; private readonly IContextProvider _contextProvider;
@@ -28,11 +28,28 @@ public class CustomResolver : IValueResolver<AccountAccessDto, AccessRightsViewM
{ {
return source.OwnerId == _contextProvider.UserId; 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>() CreateMap<AccountDetailedDto, AccountDetailedViewModel>()
.ForMember(x => x.Account, o => o.MapFrom(x => x.Account)) .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<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>() CreateMap<AccountAccountCategoryDto, AccountCategoryViewModel>()
.ForMember(x => x.Id, o => o.MapFrom(x => x.CategoryId)) .ForMember(x => x.Id, o => o.MapFrom(x => x.CategoryId))
.ForMember(x => x.Name, o => o.MapFrom(x => x.Category!.Name)) .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>() CreateMap<AccountAccessViewModel.AccountAccessItemViewModel, AccountAccessDto>()
.ForMember(x => x.IsAllowWrite, o => o.MapFrom(x => x.AllowWrite)) .ForMember(x => x.IsAllowWrite, o => o.MapFrom(x => x.AllowWrite))
; ;
+6 -20
View File
@@ -1,25 +1,11 @@
namespace MyOffice.Web.Models.User namespace MyOffice.Web.Models.User;
{
using Core.Extensions;
using MyOffice.Data.Models.Users;
public class UserViewModel using Core.Extensions;
{ using MyOffice.Data.Models.Users;
public class UserViewModel
{
public string Id { get; set; } = null!; public string Id { get; set; } = null!;
public string UserName { get; set; } = null!; public string UserName { get; set; } = null!;
public string Email { 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,
};
}
}
} }
+4 -2
View File
@@ -44,6 +44,7 @@ using Services.Item;
using MyOffice.Services.Dashboard; using MyOffice.Services.Dashboard;
using MyOffice.Services.Identity; using MyOffice.Services.Identity;
using MyOffice.Services.Mapper; using MyOffice.Services.Mapper;
using MyOffice.Services.Account.Domain;
//TODO: Data.Model only Repository and Service, response <-> mapper <-> web <-> mapper <-> service <-> repository //TODO: Data.Model only Repository and Service, response <-> mapper <-> web <-> mapper <-> service <-> repository
//TODO: Project management //TODO: Project management
@@ -252,8 +253,8 @@ public class Program
c.AllowNullCollections = true; c.AllowNullCollections = true;
c.AllowNullDestinationValues = true; c.AllowNullDestinationValues = true;
}, },
typeof(AccountViewModelProfile), typeof(AccountDto).Assembly,
typeof(AccountServiceProfile) typeof(AccountViewModel).Assembly
); );
} }
@@ -421,6 +422,7 @@ public class Program
.AllowAnyMethod()); .AllowAnyMethod());
app.UseIdentityServer(); app.UseIdentityServer();
//app.UseAuthentication();
app.UseAuthorization(); app.UseAuthorization();
app.MapControllers(); app.MapControllers();