初始化
This commit is contained in:
@@ -80,6 +80,108 @@ namespace FutureMailAPI.Controllers
|
||||
result);
|
||||
}
|
||||
|
||||
// 直接接收前端原始格式的创建邮件接口
|
||||
[HttpPost("create-raw")]
|
||||
public async Task<IActionResult> CreateMailRaw()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 读取请求体
|
||||
var request = HttpContext.Request;
|
||||
using var reader = new StreamReader(request.Body);
|
||||
var body = await reader.ReadToEndAsync();
|
||||
|
||||
// 解析JSON
|
||||
var rawMail = System.Text.Json.JsonSerializer.Deserialize<Dictionary<string, object>>(body);
|
||||
if (rawMail == null)
|
||||
{
|
||||
return BadRequest(ApiResponse<SentMailResponseDto>.ErrorResult("请求数据为空"));
|
||||
}
|
||||
|
||||
// 创建兼容DTO
|
||||
var compatDto = new SentMailCreateCompatDto();
|
||||
|
||||
// 解析各个字段
|
||||
if (rawMail.ContainsKey("title") && rawMail["title"] != null)
|
||||
compatDto.title = rawMail["title"].ToString() ?? string.Empty;
|
||||
|
||||
if (rawMail.ContainsKey("content") && rawMail["content"] != null)
|
||||
compatDto.content = rawMail["content"].ToString() ?? string.Empty;
|
||||
|
||||
if (rawMail.ContainsKey("recipientType") && rawMail["recipientType"] != null)
|
||||
{
|
||||
var recipientTypeStr = rawMail["recipientType"].ToString();
|
||||
if (Enum.TryParse<RecipientTypeEnum>(recipientTypeStr, true, out var recipientType))
|
||||
compatDto.recipientType = recipientType;
|
||||
}
|
||||
|
||||
if (rawMail.ContainsKey("recipientEmail") && rawMail["recipientEmail"] != null)
|
||||
compatDto.recipientEmail = rawMail["recipientEmail"].ToString();
|
||||
|
||||
if (rawMail.ContainsKey("sendTime") && rawMail["sendTime"] != null)
|
||||
{
|
||||
if (DateTime.TryParse(rawMail["sendTime"].ToString(), out var sendTime))
|
||||
compatDto.sendTime = sendTime;
|
||||
}
|
||||
|
||||
if (rawMail.ContainsKey("triggerType") && rawMail["triggerType"] != null)
|
||||
{
|
||||
var triggerTypeStr = rawMail["triggerType"].ToString();
|
||||
if (Enum.TryParse<TriggerTypeEnum>(triggerTypeStr, true, out var triggerType))
|
||||
compatDto.triggerType = triggerType;
|
||||
}
|
||||
|
||||
if (rawMail.ContainsKey("triggerCondition"))
|
||||
compatDto.triggerCondition = rawMail["triggerCondition"];
|
||||
|
||||
if (rawMail.ContainsKey("attachments"))
|
||||
{
|
||||
try
|
||||
{
|
||||
compatDto.attachments = System.Text.Json.JsonSerializer.Deserialize<List<object>>(rawMail["attachments"].ToString());
|
||||
}
|
||||
catch
|
||||
{
|
||||
compatDto.attachments = new List<object>();
|
||||
}
|
||||
}
|
||||
|
||||
if (rawMail.ContainsKey("isEncrypted"))
|
||||
compatDto.isEncrypted = bool.Parse(rawMail["isEncrypted"].ToString());
|
||||
|
||||
if (rawMail.ContainsKey("capsuleStyle"))
|
||||
compatDto.capsuleStyle = rawMail["capsuleStyle"].ToString() ?? "default";
|
||||
|
||||
// 从JWT令牌中获取当前用户ID
|
||||
var currentUserId = GetCurrentUserId();
|
||||
|
||||
if (currentUserId <= 0)
|
||||
{
|
||||
return Unauthorized(ApiResponse<SentMailResponseDto>.ErrorResult("未授权访问"));
|
||||
}
|
||||
|
||||
// 转换为内部DTO
|
||||
var internalDto = compatDto.ToInternalDto();
|
||||
|
||||
var result = await _mailService.CreateMailAsync(currentUserId, internalDto);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
return BadRequest(result);
|
||||
}
|
||||
|
||||
return CreatedAtAction(
|
||||
nameof(GetMail),
|
||||
new { mailId = result.Data!.Id },
|
||||
result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
_logger.LogError(ex, "创建邮件时发生错误");
|
||||
return StatusCode(500, ApiResponse<SentMailResponseDto>.ErrorResult("服务器内部错误"));
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet("{mailId}")]
|
||||
public async Task<IActionResult> GetMail(int mailId)
|
||||
{
|
||||
@@ -255,5 +357,198 @@ namespace FutureMailAPI.Controllers
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 存入胶囊 - 创建胶囊邮件
|
||||
/// </summary>
|
||||
/// <param name="dto">存入胶囊请求</param>
|
||||
/// <returns>操作结果</returns>
|
||||
[HttpPost("capsule")]
|
||||
public async Task<IActionResult> SaveToCapsule([FromBody] SaveToCapsuleDto dto)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(ApiResponse<SaveToCapsuleResponseDto>.ErrorResult("请求参数无效"));
|
||||
}
|
||||
|
||||
var currentUserId = GetCurrentUserId();
|
||||
|
||||
if (currentUserId <= 0)
|
||||
{
|
||||
return Unauthorized(ApiResponse<SaveToCapsuleResponseDto>.ErrorResult("未授权访问"));
|
||||
}
|
||||
|
||||
var result = await _mailService.SaveToCapsuleAsync(currentUserId, dto);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
return BadRequest(result);
|
||||
}
|
||||
|
||||
return CreatedAtAction(
|
||||
nameof(GetCapsuleMail),
|
||||
new { id = result.Data!.Id },
|
||||
result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取胶囊邮件列表
|
||||
/// </summary>
|
||||
/// <param name="pageIndex">页码</param>
|
||||
/// <param name="pageSize">页大小</param>
|
||||
/// <param name="status">状态筛选</param>
|
||||
/// <param name="recipientType">收件人类型筛选</param>
|
||||
/// <param name="keyword">关键词搜索</param>
|
||||
/// <param name="startDate">开始日期</param>
|
||||
/// <param name="endDate">结束日期</param>
|
||||
/// <returns>胶囊邮件列表</returns>
|
||||
[HttpGet("capsule")]
|
||||
public async Task<IActionResult> GetCapsuleMails(
|
||||
[FromQuery] int pageIndex = 1,
|
||||
[FromQuery] int pageSize = 10,
|
||||
[FromQuery] int? status = null,
|
||||
[FromQuery] int? recipientType = null,
|
||||
[FromQuery] string? keyword = null,
|
||||
[FromQuery] DateTime? startDate = null,
|
||||
[FromQuery] DateTime? endDate = null)
|
||||
{
|
||||
var queryDto = new MailListQueryDto
|
||||
{
|
||||
PageIndex = pageIndex,
|
||||
PageSize = pageSize,
|
||||
Status = status,
|
||||
RecipientType = recipientType,
|
||||
Keyword = keyword,
|
||||
StartDate = startDate,
|
||||
EndDate = endDate
|
||||
};
|
||||
|
||||
var currentUserId = GetCurrentUserId();
|
||||
|
||||
if (currentUserId <= 0)
|
||||
{
|
||||
return Unauthorized(ApiResponse<PagedResponse<CapsuleMailListResponseDto>>.ErrorResult("未授权访问"));
|
||||
}
|
||||
|
||||
var result = await _mailService.GetCapsuleMailsAsync(currentUserId, queryDto);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
return BadRequest(result);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 获取胶囊邮件详情
|
||||
/// </summary>
|
||||
/// <param name="id">邮件ID</param>
|
||||
/// <returns>胶囊邮件详情</returns>
|
||||
[HttpGet("capsule/{id}")]
|
||||
public async Task<IActionResult> GetCapsuleMail(int id)
|
||||
{
|
||||
var currentUserId = GetCurrentUserId();
|
||||
|
||||
if (currentUserId <= 0)
|
||||
{
|
||||
return Unauthorized(ApiResponse<CapsuleMailDetailResponseDto>.ErrorResult("未授权访问"));
|
||||
}
|
||||
|
||||
var result = await _mailService.GetCapsuleMailByIdAsync(currentUserId, id);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
return NotFound(result);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新胶囊邮件
|
||||
/// </summary>
|
||||
/// <param name="id">邮件ID</param>
|
||||
/// <param name="dto">更新请求</param>
|
||||
/// <returns>更新后的胶囊邮件详情</returns>
|
||||
[HttpPut("capsule/{id}")]
|
||||
public async Task<IActionResult> UpdateCapsuleMail(int id, [FromBody] UpdateCapsuleMailDto dto)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(ApiResponse<CapsuleMailDetailResponseDto>.ErrorResult("请求参数无效"));
|
||||
}
|
||||
|
||||
var currentUserId = GetCurrentUserId();
|
||||
|
||||
if (currentUserId <= 0)
|
||||
{
|
||||
return Unauthorized(ApiResponse<CapsuleMailDetailResponseDto>.ErrorResult("未授权访问"));
|
||||
}
|
||||
|
||||
var result = await _mailService.UpdateCapsuleMailAsync(currentUserId, id, dto);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
return BadRequest(result);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 撤销胶囊邮件
|
||||
/// </summary>
|
||||
/// <param name="id">邮件ID</param>
|
||||
/// <returns>操作结果</returns>
|
||||
[HttpPost("capsule/{id}/revoke")]
|
||||
public async Task<IActionResult> RevokeCapsuleMail(int id)
|
||||
{
|
||||
var currentUserId = GetCurrentUserId();
|
||||
|
||||
if (currentUserId <= 0)
|
||||
{
|
||||
return Unauthorized(ApiResponse<bool>.ErrorResult("未授权访问"));
|
||||
}
|
||||
|
||||
var result = await _mailService.RevokeCapsuleMailAsync(currentUserId, id);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
return BadRequest(result);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送至未来 - 将草稿状态的邮件设置为在未来特定时间自动发送
|
||||
/// </summary>
|
||||
/// <param name="sendToFutureDto">发送至未来请求DTO</param>
|
||||
/// <returns>发送至未来响应DTO</returns>
|
||||
[HttpPost("send-to-future")]
|
||||
public async Task<IActionResult> SendToFuture([FromBody] SendToFutureDto sendToFutureDto)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return BadRequest(ApiResponse<SendToFutureResponseDto>.ErrorResult("请求参数无效"));
|
||||
}
|
||||
|
||||
var currentUserId = GetCurrentUserId();
|
||||
|
||||
if (currentUserId <= 0)
|
||||
{
|
||||
return Unauthorized(ApiResponse<SendToFutureResponseDto>.ErrorResult("未授权访问"));
|
||||
}
|
||||
|
||||
var result = await _mailService.SendToFutureAsync(currentUserId, sendToFutureDto);
|
||||
|
||||
if (!result.Success)
|
||||
{
|
||||
return BadRequest(result);
|
||||
}
|
||||
|
||||
return Ok(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -189,4 +189,130 @@ namespace FutureMailAPI.DTOs
|
||||
public DateTime? StartDate { get; set; }
|
||||
public DateTime? EndDate { get; set; }
|
||||
}
|
||||
|
||||
// 存入胶囊请求DTO
|
||||
public class SaveToCapsuleDto
|
||||
{
|
||||
[Required(ErrorMessage = "标题是必填项")]
|
||||
[StringLength(200, ErrorMessage = "标题长度不能超过200个字符")]
|
||||
public string Title { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "内容是必填项")]
|
||||
public string Content { get; set; } = string.Empty;
|
||||
|
||||
[Required(ErrorMessage = "收件人类型是必填项")]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public RecipientTypeEnum RecipientType { get; set; }
|
||||
|
||||
public string? RecipientEmail { get; set; }
|
||||
|
||||
public DateTime? SendTime { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "触发条件类型是必填项")]
|
||||
[JsonConverter(typeof(JsonStringEnumConverter))]
|
||||
public TriggerTypeEnum TriggerType { get; set; } = TriggerTypeEnum.TIME;
|
||||
|
||||
public object? TriggerCondition { get; set; }
|
||||
|
||||
public List<object>? Attachments { get; set; }
|
||||
|
||||
public bool IsEncrypted { get; set; } = false;
|
||||
|
||||
[Required(ErrorMessage = "胶囊样式是必填项")]
|
||||
public string CapsuleStyle { get; set; } = "default";
|
||||
}
|
||||
|
||||
// 存入胶囊响应DTO
|
||||
public class SaveToCapsuleResponseDto
|
||||
{
|
||||
public int Id { get; set; }
|
||||
public string MailId { get; set; } = string.Empty;
|
||||
public string CapsuleId { get; set; } = string.Empty;
|
||||
public string Status { get; set; } = string.Empty;
|
||||
public DateTime CreatedAt { get; set; }
|
||||
}
|
||||
|
||||
// 胶囊邮件列表响应DTO
|
||||
public class CapsuleMailListResponseDto
|
||||
{
|
||||
public string MailId { get; set; } = string.Empty;
|
||||
public string Title { get; set; } = string.Empty;
|
||||
public UserInfoDto Sender { get; set; } = new();
|
||||
public UserInfoDto Recipient { get; set; } = new();
|
||||
public DateTime SendTime { get; set; }
|
||||
public DateTime? DeliveryTime { get; set; }
|
||||
public string Status { get; set; } = string.Empty;
|
||||
public bool HasAttachments { get; set; }
|
||||
public bool IsEncrypted { get; set; }
|
||||
public string CapsuleStyle { get; set; } = string.Empty;
|
||||
public int? Countdown { get; set; } // 倒计时秒数(仅status=PENDING时返回)
|
||||
}
|
||||
|
||||
// 胶囊邮件详情响应DTO
|
||||
public class CapsuleMailDetailResponseDto
|
||||
{
|
||||
public string MailId { get; set; } = string.Empty;
|
||||
public string Title { get; set; } = string.Empty;
|
||||
public string Content { get; set; } = string.Empty;
|
||||
public UserInfoDto Sender { get; set; } = new();
|
||||
public UserInfoDto Recipient { get; set; } = new();
|
||||
public DateTime SendTime { get; set; }
|
||||
public DateTime CreatedAt { get; set; }
|
||||
public DateTime? DeliveryTime { get; set; }
|
||||
public string Status { get; set; } = string.Empty;
|
||||
public string TriggerType { get; set; } = string.Empty;
|
||||
public object? TriggerCondition { get; set; }
|
||||
public List<AttachmentDto> Attachments { get; set; } = new();
|
||||
public bool IsEncrypted { get; set; }
|
||||
public string CapsuleStyle { get; set; } = string.Empty;
|
||||
public bool CanEdit { get; set; } // 是否可编辑(仅草稿状态)
|
||||
public bool CanRevoke { get; set; } // 是否可撤销(仅待投递状态)
|
||||
}
|
||||
|
||||
|
||||
|
||||
// 附件DTO
|
||||
public class AttachmentDto
|
||||
{
|
||||
public string Id { get; set; } = string.Empty;
|
||||
public string Type { get; set; } = string.Empty;
|
||||
public string Url { get; set; } = string.Empty;
|
||||
public string? Thumbnail { get; set; }
|
||||
public long Size { get; set; }
|
||||
}
|
||||
|
||||
// 更新胶囊邮件DTO
|
||||
public class UpdateCapsuleMailDto
|
||||
{
|
||||
public string? Title { get; set; }
|
||||
public string? Content { get; set; }
|
||||
public RecipientTypeEnum? RecipientType { get; set; }
|
||||
public string? RecipientEmail { get; set; }
|
||||
public DateTime? SendTime { get; set; }
|
||||
public TriggerTypeEnum? TriggerType { get; set; }
|
||||
public object? TriggerCondition { get; set; }
|
||||
public List<object>? Attachments { get; set; }
|
||||
public bool? IsEncrypted { get; set; }
|
||||
public string? CapsuleStyle { get; set; }
|
||||
}
|
||||
|
||||
// 发送至未来请求DTO
|
||||
public class SendToFutureDto
|
||||
{
|
||||
[Required(ErrorMessage = "邮件ID是必填项")]
|
||||
public int MailId { get; set; }
|
||||
|
||||
[Required(ErrorMessage = "投递时间是必填项")]
|
||||
public DateTime DeliveryTime { get; set; }
|
||||
}
|
||||
|
||||
// 发送至未来响应DTO
|
||||
public class SendToFutureResponseDto
|
||||
{
|
||||
public int MailId { get; set; }
|
||||
public string Title { get; set; } = string.Empty;
|
||||
public DateTime DeliveryTime { get; set; }
|
||||
public string Status { get; set; } = string.Empty;
|
||||
public DateTime SentAt { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@ namespace FutureMailAPI.DTOs
|
||||
public int UserId { get; set; }
|
||||
public string Username { get; set; } = string.Empty;
|
||||
public string? Avatar { get; set; }
|
||||
public string Email { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class SubscriptionResponseDto
|
||||
|
||||
@@ -36,7 +36,7 @@ namespace FutureMailAPI.Data
|
||||
.HasForeignKey(e => e.SenderId)
|
||||
.OnDelete(DeleteBehavior.Restrict);
|
||||
|
||||
entity.HasOne<User>()
|
||||
entity.HasOne(e => e.Recipient)
|
||||
.WithMany()
|
||||
.HasForeignKey(e => e.RecipientId)
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
@@ -52,8 +52,8 @@ namespace FutureMailAPI.Data
|
||||
.HasForeignKey(e => e.SentMailId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
entity.HasOne<User>()
|
||||
.WithMany()
|
||||
entity.HasOne(e => e.Recipient)
|
||||
.WithMany(u => u.ReceivedMails)
|
||||
.HasForeignKey(e => e.RecipientId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
@@ -68,9 +68,10 @@ namespace FutureMailAPI.Data
|
||||
.HasForeignKey(e => e.UserId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
// 一对一关系配置
|
||||
entity.HasOne<SentMail>()
|
||||
.WithMany()
|
||||
.HasForeignKey(e => e.SentMailId)
|
||||
.WithOne(m => m.TimeCapsule)
|
||||
.HasForeignKey<TimeCapsule>(e => e.SentMailId)
|
||||
.OnDelete(DeleteBehavior.Cascade);
|
||||
|
||||
entity.Property(e => e.CreatedAt).HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
495
FutureMailAPI/Migrations/20251018051334_AddSentMailCreatedAt.Designer.cs
generated
Normal file
495
FutureMailAPI/Migrations/20251018051334_AddSentMailCreatedAt.Designer.cs
generated
Normal file
@@ -0,0 +1,495 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using FutureMailAPI.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace FutureMailAPI.Migrations
|
||||
{
|
||||
[DbContext(typeof(FutureMailDbContext))]
|
||||
[Migration("20251018051334_AddSentMailCreatedAt")]
|
||||
partial class AddSentMailCreatedAt
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "9.0.9");
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.OAuthClient", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClientId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClientSecret")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RedirectUris")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Scopes")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ClientId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("OAuthClients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.OAuthToken", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("AccessToken")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ClientId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<DateTime>("ExpiresAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RefreshToken")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("RevokedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Scope")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("TokenType")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AccessToken")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("ClientId");
|
||||
|
||||
b.HasIndex("RefreshToken")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("OAuthTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.ReceivedMail", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsRead")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsReplied")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("ReadAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("ReceivedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<int>("RecipientId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("RecipientId1")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("ReplyMailId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SentMailId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RecipientId");
|
||||
|
||||
b.HasIndex("RecipientId1");
|
||||
|
||||
b.HasIndex("SentMailId");
|
||||
|
||||
b.ToTable("ReceivedMails");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.SentMail", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Attachments")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Content")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("DeliveryTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("EncryptionKey")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsEncrypted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("RecipientId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("RecipientId1")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("RecipientType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SenderId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("SentAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Theme")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("TriggerDetails")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("TriggerType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RecipientId");
|
||||
|
||||
b.HasIndex("RecipientId1");
|
||||
|
||||
b.HasIndex("SenderId");
|
||||
|
||||
b.ToTable("SentMails");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.TimeCapsule", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Color")
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<double>("GlowIntensity")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("Opacity")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("PositionX")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("PositionY")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("PositionZ")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("Rotation")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<int>("SentMailId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SentMailId1")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<double>("Size")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Style")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SentMailId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("SentMailId1");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("TimeCapsules");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Avatar")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("LastLoginAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Nickname")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PreferredBackground")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PreferredScene")
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RefreshToken")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("RefreshTokenExpiryTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Salt")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Email")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("Username")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.OAuthToken", b =>
|
||||
{
|
||||
b.HasOne("FutureMailAPI.Models.OAuthClient", "Client")
|
||||
.WithMany("Tokens")
|
||||
.HasForeignKey("ClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("FutureMailAPI.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Client");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.ReceivedMail", b =>
|
||||
{
|
||||
b.HasOne("FutureMailAPI.Models.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RecipientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("FutureMailAPI.Models.User", "Recipient")
|
||||
.WithMany("ReceivedMails")
|
||||
.HasForeignKey("RecipientId1")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("FutureMailAPI.Models.SentMail", "SentMail")
|
||||
.WithMany()
|
||||
.HasForeignKey("SentMailId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Recipient");
|
||||
|
||||
b.Navigation("SentMail");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.SentMail", b =>
|
||||
{
|
||||
b.HasOne("FutureMailAPI.Models.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RecipientId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("FutureMailAPI.Models.User", "Recipient")
|
||||
.WithMany()
|
||||
.HasForeignKey("RecipientId1");
|
||||
|
||||
b.HasOne("FutureMailAPI.Models.User", "Sender")
|
||||
.WithMany("SentMails")
|
||||
.HasForeignKey("SenderId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Recipient");
|
||||
|
||||
b.Navigation("Sender");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.TimeCapsule", b =>
|
||||
{
|
||||
b.HasOne("FutureMailAPI.Models.SentMail", null)
|
||||
.WithOne("TimeCapsule")
|
||||
.HasForeignKey("FutureMailAPI.Models.TimeCapsule", "SentMailId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("FutureMailAPI.Models.SentMail", "SentMail")
|
||||
.WithMany()
|
||||
.HasForeignKey("SentMailId1")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("FutureMailAPI.Models.User", "User")
|
||||
.WithMany("TimeCapsules")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("SentMail");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.OAuthClient", b =>
|
||||
{
|
||||
b.Navigation("Tokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.SentMail", b =>
|
||||
{
|
||||
b.Navigation("TimeCapsule");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.User", b =>
|
||||
{
|
||||
b.Navigation("ReceivedMails");
|
||||
|
||||
b.Navigation("SentMails");
|
||||
|
||||
b.Navigation("TimeCapsules");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace FutureMailAPI.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class AddSentMailCreatedAt : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_TimeCapsules_SentMailId",
|
||||
table: "TimeCapsules");
|
||||
|
||||
migrationBuilder.AddColumn<double>(
|
||||
name: "GlowIntensity",
|
||||
table: "TimeCapsules",
|
||||
type: "REAL",
|
||||
nullable: false,
|
||||
defaultValue: 0.0);
|
||||
|
||||
migrationBuilder.AddColumn<string>(
|
||||
name: "Style",
|
||||
table: "TimeCapsules",
|
||||
type: "TEXT",
|
||||
maxLength: 50,
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<DateTime>(
|
||||
name: "CreatedAt",
|
||||
table: "SentMails",
|
||||
type: "TEXT",
|
||||
nullable: false,
|
||||
defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_TimeCapsules_SentMailId",
|
||||
table: "TimeCapsules",
|
||||
column: "SentMailId",
|
||||
unique: true);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_TimeCapsules_SentMailId",
|
||||
table: "TimeCapsules");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "GlowIntensity",
|
||||
table: "TimeCapsules");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "Style",
|
||||
table: "TimeCapsules");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "CreatedAt",
|
||||
table: "SentMails");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_TimeCapsules_SentMailId",
|
||||
table: "TimeCapsules",
|
||||
column: "SentMailId");
|
||||
}
|
||||
}
|
||||
}
|
||||
475
FutureMailAPI/Migrations/20251018071917_FixDuplicateForeignKeys.Designer.cs
generated
Normal file
475
FutureMailAPI/Migrations/20251018071917_FixDuplicateForeignKeys.Designer.cs
generated
Normal file
@@ -0,0 +1,475 @@
|
||||
// <auto-generated />
|
||||
using System;
|
||||
using FutureMailAPI.Data;
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace FutureMailAPI.Migrations
|
||||
{
|
||||
[DbContext(typeof(FutureMailDbContext))]
|
||||
[Migration("20251018071917_FixDuplicateForeignKeys")]
|
||||
partial class FixDuplicateForeignKeys
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void BuildTargetModel(ModelBuilder modelBuilder)
|
||||
{
|
||||
#pragma warning disable 612, 618
|
||||
modelBuilder.HasAnnotation("ProductVersion", "9.0.9");
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.OAuthClient", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("ClientId")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("ClientSecret")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Name")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RedirectUris")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Scopes")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("UpdatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("ClientId")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("OAuthClients");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.OAuthToken", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("AccessToken")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("ClientId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<DateTime>("ExpiresAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RefreshToken")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("RevokedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Scope")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("TokenType")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("UpdatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("AccessToken")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("ClientId");
|
||||
|
||||
b.HasIndex("RefreshToken")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("OAuthTokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.ReceivedMail", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsRead")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<bool>("IsReplied")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("ReadAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("ReceivedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<int>("RecipientId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("ReplyMailId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SentMailId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RecipientId");
|
||||
|
||||
b.HasIndex("SentMailId");
|
||||
|
||||
b.ToTable("ReceivedMails");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.SentMail", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Attachments")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Content")
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("DeliveryTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("EncryptionKey")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsEncrypted")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("RecipientId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("RecipientType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SenderId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime>("SentAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Theme")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Title")
|
||||
.IsRequired()
|
||||
.HasMaxLength(200)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("TriggerDetails")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("TriggerType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("RecipientId");
|
||||
|
||||
b.HasIndex("SenderId");
|
||||
|
||||
b.ToTable("SentMails");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.TimeCapsule", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Color")
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<double>("GlowIntensity")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("Opacity")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("PositionX")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("PositionY")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("PositionZ")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("Rotation")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<int>("SentMailId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("SentMailId1")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<double>("Size")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Style")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("UserId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SentMailId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("SentMailId1");
|
||||
|
||||
b.HasIndex("UserId");
|
||||
|
||||
b.ToTable("TimeCapsules");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.User", b =>
|
||||
{
|
||||
b.Property<int>("Id")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Avatar")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.ValueGeneratedOnAdd()
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<string>("Email")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<bool>("IsActive")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<DateTime?>("LastLoginAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Nickname")
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PasswordHash")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PreferredBackground")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("PreferredScene")
|
||||
.HasMaxLength(20)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("RefreshToken")
|
||||
.HasMaxLength(500)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime?>("RefreshTokenExpiryTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Salt")
|
||||
.IsRequired()
|
||||
.HasMaxLength(255)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<string>("Username")
|
||||
.IsRequired()
|
||||
.HasMaxLength(100)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("Email")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("Username")
|
||||
.IsUnique();
|
||||
|
||||
b.ToTable("Users");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.OAuthToken", b =>
|
||||
{
|
||||
b.HasOne("FutureMailAPI.Models.OAuthClient", "Client")
|
||||
.WithMany("Tokens")
|
||||
.HasForeignKey("ClientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("FutureMailAPI.Models.User", "User")
|
||||
.WithMany()
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Client");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.ReceivedMail", b =>
|
||||
{
|
||||
b.HasOne("FutureMailAPI.Models.User", "Recipient")
|
||||
.WithMany("ReceivedMails")
|
||||
.HasForeignKey("RecipientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("FutureMailAPI.Models.SentMail", "SentMail")
|
||||
.WithMany()
|
||||
.HasForeignKey("SentMailId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Recipient");
|
||||
|
||||
b.Navigation("SentMail");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.SentMail", b =>
|
||||
{
|
||||
b.HasOne("FutureMailAPI.Models.User", "Recipient")
|
||||
.WithMany()
|
||||
.HasForeignKey("RecipientId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("FutureMailAPI.Models.User", "Sender")
|
||||
.WithMany("SentMails")
|
||||
.HasForeignKey("SenderId")
|
||||
.OnDelete(DeleteBehavior.Restrict)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("Recipient");
|
||||
|
||||
b.Navigation("Sender");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.TimeCapsule", b =>
|
||||
{
|
||||
b.HasOne("FutureMailAPI.Models.SentMail", null)
|
||||
.WithOne("TimeCapsule")
|
||||
.HasForeignKey("FutureMailAPI.Models.TimeCapsule", "SentMailId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("FutureMailAPI.Models.SentMail", "SentMail")
|
||||
.WithMany()
|
||||
.HasForeignKey("SentMailId1")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("FutureMailAPI.Models.User", "User")
|
||||
.WithMany("TimeCapsules")
|
||||
.HasForeignKey("UserId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.Navigation("SentMail");
|
||||
|
||||
b.Navigation("User");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.OAuthClient", b =>
|
||||
{
|
||||
b.Navigation("Tokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.SentMail", b =>
|
||||
{
|
||||
b.Navigation("TimeCapsule");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.User", b =>
|
||||
{
|
||||
b.Navigation("ReceivedMails");
|
||||
|
||||
b.Navigation("SentMails");
|
||||
|
||||
b.Navigation("TimeCapsules");
|
||||
});
|
||||
#pragma warning restore 612, 618
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using Microsoft.EntityFrameworkCore.Migrations;
|
||||
|
||||
#nullable disable
|
||||
|
||||
namespace FutureMailAPI.Migrations
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public partial class FixDuplicateForeignKeys : Migration
|
||||
{
|
||||
/// <inheritdoc />
|
||||
protected override void Up(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_ReceivedMails_Users_RecipientId1",
|
||||
table: "ReceivedMails");
|
||||
|
||||
migrationBuilder.DropForeignKey(
|
||||
name: "FK_SentMails_Users_RecipientId1",
|
||||
table: "SentMails");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_SentMails_RecipientId1",
|
||||
table: "SentMails");
|
||||
|
||||
migrationBuilder.DropIndex(
|
||||
name: "IX_ReceivedMails_RecipientId1",
|
||||
table: "ReceivedMails");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "RecipientId1",
|
||||
table: "SentMails");
|
||||
|
||||
migrationBuilder.DropColumn(
|
||||
name: "RecipientId1",
|
||||
table: "ReceivedMails");
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Down(MigrationBuilder migrationBuilder)
|
||||
{
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "RecipientId1",
|
||||
table: "SentMails",
|
||||
type: "INTEGER",
|
||||
nullable: true);
|
||||
|
||||
migrationBuilder.AddColumn<int>(
|
||||
name: "RecipientId1",
|
||||
table: "ReceivedMails",
|
||||
type: "INTEGER",
|
||||
nullable: false,
|
||||
defaultValue: 0);
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_SentMails_RecipientId1",
|
||||
table: "SentMails",
|
||||
column: "RecipientId1");
|
||||
|
||||
migrationBuilder.CreateIndex(
|
||||
name: "IX_ReceivedMails_RecipientId1",
|
||||
table: "ReceivedMails",
|
||||
column: "RecipientId1");
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_ReceivedMails_Users_RecipientId1",
|
||||
table: "ReceivedMails",
|
||||
column: "RecipientId1",
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id",
|
||||
onDelete: ReferentialAction.Cascade);
|
||||
|
||||
migrationBuilder.AddForeignKey(
|
||||
name: "FK_SentMails_Users_RecipientId1",
|
||||
table: "SentMails",
|
||||
column: "RecipientId1",
|
||||
principalTable: "Users",
|
||||
principalColumn: "Id");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,9 +148,6 @@ namespace FutureMailAPI.Migrations
|
||||
b.Property<int>("RecipientId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("RecipientId1")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("ReplyMailId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
@@ -161,8 +158,6 @@ namespace FutureMailAPI.Migrations
|
||||
|
||||
b.HasIndex("RecipientId");
|
||||
|
||||
b.HasIndex("RecipientId1");
|
||||
|
||||
b.HasIndex("SentMailId");
|
||||
|
||||
b.ToTable("ReceivedMails");
|
||||
@@ -181,6 +176,9 @@ namespace FutureMailAPI.Migrations
|
||||
.IsRequired()
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("CreatedAt")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<DateTime>("DeliveryTime")
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
@@ -193,9 +191,6 @@ namespace FutureMailAPI.Migrations
|
||||
b.Property<int?>("RecipientId")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int?>("RecipientId1")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<int>("RecipientType")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
@@ -229,8 +224,6 @@ namespace FutureMailAPI.Migrations
|
||||
|
||||
b.HasIndex("RecipientId");
|
||||
|
||||
b.HasIndex("RecipientId1");
|
||||
|
||||
b.HasIndex("SenderId");
|
||||
|
||||
b.ToTable("SentMails");
|
||||
@@ -251,6 +244,9 @@ namespace FutureMailAPI.Migrations
|
||||
.HasColumnType("TEXT")
|
||||
.HasDefaultValueSql("CURRENT_TIMESTAMP");
|
||||
|
||||
b.Property<double>("GlowIntensity")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
b.Property<double>("Opacity")
|
||||
.HasColumnType("REAL");
|
||||
|
||||
@@ -278,6 +274,10 @@ namespace FutureMailAPI.Migrations
|
||||
b.Property<int>("Status")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
b.Property<string>("Style")
|
||||
.HasMaxLength(50)
|
||||
.HasColumnType("TEXT");
|
||||
|
||||
b.Property<int>("Type")
|
||||
.HasColumnType("INTEGER");
|
||||
|
||||
@@ -286,7 +286,8 @@ namespace FutureMailAPI.Migrations
|
||||
|
||||
b.HasKey("Id");
|
||||
|
||||
b.HasIndex("SentMailId");
|
||||
b.HasIndex("SentMailId")
|
||||
.IsUnique();
|
||||
|
||||
b.HasIndex("SentMailId1");
|
||||
|
||||
@@ -387,15 +388,9 @@ namespace FutureMailAPI.Migrations
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.ReceivedMail", b =>
|
||||
{
|
||||
b.HasOne("FutureMailAPI.Models.User", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("RecipientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
b.HasOne("FutureMailAPI.Models.User", "Recipient")
|
||||
.WithMany("ReceivedMails")
|
||||
.HasForeignKey("RecipientId1")
|
||||
.HasForeignKey("RecipientId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
@@ -412,15 +407,11 @@ namespace FutureMailAPI.Migrations
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.SentMail", b =>
|
||||
{
|
||||
b.HasOne("FutureMailAPI.Models.User", null)
|
||||
b.HasOne("FutureMailAPI.Models.User", "Recipient")
|
||||
.WithMany()
|
||||
.HasForeignKey("RecipientId")
|
||||
.OnDelete(DeleteBehavior.SetNull);
|
||||
|
||||
b.HasOne("FutureMailAPI.Models.User", "Recipient")
|
||||
.WithMany()
|
||||
.HasForeignKey("RecipientId1");
|
||||
|
||||
b.HasOne("FutureMailAPI.Models.User", "Sender")
|
||||
.WithMany("SentMails")
|
||||
.HasForeignKey("SenderId")
|
||||
@@ -435,8 +426,8 @@ namespace FutureMailAPI.Migrations
|
||||
modelBuilder.Entity("FutureMailAPI.Models.TimeCapsule", b =>
|
||||
{
|
||||
b.HasOne("FutureMailAPI.Models.SentMail", null)
|
||||
.WithMany()
|
||||
.HasForeignKey("SentMailId")
|
||||
.WithOne("TimeCapsule")
|
||||
.HasForeignKey("FutureMailAPI.Models.TimeCapsule", "SentMailId")
|
||||
.OnDelete(DeleteBehavior.Cascade)
|
||||
.IsRequired();
|
||||
|
||||
@@ -462,6 +453,11 @@ namespace FutureMailAPI.Migrations
|
||||
b.Navigation("Tokens");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.SentMail", b =>
|
||||
{
|
||||
b.Navigation("TimeCapsule");
|
||||
});
|
||||
|
||||
modelBuilder.Entity("FutureMailAPI.Models.User", b =>
|
||||
{
|
||||
b.Navigation("ReceivedMails");
|
||||
|
||||
@@ -28,6 +28,9 @@ namespace FutureMailAPI.Models
|
||||
// 发送时间
|
||||
public DateTime SentAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
// 创建时间
|
||||
public DateTime CreatedAt { get; set; } = DateTime.UtcNow;
|
||||
|
||||
// 投递时间
|
||||
[Required]
|
||||
public DateTime DeliveryTime { get; set; }
|
||||
@@ -61,5 +64,7 @@ namespace FutureMailAPI.Models
|
||||
public virtual User Sender { get; set; } = null!;
|
||||
|
||||
public virtual User? Recipient { get; set; }
|
||||
|
||||
public virtual TimeCapsule? TimeCapsule { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,13 @@ namespace FutureMailAPI.Models
|
||||
// 胶囊旋转角度
|
||||
public double Rotation { get; set; } = 0;
|
||||
|
||||
// 胶囊样式/皮肤
|
||||
[MaxLength(50)]
|
||||
public string? Style { get; set; }
|
||||
|
||||
// 发光强度
|
||||
public double GlowIntensity { get; set; } = 0.8;
|
||||
|
||||
// 胶囊状态: 0-未激活, 1-漂浮中, 2-即将到达, 3-已开启
|
||||
[Required]
|
||||
public int Status { get; set; } = 0;
|
||||
|
||||
@@ -17,5 +17,15 @@ namespace FutureMailAPI.Services
|
||||
Task<ApiResponse<bool>> MarkReceivedMailAsReadAsync(int userId, int mailId);
|
||||
Task<ApiResponse<bool>> MarkAsReadAsync(int userId, int mailId);
|
||||
Task<ApiResponse<bool>> RevokeMailAsync(int userId, int mailId);
|
||||
|
||||
// 存入胶囊相关方法
|
||||
Task<ApiResponse<SaveToCapsuleResponseDto>> SaveToCapsuleAsync(int userId, SaveToCapsuleDto saveToCapsuleDto);
|
||||
Task<ApiResponse<PagedResponse<CapsuleMailListResponseDto>>> GetCapsuleMailsAsync(int userId, MailListQueryDto queryDto);
|
||||
Task<ApiResponse<CapsuleMailDetailResponseDto>> GetCapsuleMailByIdAsync(int userId, int mailId);
|
||||
Task<ApiResponse<CapsuleMailDetailResponseDto>> UpdateCapsuleMailAsync(int userId, int mailId, UpdateCapsuleMailDto updateDto);
|
||||
Task<ApiResponse<bool>> RevokeCapsuleMailAsync(int userId, int mailId);
|
||||
|
||||
// 发送至未来功能
|
||||
Task<ApiResponse<SendToFutureResponseDto>> SendToFutureAsync(int userId, SendToFutureDto sendToFutureDto);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@ using Microsoft.EntityFrameworkCore;
|
||||
using FutureMailAPI.Data;
|
||||
using FutureMailAPI.Models;
|
||||
using FutureMailAPI.DTOs;
|
||||
using System.Text.Json;
|
||||
|
||||
namespace FutureMailAPI.Services
|
||||
{
|
||||
@@ -382,6 +383,393 @@ namespace FutureMailAPI.Services
|
||||
return ApiResponse<bool>.SuccessResult(true, "邮件已撤销");
|
||||
}
|
||||
|
||||
// 存入胶囊相关方法实现
|
||||
public async Task<ApiResponse<SaveToCapsuleResponseDto>> SaveToCapsuleAsync(int userId, SaveToCapsuleDto saveToCapsuleDto)
|
||||
{
|
||||
// 验证收件人类型
|
||||
if (saveToCapsuleDto.RecipientType == RecipientTypeEnum.SPECIFIC && string.IsNullOrEmpty(saveToCapsuleDto.RecipientEmail))
|
||||
{
|
||||
return ApiResponse<SaveToCapsuleResponseDto>.ErrorResult("指定收件人时,收件人邮箱是必填项");
|
||||
}
|
||||
|
||||
// 验证发送时间
|
||||
if (saveToCapsuleDto.SendTime.HasValue && saveToCapsuleDto.SendTime.Value <= DateTime.UtcNow)
|
||||
{
|
||||
return ApiResponse<SaveToCapsuleResponseDto>.ErrorResult("发送时间必须是未来时间");
|
||||
}
|
||||
|
||||
// 创建邮件
|
||||
var mail = new SentMail
|
||||
{
|
||||
Title = saveToCapsuleDto.Title,
|
||||
Content = saveToCapsuleDto.Content,
|
||||
SenderId = userId,
|
||||
RecipientType = (int)saveToCapsuleDto.RecipientType,
|
||||
SentAt = DateTime.UtcNow,
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
DeliveryTime = saveToCapsuleDto.SendTime ?? DateTime.UtcNow.AddDays(1), // 默认一天后发送
|
||||
Status = 0, // 草稿状态
|
||||
TriggerType = (int)saveToCapsuleDto.TriggerType,
|
||||
TriggerDetails = saveToCapsuleDto.TriggerCondition != null ? JsonSerializer.Serialize(saveToCapsuleDto.TriggerCondition) : null,
|
||||
Attachments = saveToCapsuleDto.Attachments != null ? JsonSerializer.Serialize(saveToCapsuleDto.Attachments) : null,
|
||||
IsEncrypted = saveToCapsuleDto.IsEncrypted,
|
||||
Theme = saveToCapsuleDto.CapsuleStyle
|
||||
};
|
||||
|
||||
// 如果是指定收件人,查找收件人ID
|
||||
if (saveToCapsuleDto.RecipientType == RecipientTypeEnum.SPECIFIC && !string.IsNullOrEmpty(saveToCapsuleDto.RecipientEmail))
|
||||
{
|
||||
var recipient = await _context.Users
|
||||
.FirstOrDefaultAsync(u => u.Email == saveToCapsuleDto.RecipientEmail);
|
||||
|
||||
if (recipient == null)
|
||||
{
|
||||
return ApiResponse<SaveToCapsuleResponseDto>.ErrorResult("收件人不存在");
|
||||
}
|
||||
|
||||
mail.RecipientId = recipient.Id;
|
||||
}
|
||||
|
||||
_context.SentMails.Add(mail);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// 创建时间胶囊
|
||||
var timeCapsule = new TimeCapsule
|
||||
{
|
||||
UserId = userId,
|
||||
SentMailId = mail.Id,
|
||||
Status = 0, // 草稿状态
|
||||
CreatedAt = DateTime.UtcNow,
|
||||
PositionX = 0.5f, // 默认位置
|
||||
PositionY = 0.5f,
|
||||
PositionZ = 0.5f,
|
||||
Style = saveToCapsuleDto.CapsuleStyle,
|
||||
GlowIntensity = 0.8f // 默认发光强度
|
||||
};
|
||||
|
||||
_context.TimeCapsules.Add(timeCapsule);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var response = new SaveToCapsuleResponseDto
|
||||
{
|
||||
Id = mail.Id,
|
||||
MailId = mail.Id.ToString(),
|
||||
CapsuleId = timeCapsule.Id.ToString(),
|
||||
Status = "DRAFT",
|
||||
CreatedAt = mail.CreatedAt
|
||||
};
|
||||
|
||||
return ApiResponse<SaveToCapsuleResponseDto>.SuccessResult(response, "邮件已存入胶囊");
|
||||
}
|
||||
|
||||
public async Task<ApiResponse<PagedResponse<CapsuleMailListResponseDto>>> GetCapsuleMailsAsync(int userId, MailListQueryDto queryDto)
|
||||
{
|
||||
var query = _context.SentMails
|
||||
.Where(m => m.SenderId == userId && m.Status == 0) // 只查询草稿状态的邮件
|
||||
.Include(m => m.Sender)
|
||||
.Include(m => m.Recipient)
|
||||
.Include(m => m.TimeCapsule)
|
||||
.AsQueryable();
|
||||
|
||||
// 应用筛选条件
|
||||
if (queryDto.Status.HasValue)
|
||||
{
|
||||
query = query.Where(m => m.Status == queryDto.Status.Value);
|
||||
}
|
||||
|
||||
if (queryDto.RecipientType.HasValue)
|
||||
{
|
||||
query = query.Where(m => m.RecipientType == queryDto.RecipientType.Value);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(queryDto.Keyword))
|
||||
{
|
||||
query = query.Where(m => m.Title.Contains(queryDto.Keyword) || m.Content.Contains(queryDto.Keyword));
|
||||
}
|
||||
|
||||
if (queryDto.StartDate.HasValue)
|
||||
{
|
||||
query = query.Where(m => m.SentAt >= queryDto.StartDate.Value);
|
||||
}
|
||||
|
||||
if (queryDto.EndDate.HasValue)
|
||||
{
|
||||
query = query.Where(m => m.SentAt <= queryDto.EndDate.Value);
|
||||
}
|
||||
|
||||
// 排序
|
||||
query = query.OrderByDescending(m => m.SentAt);
|
||||
|
||||
// 分页
|
||||
var totalCount = await query.CountAsync();
|
||||
var mails = await query
|
||||
.Skip((queryDto.PageIndex - 1) * queryDto.PageSize)
|
||||
.Take(queryDto.PageSize)
|
||||
.ToListAsync();
|
||||
|
||||
var mailDtos = mails.Select(MapToCapsuleMailListResponseDto).ToList();
|
||||
|
||||
var pagedResponse = new PagedResponse<CapsuleMailListResponseDto>(
|
||||
mailDtos, queryDto.PageIndex, queryDto.PageSize, totalCount);
|
||||
|
||||
return ApiResponse<PagedResponse<CapsuleMailListResponseDto>>.SuccessResult(pagedResponse);
|
||||
}
|
||||
|
||||
public async Task<ApiResponse<CapsuleMailDetailResponseDto>> GetCapsuleMailByIdAsync(int userId, int mailId)
|
||||
{
|
||||
var mail = await _context.SentMails
|
||||
.Include(m => m.Sender)
|
||||
.Include(m => m.Recipient)
|
||||
.Include(m => m.TimeCapsule)
|
||||
.FirstOrDefaultAsync(m => m.Id == mailId && m.SenderId == userId);
|
||||
|
||||
if (mail == null)
|
||||
{
|
||||
return ApiResponse<CapsuleMailDetailResponseDto>.ErrorResult("邮件不存在");
|
||||
}
|
||||
|
||||
var mailDto = MapToCapsuleMailDetailResponseDto(mail);
|
||||
|
||||
return ApiResponse<CapsuleMailDetailResponseDto>.SuccessResult(mailDto);
|
||||
}
|
||||
|
||||
public async Task<ApiResponse<CapsuleMailDetailResponseDto>> UpdateCapsuleMailAsync(int userId, int mailId, UpdateCapsuleMailDto updateDto)
|
||||
{
|
||||
var mail = await _context.SentMails
|
||||
.Include(m => m.Sender)
|
||||
.Include(m => m.Recipient)
|
||||
.Include(m => m.TimeCapsule)
|
||||
.FirstOrDefaultAsync(m => m.Id == mailId && m.SenderId == userId);
|
||||
|
||||
if (mail == null)
|
||||
{
|
||||
return ApiResponse<CapsuleMailDetailResponseDto>.ErrorResult("邮件不存在");
|
||||
}
|
||||
|
||||
// 检查邮件状态,只有草稿状态的邮件才能编辑
|
||||
if (mail.Status != 0)
|
||||
{
|
||||
return ApiResponse<CapsuleMailDetailResponseDto>.ErrorResult("只有草稿状态的邮件才能编辑");
|
||||
}
|
||||
|
||||
// 更新邮件信息
|
||||
if (!string.IsNullOrEmpty(updateDto.Title))
|
||||
{
|
||||
mail.Title = updateDto.Title;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(updateDto.Content))
|
||||
{
|
||||
mail.Content = updateDto.Content;
|
||||
}
|
||||
|
||||
if (updateDto.RecipientType.HasValue)
|
||||
{
|
||||
mail.RecipientType = (int)updateDto.RecipientType.Value;
|
||||
|
||||
// 如果是指定收件人,查找收件人ID
|
||||
if (updateDto.RecipientType.Value == RecipientTypeEnum.SPECIFIC && !string.IsNullOrEmpty(updateDto.RecipientEmail))
|
||||
{
|
||||
var recipient = await _context.Users
|
||||
.FirstOrDefaultAsync(u => u.Email == updateDto.RecipientEmail);
|
||||
|
||||
if (recipient == null)
|
||||
{
|
||||
return ApiResponse<CapsuleMailDetailResponseDto>.ErrorResult("收件人不存在");
|
||||
}
|
||||
|
||||
mail.RecipientId = recipient.Id;
|
||||
}
|
||||
}
|
||||
|
||||
if (updateDto.SendTime.HasValue)
|
||||
{
|
||||
if (updateDto.SendTime.Value <= DateTime.UtcNow)
|
||||
{
|
||||
return ApiResponse<CapsuleMailDetailResponseDto>.ErrorResult("发送时间必须是未来时间");
|
||||
}
|
||||
|
||||
mail.DeliveryTime = updateDto.SendTime.Value;
|
||||
}
|
||||
|
||||
if (updateDto.TriggerType.HasValue)
|
||||
{
|
||||
mail.TriggerType = (int)updateDto.TriggerType.Value;
|
||||
}
|
||||
|
||||
if (updateDto.TriggerCondition != null)
|
||||
{
|
||||
mail.TriggerDetails = JsonSerializer.Serialize(updateDto.TriggerCondition);
|
||||
}
|
||||
|
||||
if (updateDto.Attachments != null)
|
||||
{
|
||||
mail.Attachments = JsonSerializer.Serialize(updateDto.Attachments);
|
||||
}
|
||||
|
||||
if (updateDto.IsEncrypted.HasValue)
|
||||
{
|
||||
mail.IsEncrypted = updateDto.IsEncrypted.Value;
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(updateDto.CapsuleStyle))
|
||||
{
|
||||
mail.Theme = updateDto.CapsuleStyle;
|
||||
|
||||
// 更新时间胶囊样式
|
||||
if (mail.TimeCapsule != null)
|
||||
{
|
||||
mail.TimeCapsule.Style = updateDto.CapsuleStyle;
|
||||
}
|
||||
}
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
var mailResponse = MapToCapsuleMailDetailResponseDto(mail);
|
||||
|
||||
return ApiResponse<CapsuleMailDetailResponseDto>.SuccessResult(mailResponse, "胶囊邮件更新成功");
|
||||
}
|
||||
|
||||
public async Task<ApiResponse<bool>> RevokeCapsuleMailAsync(int userId, int mailId)
|
||||
{
|
||||
var mail = await _context.SentMails
|
||||
.Include(m => m.TimeCapsule)
|
||||
.FirstOrDefaultAsync(m => m.Id == mailId && m.SenderId == userId);
|
||||
|
||||
if (mail == null)
|
||||
{
|
||||
return ApiResponse<bool>.ErrorResult("邮件不存在");
|
||||
}
|
||||
|
||||
// 检查邮件状态,只有草稿或待投递状态的邮件才能撤销
|
||||
if (mail.Status > 1)
|
||||
{
|
||||
return ApiResponse<bool>.ErrorResult("已投递的邮件不能撤销");
|
||||
}
|
||||
|
||||
// 更新邮件状态为已撤销
|
||||
mail.Status = 4; // 4-已撤销
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// 更新相关的时间胶囊状态
|
||||
if (mail.TimeCapsule != null)
|
||||
{
|
||||
mail.TimeCapsule.Status = 3; // 3-已撤销
|
||||
await _context.SaveChangesAsync();
|
||||
}
|
||||
|
||||
return ApiResponse<bool>.SuccessResult(true, "胶囊邮件已撤销");
|
||||
}
|
||||
|
||||
private static CapsuleMailListResponseDto MapToCapsuleMailListResponseDto(SentMail mail)
|
||||
{
|
||||
return new CapsuleMailListResponseDto
|
||||
{
|
||||
MailId = mail.Id.ToString(),
|
||||
Title = mail.Title,
|
||||
Sender = MapToUserInfoDto(mail.Sender),
|
||||
Recipient = mail.Recipient != null ? MapToUserInfoDto(mail.Recipient) : new UserInfoDto(),
|
||||
SendTime = mail.SentAt,
|
||||
DeliveryTime = mail.DeliveryTime,
|
||||
Status = mail.Status switch
|
||||
{
|
||||
0 => "DRAFT",
|
||||
1 => "PENDING",
|
||||
2 => "DELIVERING",
|
||||
3 => "DELIVERED",
|
||||
_ => "UNKNOWN"
|
||||
},
|
||||
HasAttachments = !string.IsNullOrEmpty(mail.Attachments),
|
||||
IsEncrypted = mail.IsEncrypted,
|
||||
CapsuleStyle = mail.Theme ?? "default",
|
||||
Countdown = mail.Status == 1 ? (int)(mail.DeliveryTime - DateTime.UtcNow).TotalSeconds : null
|
||||
};
|
||||
}
|
||||
|
||||
private static CapsuleMailDetailResponseDto MapToCapsuleMailDetailResponseDto(SentMail mail)
|
||||
{
|
||||
List<AttachmentDto> attachments = new List<AttachmentDto>();
|
||||
|
||||
if (!string.IsNullOrEmpty(mail.Attachments))
|
||||
{
|
||||
try
|
||||
{
|
||||
var attachmentList = JsonSerializer.Deserialize<List<object>>(mail.Attachments);
|
||||
if (attachmentList != null)
|
||||
{
|
||||
attachments = attachmentList.Select(a => new AttachmentDto
|
||||
{
|
||||
Id = Guid.NewGuid().ToString(),
|
||||
Type = "IMAGE", // 默认类型,实际应根据数据解析
|
||||
Url = a.ToString() ?? "",
|
||||
Size = 0 // 默认大小,实际应根据数据解析
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 解析失败时忽略附件
|
||||
}
|
||||
}
|
||||
|
||||
object? triggerCondition = null;
|
||||
if (!string.IsNullOrEmpty(mail.TriggerDetails))
|
||||
{
|
||||
try
|
||||
{
|
||||
triggerCondition = JsonSerializer.Deserialize<object>(mail.TriggerDetails);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 解析失败时忽略触发条件
|
||||
}
|
||||
}
|
||||
|
||||
return new CapsuleMailDetailResponseDto
|
||||
{
|
||||
MailId = mail.Id.ToString(),
|
||||
Title = mail.Title,
|
||||
Content = mail.Content,
|
||||
Sender = MapToUserInfoDto(mail.Sender),
|
||||
Recipient = mail.Recipient != null ? MapToUserInfoDto(mail.Recipient) : new UserInfoDto(),
|
||||
SendTime = mail.SentAt,
|
||||
CreatedAt = mail.CreatedAt,
|
||||
DeliveryTime = mail.DeliveryTime,
|
||||
Status = mail.Status switch
|
||||
{
|
||||
0 => "DRAFT",
|
||||
1 => "PENDING",
|
||||
2 => "DELIVERING",
|
||||
3 => "DELIVERED",
|
||||
_ => "UNKNOWN"
|
||||
},
|
||||
TriggerType = mail.TriggerType switch
|
||||
{
|
||||
0 => "TIME",
|
||||
1 => "LOCATION",
|
||||
2 => "EVENT",
|
||||
_ => "UNKNOWN"
|
||||
},
|
||||
TriggerCondition = triggerCondition,
|
||||
Attachments = attachments,
|
||||
IsEncrypted = mail.IsEncrypted,
|
||||
CapsuleStyle = mail.Theme ?? "default",
|
||||
CanEdit = mail.Status == 0, // 只有草稿状态可编辑
|
||||
CanRevoke = mail.Status <= 1 // 草稿或待投递状态可撤销
|
||||
};
|
||||
}
|
||||
|
||||
private static UserInfoDto MapToUserInfoDto(User user)
|
||||
{
|
||||
return new UserInfoDto
|
||||
{
|
||||
UserId = user.Id,
|
||||
Username = user.Username,
|
||||
Avatar = user.Avatar ?? "",
|
||||
Email = user.Email
|
||||
};
|
||||
}
|
||||
|
||||
private async Task<SentMailResponseDto> GetSentMailWithDetailsAsync(int mailId)
|
||||
{
|
||||
var mail = await _context.SentMails
|
||||
@@ -471,5 +859,70 @@ namespace FutureMailAPI.Services
|
||||
_ => "未知"
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 发送至未来 - 将草稿状态的邮件设置为在未来特定时间自动发送
|
||||
/// </summary>
|
||||
/// <param name="userId">用户ID</param>
|
||||
/// <param name="sendToFutureDto">发送至未来请求DTO</param>
|
||||
/// <returns>发送至未来响应DTO</returns>
|
||||
public async Task<ApiResponse<SendToFutureResponseDto>> SendToFutureAsync(int userId, SendToFutureDto sendToFutureDto)
|
||||
{
|
||||
// 检查投递时间是否在未来
|
||||
if (sendToFutureDto.DeliveryTime <= DateTime.UtcNow)
|
||||
{
|
||||
return ApiResponse<SendToFutureResponseDto>.ErrorResult("投递时间必须是未来时间");
|
||||
}
|
||||
|
||||
// 查找邮件
|
||||
var mail = await _context.SentMails
|
||||
.Include(m => m.Sender)
|
||||
.FirstOrDefaultAsync(m => m.Id == sendToFutureDto.MailId && m.SenderId == userId);
|
||||
|
||||
if (mail == null)
|
||||
{
|
||||
return ApiResponse<SendToFutureResponseDto>.ErrorResult("邮件不存在");
|
||||
}
|
||||
|
||||
// 检查邮件是否为草稿状态
|
||||
if (mail.Status != 0)
|
||||
{
|
||||
return ApiResponse<SendToFutureResponseDto>.ErrorResult("只有草稿状态的邮件可以设置为发送至未来");
|
||||
}
|
||||
|
||||
// 更新邮件状态和投递时间
|
||||
mail.DeliveryTime = sendToFutureDto.DeliveryTime;
|
||||
mail.Status = 1; // 设置为已发送(待投递)状态
|
||||
mail.SentAt = DateTime.UtcNow; // 设置发送时间为当前时间
|
||||
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// 创建时间胶囊
|
||||
var timeCapsule = new TimeCapsule
|
||||
{
|
||||
UserId = userId,
|
||||
SentMailId = mail.Id,
|
||||
PositionX = 0,
|
||||
PositionY = 0,
|
||||
PositionZ = 0,
|
||||
Status = 1, // 漂浮中
|
||||
Type = 0 // 普通
|
||||
};
|
||||
|
||||
_context.TimeCapsules.Add(timeCapsule);
|
||||
await _context.SaveChangesAsync();
|
||||
|
||||
// 构建响应
|
||||
var response = new SendToFutureResponseDto
|
||||
{
|
||||
MailId = mail.Id,
|
||||
Title = mail.Title,
|
||||
DeliveryTime = mail.DeliveryTime,
|
||||
Status = GetStatusText(mail.Status),
|
||||
SentAt = mail.SentAt
|
||||
};
|
||||
|
||||
return ApiResponse<SendToFutureResponseDto>.SuccessResult(response, "邮件已设置为发送至未来");
|
||||
}
|
||||
}
|
||||
}
|
||||
Binary file not shown.
Binary file not shown.
@@ -83,6 +83,55 @@
|
||||
<param name="fileId">文件ID</param>
|
||||
<returns>文件信息</returns>
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Controllers.MailsController.SaveToCapsule(FutureMailAPI.DTOs.SaveToCapsuleDto)">
|
||||
<summary>
|
||||
存入胶囊 - 创建胶囊邮件
|
||||
</summary>
|
||||
<param name="dto">存入胶囊请求</param>
|
||||
<returns>操作结果</returns>
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Controllers.MailsController.GetCapsuleMails(System.Int32,System.Int32,System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.Nullable{System.DateTime},System.Nullable{System.DateTime})">
|
||||
<summary>
|
||||
获取胶囊邮件列表
|
||||
</summary>
|
||||
<param name="pageIndex">页码</param>
|
||||
<param name="pageSize">页大小</param>
|
||||
<param name="status">状态筛选</param>
|
||||
<param name="recipientType">收件人类型筛选</param>
|
||||
<param name="keyword">关键词搜索</param>
|
||||
<param name="startDate">开始日期</param>
|
||||
<param name="endDate">结束日期</param>
|
||||
<returns>胶囊邮件列表</returns>
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Controllers.MailsController.GetCapsuleMail(System.Int32)">
|
||||
<summary>
|
||||
获取胶囊邮件详情
|
||||
</summary>
|
||||
<param name="id">邮件ID</param>
|
||||
<returns>胶囊邮件详情</returns>
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Controllers.MailsController.UpdateCapsuleMail(System.Int32,FutureMailAPI.DTOs.UpdateCapsuleMailDto)">
|
||||
<summary>
|
||||
更新胶囊邮件
|
||||
</summary>
|
||||
<param name="id">邮件ID</param>
|
||||
<param name="dto">更新请求</param>
|
||||
<returns>更新后的胶囊邮件详情</returns>
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Controllers.MailsController.RevokeCapsuleMail(System.Int32)">
|
||||
<summary>
|
||||
撤销胶囊邮件
|
||||
</summary>
|
||||
<param name="id">邮件ID</param>
|
||||
<returns>操作结果</returns>
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Controllers.MailsController.SendToFuture(FutureMailAPI.DTOs.SendToFutureDto)">
|
||||
<summary>
|
||||
发送至未来 - 将草稿状态的邮件设置为在未来特定时间自动发送
|
||||
</summary>
|
||||
<param name="sendToFutureDto">发送至未来请求DTO</param>
|
||||
<returns>发送至未来响应DTO</returns>
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Controllers.NotificationController.RegisterDevice(FutureMailAPI.DTOs.NotificationDeviceRequestDto)">
|
||||
<summary>
|
||||
注册设备
|
||||
@@ -207,5 +256,37 @@
|
||||
<member name="M:FutureMailAPI.Migrations.AddSaltToUser.Down(Microsoft.EntityFrameworkCore.Migrations.MigrationBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="T:FutureMailAPI.Migrations.AddSentMailCreatedAt">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Migrations.AddSentMailCreatedAt.Up(Microsoft.EntityFrameworkCore.Migrations.MigrationBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Migrations.AddSentMailCreatedAt.Down(Microsoft.EntityFrameworkCore.Migrations.MigrationBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Migrations.AddSentMailCreatedAt.BuildTargetModel(Microsoft.EntityFrameworkCore.ModelBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="T:FutureMailAPI.Migrations.FixDuplicateForeignKeys">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Migrations.FixDuplicateForeignKeys.Up(Microsoft.EntityFrameworkCore.Migrations.MigrationBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Migrations.FixDuplicateForeignKeys.Down(Microsoft.EntityFrameworkCore.Migrations.MigrationBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Migrations.FixDuplicateForeignKeys.BuildTargetModel(Microsoft.EntityFrameworkCore.ModelBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Services.MailService.SendToFutureAsync(System.Int32,FutureMailAPI.DTOs.SendToFutureDto)">
|
||||
<summary>
|
||||
发送至未来 - 将草稿状态的邮件设置为在未来特定时间自动发送
|
||||
</summary>
|
||||
<param name="userId">用户ID</param>
|
||||
<param name="sendToFutureDto">发送至未来请求DTO</param>
|
||||
<returns>发送至未来响应DTO</returns>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
|
||||
@@ -1 +1 @@
|
||||
51372bde626c0ba3aa5386f92d0ea465adcc4b558852e21737182a326708e608
|
||||
96b95197304e11878aba7d6a0ad52cc38a6b9883e011012e3da5e389d5e93831
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -83,6 +83,55 @@
|
||||
<param name="fileId">文件ID</param>
|
||||
<returns>文件信息</returns>
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Controllers.MailsController.SaveToCapsule(FutureMailAPI.DTOs.SaveToCapsuleDto)">
|
||||
<summary>
|
||||
存入胶囊 - 创建胶囊邮件
|
||||
</summary>
|
||||
<param name="dto">存入胶囊请求</param>
|
||||
<returns>操作结果</returns>
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Controllers.MailsController.GetCapsuleMails(System.Int32,System.Int32,System.Nullable{System.Int32},System.Nullable{System.Int32},System.String,System.Nullable{System.DateTime},System.Nullable{System.DateTime})">
|
||||
<summary>
|
||||
获取胶囊邮件列表
|
||||
</summary>
|
||||
<param name="pageIndex">页码</param>
|
||||
<param name="pageSize">页大小</param>
|
||||
<param name="status">状态筛选</param>
|
||||
<param name="recipientType">收件人类型筛选</param>
|
||||
<param name="keyword">关键词搜索</param>
|
||||
<param name="startDate">开始日期</param>
|
||||
<param name="endDate">结束日期</param>
|
||||
<returns>胶囊邮件列表</returns>
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Controllers.MailsController.GetCapsuleMail(System.Int32)">
|
||||
<summary>
|
||||
获取胶囊邮件详情
|
||||
</summary>
|
||||
<param name="id">邮件ID</param>
|
||||
<returns>胶囊邮件详情</returns>
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Controllers.MailsController.UpdateCapsuleMail(System.Int32,FutureMailAPI.DTOs.UpdateCapsuleMailDto)">
|
||||
<summary>
|
||||
更新胶囊邮件
|
||||
</summary>
|
||||
<param name="id">邮件ID</param>
|
||||
<param name="dto">更新请求</param>
|
||||
<returns>更新后的胶囊邮件详情</returns>
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Controllers.MailsController.RevokeCapsuleMail(System.Int32)">
|
||||
<summary>
|
||||
撤销胶囊邮件
|
||||
</summary>
|
||||
<param name="id">邮件ID</param>
|
||||
<returns>操作结果</returns>
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Controllers.MailsController.SendToFuture(FutureMailAPI.DTOs.SendToFutureDto)">
|
||||
<summary>
|
||||
发送至未来 - 将草稿状态的邮件设置为在未来特定时间自动发送
|
||||
</summary>
|
||||
<param name="sendToFutureDto">发送至未来请求DTO</param>
|
||||
<returns>发送至未来响应DTO</returns>
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Controllers.NotificationController.RegisterDevice(FutureMailAPI.DTOs.NotificationDeviceRequestDto)">
|
||||
<summary>
|
||||
注册设备
|
||||
@@ -207,5 +256,37 @@
|
||||
<member name="M:FutureMailAPI.Migrations.AddSaltToUser.Down(Microsoft.EntityFrameworkCore.Migrations.MigrationBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="T:FutureMailAPI.Migrations.AddSentMailCreatedAt">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Migrations.AddSentMailCreatedAt.Up(Microsoft.EntityFrameworkCore.Migrations.MigrationBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Migrations.AddSentMailCreatedAt.Down(Microsoft.EntityFrameworkCore.Migrations.MigrationBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Migrations.AddSentMailCreatedAt.BuildTargetModel(Microsoft.EntityFrameworkCore.ModelBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="T:FutureMailAPI.Migrations.FixDuplicateForeignKeys">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Migrations.FixDuplicateForeignKeys.Up(Microsoft.EntityFrameworkCore.Migrations.MigrationBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Migrations.FixDuplicateForeignKeys.Down(Microsoft.EntityFrameworkCore.Migrations.MigrationBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Migrations.FixDuplicateForeignKeys.BuildTargetModel(Microsoft.EntityFrameworkCore.ModelBuilder)">
|
||||
<inheritdoc />
|
||||
</member>
|
||||
<member name="M:FutureMailAPI.Services.MailService.SendToFutureAsync(System.Int32,FutureMailAPI.DTOs.SendToFutureDto)">
|
||||
<summary>
|
||||
发送至未来 - 将草稿状态的邮件设置为在未来特定时间自动发送
|
||||
</summary>
|
||||
<param name="userId">用户ID</param>
|
||||
<param name="sendToFutureDto">发送至未来请求DTO</param>
|
||||
<returns>发送至未来响应DTO</returns>
|
||||
</member>
|
||||
</members>
|
||||
</doc>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
@@ -1 +1 @@
|
||||
{"GlobalPropertiesHash":"1nyXR9zdL54Badakr4zt6ZsTCwUunwdqRSmf7XLLUwI=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["PSBb4S8lcZQPImBE8id7O4eeN8h3whFn6j1jGYFQciQ=","FLPLXKwQVK16UZsWKzZrjH5kq4sMEtCZqAIkpUwa2pU=","qvO3Mvo7bXJuih7HQYVXFfIR0uMf6fdipVLWW\u002BbFgXY=","XAE6ulqLzJRH50\u002Bc9Nteizd/x9s3rvSHUFwFL265XX4=","talZRfyIQIv4aZc27HTn01\u002B12VbY6LMFOy3\u002B3r448jo=","kyazWY\u002B8n0dtdadKg35ovAVMceUhOAzyYnxEaTobs08="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
{"GlobalPropertiesHash":"1nyXR9zdL54Badakr4zt6ZsTCwUunwdqRSmf7XLLUwI=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["PSBb4S8lcZQPImBE8id7O4eeN8h3whFn6j1jGYFQciQ=","FLPLXKwQVK16UZsWKzZrjH5kq4sMEtCZqAIkpUwa2pU=","ed7if\u002BhRbLX5eYApJ6Bg4oF5be3kjR0VKVKgf\u002BgmyVo=","XAE6ulqLzJRH50\u002Bc9Nteizd/x9s3rvSHUFwFL265XX4=","talZRfyIQIv4aZc27HTn01\u002B12VbY6LMFOy3\u002B3r448jo=","R7hxHyYox4qeYIBY\u002Bo3l0eo8ZIIfGZeN7PS3V61Q7Ks="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
@@ -1 +1 @@
|
||||
{"GlobalPropertiesHash":"hRzLFfhtQD0jC2zNthCXf5A5W0LGZjQdHMs0v5Enof8=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["PSBb4S8lcZQPImBE8id7O4eeN8h3whFn6j1jGYFQciQ=","FLPLXKwQVK16UZsWKzZrjH5kq4sMEtCZqAIkpUwa2pU=","qvO3Mvo7bXJuih7HQYVXFfIR0uMf6fdipVLWW\u002BbFgXY=","XAE6ulqLzJRH50\u002Bc9Nteizd/x9s3rvSHUFwFL265XX4=","talZRfyIQIv4aZc27HTn01\u002B12VbY6LMFOy3\u002B3r448jo=","kyazWY\u002B8n0dtdadKg35ovAVMceUhOAzyYnxEaTobs08="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
{"GlobalPropertiesHash":"hRzLFfhtQD0jC2zNthCXf5A5W0LGZjQdHMs0v5Enof8=","FingerprintPatternsHash":"gq3WsqcKBUGTSNle7RKKyXRIwh7M8ccEqOqYvIzoM04=","PropertyOverridesHash":"8ZRc1sGeVrPBx4lD717BgRaQekyh78QKV9SKsdt638U=","InputHashes":["PSBb4S8lcZQPImBE8id7O4eeN8h3whFn6j1jGYFQciQ=","FLPLXKwQVK16UZsWKzZrjH5kq4sMEtCZqAIkpUwa2pU=","ed7if\u002BhRbLX5eYApJ6Bg4oF5be3kjR0VKVKgf\u002BgmyVo=","XAE6ulqLzJRH50\u002Bc9Nteizd/x9s3rvSHUFwFL265XX4=","talZRfyIQIv4aZc27HTn01\u002B12VbY6LMFOy3\u002B3r448jo=","R7hxHyYox4qeYIBY\u002Bo3l0eo8ZIIfGZeN7PS3V61Q7Ks="],"CachedAssets":{},"CachedCopyCandidates":{}}
|
||||
Reference in New Issue
Block a user