refactor: 移除租户端 API 项目
This commit is contained in:
@@ -33,10 +33,6 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeoutSaaS.Module.Authoriz
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeoutSaaS.Module.Tenancy", "src\Modules\TakeoutSaaS.Module.Tenancy\TakeoutSaaS.Module.Tenancy.csproj", "{5B1DAF2B-C36C-4CB1-9452-81D5D6F79D38}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeoutSaaS.Module.Tenancy", "src\Modules\TakeoutSaaS.Module.Tenancy\TakeoutSaaS.Module.Tenancy.csproj", "{5B1DAF2B-C36C-4CB1-9452-81D5D6F79D38}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeoutSaaS.MiniApi", "src\Api\TakeoutSaaS.MiniApi\TakeoutSaaS.MiniApi.csproj", "{12ECF33A-D5E3-4F8B-A9D9-60F7F55B869D}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeoutSaaS.UserApi", "src\Api\TakeoutSaaS.UserApi\TakeoutSaaS.UserApi.csproj", "{1C0BCC51-AF18-44F3-A1E6-A693F74276B5}"
|
|
||||||
EndProject
|
|
||||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Gateway", "Gateway", "{6306A8FB-679E-111F-6585-8F70E0EE6013}"
|
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Gateway", "Gateway", "{6306A8FB-679E-111F-6585-8F70E0EE6013}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeoutSaaS.ApiGateway", "src\Gateway\TakeoutSaaS.ApiGateway\TakeoutSaaS.ApiGateway.csproj", "{A2620200-D487-49A7-ABAF-9B84951F81DD}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TakeoutSaaS.ApiGateway", "src\Gateway\TakeoutSaaS.ApiGateway\TakeoutSaaS.ApiGateway.csproj", "{A2620200-D487-49A7-ABAF-9B84951F81DD}"
|
||||||
@@ -167,30 +163,6 @@ Global
|
|||||||
{5B1DAF2B-C36C-4CB1-9452-81D5D6F79D38}.Release|x64.Build.0 = Release|Any CPU
|
{5B1DAF2B-C36C-4CB1-9452-81D5D6F79D38}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{5B1DAF2B-C36C-4CB1-9452-81D5D6F79D38}.Release|x86.ActiveCfg = Release|Any CPU
|
{5B1DAF2B-C36C-4CB1-9452-81D5D6F79D38}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{5B1DAF2B-C36C-4CB1-9452-81D5D6F79D38}.Release|x86.Build.0 = Release|Any CPU
|
{5B1DAF2B-C36C-4CB1-9452-81D5D6F79D38}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{12ECF33A-D5E3-4F8B-A9D9-60F7F55B869D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{12ECF33A-D5E3-4F8B-A9D9-60F7F55B869D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{12ECF33A-D5E3-4F8B-A9D9-60F7F55B869D}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{12ECF33A-D5E3-4F8B-A9D9-60F7F55B869D}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{12ECF33A-D5E3-4F8B-A9D9-60F7F55B869D}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{12ECF33A-D5E3-4F8B-A9D9-60F7F55B869D}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{12ECF33A-D5E3-4F8B-A9D9-60F7F55B869D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{12ECF33A-D5E3-4F8B-A9D9-60F7F55B869D}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{12ECF33A-D5E3-4F8B-A9D9-60F7F55B869D}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{12ECF33A-D5E3-4F8B-A9D9-60F7F55B869D}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{12ECF33A-D5E3-4F8B-A9D9-60F7F55B869D}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{12ECF33A-D5E3-4F8B-A9D9-60F7F55B869D}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{1C0BCC51-AF18-44F3-A1E6-A693F74276B5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{1C0BCC51-AF18-44F3-A1E6-A693F74276B5}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{1C0BCC51-AF18-44F3-A1E6-A693F74276B5}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{1C0BCC51-AF18-44F3-A1E6-A693F74276B5}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{1C0BCC51-AF18-44F3-A1E6-A693F74276B5}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{1C0BCC51-AF18-44F3-A1E6-A693F74276B5}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{1C0BCC51-AF18-44F3-A1E6-A693F74276B5}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{1C0BCC51-AF18-44F3-A1E6-A693F74276B5}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{1C0BCC51-AF18-44F3-A1E6-A693F74276B5}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{1C0BCC51-AF18-44F3-A1E6-A693F74276B5}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{1C0BCC51-AF18-44F3-A1E6-A693F74276B5}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{1C0BCC51-AF18-44F3-A1E6-A693F74276B5}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{A2620200-D487-49A7-ABAF-9B84951F81DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
{A2620200-D487-49A7-ABAF-9B84951F81DD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
{A2620200-D487-49A7-ABAF-9B84951F81DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{A2620200-D487-49A7-ABAF-9B84951F81DD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{A2620200-D487-49A7-ABAF-9B84951F81DD}.Debug|x64.ActiveCfg = Debug|Any CPU
|
{A2620200-D487-49A7-ABAF-9B84951F81DD}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
@@ -330,8 +302,6 @@ Global
|
|||||||
{EC447DCF-ABFA-6E24-52A5-D7FD48A5C558} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
|
{EC447DCF-ABFA-6E24-52A5-D7FD48A5C558} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
|
||||||
{6CB8487D-5C74-487C-9D84-E57838BDA015} = {EC447DCF-ABFA-6E24-52A5-D7FD48A5C558}
|
{6CB8487D-5C74-487C-9D84-E57838BDA015} = {EC447DCF-ABFA-6E24-52A5-D7FD48A5C558}
|
||||||
{5B1DAF2B-C36C-4CB1-9452-81D5D6F79D38} = {EC447DCF-ABFA-6E24-52A5-D7FD48A5C558}
|
{5B1DAF2B-C36C-4CB1-9452-81D5D6F79D38} = {EC447DCF-ABFA-6E24-52A5-D7FD48A5C558}
|
||||||
{12ECF33A-D5E3-4F8B-A9D9-60F7F55B869D} = {81034408-37C8-1011-444E-4C15C2FADA8E}
|
|
||||||
{1C0BCC51-AF18-44F3-A1E6-A693F74276B5} = {81034408-37C8-1011-444E-4C15C2FADA8E}
|
|
||||||
{6306A8FB-679E-111F-6585-8F70E0EE6013} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
|
{6306A8FB-679E-111F-6585-8F70E0EE6013} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
|
||||||
{A2620200-D487-49A7-ABAF-9B84951F81DD} = {6306A8FB-679E-111F-6585-8F70E0EE6013}
|
{A2620200-D487-49A7-ABAF-9B84951F81DD} = {6306A8FB-679E-111F-6585-8F70E0EE6013}
|
||||||
{BBC99B58-ECA8-42C3-9070-9AA058D778D3} = {8D626EA8-CB54-BC41-363A-217881BEBA6E}
|
{BBC99B58-ECA8-42C3-9070-9AA058D778D3} = {8D626EA8-CB54-BC41-363A-217881BEBA6E}
|
||||||
|
|||||||
@@ -1,20 +0,0 @@
|
|||||||
using System.ComponentModel.DataAnnotations;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
|
|
||||||
namespace TakeoutSaaS.MiniApi.Contracts.Requests;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 文件上传表单请求。
|
|
||||||
/// </summary>
|
|
||||||
public sealed record FileUploadFormRequest
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 上传文件。
|
|
||||||
/// </summary>
|
|
||||||
[Required]
|
|
||||||
public required IFormFile File { get; init; }
|
|
||||||
/// <summary>
|
|
||||||
/// 上传类型。
|
|
||||||
/// </summary>
|
|
||||||
public string? Type { get; init; }
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using TakeoutSaaS.Application.Identity.Abstractions;
|
|
||||||
using TakeoutSaaS.Application.Identity.Contracts;
|
|
||||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
|
||||||
using TakeoutSaaS.Shared.Web.Api;
|
|
||||||
|
|
||||||
namespace TakeoutSaaS.MiniApi.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 小程序登录认证
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>提供小程序端的微信登录与 Token 刷新能力。</remarks>
|
|
||||||
/// <param name="authService">小程序认证服务</param>
|
|
||||||
[ApiVersion("1.0")]
|
|
||||||
[Authorize]
|
|
||||||
[Route("api/mini/v{version:apiVersion}/auth")]
|
|
||||||
public sealed class AuthController(IMiniAuthService authService) : BaseApiController
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 微信登录
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="request">微信登录请求。</param>
|
|
||||||
/// <param name="cancellationToken">取消标记。</param>
|
|
||||||
/// <returns>包含访问令牌与刷新令牌的响应。</returns>
|
|
||||||
[HttpPost("wechat/login")]
|
|
||||||
[AllowAnonymous]
|
|
||||||
[ProducesResponseType(typeof(ApiResponse<TokenResponse>), StatusCodes.Status200OK)]
|
|
||||||
public async Task<ApiResponse<TokenResponse>> LoginWithWeChat([FromBody] WeChatLoginRequest request, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
// 1. 调用认证服务完成微信登录
|
|
||||||
var response = await authService.LoginWithWeChatAsync(request, cancellationToken);
|
|
||||||
|
|
||||||
// 2. 返回访问与刷新令牌
|
|
||||||
return ApiResponse<TokenResponse>.Ok(response);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 刷新 Token
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="request">刷新令牌请求。</param>
|
|
||||||
/// <param name="cancellationToken">取消标记。</param>
|
|
||||||
/// <returns>新的访问令牌与刷新令牌。</returns>
|
|
||||||
[HttpPost("refresh")]
|
|
||||||
[AllowAnonymous]
|
|
||||||
[ProducesResponseType(typeof(ApiResponse<TokenResponse>), StatusCodes.Status200OK)]
|
|
||||||
public async Task<ApiResponse<TokenResponse>> RefreshToken([FromBody] RefreshTokenRequest request, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
// 1. 调用认证服务刷新 Token
|
|
||||||
var response = await authService.RefreshTokenAsync(request, cancellationToken);
|
|
||||||
|
|
||||||
// 2. 返回新的令牌
|
|
||||||
return ApiResponse<TokenResponse>.Ok(response);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,54 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using TakeoutSaaS.Application.Storage.Abstractions;
|
|
||||||
using TakeoutSaaS.Application.Storage.Contracts;
|
|
||||||
using TakeoutSaaS.Application.Storage.Extensions;
|
|
||||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
|
||||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
|
||||||
using TakeoutSaaS.Shared.Web.Api;
|
|
||||||
using TakeoutSaaS.MiniApi.Contracts.Requests;
|
|
||||||
|
|
||||||
namespace TakeoutSaaS.MiniApi.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 小程序文件上传。
|
|
||||||
/// </summary>
|
|
||||||
[ApiVersion("1.0")]
|
|
||||||
[Authorize]
|
|
||||||
[Route("api/mini/v{version:apiVersion}/files")]
|
|
||||||
public sealed class FilesController(IFileStorageService fileStorageService) : BaseApiController
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 上传图片或文件。
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="request">表单请求,包含文件与类型。</param>
|
|
||||||
/// <param name="cancellationToken">取消标记。</param>
|
|
||||||
/// <returns>上传结果,包含访问链接等信息。</returns>
|
|
||||||
[HttpPost("upload")]
|
|
||||||
[Consumes("multipart/form-data")]
|
|
||||||
[RequestFormLimits(MultipartBodyLengthLimit = 30 * 1024 * 1024)]
|
|
||||||
[ProducesResponseType(typeof(ApiResponse<FileUploadResponse>), StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(typeof(ApiResponse<FileUploadResponse>), StatusCodes.Status400BadRequest)]
|
|
||||||
public async Task<ApiResponse<FileUploadResponse>> Upload([FromForm] FileUploadFormRequest request, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
// 1. 校验文件有效性
|
|
||||||
if (request.File is null || request.File.Length == 0)
|
|
||||||
{
|
|
||||||
return ApiResponse<FileUploadResponse>.Error(ErrorCodes.BadRequest, "文件不能为空");
|
|
||||||
}
|
|
||||||
// 2. 解析上传类型
|
|
||||||
if (!UploadFileTypeParser.TryParse(request.Type, out var uploadType))
|
|
||||||
{
|
|
||||||
return ApiResponse<FileUploadResponse>.Error(ErrorCodes.BadRequest, "上传类型不合法");
|
|
||||||
}
|
|
||||||
// 3. 提取请求来源
|
|
||||||
var origin = Request.Headers["Origin"].FirstOrDefault() ?? Request.Headers["Referer"].FirstOrDefault();
|
|
||||||
await using var stream = request.File.OpenReadStream();
|
|
||||||
// 4. 调用存储服务执行上传
|
|
||||||
var result = await fileStorageService.UploadAsync(
|
|
||||||
new UploadFileRequest(uploadType, stream, request.File.FileName, request.File.ContentType ?? string.Empty, request.File.Length, origin),
|
|
||||||
cancellationToken);
|
|
||||||
// 5. 返回上传结果
|
|
||||||
return ApiResponse<FileUploadResponse>.Ok(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
|
||||||
using TakeoutSaaS.Shared.Web.Api;
|
|
||||||
|
|
||||||
namespace TakeoutSaaS.MiniApi.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 小程序端 - 健康检查。
|
|
||||||
/// </summary>
|
|
||||||
[ApiVersion("1.0")]
|
|
||||||
[AllowAnonymous]
|
|
||||||
[Route("api/mini/v{version:apiVersion}/[controller]")]
|
|
||||||
public class HealthController : BaseApiController
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 获取服务健康状态。
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>健康状态</returns>
|
|
||||||
[HttpGet]
|
|
||||||
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
|
|
||||||
public ApiResponse<object> Get()
|
|
||||||
{
|
|
||||||
// 1. 构造健康状态
|
|
||||||
var payload = new { status = "OK", service = "MiniApi", time = DateTime.UtcNow };
|
|
||||||
|
|
||||||
// 2. 返回健康响应
|
|
||||||
return ApiResponse<object>.Ok(payload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using TakeoutSaaS.Application.Identity.Abstractions;
|
|
||||||
using TakeoutSaaS.Application.Identity.Contracts;
|
|
||||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
|
||||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
|
||||||
using TakeoutSaaS.Shared.Web.Api;
|
|
||||||
using TakeoutSaaS.Shared.Web.Security;
|
|
||||||
|
|
||||||
namespace TakeoutSaaS.MiniApi.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前用户信息
|
|
||||||
/// </summary>
|
|
||||||
/// <remarks>提供小程序端当前用户档案查询。</remarks>
|
|
||||||
/// <param name="authService">小程序认证服务</param>
|
|
||||||
[ApiVersion("1.0")]
|
|
||||||
[Authorize]
|
|
||||||
[Route("api/mini/v{version:apiVersion}/me")]
|
|
||||||
public sealed class MeController(IMiniAuthService authService) : BaseApiController
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 获取用户档案
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="cancellationToken">取消标记。</param>
|
|
||||||
/// <returns>当前用户档案信息。</returns>
|
|
||||||
[HttpGet]
|
|
||||||
[ProducesResponseType(typeof(ApiResponse<CurrentUserProfile>), StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(typeof(ApiResponse<CurrentUserProfile>), StatusCodes.Status401Unauthorized)]
|
|
||||||
public async Task<ApiResponse<CurrentUserProfile>> Get(CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
// 1. 从 JWT 中解析用户标识
|
|
||||||
var userId = User.GetUserId();
|
|
||||||
if (userId == 0)
|
|
||||||
{
|
|
||||||
return ApiResponse<CurrentUserProfile>.Error(ErrorCodes.Unauthorized, "Token 缺少有效的用户标识");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. 查询用户档案并返回
|
|
||||||
var profile = await authService.GetProfileAsync(userId, cancellationToken);
|
|
||||||
return ApiResponse<CurrentUserProfile>.Ok(profile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
using System;
|
|
||||||
using MediatR;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using TakeoutSaaS.Application.App.Products.Dto;
|
|
||||||
using TakeoutSaaS.Application.App.Products.Queries;
|
|
||||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
|
||||||
using TakeoutSaaS.Shared.Web.Api;
|
|
||||||
|
|
||||||
namespace TakeoutSaaS.MiniApi.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 小程序端菜单查询。
|
|
||||||
/// </summary>
|
|
||||||
[ApiVersion("1.0")]
|
|
||||||
[Authorize]
|
|
||||||
[Route("api/mini/v{version:apiVersion}/stores/{storeId:long}/menu")]
|
|
||||||
public sealed class MenusController(IMediator mediator) : BaseApiController
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 获取门店菜单(含分类与商品详情)。
|
|
||||||
/// </summary>
|
|
||||||
[HttpGet]
|
|
||||||
[ProducesResponseType(typeof(ApiResponse<StoreMenuDto>), StatusCodes.Status200OK)]
|
|
||||||
public async Task<ApiResponse<StoreMenuDto>> GetMenu(long storeId, [FromQuery] DateTime? updatedAfter, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
// 1. 组装查询
|
|
||||||
var query = new GetStoreMenuQuery
|
|
||||||
{
|
|
||||||
StoreId = storeId,
|
|
||||||
UpdatedAfter = updatedAfter
|
|
||||||
};
|
|
||||||
// 2. 拉取菜单
|
|
||||||
var result = await mediator.Send(query, cancellationToken);
|
|
||||||
return ApiResponse<StoreMenuDto>.Ok(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
using System;
|
|
||||||
using MediatR;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using TakeoutSaaS.Application.App.Stores.Dto;
|
|
||||||
using TakeoutSaaS.Application.App.Stores.Queries;
|
|
||||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
|
||||||
using TakeoutSaaS.Shared.Web.Api;
|
|
||||||
|
|
||||||
namespace TakeoutSaaS.MiniApi.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 小程序端自提档期查询。
|
|
||||||
/// </summary>
|
|
||||||
[ApiVersion("1.0")]
|
|
||||||
[Authorize]
|
|
||||||
[Route("api/mini/v{version:apiVersion}/stores/{storeId:long}/pickup-slots")]
|
|
||||||
public sealed class PickupSlotsController(IMediator mediator) : BaseApiController
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 获取指定日期可用档期。
|
|
||||||
/// </summary>
|
|
||||||
[HttpGet]
|
|
||||||
[ProducesResponseType(typeof(ApiResponse<IReadOnlyList<StorePickupSlotDto>>), StatusCodes.Status200OK)]
|
|
||||||
public async Task<ApiResponse<IReadOnlyList<StorePickupSlotDto>>> GetSlots(long storeId, [FromQuery] DateTime date, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var result = await mediator.Send(new GetAvailablePickupSlotsQuery { StoreId = storeId, Date = date }, cancellationToken);
|
|
||||||
return ApiResponse<IReadOnlyList<StorePickupSlotDto>>.Ok(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using MediatR;
|
|
||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Http;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using TakeoutSaaS.Application.App.Stores.Dto;
|
|
||||||
using TakeoutSaaS.Application.App.Stores.Queries;
|
|
||||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
|
||||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
|
||||||
using TakeoutSaaS.Shared.Web.Api;
|
|
||||||
|
|
||||||
namespace TakeoutSaaS.MiniApi.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 桌码上下文。
|
|
||||||
/// </summary>
|
|
||||||
[ApiVersion("1.0")]
|
|
||||||
[Authorize]
|
|
||||||
[Route("api/mini/v{version:apiVersion}/tables")]
|
|
||||||
public sealed class TablesController(IMediator mediator) : BaseApiController
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 解析桌码并返回上下文。
|
|
||||||
/// </summary>
|
|
||||||
[HttpGet("{code}/context")]
|
|
||||||
[ProducesResponseType(typeof(ApiResponse<StoreTableContextDto>), StatusCodes.Status200OK)]
|
|
||||||
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status404NotFound)]
|
|
||||||
public async Task<ApiResponse<StoreTableContextDto>> GetContext(string code, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
var result = await mediator.Send(new GetStoreTableContextQuery { TableCode = code }, cancellationToken);
|
|
||||||
return result is null
|
|
||||||
? ApiResponse<StoreTableContextDto>.Error(ErrorCodes.NotFound, "桌码不存在")
|
|
||||||
: ApiResponse<StoreTableContextDto>.Ok(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
|
||||||
WORKDIR /src
|
|
||||||
COPY . .
|
|
||||||
RUN dotnet restore src/Api/TakeoutSaaS.MiniApi/TakeoutSaaS.MiniApi.csproj
|
|
||||||
RUN dotnet publish src/Api/TakeoutSaaS.MiniApi/TakeoutSaaS.MiniApi.csproj -c Release -o /app/publish
|
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:10.0
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=build /app/publish .
|
|
||||||
EXPOSE 7701
|
|
||||||
ENV ASPNETCORE_URLS=http://+:7701
|
|
||||||
ENTRYPOINT ["dotnet", "TakeoutSaaS.MiniApi.dll"]
|
|
||||||
@@ -1,176 +0,0 @@
|
|||||||
using FluentValidation;
|
|
||||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
|
||||||
using Microsoft.Extensions.Caching.StackExchangeRedis;
|
|
||||||
using OpenTelemetry.Metrics;
|
|
||||||
using OpenTelemetry.Resources;
|
|
||||||
using OpenTelemetry.Trace;
|
|
||||||
using Serilog;
|
|
||||||
using TakeoutSaaS.Application.Messaging.Extensions;
|
|
||||||
using TakeoutSaaS.Application.Sms.Extensions;
|
|
||||||
using TakeoutSaaS.Application.Storage.Extensions;
|
|
||||||
using TakeoutSaaS.Module.Messaging.Extensions;
|
|
||||||
using TakeoutSaaS.Module.Sms.Extensions;
|
|
||||||
using TakeoutSaaS.Module.Storage.Extensions;
|
|
||||||
using TakeoutSaaS.Module.Tenancy.Extensions;
|
|
||||||
using TakeoutSaaS.Shared.Abstractions.Ids;
|
|
||||||
using TakeoutSaaS.Shared.Kernel.Ids;
|
|
||||||
using TakeoutSaaS.Shared.Web.Extensions;
|
|
||||||
using TakeoutSaaS.Shared.Web.Swagger;
|
|
||||||
using System.Reflection;
|
|
||||||
|
|
||||||
// 1. 创建构建器与日志模板
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
|
||||||
const string logTemplate = "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {Level:u3}] [TraceId:{TraceId}] [SpanId:{SpanId}] [Service:{Service}] {SourceContext} {Message:lj}{NewLine}{Exception}";
|
|
||||||
var isDevelopment = builder.Environment.IsDevelopment();
|
|
||||||
|
|
||||||
// 2. 注册雪花 ID 生成器与 Serilog
|
|
||||||
builder.Services.AddSingleton<IIdGenerator>(_ => new SnowflakeIdGenerator());
|
|
||||||
builder.Host.UseSerilog((_, _, configuration) =>
|
|
||||||
{
|
|
||||||
configuration
|
|
||||||
.Enrich.FromLogContext()
|
|
||||||
.Enrich.WithProperty("Service", "MiniApi")
|
|
||||||
.WriteTo.Console(outputTemplate: logTemplate)
|
|
||||||
.WriteTo.File(
|
|
||||||
"logs/mini-api-.log",
|
|
||||||
rollingInterval: RollingInterval.Day,
|
|
||||||
retainedFileCountLimit: 7,
|
|
||||||
shared: true,
|
|
||||||
outputTemplate: logTemplate);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 3. 注册通用 Web 能力,开发环境启用 Swagger
|
|
||||||
builder.Services.AddSharedWebCore();
|
|
||||||
if (isDevelopment)
|
|
||||||
{
|
|
||||||
builder.Services.AddSharedSwagger(options =>
|
|
||||||
{
|
|
||||||
options.Title = "外卖SaaS - 小程序端";
|
|
||||||
options.Description = "小程序 API 文档";
|
|
||||||
options.EnableAuthorization = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
builder.Services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());
|
|
||||||
|
|
||||||
// 4. 注册 Redis 分布式缓存,供验证码等功能使用
|
|
||||||
var redisConnection = builder.Configuration.GetValue<string>("Redis");
|
|
||||||
builder.Services.AddStackExchangeRedisCache(options =>
|
|
||||||
{
|
|
||||||
options.Configuration = redisConnection;
|
|
||||||
});
|
|
||||||
|
|
||||||
// 4. 注册多租户与业务模块
|
|
||||||
builder.Services.AddTenantResolution(builder.Configuration);
|
|
||||||
builder.Services.AddStorageModule(builder.Configuration);
|
|
||||||
builder.Services.AddStorageApplication();
|
|
||||||
builder.Services.AddSmsModule(builder.Configuration);
|
|
||||||
builder.Services.AddSmsApplication(builder.Configuration);
|
|
||||||
builder.Services.AddMessagingModule(builder.Configuration);
|
|
||||||
builder.Services.AddMessagingApplication();
|
|
||||||
builder.Services.AddHealthChecks();
|
|
||||||
|
|
||||||
// 5. 配置 OpenTelemetry 采集
|
|
||||||
var otelSection = builder.Configuration.GetSection("Otel");
|
|
||||||
var otelEndpoint = otelSection.GetValue<string>("Endpoint");
|
|
||||||
var useConsoleExporter = otelSection.GetValue<bool?>("UseConsoleExporter") ?? builder.Environment.IsDevelopment();
|
|
||||||
builder.Services.AddOpenTelemetry()
|
|
||||||
.ConfigureResource(resource => resource.AddService(
|
|
||||||
serviceName: "TakeoutSaaS.MiniApi",
|
|
||||||
serviceVersion: "1.0.0",
|
|
||||||
serviceInstanceId: Environment.MachineName))
|
|
||||||
.WithTracing(tracing =>
|
|
||||||
{
|
|
||||||
tracing
|
|
||||||
.SetSampler(new ParentBasedSampler(new AlwaysOnSampler()))
|
|
||||||
.AddAspNetCoreInstrumentation()
|
|
||||||
.AddHttpClientInstrumentation()
|
|
||||||
.AddEntityFrameworkCoreInstrumentation();
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(otelEndpoint))
|
|
||||||
{
|
|
||||||
tracing.AddOtlpExporter(exporter =>
|
|
||||||
{
|
|
||||||
exporter.Endpoint = new Uri(otelEndpoint);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useConsoleExporter)
|
|
||||||
{
|
|
||||||
tracing.AddConsoleExporter();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.WithMetrics(metrics =>
|
|
||||||
{
|
|
||||||
metrics
|
|
||||||
.AddAspNetCoreInstrumentation()
|
|
||||||
.AddHttpClientInstrumentation()
|
|
||||||
.AddRuntimeInstrumentation()
|
|
||||||
.AddPrometheusExporter();
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(otelEndpoint))
|
|
||||||
{
|
|
||||||
metrics.AddOtlpExporter(exporter =>
|
|
||||||
{
|
|
||||||
exporter.Endpoint = new Uri(otelEndpoint);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useConsoleExporter)
|
|
||||||
{
|
|
||||||
metrics.AddConsoleExporter();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 6. 配置 CORS
|
|
||||||
var miniOrigins = ResolveCorsOrigins(builder.Configuration, "Cors:Mini");
|
|
||||||
builder.Services.AddCors(options =>
|
|
||||||
{
|
|
||||||
options.AddPolicy("MiniApiCors", policy =>
|
|
||||||
{
|
|
||||||
ConfigureCorsPolicy(policy, miniOrigins);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 7. 构建应用并配置中间件管道
|
|
||||||
var app = builder.Build();
|
|
||||||
|
|
||||||
app.UseCors("MiniApiCors");
|
|
||||||
app.UseTenantResolution();
|
|
||||||
app.UseSharedWebCore();
|
|
||||||
if (app.Environment.IsDevelopment())
|
|
||||||
{
|
|
||||||
app.UseSharedSwagger();
|
|
||||||
}
|
|
||||||
|
|
||||||
app.MapHealthChecks("/healthz");
|
|
||||||
app.MapPrometheusScrapingEndpoint();
|
|
||||||
app.MapControllers();
|
|
||||||
app.Run();
|
|
||||||
|
|
||||||
// 8. 解析配置中的 CORS 域名
|
|
||||||
static string[] ResolveCorsOrigins(IConfiguration configuration, string sectionKey)
|
|
||||||
{
|
|
||||||
var origins = configuration.GetSection(sectionKey).Get<string[]>();
|
|
||||||
return origins?
|
|
||||||
.Where(origin => !string.IsNullOrWhiteSpace(origin))
|
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
||||||
.ToArray() ?? [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 9. 构建 CORS 策略
|
|
||||||
static void ConfigureCorsPolicy(CorsPolicyBuilder policy, string[] origins)
|
|
||||||
{
|
|
||||||
if (origins.Length == 0)
|
|
||||||
{
|
|
||||||
policy.AllowAnyOrigin();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
policy.WithOrigins(origins)
|
|
||||||
.AllowCredentials();
|
|
||||||
}
|
|
||||||
|
|
||||||
policy
|
|
||||||
.AllowAnyHeader()
|
|
||||||
.AllowAnyMethod();
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"profiles": {
|
|
||||||
"TakeoutSaaS.MiniApi": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
},
|
|
||||||
"applicationUrl": "http://localhost:2681"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
@@ -1,175 +0,0 @@
|
|||||||
{
|
|
||||||
"Database": {
|
|
||||||
"DataSources": {
|
|
||||||
"AppDatabase": {
|
|
||||||
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
|
||||||
"Reads": [
|
|
||||||
"Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
|
||||||
],
|
|
||||||
"CommandTimeoutSeconds": 30,
|
|
||||||
"MaxRetryCount": 3,
|
|
||||||
"MaxRetryDelaySeconds": 5
|
|
||||||
},
|
|
||||||
"IdentityDatabase": {
|
|
||||||
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
|
||||||
"Reads": [
|
|
||||||
"Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
|
||||||
],
|
|
||||||
"CommandTimeoutSeconds": 30,
|
|
||||||
"MaxRetryCount": 3,
|
|
||||||
"MaxRetryDelaySeconds": 5
|
|
||||||
},
|
|
||||||
"DictionaryDatabase": {
|
|
||||||
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
|
||||||
"Reads": [
|
|
||||||
"Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
|
||||||
],
|
|
||||||
"CommandTimeoutSeconds": 30,
|
|
||||||
"MaxRetryCount": 3,
|
|
||||||
"MaxRetryDelaySeconds": 5
|
|
||||||
},
|
|
||||||
"LogsDatabase": {
|
|
||||||
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
|
||||||
"Reads": [
|
|
||||||
"Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
|
||||||
],
|
|
||||||
"CommandTimeoutSeconds": 30,
|
|
||||||
"MaxRetryCount": 3,
|
|
||||||
"MaxRetryDelaySeconds": 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Redis": "49.232.6.45:6379,password=MsuMshk112233,abortConnect=false",
|
|
||||||
"Identity": {
|
|
||||||
"Jwt": {
|
|
||||||
"Issuer": "takeout-saas",
|
|
||||||
"Audience": "takeout-saas-clients",
|
|
||||||
"Secret": "psZEx_O##]Mq(W.1$?8Aia*LM03sXGGx",
|
|
||||||
"AccessTokenExpirationMinutes": 120,
|
|
||||||
"RefreshTokenExpirationMinutes": 10080
|
|
||||||
},
|
|
||||||
"LoginRateLimit": {
|
|
||||||
"WindowSeconds": 60,
|
|
||||||
"MaxAttempts": 5
|
|
||||||
},
|
|
||||||
"RefreshTokenStore": {
|
|
||||||
"Prefix": "identity:refresh:"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Dictionary": {
|
|
||||||
"Cache": {
|
|
||||||
"SlidingExpiration": "00:30:00"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Tenancy": {
|
|
||||||
"TenantIdHeaderName": "X-Tenant-Id",
|
|
||||||
"TenantCodeHeaderName": "X-Tenant-Code",
|
|
||||||
"IgnoredPaths": [
|
|
||||||
"/health"
|
|
||||||
],
|
|
||||||
"RootDomain": ""
|
|
||||||
},
|
|
||||||
"Storage": {
|
|
||||||
"Provider": "TencentCos",
|
|
||||||
"CdnBaseUrl": "https://saas2025-1388556178.cos.ap-beijing.myqcloud.com",
|
|
||||||
"TencentCos": {
|
|
||||||
"SecretId": "AKID52mHageV8ZnnY5NRL3Xq270fAcw2vb5R",
|
|
||||||
"SecretKey": "B8sPitsiEXcS4ScaMvGMErFOL3ZqsgFa",
|
|
||||||
"Region": "ap-beijing",
|
|
||||||
"Bucket": "saas2025-1388556178",
|
|
||||||
"Endpoint": "https://saas2025-1388556178.cos.ap-beijing.myqcloud.com",
|
|
||||||
"CdnBaseUrl": "https://saas2025-1388556178.cos.ap-beijing.myqcloud.com",
|
|
||||||
"UseHttps": true,
|
|
||||||
"ForcePathStyle": false
|
|
||||||
},
|
|
||||||
"QiniuKodo": {
|
|
||||||
"AccessKey": "QINIU_ACCESS_KEY",
|
|
||||||
"SecretKey": "QINIU_SECRET_KEY",
|
|
||||||
"Bucket": "takeout-files",
|
|
||||||
"DownloadDomain": "",
|
|
||||||
"Endpoint": "",
|
|
||||||
"UseHttps": true,
|
|
||||||
"SignedUrlExpirationMinutes": 30
|
|
||||||
},
|
|
||||||
"AliyunOss": {
|
|
||||||
"AccessKeyId": "OSS_ACCESS_KEY_ID",
|
|
||||||
"AccessKeySecret": "OSS_ACCESS_KEY_SECRET",
|
|
||||||
"Endpoint": "https://oss-cn-hangzhou.aliyuncs.com",
|
|
||||||
"Bucket": "takeout-files",
|
|
||||||
"CdnBaseUrl": "",
|
|
||||||
"UseHttps": true
|
|
||||||
},
|
|
||||||
"Security": {
|
|
||||||
"MaxFileSizeBytes": 10485760,
|
|
||||||
"AllowedImageExtensions": [
|
|
||||||
".jpg",
|
|
||||||
".jpeg",
|
|
||||||
".png",
|
|
||||||
".webp",
|
|
||||||
".gif"
|
|
||||||
],
|
|
||||||
"AllowedFileExtensions": [
|
|
||||||
".jpg",
|
|
||||||
".jpeg",
|
|
||||||
".png",
|
|
||||||
".webp",
|
|
||||||
".gif",
|
|
||||||
".pdf"
|
|
||||||
],
|
|
||||||
"DefaultUrlExpirationMinutes": 30,
|
|
||||||
"EnableRefererValidation": true,
|
|
||||||
"AllowedReferers": [
|
|
||||||
"https://admin.example.com",
|
|
||||||
"https://miniapp.example.com"
|
|
||||||
],
|
|
||||||
"AntiLeechTokenSecret": "ReplaceWithARandomToken"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Sms": {
|
|
||||||
"Provider": "Tencent",
|
|
||||||
"DefaultSignName": "外卖SaaS",
|
|
||||||
"UseMock": true,
|
|
||||||
"Tencent": {
|
|
||||||
"SecretId": "TENCENT_SMS_SECRET_ID",
|
|
||||||
"SecretKey": "TENCENT_SMS_SECRET_KEY",
|
|
||||||
"SdkAppId": "1400000000",
|
|
||||||
"SignName": "外卖SaaS",
|
|
||||||
"Region": "ap-beijing",
|
|
||||||
"Endpoint": "https://sms.tencentcloudapi.com"
|
|
||||||
},
|
|
||||||
"Aliyun": {
|
|
||||||
"AccessKeyId": "ALIYUN_SMS_AK",
|
|
||||||
"AccessKeySecret": "ALIYUN_SMS_SK",
|
|
||||||
"Endpoint": "dysmsapi.aliyuncs.com",
|
|
||||||
"SignName": "外卖SaaS",
|
|
||||||
"Region": "cn-hangzhou"
|
|
||||||
},
|
|
||||||
"SceneTemplates": {
|
|
||||||
"login": "LOGIN_TEMPLATE_ID",
|
|
||||||
"register": "REGISTER_TEMPLATE_ID",
|
|
||||||
"reset": "RESET_TEMPLATE_ID"
|
|
||||||
},
|
|
||||||
"VerificationCode": {
|
|
||||||
"CodeLength": 6,
|
|
||||||
"ExpireMinutes": 5,
|
|
||||||
"CooldownSeconds": 60,
|
|
||||||
"CachePrefix": "sms:code"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RabbitMQ": {
|
|
||||||
"Host": "49.232.6.45",
|
|
||||||
"Port": 5672,
|
|
||||||
"Username": "Admin",
|
|
||||||
"Password": "MsuMshk112233",
|
|
||||||
"VirtualHost": "/",
|
|
||||||
"Exchange": "takeout.events",
|
|
||||||
"ExchangeType": "topic",
|
|
||||||
"PrefetchCount": 20
|
|
||||||
},
|
|
||||||
"Otel": {
|
|
||||||
"Endpoint": "",
|
|
||||||
"Sampling": "ParentBasedAlwaysOn",
|
|
||||||
"UseConsoleExporter": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,175 +0,0 @@
|
|||||||
{
|
|
||||||
"Database": {
|
|
||||||
"DataSources": {
|
|
||||||
"AppDatabase": {
|
|
||||||
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
|
||||||
"Reads": [
|
|
||||||
"Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
|
||||||
],
|
|
||||||
"CommandTimeoutSeconds": 30,
|
|
||||||
"MaxRetryCount": 3,
|
|
||||||
"MaxRetryDelaySeconds": 5
|
|
||||||
},
|
|
||||||
"IdentityDatabase": {
|
|
||||||
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
|
||||||
"Reads": [
|
|
||||||
"Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
|
||||||
],
|
|
||||||
"CommandTimeoutSeconds": 30,
|
|
||||||
"MaxRetryCount": 3,
|
|
||||||
"MaxRetryDelaySeconds": 5
|
|
||||||
},
|
|
||||||
"DictionaryDatabase": {
|
|
||||||
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
|
||||||
"Reads": [
|
|
||||||
"Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
|
||||||
],
|
|
||||||
"CommandTimeoutSeconds": 30,
|
|
||||||
"MaxRetryCount": 3,
|
|
||||||
"MaxRetryDelaySeconds": 5
|
|
||||||
},
|
|
||||||
"LogsDatabase": {
|
|
||||||
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
|
||||||
"Reads": [
|
|
||||||
"Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
|
||||||
],
|
|
||||||
"CommandTimeoutSeconds": 30,
|
|
||||||
"MaxRetryCount": 3,
|
|
||||||
"MaxRetryDelaySeconds": 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Redis": "49.232.6.45:6379,password=MsuMshk112233,abortConnect=false",
|
|
||||||
"Identity": {
|
|
||||||
"Jwt": {
|
|
||||||
"Issuer": "takeout-saas",
|
|
||||||
"Audience": "takeout-saas-clients",
|
|
||||||
"Secret": "psZEx_O##]Mq(W.1$?8Aia*LM03sXGGx",
|
|
||||||
"AccessTokenExpirationMinutes": 120,
|
|
||||||
"RefreshTokenExpirationMinutes": 10080
|
|
||||||
},
|
|
||||||
"LoginRateLimit": {
|
|
||||||
"WindowSeconds": 60,
|
|
||||||
"MaxAttempts": 5
|
|
||||||
},
|
|
||||||
"RefreshTokenStore": {
|
|
||||||
"Prefix": "identity:refresh:"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Dictionary": {
|
|
||||||
"Cache": {
|
|
||||||
"SlidingExpiration": "00:30:00"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Tenancy": {
|
|
||||||
"TenantIdHeaderName": "X-Tenant-Id",
|
|
||||||
"TenantCodeHeaderName": "X-Tenant-Code",
|
|
||||||
"IgnoredPaths": [
|
|
||||||
"/health"
|
|
||||||
],
|
|
||||||
"RootDomain": ""
|
|
||||||
},
|
|
||||||
"Storage": {
|
|
||||||
"Provider": "TencentCos",
|
|
||||||
"CdnBaseUrl": "https://saas2025-1388556178.cos.ap-beijing.myqcloud.com",
|
|
||||||
"TencentCos": {
|
|
||||||
"SecretId": "AKID52mHageV8ZnnY5NRL3Xq270fAcw2vb5R",
|
|
||||||
"SecretKey": "B8sPitsiEXcS4ScaMvGMErFOL3ZqsgFa",
|
|
||||||
"Region": "ap-beijing",
|
|
||||||
"Bucket": "saas2025-1388556178",
|
|
||||||
"Endpoint": "https://saas2025-1388556178.cos.ap-beijing.myqcloud.com",
|
|
||||||
"CdnBaseUrl": "https://saas2025-1388556178.cos.ap-beijing.myqcloud.com",
|
|
||||||
"UseHttps": true,
|
|
||||||
"ForcePathStyle": false
|
|
||||||
},
|
|
||||||
"QiniuKodo": {
|
|
||||||
"AccessKey": "QINIU_ACCESS_KEY",
|
|
||||||
"SecretKey": "QINIU_SECRET_KEY",
|
|
||||||
"Bucket": "takeout-files",
|
|
||||||
"DownloadDomain": "",
|
|
||||||
"Endpoint": "",
|
|
||||||
"UseHttps": true,
|
|
||||||
"SignedUrlExpirationMinutes": 30
|
|
||||||
},
|
|
||||||
"AliyunOss": {
|
|
||||||
"AccessKeyId": "OSS_ACCESS_KEY_ID",
|
|
||||||
"AccessKeySecret": "OSS_ACCESS_KEY_SECRET",
|
|
||||||
"Endpoint": "https://oss-cn-hangzhou.aliyuncs.com",
|
|
||||||
"Bucket": "takeout-files",
|
|
||||||
"CdnBaseUrl": "",
|
|
||||||
"UseHttps": true
|
|
||||||
},
|
|
||||||
"Security": {
|
|
||||||
"MaxFileSizeBytes": 10485760,
|
|
||||||
"AllowedImageExtensions": [
|
|
||||||
".jpg",
|
|
||||||
".jpeg",
|
|
||||||
".png",
|
|
||||||
".webp",
|
|
||||||
".gif"
|
|
||||||
],
|
|
||||||
"AllowedFileExtensions": [
|
|
||||||
".jpg",
|
|
||||||
".jpeg",
|
|
||||||
".png",
|
|
||||||
".webp",
|
|
||||||
".gif",
|
|
||||||
".pdf"
|
|
||||||
],
|
|
||||||
"DefaultUrlExpirationMinutes": 30,
|
|
||||||
"EnableRefererValidation": true,
|
|
||||||
"AllowedReferers": [
|
|
||||||
"https://admin.example.com",
|
|
||||||
"https://miniapp.example.com"
|
|
||||||
],
|
|
||||||
"AntiLeechTokenSecret": "ReplaceWithARandomToken"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Sms": {
|
|
||||||
"Provider": "Tencent",
|
|
||||||
"DefaultSignName": "外卖SaaS",
|
|
||||||
"UseMock": true,
|
|
||||||
"Tencent": {
|
|
||||||
"SecretId": "TENCENT_SMS_SECRET_ID",
|
|
||||||
"SecretKey": "TENCENT_SMS_SECRET_KEY",
|
|
||||||
"SdkAppId": "1400000000",
|
|
||||||
"SignName": "外卖SaaS",
|
|
||||||
"Region": "ap-beijing",
|
|
||||||
"Endpoint": "https://sms.tencentcloudapi.com"
|
|
||||||
},
|
|
||||||
"Aliyun": {
|
|
||||||
"AccessKeyId": "ALIYUN_SMS_AK",
|
|
||||||
"AccessKeySecret": "ALIYUN_SMS_SK",
|
|
||||||
"Endpoint": "dysmsapi.aliyuncs.com",
|
|
||||||
"SignName": "外卖SaaS",
|
|
||||||
"Region": "cn-hangzhou"
|
|
||||||
},
|
|
||||||
"SceneTemplates": {
|
|
||||||
"login": "LOGIN_TEMPLATE_ID",
|
|
||||||
"register": "REGISTER_TEMPLATE_ID",
|
|
||||||
"reset": "RESET_TEMPLATE_ID"
|
|
||||||
},
|
|
||||||
"VerificationCode": {
|
|
||||||
"CodeLength": 6,
|
|
||||||
"ExpireMinutes": 5,
|
|
||||||
"CooldownSeconds": 60,
|
|
||||||
"CachePrefix": "sms:code"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"RabbitMQ": {
|
|
||||||
"Host": "49.232.6.45",
|
|
||||||
"Port": 5672,
|
|
||||||
"Username": "Admin",
|
|
||||||
"Password": "MsuMshk112233",
|
|
||||||
"VirtualHost": "/",
|
|
||||||
"Exchange": "takeout.events",
|
|
||||||
"ExchangeType": "topic",
|
|
||||||
"PrefetchCount": 20
|
|
||||||
},
|
|
||||||
"Otel": {
|
|
||||||
"Endpoint": "",
|
|
||||||
"Sampling": "ParentBasedAlwaysOn",
|
|
||||||
"UseConsoleExporter": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using Microsoft.Net.Http.Headers;
|
|
||||||
using TakeoutSaaS.Application.Dictionary.Contracts;
|
|
||||||
using TakeoutSaaS.Application.Dictionary.Models;
|
|
||||||
using TakeoutSaaS.Application.Dictionary.Services;
|
|
||||||
using TakeoutSaaS.Shared.Abstractions.Constants;
|
|
||||||
using TakeoutSaaS.Shared.Abstractions.Exceptions;
|
|
||||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
|
||||||
using TakeoutSaaS.Shared.Web.Api;
|
|
||||||
|
|
||||||
namespace TakeoutSaaS.UserApi.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 字典查询接口。
|
|
||||||
/// </summary>
|
|
||||||
[ApiVersion("1.0")]
|
|
||||||
[Authorize]
|
|
||||||
[Route("api/user/v{version:apiVersion}/dictionary")]
|
|
||||||
public sealed class DictionaryController(DictionaryQueryService queryService) : BaseApiController
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 获取指定字典分组的合并结果。
|
|
||||||
/// </summary>
|
|
||||||
[HttpGet("{code}")]
|
|
||||||
[ProducesResponseType(typeof(ApiResponse<IReadOnlyList<DictionaryItemDto>>), StatusCodes.Status200OK)]
|
|
||||||
public async Task<ApiResponse<IReadOnlyList<DictionaryItemDto>>> GetByCode(string code, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
Response.Headers[HeaderNames.CacheControl] = "max-age=1800";
|
|
||||||
var result = await queryService.GetMergedDictionaryAsync(code, cancellationToken);
|
|
||||||
return ApiResponse<IReadOnlyList<DictionaryItemDto>>.Ok(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 批量获取字典分组。
|
|
||||||
/// </summary>
|
|
||||||
[HttpPost("batch")]
|
|
||||||
[ProducesResponseType(typeof(ApiResponse<IReadOnlyDictionary<string, IReadOnlyList<DictionaryItemDto>>>), StatusCodes.Status200OK)]
|
|
||||||
public async Task<ApiResponse<IReadOnlyDictionary<string, IReadOnlyList<DictionaryItemDto>>>> BatchGet(
|
|
||||||
[FromBody] DictionaryBatchQueryRequest request,
|
|
||||||
CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
if (request.Codes.Count > 20)
|
|
||||||
{
|
|
||||||
throw new BusinessException(ErrorCodes.ValidationFailed, "最多支持 20 个字典编码");
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = await queryService.BatchGetDictionariesAsync(request.Codes, cancellationToken);
|
|
||||||
return ApiResponse<IReadOnlyDictionary<string, IReadOnlyList<DictionaryItemDto>>>.Ok(result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Authorization;
|
|
||||||
using Microsoft.AspNetCore.Mvc;
|
|
||||||
using TakeoutSaaS.Shared.Abstractions.Results;
|
|
||||||
using TakeoutSaaS.Shared.Web.Api;
|
|
||||||
|
|
||||||
namespace TakeoutSaaS.UserApi.Controllers;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 用户端 - 健康检查。
|
|
||||||
/// </summary>
|
|
||||||
[ApiVersion("1.0")]
|
|
||||||
[AllowAnonymous]
|
|
||||||
[Route("api/user/v{version:apiVersion}/[controller]")]
|
|
||||||
public class HealthController : BaseApiController
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 获取服务健康状态。
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>健康状态</returns>
|
|
||||||
[HttpGet]
|
|
||||||
[ProducesResponseType(typeof(ApiResponse<object>), StatusCodes.Status200OK)]
|
|
||||||
public ApiResponse<object> Get()
|
|
||||||
{
|
|
||||||
// 1. 构造健康状态
|
|
||||||
var payload = new { status = "OK", service = "UserApi", time = DateTime.UtcNow };
|
|
||||||
|
|
||||||
// 2. 返回健康响应
|
|
||||||
return ApiResponse<object>.Ok(payload);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build
|
|
||||||
WORKDIR /src
|
|
||||||
COPY . .
|
|
||||||
RUN dotnet restore src/Api/TakeoutSaaS.UserApi/TakeoutSaaS.UserApi.csproj
|
|
||||||
RUN dotnet publish src/Api/TakeoutSaaS.UserApi/TakeoutSaaS.UserApi.csproj -c Release -o /app/publish
|
|
||||||
|
|
||||||
FROM mcr.microsoft.com/dotnet/aspnet:10.0
|
|
||||||
WORKDIR /app
|
|
||||||
COPY --from=build /app/publish .
|
|
||||||
EXPOSE 7901
|
|
||||||
ENV ASPNETCORE_URLS=http://+:7901
|
|
||||||
ENTRYPOINT ["dotnet", "TakeoutSaaS.UserApi.dll"]
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
|
||||||
using OpenTelemetry.Metrics;
|
|
||||||
using OpenTelemetry.Resources;
|
|
||||||
using OpenTelemetry.Trace;
|
|
||||||
using Serilog;
|
|
||||||
using TakeoutSaaS.Infrastructure.Identity.Extensions;
|
|
||||||
using TakeoutSaaS.Module.Dictionary.Extensions;
|
|
||||||
using TakeoutSaaS.Module.Tenancy.Extensions;
|
|
||||||
using TakeoutSaaS.Shared.Abstractions.Ids;
|
|
||||||
using TakeoutSaaS.Shared.Kernel.Ids;
|
|
||||||
using TakeoutSaaS.Shared.Web.Extensions;
|
|
||||||
using TakeoutSaaS.Shared.Web.Swagger;
|
|
||||||
|
|
||||||
// 1. 创建构建器与日志模板
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
|
||||||
const string logTemplate = "[{Timestamp:yyyy-MM-dd HH:mm:ss.fff zzz} {Level:u3}] [TraceId:{TraceId}] [SpanId:{SpanId}] [Service:{Service}] {SourceContext} {Message:lj}{NewLine}{Exception}";
|
|
||||||
var isDevelopment = builder.Environment.IsDevelopment();
|
|
||||||
|
|
||||||
// 2. 注册雪花 ID 生成器与 Serilog
|
|
||||||
builder.Services.AddSingleton<IIdGenerator>(_ => new SnowflakeIdGenerator());
|
|
||||||
builder.Host.UseSerilog((_, _, configuration) =>
|
|
||||||
{
|
|
||||||
configuration
|
|
||||||
.Enrich.FromLogContext()
|
|
||||||
.Enrich.WithProperty("Service", "UserApi")
|
|
||||||
.WriteTo.Console(outputTemplate: logTemplate)
|
|
||||||
.WriteTo.File(
|
|
||||||
"logs/user-api-.log",
|
|
||||||
rollingInterval: RollingInterval.Day,
|
|
||||||
retainedFileCountLimit: 7,
|
|
||||||
shared: true,
|
|
||||||
outputTemplate: logTemplate);
|
|
||||||
});
|
|
||||||
|
|
||||||
// 3. 注册通用 Web 能力,开发环境启用 Swagger
|
|
||||||
builder.Services.AddSharedWebCore();
|
|
||||||
if (isDevelopment)
|
|
||||||
{
|
|
||||||
builder.Services.AddSharedSwagger(options =>
|
|
||||||
{
|
|
||||||
options.Title = "外卖SaaS - 用户端";
|
|
||||||
options.Description = "C 端用户 API 文档";
|
|
||||||
options.EnableAuthorization = true;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. 注册多租户与健康检查
|
|
||||||
builder.Services.AddTenantResolution(builder.Configuration);
|
|
||||||
builder.Services.AddJwtAuthentication(builder.Configuration);
|
|
||||||
builder.Services.AddAuthorization();
|
|
||||||
builder.Services.AddDictionaryModule(builder.Configuration);
|
|
||||||
builder.Services.AddHealthChecks();
|
|
||||||
|
|
||||||
// 5. 配置 OpenTelemetry 采集
|
|
||||||
var otelSection = builder.Configuration.GetSection("Otel");
|
|
||||||
var otelEndpoint = otelSection.GetValue<string>("Endpoint");
|
|
||||||
var useConsoleExporter = otelSection.GetValue<bool?>("UseConsoleExporter") ?? builder.Environment.IsDevelopment();
|
|
||||||
builder.Services.AddOpenTelemetry()
|
|
||||||
.ConfigureResource(resource => resource.AddService(
|
|
||||||
serviceName: "TakeoutSaaS.UserApi",
|
|
||||||
serviceVersion: "1.0.0",
|
|
||||||
serviceInstanceId: Environment.MachineName))
|
|
||||||
.WithTracing(tracing =>
|
|
||||||
{
|
|
||||||
tracing
|
|
||||||
.SetSampler(new ParentBasedSampler(new AlwaysOnSampler()))
|
|
||||||
.AddAspNetCoreInstrumentation()
|
|
||||||
.AddHttpClientInstrumentation()
|
|
||||||
.AddEntityFrameworkCoreInstrumentation();
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(otelEndpoint))
|
|
||||||
{
|
|
||||||
tracing.AddOtlpExporter(exporter =>
|
|
||||||
{
|
|
||||||
exporter.Endpoint = new Uri(otelEndpoint);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useConsoleExporter)
|
|
||||||
{
|
|
||||||
tracing.AddConsoleExporter();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.WithMetrics(metrics =>
|
|
||||||
{
|
|
||||||
metrics
|
|
||||||
.AddAspNetCoreInstrumentation()
|
|
||||||
.AddHttpClientInstrumentation()
|
|
||||||
.AddRuntimeInstrumentation()
|
|
||||||
.AddPrometheusExporter();
|
|
||||||
|
|
||||||
if (!string.IsNullOrWhiteSpace(otelEndpoint))
|
|
||||||
{
|
|
||||||
metrics.AddOtlpExporter(exporter =>
|
|
||||||
{
|
|
||||||
exporter.Endpoint = new Uri(otelEndpoint);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (useConsoleExporter)
|
|
||||||
{
|
|
||||||
metrics.AddConsoleExporter();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 6. 配置 CORS
|
|
||||||
var userOrigins = ResolveCorsOrigins(builder.Configuration, "Cors:User");
|
|
||||||
builder.Services.AddCors(options =>
|
|
||||||
{
|
|
||||||
options.AddPolicy("UserApiCors", policy =>
|
|
||||||
{
|
|
||||||
ConfigureCorsPolicy(policy, userOrigins);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// 7. 构建应用并配置中间件管道
|
|
||||||
var app = builder.Build();
|
|
||||||
|
|
||||||
app.UseCors("UserApiCors");
|
|
||||||
app.UseTenantResolution();
|
|
||||||
app.UseSharedWebCore();
|
|
||||||
app.UseAuthentication();
|
|
||||||
app.UseAuthorization();
|
|
||||||
if (app.Environment.IsDevelopment())
|
|
||||||
{
|
|
||||||
app.UseSharedSwagger();
|
|
||||||
}
|
|
||||||
|
|
||||||
app.MapHealthChecks("/healthz");
|
|
||||||
app.MapPrometheusScrapingEndpoint();
|
|
||||||
app.MapControllers();
|
|
||||||
app.Run();
|
|
||||||
|
|
||||||
// 8. 解析配置中的 CORS 域名
|
|
||||||
static string[] ResolveCorsOrigins(IConfiguration configuration, string sectionKey)
|
|
||||||
{
|
|
||||||
var origins = configuration.GetSection(sectionKey).Get<string[]>();
|
|
||||||
return origins?
|
|
||||||
.Where(origin => !string.IsNullOrWhiteSpace(origin))
|
|
||||||
.Distinct(StringComparer.OrdinalIgnoreCase)
|
|
||||||
.ToArray() ?? [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// 9. 构建 CORS 策略
|
|
||||||
static void ConfigureCorsPolicy(CorsPolicyBuilder policy, string[] origins)
|
|
||||||
{
|
|
||||||
if (origins.Length == 0)
|
|
||||||
{
|
|
||||||
policy.AllowAnyOrigin();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
policy.WithOrigins(origins)
|
|
||||||
.AllowCredentials();
|
|
||||||
}
|
|
||||||
|
|
||||||
policy
|
|
||||||
.AllowAnyHeader()
|
|
||||||
.AllowAnyMethod();
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"profiles": {
|
|
||||||
"TakeoutSaaS.UserApi": {
|
|
||||||
"commandName": "Project",
|
|
||||||
"launchBrowser": true,
|
|
||||||
"environmentVariables": {
|
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development"
|
|
||||||
},
|
|
||||||
"applicationUrl": "http://localhost:2682"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Binary file not shown.
@@ -1,78 +0,0 @@
|
|||||||
{
|
|
||||||
"Database": {
|
|
||||||
"DataSources": {
|
|
||||||
"AppDatabase": {
|
|
||||||
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
|
||||||
"Reads": [
|
|
||||||
"Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
|
||||||
],
|
|
||||||
"CommandTimeoutSeconds": 30,
|
|
||||||
"MaxRetryCount": 3,
|
|
||||||
"MaxRetryDelaySeconds": 5
|
|
||||||
},
|
|
||||||
"IdentityDatabase": {
|
|
||||||
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
|
||||||
"Reads": [
|
|
||||||
"Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
|
||||||
],
|
|
||||||
"CommandTimeoutSeconds": 30,
|
|
||||||
"MaxRetryCount": 3,
|
|
||||||
"MaxRetryDelaySeconds": 5
|
|
||||||
},
|
|
||||||
"DictionaryDatabase": {
|
|
||||||
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
|
||||||
"Reads": [
|
|
||||||
"Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
|
||||||
],
|
|
||||||
"CommandTimeoutSeconds": 30,
|
|
||||||
"MaxRetryCount": 3,
|
|
||||||
"MaxRetryDelaySeconds": 5
|
|
||||||
},
|
|
||||||
"LogsDatabase": {
|
|
||||||
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
|
||||||
"Reads": [
|
|
||||||
"Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
|
||||||
],
|
|
||||||
"CommandTimeoutSeconds": 30,
|
|
||||||
"MaxRetryCount": 3,
|
|
||||||
"MaxRetryDelaySeconds": 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Redis": "49.232.6.45:6379,password=MsuMshk112233,abortConnect=false",
|
|
||||||
"Identity": {
|
|
||||||
"Jwt": {
|
|
||||||
"Issuer": "takeout-saas",
|
|
||||||
"Audience": "takeout-saas-clients",
|
|
||||||
"Secret": "psZEx_O##]Mq(W.1$?8Aia*LM03sXGGx",
|
|
||||||
"AccessTokenExpirationMinutes": 120,
|
|
||||||
"RefreshTokenExpirationMinutes": 10080
|
|
||||||
},
|
|
||||||
"LoginRateLimit": {
|
|
||||||
"WindowSeconds": 60,
|
|
||||||
"MaxAttempts": 5
|
|
||||||
},
|
|
||||||
"RefreshTokenStore": {
|
|
||||||
"Prefix": "identity:refresh:"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Dictionary": {
|
|
||||||
"Cache": {
|
|
||||||
"SlidingExpiration": "00:30:00"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Tenancy": {
|
|
||||||
"TenantIdHeaderName": "X-Tenant-Id",
|
|
||||||
"TenantCodeHeaderName": "X-Tenant-Code",
|
|
||||||
"IgnoredPaths": [
|
|
||||||
"/health"
|
|
||||||
],
|
|
||||||
"RootDomain": ""
|
|
||||||
},
|
|
||||||
"Otel": {
|
|
||||||
"Endpoint": "",
|
|
||||||
"Sampling": "ParentBasedAlwaysOn",
|
|
||||||
"UseConsoleExporter": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,78 +0,0 @@
|
|||||||
{
|
|
||||||
"Database": {
|
|
||||||
"DataSources": {
|
|
||||||
"AppDatabase": {
|
|
||||||
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
|
||||||
"Reads": [
|
|
||||||
"Host=120.53.222.17;Port=5432;Database=takeout_app_db;Username=app_user;Password=AppUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
|
||||||
],
|
|
||||||
"CommandTimeoutSeconds": 30,
|
|
||||||
"MaxRetryCount": 3,
|
|
||||||
"MaxRetryDelaySeconds": 5
|
|
||||||
},
|
|
||||||
"IdentityDatabase": {
|
|
||||||
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
|
||||||
"Reads": [
|
|
||||||
"Host=120.53.222.17;Port=5432;Database=takeout_identity_db;Username=identity_user;Password=IdentityUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
|
||||||
],
|
|
||||||
"CommandTimeoutSeconds": 30,
|
|
||||||
"MaxRetryCount": 3,
|
|
||||||
"MaxRetryDelaySeconds": 5
|
|
||||||
},
|
|
||||||
"DictionaryDatabase": {
|
|
||||||
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
|
||||||
"Reads": [
|
|
||||||
"Host=120.53.222.17;Port=5432;Database=takeout_dictionary_db;Username=dictionary_user;Password=DictionaryUser112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
|
||||||
],
|
|
||||||
"CommandTimeoutSeconds": 30,
|
|
||||||
"MaxRetryCount": 3,
|
|
||||||
"MaxRetryDelaySeconds": 5
|
|
||||||
},
|
|
||||||
"LogsDatabase": {
|
|
||||||
"Write": "Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
|
||||||
"Reads": [
|
|
||||||
"Host=120.53.222.17;Port=5432;Database=takeout_logs_db;Username=logs_user;Password=Logs112233;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
|
||||||
],
|
|
||||||
"CommandTimeoutSeconds": 30,
|
|
||||||
"MaxRetryCount": 3,
|
|
||||||
"MaxRetryDelaySeconds": 5
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Redis": "49.232.6.45:6379,password=MsuMshk112233,abortConnect=false",
|
|
||||||
"Identity": {
|
|
||||||
"Jwt": {
|
|
||||||
"Issuer": "takeout-saas",
|
|
||||||
"Audience": "takeout-saas-clients",
|
|
||||||
"Secret": "psZEx_O##]Mq(W.1$?8Aia*LM03sXGGx",
|
|
||||||
"AccessTokenExpirationMinutes": 120,
|
|
||||||
"RefreshTokenExpirationMinutes": 10080
|
|
||||||
},
|
|
||||||
"LoginRateLimit": {
|
|
||||||
"WindowSeconds": 60,
|
|
||||||
"MaxAttempts": 5
|
|
||||||
},
|
|
||||||
"RefreshTokenStore": {
|
|
||||||
"Prefix": "identity:refresh:"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Dictionary": {
|
|
||||||
"Cache": {
|
|
||||||
"SlidingExpiration": "00:30:00"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"Tenancy": {
|
|
||||||
"TenantIdHeaderName": "X-Tenant-Id",
|
|
||||||
"TenantCodeHeaderName": "X-Tenant-Code",
|
|
||||||
"IgnoredPaths": [
|
|
||||||
"/health"
|
|
||||||
],
|
|
||||||
"RootDomain": ""
|
|
||||||
},
|
|
||||||
"Otel": {
|
|
||||||
"Endpoint": "",
|
|
||||||
"Sampling": "ParentBasedAlwaysOn",
|
|
||||||
"UseConsoleExporter": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user