This commit is contained in:
2023-06-17 14:16:09 +03:00
parent 62178f1f32
commit 7ae5d3bc81
180 changed files with 12932 additions and 192 deletions
@@ -0,0 +1,50 @@
namespace MyOffice.Web.Controllers;
using Core.Extensions;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Models.Account;
using MyOffice.Web.Models.AccountMotion;
using Services.Account;
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class AccountController : BaseApiController
{
private readonly ILogger<AccountController> _logger;
private readonly AccountService _accountService;
public AccountController(
ILogger<AccountController> logger,
AccountService accountService
)
{
_logger = logger;
_accountService = accountService;
}
[HttpGet("~/api/accounts")]
public object AccountsGet(string category)
{
var list = _accountService.GetByCategoryDetailed(UserId, category!.AsGuid());
return list.Select(x => x.ToModel());
}
[HttpGet("~/api/accounts/{id}/motions")]
public object AccountsMotionsGet(string category)
{
var list = _accountService.GetByCategoryDetailed(UserId, category!.AsGuid());
return list.Select(x => x.ToModel());
}
[HttpPost("~/api/accounts/{id}/motions")]
public object AccountsMotionsPost(string id, AccountMotionRequest accountMotion)
{
var list = _accountService.GetByCategoryDetailed(UserId, category!.AsGuid());
return list.Select(x => x.ToModel());
}
}
@@ -0,0 +1,95 @@
namespace MyOffice.Web.Controllers;
using Core.Extensions;
using Data.Models.Currencies;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Data.Repositories.Currency;
using Models.Currency;
using Services.Currency;
using Services.Currency.Domain;
using MyOffice.Core;
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class CurrencyController : BaseApiController
{
private readonly CurrencyService _currencyService;
private readonly ILogger<CurrencyController> _logger;
public CurrencyController(
CurrencyService currencyService,
ILogger<CurrencyController> logger
)
{
_currencyService = currencyService;
_logger = logger;
}
[HttpGet("~/api/settings/currencies")]
public object Get()
{
var list = _currencyService.GetAllWithRates(UserId);
return list.Select(x => x.Key.ToModel(x.Value));
}
[HttpPost("~/api/settings/currencies")]
public object Post(CurrencyAddModel currency)
{
var exec = _currencyService.AddCurrency(UserId, new Currency
{
UserId = UserId,
CurrencyGlobalId = currency.Id,
Name = currency.Name,
ShortName = currency.ShortName,
});
switch (exec.Status)
{
case AddCurrencyStatus.success:
case AddCurrencyStatus.exists:
_currencyService.AddCurrencyRate(UserId, exec.Result!.Id, new CurrencyRate()
{
CurrencyId = exec.Result!.Id,
Rate = currency.Rate,
Quantity = currency.Quantity,
DateTime = currency.RateDate.Date,
});
return currency;
case AddCurrencyStatus.failed:
return ProblemBadRequest("Adding currency failed.");
default:
throw new NotSupportedException(exec.Status.ToString());
}
}
[HttpPost("~/api/settings/currencies/{id}/rate")]
public object Post(string id, CurrencyRateModel currencyRate)
{
var exec = _currencyService.AddCurrencyRate(UserId, id.AsGuid(), new CurrencyRate()
{
CurrencyId = id.AsGuid(),
Quantity = currencyRate.Quantity,
Rate = currencyRate.Rate,
DateTime = currencyRate.RateDate.Date,
});
switch (exec.Status)
{
case CurrencyAddRateStatus.failed:
return ProblemBadRequest("Adding currency rate failed.");
case CurrencyAddRateStatus.not_found:
return ProblemBadRequest("Currency not found.");
case CurrencyAddRateStatus.success:
return exec.Result!;
default:
throw new NotSupportedException(exec.Status.ToString());
}
}
}
@@ -0,0 +1,30 @@
namespace MyOffice.Web.Controllers;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Data.Repositories.Currency;
using Models.Currency;
using Services.Currency;
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class GeneralController : BaseApiController
{
private readonly CurrencyService _currencyService;
public GeneralController(
CurrencyService currencyService
)
{
_currencyService = currencyService;
}
[HttpGet("~/api/general/currencies")]
public object Get()
{
var list = _currencyService.GetGlobalAll();
return list.Select(x => x.ToModel());
}
}
@@ -0,0 +1,122 @@
namespace MyOffice.Web.Controllers;
using Data.Repositories.Account;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Models.Motion;
using MyOffice.Core.Extensions;
using MyOffice.Core;
using MyOffice.Data.Repositories.Motion;
using MyOffice.Services.Account;
using MyOffice.Services.Account.Domain;
using Services.Motion;
using MyOffice.Data.Models.Motions;
using Services.Motion.Domain;
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class SettingsMotionController : BaseApiController
{
private MotionService _motionService;
public SettingsMotionController(
MotionService motionService
)
{
_motionService = motionService;
}
[HttpGet("~/api/settings/motion-categories")]
public object MotionCategories()
{
var list = _motionService.GetAllCategories(UserId);
return list.Select(x => x.ToModel()).OrderByDescending(x => x.SortOrder);
}
[HttpPost("~/api/settings/motion-categories")]
public object MotionCategoriesAdd(MotionCategoryViewModel request)
{
var exec = _motionService.CategoryAdd(UserId, new MotionCategory { Name = request.Name! });
switch (exec.Status)
{
case GeneralExecStatus.success:
return exec.Result!;
case GeneralExecStatus.failure:
case GeneralExecStatus.not_found:
return ProblemBadRequest("Adding motion category failed.");
default:
throw new NotSupportedException(exec.Status.ToString());
}
}
[HttpPut("~/api/settings/motion-categories/{id}")]
public object MotionCategoriesEdit(string id, MotionCategoryViewModel request)
{
var exec = _motionService.CategoryUpdate(UserId, id.AsGuid(), new MotionCategory { Name = request.Name! });
switch (exec.Status)
{
case GeneralExecStatus.success:
return exec.Result!;
case GeneralExecStatus.failure:
case GeneralExecStatus.not_found:
return ProblemBadRequest("Update account category failed.");
default:
throw new NotSupportedException(exec.Status.ToString());
}
}
[HttpDelete("~/api/settings/motion-categories/{id}")]
public object MotionCategoriesDelete(string id)
{
var exec = _motionService.CategoryRemove(UserId, id.AsGuid());
switch (exec.Status)
{
case MotionCategoryRemoveResult.success:
return exec.Result!;
case MotionCategoryRemoveResult.failure:
return ProblemBadRequest("Remove motion category failed.");
case MotionCategoryRemoveResult.not_found:
return ProblemBadRequest("Account motion not found.");
case MotionCategoryRemoveResult.accounts_exists:
return ProblemBadRequest("Account motion have accounts.");
default:
throw new NotSupportedException(exec.Status.ToString());
}
}
[HttpGet("~/api/settings/motions")]
public object Motions(string? category)
{
var list = category.IsMissing()
? _motionService.GetAll(UserId)
: _motionService.GetByCategory(UserId, category.AsGuid());
return list.Select(x => x.ToModel());
}
[HttpPut("~/api/settings/motions/{id}")]
public object Motions(string id, MotionEditModel request)
{
var exec = _motionService.Update(UserId, id.AsGuid(), request.Category.AsGuid());
switch (exec.Status)
{
case GeneralExecStatus.not_found:
return ProblemBadRequest("Motion not found.");
case GeneralExecStatus.failure:
return ProblemBadRequest("Motion update failed.");
case GeneralExecStatus.success:
return Ok(exec.Result!.ToModel());
default:
throw new NotSupportedException(exec.Status.ToString());
}
}
}
@@ -0,0 +1,178 @@
namespace MyOffice.Web.Controllers;
using Core;
using Core.Extensions;
using Data.Models.Accounts;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using Models.Account;
using Services.Account;
using Services.Account.Domain;
[Authorize]
[ApiController]
[Route("api/[controller]")]
public class SettingsAccountController : BaseApiController
{
private readonly ILogger<SettingsAccountController> _logger;
private readonly AccountService _accountService;
public SettingsAccountController(
ILogger<SettingsAccountController> logger,
AccountService accountService
)
{
_logger = logger;
_accountService = accountService;
}
[HttpGet("~/api/settings/account-categories")]
public object AccountCategories()
{
var list = _accountService.GetAllCategories(UserId);
return list.Select(x => x.ToModel());
}
[HttpPost("~/api/settings/account-categories")]
public object AccountCategoriesAdd(MotionCategoryViewModel request)
{
var exec = _accountService.CategoryAdd(UserId, new AccountCategory { Name = request.Name! });
switch (exec.Status)
{
case GeneralExecStatus.success:
return exec.Result!;
case GeneralExecStatus.failure:
case GeneralExecStatus.not_found:
return ProblemBadRequest("Adding account category failed.");
default:
throw new NotSupportedException(exec.Status.ToString());
}
}
[HttpPut("~/api/settings/account-categories/{id}")]
public object AccountCategoriesEdit(string id, MotionCategoryViewModel request)
{
var exec = _accountService.CategoryUpdate(UserId, id.AsGuid(), new AccountCategory { Name = request.Name! });
switch (exec.Status)
{
case GeneralExecStatus.success:
return exec.Result!;
case GeneralExecStatus.failure:
case GeneralExecStatus.not_found:
return ProblemBadRequest("Update account category failed.");
default:
throw new NotSupportedException(exec.Status.ToString());
}
}
[HttpDelete("~/api/settings/account-categories/{id}")]
public object AccountCategoriesDelete(string id)
{
var exec = _accountService.CategoryRemove(UserId, id.AsGuid());
switch (exec.Status)
{
case AccountCategoryRemoveResult.success:
return exec.Result!;
case AccountCategoryRemoveResult.failure:
return ProblemBadRequest("Remove account category failed.");
case AccountCategoryRemoveResult.not_found:
return ProblemBadRequest("Account category not found.");
case AccountCategoryRemoveResult.accounts_exists:
return ProblemBadRequest("Account category have accounts.");
default:
throw new NotSupportedException(exec.Status.ToString());
}
}
[HttpGet("~/api/settings/accounts")]
public object AccountsGet(string? category)
{
var list = category.IsPresent()
? _accountService.GetByCategory(UserId, category!.AsGuid())
: _accountService.GetAllAccounts(UserId);
return list.Select(x => x.ToModel());
}
[HttpPost("~/api/settings/accounts")]
public object AccountsAdd(AccountViewModel request)
{
var exec = _accountService.AccountAdd(UserId, new AccountAdd
{
Name = request.Name,
CurrencyId = request.CurrencyId,
CategoryId = request.CategoryId.AsGuid(),
});
switch (exec.Status)
{
case AccountAddResult.category_not_found:
return ProblemBadRequest("Category not found.");
case AccountAddResult.currency_not_found:
return ProblemBadRequest("Currency not found.");
case AccountAddResult.failure:
return ProblemBadRequest("Adding account failed.");
case AccountAddResult.success:
return exec.Result!;
default:
throw new NotSupportedException(exec.Status.ToString());
}
}
[HttpPut("~/api/settings/accounts/{id}")]
public object AccountsAdd(string id, AccountEditRequestModel request)
{
var exec = _accountService.AccountUpdate(UserId, id.AsGuid(), new AccountEdit
{
Name = request.Name,
CurrencyId = request.CurrencyId,
CategoryId = request.CategoryId?.AsGuidNull(),
UserId = request.UserId?.AsGuidNull(),
});
switch (exec.Status)
{
case AccountEditResult.not_found:
return ProblemBadRequest("Account not found.");
case AccountEditResult.category_not_found:
return ProblemBadRequest("Category not found.");
case AccountEditResult.currency_not_found:
return ProblemBadRequest("Currency not found.");
case AccountEditResult.failure:
return ProblemBadRequest("Adding account failed.");
case AccountEditResult.success:
return exec.Result!;
default:
throw new NotSupportedException(exec.Status.ToString());
}
}
[HttpDelete("~/api/settings/accounts/{id}/category/{categoryId}")]
public object AccountsCategoryRemove(string id, string categoryId)
{
var exec = _accountService.AccountCategoryRemove(UserId, id.AsGuid(), categoryId.AsGuid());
switch (exec.Status)
{
case GeneralExecStatus.not_found:
case GeneralExecStatus.failure:
return ProblemBadRequest("Category not found.");
case GeneralExecStatus.success:
return exec.Result!;
default:
throw new NotSupportedException(exec.Status.ToString());
}
}
}
+3 -1
View File
@@ -70,6 +70,7 @@ public class UserController : BaseApiController
user.FirstName = model.FirstName;
user.LastName = model.LastName;
user.FullName = model.FullName.NullIfEmpty() ?? $"{model.FirstName} {model.LastName}";
user.CurrencyId = model.Currency;
await _userManager.UpdateAsync(user);
@@ -144,7 +145,7 @@ public class ProfileModel
public string? LastName { get; set; }
public string? FullName { get; set; }
public bool? IsEmailConfirmed { get; set; }
public string? Currency { get; set; }
public List<ProviderModel>? Providers { get; set; }
}
@@ -159,6 +160,7 @@ public static class ProfileModelExtensions
LastName = user.LastName,
FullName = user.FullName,
IsEmailConfirmed = user.IsEmailConfirmed,
Currency = user.CurrencyId,
Providers = userClaims?.Select(x => new ProfileModel.ProviderModel
{
Provider = x.Provider,
@@ -86,7 +86,7 @@ public class IdentityServerConfig
RedirectUris = new[]
{
"http://localhost:4200/silent-refresh.html",
"http://localhost:4300/silent-refresh.html",
},
AllowedScopes =
@@ -13,4 +13,5 @@ public class ApplicationUser<TKey>
public string? LastName { get; set; }
public string? FullName { get; set; }
public bool IsEmailConfirmed { get; set; }
public string? CurrencyId { get; set; }
}
@@ -61,6 +61,7 @@ public class UserStore :
FirstName = user.FirstName,
LastName = user.LastName,
FullName = user.FullName,
CurrencyId = user.CurrencyId!,
IsEmailConfirmed = user.IsEmailConfirmed
});
@@ -78,6 +79,7 @@ public class UserStore :
FirstName = user.FirstName,
LastName = user.LastName,
FullName = user.FullName,
CurrencyId = user.CurrencyId!,
IsEmailConfirmed = user.IsEmailConfirmed
};
@@ -109,6 +111,7 @@ public class UserStore :
FirstName = user.FirstName,
LastName = user.LastName,
FullName = user.FullName,
CurrencyId = user.CurrencyId,
IsEmailConfirmed = user.IsEmailConfirmed
};
}
@@ -133,6 +136,7 @@ public class UserStore :
FirstName = user.FirstName,
LastName = user.LastName,
FullName = user.FullName,
CurrencyId = user.CurrencyId,
IsEmailConfirmed = user.IsEmailConfirmed
};
}
@@ -0,0 +1,27 @@
namespace MyOffice.Web.Models.Account
{
using Data.Models.Accounts;
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 static class AccessRightsViewModelExtensions
{
public static AccessRightsViewModel ToModel(this AccountAccess accountAccess)
{
return new AccessRightsViewModel
{
User = accountAccess.User!.ToModel(),
IsAllowManage = accountAccess.IsAllowManage,
IsAllowRead = accountAccess.IsAllowRead,
IsAllowWrite = accountAccess.IsAllowWrite,
};
}
}
}
@@ -0,0 +1,29 @@
namespace MyOffice.Web.Models.Account
{
using System.ComponentModel.DataAnnotations;
using Core.Extensions;
using Data.Models.Accounts;
public class MotionCategoryViewModel
{
public string? Id { get; set; }
[Required]
public string? Name { get; set; }
public bool? AllowDelete { get; set; }
}
public static class AccountCategoryViewModelExtensions
{
public static MotionCategoryViewModel ToModel(this AccountCategory input)
{
return new MotionCategoryViewModel
{
Id = input.Id.ToShort(),
Name = input.Name,
AllowDelete = !input.Accounts?.Any(),
};
}
}
}
@@ -0,0 +1,21 @@
namespace MyOffice.Web.Models.Account;
using Data.Models.Accounts;
public class AccountDetailedViewModel
{
public AccountViewModel Account { get; set; } = null!;
public decimal Rest { get; set; }
}
public static class AccountDetailedViewModelExtensions
{
public static AccountDetailedViewModel ToModel(this AccountDetailed input)
{
return new AccountDetailedViewModel
{
Account = input.Account.ToModel(),
Rest = input.Rest,
};
}
}
@@ -0,0 +1,13 @@
namespace MyOffice.Web.Models.Account;
using System.ComponentModel.DataAnnotations;
public class AccountEditRequestModel
{
[Required]
public string Name { get; set; } = null!;
[Required]
public string CurrencyId { get; set; } = null!;
public string? CategoryId { get; set; } = null!;
public string? UserId { get; set; } = null!;
}
@@ -0,0 +1,46 @@
namespace MyOffice.Web.Models.Account
{
using System.ComponentModel.DataAnnotations;
using Core.Extensions;
using Data.Models.Accounts;
using User;
public class AccountViewModel
{
public string? Id { get; set; }
[Required]
public string Name { get; set; } = null!;
[Required]
public string CurrencyId { get; set; } = null!;
public string? CurrencyName { get; set; }
public List<MotionCategoryViewModel>? Categories { get; set; }
[Required]
public string CategoryId { get; set; } = null!;
public List<AccessRightsViewModel>? AccessRights { get; set; }
}
public static class AccountViewModelExtensions
{
public static AccountViewModel ToModel(this Account input)
{
return new AccountViewModel
{
Id = input.Id.ToShort(),
Name = input.Name,
CurrencyId = input.CurrencyGlobalId,
CurrencyName = input.CurrencyGlobal!.Name,
Categories = input.Categories!
.Select(x => x.Category!.ToModel())
.ToList(),
AccessRights = input.AccessRights!
.Select(x => x.ToModel())
.ToList(),
};
}
}
}
@@ -0,0 +1,39 @@
namespace MyOffice.Web.Models.AccountMotion;
using Data.Models.Accounts;
public class AccountMotionViewModel
{
public string? Id { get; set; }
public DateTime Date { get; set; }
public string Motion { get; set; } = null!;
public string? Description { get; set; }
public decimal Plus { get; set; }
public decimal Minus { get; set; }
}
public class AccountMotionRequest
{
public DateTime Date { get; set; }
public string Motion { get; set; } = null!;
public string? Description { get; set; }
public decimal Plus { get; set; }
public decimal Minus { get; set; }
}
public static class AccountMotionViewModelExtension
{
}
public static class AccountMotionRequestExtension
{
public static AccountMotion FromModel(this AccountMotionRequest input)
{
/*return new AccountMotion
{
CreatedOn = input.Date,
mo
};*/
}
}
@@ -0,0 +1,19 @@
namespace MyOffice.Web.Models.Currency
{
public class CurrencyAddModel
{
public string Id { get; set; } = null!;
public string Name { get; set; } = null!;
public string ShortName { get; set; } = null!;
public int Quantity { get; set; }
public decimal Rate { get; set; }
public DateTime RateDate { get; set; }
}
public class CurrencyRateModel
{
public int Quantity { get; set; }
public decimal Rate { get; set; }
public DateTime RateDate { get; set; }
}
}
@@ -0,0 +1,27 @@
namespace MyOffice.Web.Models.Currency
{
using Data.Models.Currencies;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
public class CurrencyGlobalViewModel
{
public string Id { get; set; } = null!;
public string Name { get; set; } = null!;
public int Quantity { get; set; }
public string Symbol { get; set; } = null!;
}
public static class CurrencyGlobalViewModelExtensions
{
public static CurrencyGlobalViewModel ToModel(this CurrencyGlobal input)
{
return new CurrencyGlobalViewModel
{
Id = input.Id,
Name = input.Name,
Quantity = input.DefaultQuantity,
Symbol = input.Symbol,
};
}
}
}
@@ -0,0 +1,32 @@
namespace MyOffice.Web.Models.Currency
{
using Core.Extensions;
using Data.Models.Currencies;
using Microsoft.AspNetCore.Mvc.ModelBinding.Binders;
public class CurrencyViewModel
{
public string Id { get; set; } = null!;
public string Code { get; set; } = null!;
public string Name { get; set; } = null!;
public decimal? Rate { get; set; }
public int? Quantity { get; set; }
public DateTime? RateDate { get; set; }
}
public static class CurrencyViewModelExtensions
{
public static CurrencyViewModel ToModel(this Currency input, CurrencyRate? rate = null)
{
return new CurrencyViewModel
{
Id = input.Id.ToShort(),
Code = input.CurrencyGlobal!.Id,
Name = input.Name,
Quantity = rate?.Quantity,
Rate = rate?.Rate,
RateDate = rate?.DateTime,
};
}
}
}
@@ -0,0 +1,33 @@
namespace MyOffice.Web.Models.Motion
{
using System.ComponentModel.DataAnnotations;
using Core.Extensions;
using Data.Models.Accounts;
using MyOffice.Data.Models.Motions;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
public class MotionCategoryViewModel
{
public string? Id { get; set; }
[Required]
public string? Name { get; set; }
public bool AllowDelete { get; set; }
public int SortOrder { get; set; }
}
public static class MotionCategoryViewModelExtensions
{
public static MotionCategoryViewModel ToModel(this MotionCategory input)
{
return new MotionCategoryViewModel
{
Id = input.Id.ToShort(),
Name = input.Name,
AllowDelete = !input.Motions.Any() && input.Id != input.UserId,
SortOrder = input.Id == input.UserId ? 1 : 0
};
}
}
}
@@ -0,0 +1,8 @@
namespace MyOffice.Web.Models.Motion
{
public class MotionEditModel
{
public string Id { get; set; } = null!;
public string Category { get; set; } = null!;
}
}
@@ -0,0 +1,33 @@
namespace MyOffice.Web.Models.Motion
{
using System.ComponentModel.DataAnnotations;
using Core.Extensions;
using MyOffice.Data.Models.Motions;
public class MotionViewModel
{
public string? Id { get; set; }
public string CategoryId { get; set; } = null!;
public string Category { get; set; } = null!;
[Required]
public string? Name { get; set; }
public bool AllowDelete { get; set; }
}
public static class MotionViewModelExtensions
{
public static MotionViewModel ToModel(this MotionAccount input)
{
return new MotionViewModel
{
Id = input.MotionGlobalId.ToShort(),
CategoryId = input.Category.Id.ToShort(),
Category = input.Category.Name,
Name = input.MotionGlobal.Name,
AllowDelete = !input.Motions.Any(),
};
}
}
}
+25
View File
@@ -0,0 +1,25 @@
namespace MyOffice.Web.Models.User
{
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,
};
}
}
}
+57 -9
View File
@@ -23,7 +23,11 @@ using IdentityServer4.Extensions;
using IdentityServer4.Models;
using Microsoft.IdentityModel.Tokens;
using System.Security.Cryptography;
using System.Text.Json;
using System.Text.Json.Serialization;
using Core.Identity;
using Data.Repositories.Account;
using Data.Repositories.Currency;
using Data.Repositories.Users;
using DbContext;
using Services.Users;
@@ -32,6 +36,10 @@ using Identity.Configure;
using Infrastructure;
using Microsoft.Extensions.Logging.Console;
using IdentityServer4.Services;
using MyOffice.Services.Currency;
using Services.Account;
using MyOffice.Data.Repositories.Motion;
using Services.Motion;
public class Program
{
@@ -92,6 +100,9 @@ public class Program
.AddJsonOptions(options =>
{
options.AllowInputFormatterExceptionMessages = builder.Environment.IsDevelopment();
options.JsonSerializerOptions.MaxDepth = 0;
options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
options.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
});
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
@@ -155,8 +166,9 @@ public class Program
LoginUrl = "/authentication/signin",
LoginReturnUrlParameter = "returnUrl"
};
//o.IssuerUri = "http://localhost:9300";
})
.AddSigningCredential(CreateSigningCredential())
.AddSigningCredential(CreateSigningCredential(builder))
.AddPersistedGrantStore<PersistedGrantStore>()
.AddInMemoryIdentityResources(IdentityServerConfig.GetIdentityResources())
.AddInMemoryApiScopes(IdentityServerConfig.GetApiScopes())
@@ -196,11 +208,27 @@ public class Program
{
builder.Services.AddScoped<IUserRepository, UserRepository>();
builder.Services.AddScoped<IUserExternalRepository, UserExternalRepository>();
builder.Services.AddScoped<ICurrencyGlobalRepository, CurrencyGlobalRepository>();
builder.Services.AddScoped<ICurrencyRepository, CurrencyRepository>();
builder.Services.AddScoped<ICurrencyRateRepository, CurrencyRateRepository>();
builder.Services.AddScoped<IAccountCategoryRepository, AccountCategoryRepository>();
builder.Services.AddScoped<IAccountRepository, AccountRepository>();
builder.Services.AddScoped<IAccountAccountCategoryRepository, AccountAccountCategoryRepository>();
builder.Services.AddScoped<IMotionCategoryRepository, MotionCategoryRepository>();
builder.Services.AddScoped<IMotionRepository, MotionRepository>();
builder.Services.AddScoped<IMotionGlobalRepository, MotionGlobalRepository>();
builder.Services.AddScoped<IAccountMotionRepository, AccountMotionRepository>();
}
private static void AddBusinessServices(WebApplicationBuilder builder)
{
builder.Services.AddScoped<UserService, UserService>();
builder.Services.AddScoped<CurrencyService, CurrencyService>();
builder.Services.AddScoped<AccountService, AccountService>();
builder.Services.AddScoped<MotionService, MotionService>();
}
private static readonly ConcurrentDictionary<string, PhysicalFileInfo> _staticFilesCache = new();
@@ -225,6 +253,8 @@ public class Program
app.UseDefaultFiles();
app.UseStaticFiles();
var logger = app.Logger;
// configuration on first request
app.Use(async (ctx, next) =>
{
@@ -244,7 +274,7 @@ public class Program
// set real frontend host
globalSettings = ctx.RequestServices.GetRequiredService<GlobalSettings>();
globalSettings.Host = GetFrontendHost(ctx);
globalSettings.Host = GetFrontendHost(ctx, logger);
// update identity server
var options = ctx.RequestServices.GetRequiredService<IdentityServerOptions>();
@@ -265,7 +295,10 @@ public class Program
if (path.Value.EqualsIgnoreCase("/.well-known/openid-configuration"))
{
globalSettings ??= ctx.RequestServices.GetRequiredService<GlobalSettings>();
logger.LogInformation($"OC Host: {globalSettings.Host}");
ctx.SetIdentityServerOrigin(globalSettings.Host);
var options = ctx.RequestServices.GetRequiredService<IdentityServerOptions>();
options.IssuerUri = globalSettings.Host;
}
await next();
@@ -286,13 +319,11 @@ public class Program
var wwwrootPath = Path.Combine(webRootPath, "wwwroot");
app.Use(async (context, next) =>
{
//app.Logger.LogWarning($"?path: {context.Request.Path}");
var path = context.Request.Path;
if (path.Value == null) return;
if (coreRoutes.Any(x => path.StartsWithSegments(x, StringComparison.OrdinalIgnoreCase)))
{
//app.Logger.LogWarning($"*path: {path.Value}");
await next();
}
else
@@ -303,11 +334,9 @@ public class Program
var fileInfo = new FileInfo(Path.Combine(wwwrootPath, segments.LastOrDefault()!));
if (!fileInfo.Exists)
{
//app.Logger.LogWarning($"-path: {fileInfo.FullName}");
return;
}
//app.Logger.LogWarning($"+path: {fileInfo.FullName}");
physicalFileInfo = new PhysicalFileInfo(fileInfo);
_staticFilesCache.TryAdd(path.Value, physicalFileInfo);
}
@@ -328,7 +357,7 @@ public class Program
app.MapControllers();
}
private static string GetFrontendHost(HttpContext ctx)
private static string GetFrontendHost(HttpContext ctx, ILogger logger)
{
// get X-Forwarded-Proto when reversed proxy used
// internet <-> nginx (https) <-> site(http)
@@ -340,12 +369,31 @@ public class Program
host += $"://{ctx.Request.Host.Value}";
logger.LogCritical($"FR Host: {host}");
if (host.Contains(":4300"))
{
logger.LogCritical(ctx.Request.Path);
logger.LogCritical(string.Join('|', ctx.Request.Headers.Select(x => $"{x.Key}={x.Value}")));
}
return host;
}
private static SigningCredentials CreateSigningCredential()
private static SigningCredentials CreateSigningCredential(WebApplicationBuilder builder)
{
var rsaSecurityKey = new RsaSecurityKey(new RSACryptoServiceProvider(2048));
var rsa = RSA.Create();
var webRootPath = builder.Configuration.GetValue<string>(WebHostDefaults.ContentRootKey);
var privateKey = File.ReadAllText(Path.Combine(webRootPath, "rsa_key.pem"));
privateKey = privateKey
.Replace("-----BEGIN RSA PRIVATE KEY-----", string.Empty)
.Replace("-----END RSA PRIVATE KEY-----", string.Empty)
.Replace(Environment.NewLine, string.Empty);
var privateKeyBytes = Convert.FromBase64String(privateKey);
rsa.ImportRSAPrivateKey(privateKeyBytes, out int _);
var rsaSecurityKey = new RsaSecurityKey(rsa);
var credentials = new SigningCredentials(rsaSecurityKey, SecurityAlgorithms.RsaSha256);
return credentials;
+17 -3
View File
@@ -24,6 +24,18 @@
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"watch": {
"commandName": "Executable",
"executablePath": "dotnet",
"workingDirectory": "$(ProjectDir)",
"hotReloadEnabled": true,
"hotReloadProfile": "aspnetcore",
"commandLineArgs": "watch run",
"launchBrowser": false,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
},
"$schema": "https://json.schemastore.org/launchsettings.json",
@@ -31,12 +43,14 @@
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iis": {
"applicationUrl": "http://localhost:9100",
"sslPort": 9101
"applicationUrl": "http://localhost:9300"
},
"iisExpress": {
"applicationUrl": "http://localhost:9100",
"applicationUrl": "http://localhost:9300",
"sslPort": 9101
},
"watch": {
"applicationUrl": "http://localhost:9300"
}
}
}
+1 -1
View File
@@ -1,5 +1,5 @@
{
"DatabaseProvider": "sqlite",
"DatabaseProvider": "npgsql",
"Logging": {
"LogLevel": {
"Default": "Information",
+27
View File
@@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpQIBAAKCAQEA2njH76FRUMVmz67eVl6VXO9GSez3QIuTWtPZv07TFgiUBoV4
eFovUnHN9zKGCqvrQNogqPfosLGVOWMC8DqUqfWCaamHOC61gz+2LZrtfXASrdBM
qc1mReQA11Xbdd+XaQOIDZ1VfLc7jZbAPIwHDXcFmdOjonU1v6SYX7ESea58G9fJ
CiDuZi2/vmJB0LS1cjRoB75dsUKJq5ZaXYowpoQm7+ogOdAQw5Je2Mb/8FWbjqt0
NyLo9XSz8pSsF0hkfhfSZDQBYZqbz7P9m8C5AuRh66euxKNPV6orOuTyU/hX3lQ/
39eS9Rxsgogp7NnPaHKn9BQwUcFXDFy5wT8FNQIDAQABAoIBAQCpPeGct/o3OQTB
JDUm8VSBzvZDdGfBv55iQTUwp06Mhg6t0p2Vlj+MfY7RzXjbMX0oGxIr8wh2QMtZ
zmLLWIYr932Ufvi6RCzmxOdLAvaxMq21qmSJMg3lXJBuQBunf5NajZrK+TPtTkC7
GapH/S3Fd4uGM9ZSlrwRft9vWcv3KA5QZwmuHKRMhHUpAA9GwHNpKk9Zkl8dvBsF
E10zSaarHYY5IoWZAmRg+NzFRas3Jiiljy7WIHEoerfGgmWdT72f+Z3oCALcIX0r
haoufXhmwCktk/6uMFlweH/7Gh1nhAPPaq06VsaECosw1ScMxEQRfNBfczx31pVn
DTMH/gHNAoGBAPaQjOrI3DxiK419as65Mq7VvyiBf5KkLWRGTnpHDC2JFWWqRk4C
JpStOvU8GZP0m4xdszFosT/A2hSf8sAP5yi8JEwQcVn1Cb/CELPSEsZMW9ltrjUY
bXj2VaU0pluSLGAoa5ZTco0xPJybrQAmJkDi4aQMdpcfZN0vGDTTIWx3AoGBAOLV
BXapg6c+gyS1G7F7pGeHaD22+hYbfigBtzilI4aSn4itZQTSHLzr1RjKfvVPa2DG
Qyod9kQLV59ARF0h5CabIh9gmAP/ZnDla4zuqFI/ARvIhWwMDUxLLx3LQejIzHCh
nuDCEkq01l8Zr/HpS8iz5vBzHKIZ73O6wQ1aQsKzAoGBAIEQH0NSyr2s4YFZsgvt
s1MDPeG1D5Mx7zS6/J9TC1PWmuWxoMV6qLlQiDkQMY9aDgYGkiL92zI0/7KmGwpg
CK8w9IsAXGUrN+QxcE7AWuWD2NxSZksSs1MLFr+4dJAgTqwy3EY+/gpcSI7tijw2
u/VhDZ2yjG0EmOaSnUghcDB3AoGBAKp4l6uPSA8Xzu12YsKm/m6D+BZxfk/BB7W/
XFho22MWrGjGj2XpFonw3uzLulBYCIXpWq67Z8nJkGdxoC8x+kn9Ss60BGr0taNg
98wpzDxLd2TO9V63TAMredR1Xio5RlPbUxDtKVwVvgoovu8aesbyVTwd9sXooemi
z9VeIVA7AoGAIEYLCrD58OQEM8on1S0Fwq7M3dOe39GHHz832ruuMJmnHJD4sm1R
aji296AtFBVdbGb9Gvh806o2NU3HgTrQ1ObkOWl+y7Rzvv+mDbyowxq21voHkja6
1JCEQYDwASRWqbHb1EKaZ0BzYUvTvO3VFco/mwILeMvHMcEO3gzbiF4=
-----END RSA PRIVATE KEY-----
+1 -1
View File
@@ -8,7 +8,7 @@
<aspNetCore processPath="bin\Debug\net6.0\MyOffice.Web.exe" arguments="" stdoutLogEnabled="true" stdoutLogFile=".\logs\stdout" hostingModel="InProcess">
<environmentVariables>
<environmentVariable name="ASPNETCORE_ENVIRONMENT" value="Development" />
<environmentVariable name="ASPNETCORE_HTTPS_PORT" value="9101" />
<environmentVariable name="ASPNETCORE_HTTPS_PORT" value="9301" />
</environmentVariables>
</aspNetCore>
</system.webServer>