feat: finalize core modules and gateway
This commit is contained in:
52
src/Api/TakeoutSaaS.MiniApi/Controllers/FilesController.cs
Normal file
52
src/Api/TakeoutSaaS.MiniApi/Controllers/FilesController.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
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;
|
||||
|
||||
namespace TakeoutSaaS.MiniApi.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// 小程序文件上传。
|
||||
/// </summary>
|
||||
[ApiVersion("1.0")]
|
||||
[Authorize]
|
||||
[Route("api/mini/v{version:apiVersion}/files")]
|
||||
public sealed class FilesController(IFileStorageService fileStorageService) : BaseApiController
|
||||
{
|
||||
private readonly IFileStorageService _fileStorageService = fileStorageService;
|
||||
|
||||
/// <summary>
|
||||
/// 上传图片或文件。
|
||||
/// </summary>
|
||||
[HttpPost("upload")]
|
||||
[RequestFormLimits(MultipartBodyLengthLimit = 30 * 1024 * 1024)]
|
||||
[ProducesResponseType(typeof(ApiResponse<FileUploadResponse>), StatusCodes.Status200OK)]
|
||||
[ProducesResponseType(typeof(ApiResponse<FileUploadResponse>), StatusCodes.Status400BadRequest)]
|
||||
public async Task<ApiResponse<FileUploadResponse>> Upload([FromForm] IFormFile? file, [FromForm] string? type, CancellationToken cancellationToken)
|
||||
{
|
||||
if (file == null || file.Length == 0)
|
||||
{
|
||||
return ApiResponse<FileUploadResponse>.Error(ErrorCodes.BadRequest, "文件不能为空");
|
||||
}
|
||||
|
||||
if (!UploadFileTypeParser.TryParse(type, out var uploadType))
|
||||
{
|
||||
return ApiResponse<FileUploadResponse>.Error(ErrorCodes.BadRequest, "上传类型不合法");
|
||||
}
|
||||
|
||||
var origin = Request.Headers["Origin"].FirstOrDefault() ?? Request.Headers["Referer"].FirstOrDefault();
|
||||
await using var stream = file.OpenReadStream();
|
||||
|
||||
var result = await _fileStorageService.UploadAsync(
|
||||
new UploadFileRequest(uploadType, stream, file.FileName, file.ContentType ?? string.Empty, file.Length, origin),
|
||||
cancellationToken);
|
||||
|
||||
return ApiResponse<FileUploadResponse>.Ok(result);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,11 @@
|
||||
using Microsoft.AspNetCore.Cors.Infrastructure;
|
||||
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.Web.Extensions;
|
||||
using TakeoutSaaS.Shared.Web.Swagger;
|
||||
@@ -22,6 +28,12 @@ builder.Services.AddSharedSwagger(options =>
|
||||
options.EnableAuthorization = true;
|
||||
});
|
||||
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();
|
||||
|
||||
var miniOrigins = ResolveCorsOrigins(builder.Configuration, "Cors:Mini");
|
||||
builder.Services.AddCors(options =>
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Core\TakeoutSaaS.Shared.Web\TakeoutSaaS.Shared.Web.csproj" />
|
||||
<ProjectReference Include="..\..\Application\TakeoutSaaS.Application\TakeoutSaaS.Application.csproj" />
|
||||
<ProjectReference Include="..\..\Modules\TakeoutSaaS.Module.Messaging\TakeoutSaaS.Module.Messaging.csproj" />
|
||||
<ProjectReference Include="..\..\Modules\TakeoutSaaS.Module.Sms\TakeoutSaaS.Module.Sms.csproj" />
|
||||
<ProjectReference Include="..\..\Modules\TakeoutSaaS.Module.Storage\TakeoutSaaS.Module.Storage.csproj" />
|
||||
<ProjectReference Include="..\..\Modules\TakeoutSaaS.Module.Tenancy\TakeoutSaaS.Module.Tenancy.csproj" />
|
||||
<ProjectReference Include="..\..\Infrastructure\TakeoutSaaS.Infrastructure\TakeoutSaaS.Infrastructure.csproj" />
|
||||
|
||||
|
||||
133
src/Api/TakeoutSaaS.MiniApi/appsettings.Development.json
Normal file
133
src/Api/TakeoutSaaS.MiniApi/appsettings.Development.json
Normal file
@@ -0,0 +1,133 @@
|
||||
{
|
||||
"Database": {
|
||||
"DataSources": {
|
||||
"AppDatabase": {
|
||||
"Write": "Host=localhost;Port=5432;Database=takeout_saas_app;Username=app_user;Password=app_password;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
||||
"Reads": [
|
||||
"Host=localhost;Port=5432;Database=takeout_saas_app;Username=app_user;Password=app_password;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
||||
],
|
||||
"CommandTimeoutSeconds": 30,
|
||||
"MaxRetryCount": 3,
|
||||
"MaxRetryDelaySeconds": 5
|
||||
},
|
||||
"IdentityDatabase": {
|
||||
"Write": "Host=localhost;Port=5432;Database=takeout_saas_identity;Username=identity_user;Password=identity_password;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50",
|
||||
"Reads": [
|
||||
"Host=localhost;Port=5432;Database=takeout_saas_identity;Username=identity_user;Password=identity_password;Pooling=true;Minimum Pool Size=5;Maximum Pool Size=50"
|
||||
],
|
||||
"CommandTimeoutSeconds": 30,
|
||||
"MaxRetryCount": 3,
|
||||
"MaxRetryDelaySeconds": 5
|
||||
}
|
||||
}
|
||||
},
|
||||
"Redis": "localhost:6379,abortConnect=false",
|
||||
"Identity": {
|
||||
"Jwt": {
|
||||
"Issuer": "takeout-saas",
|
||||
"Audience": "takeout-saas-clients",
|
||||
"Secret": "ReplaceWithA32CharLongSecretKey_____",
|
||||
"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://cdn.example.com",
|
||||
"TencentCos": {
|
||||
"SecretId": "COS_SECRET_ID",
|
||||
"SecretKey": "COS_SECRET_KEY",
|
||||
"Region": "ap-guangzhou",
|
||||
"Bucket": "takeout-bucket-123456",
|
||||
"Endpoint": "",
|
||||
"CdnBaseUrl": "https://cdn.example.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-guangzhou",
|
||||
"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": "localhost",
|
||||
"Port": 5672,
|
||||
"Username": "admin",
|
||||
"Password": "password",
|
||||
"VirtualHost": "/",
|
||||
"Exchange": "takeout.events",
|
||||
"ExchangeType": "topic",
|
||||
"PrefetchCount": 20
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user