flower-story/Server/Controller/FlowerApiController.cs
2023-05-25 21:54:40 +08:00

484 lines
16 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Blahblah.FlowerStory.Server.Data;
using Blahblah.FlowerStory.Server.Data.Model;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
namespace Blahblah.FlowerStory.Server.Controller;
/// <summary>
/// 花草相关 API 服务
/// </summary>
[ApiController]
[Produces("application/json")]
[Route("api/flower")]
public class FlowerApiController : BaseController
{
/// <inheritdoc/>
public FlowerApiController(FlowerDatabase database, ILogger<BaseController>? logger = null) : base(database, logger)
{
}
/// <summary>
/// 获取用户名下所有符合条件的花草
/// </summary>
/// <remarks>
/// 请求示例:
///
/// GET /api/flower/query
/// Authorization: authorization id
///
/// 参数:
///
/// cid: int?
/// key: string?
/// from: long?
/// to: long?
/// cfrom: decimal?
/// cto: decimal?
/// p: bool?
///
/// </remarks>
/// <param name="categoryId">类别 id</param>
/// <param name="key">查询关键字</param>
/// <param name="buyFrom">起始购买日期</param>
/// <param name="buyTo">结束购买日期</param>
/// <param name="costFrom">开销最小值</param>
/// <param name="costTo">开销最大值</param>
/// <param name="includePhoto">是否包含封面图片</param>
/// <returns>会话有效则返回符合条件的花草集</returns>
/// <response code="200">返回符合条件的花草集</response>
/// <response code="401">未找到登录会话或已过期</response>
/// <response code="403">用户已禁用</response>
/// <response code="404">未找到关联用户</response>
[Route("query", Name = "queryFlowers")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[HttpGet]
[ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
public ActionResult<FlowerItem[]> GetFlowers(
[FromQuery(Name = "cid")] int? categoryId,
[FromQuery] string? key,
[FromQuery(Name = "from")] long? buyFrom,
[FromQuery(Name = "to")] long? buyTo,
[FromQuery(Name = "cfrom")] decimal? costFrom,
[FromQuery(Name = "cto")] decimal? costTo,
[FromQuery(Name = "p")] bool? includePhoto)
{
var (result, user) = CheckPermission();
if (result != null)
{
return result;
}
if (user == null)
{
return NotFound();
}
SaveDatabase();
var flowers = database.Flowers.Where(f => f.OwnerId == user.Id);
if (categoryId != null)
{
flowers = flowers.Where(f => f.CategoryId == categoryId);
}
if (key != null)
{
flowers = flowers.Where(f =>
f.Name.ToLower().Contains(key.ToLower()) ||
f.Purchase != null &&
f.Purchase.ToLower().Contains(key.ToLower()));
}
if (buyFrom != null)
{
flowers = flowers.Where(f => f.DateBuyUnixTime >= buyFrom);
}
if (buyTo != null)
{
flowers = flowers.Where(f => f.DateBuyUnixTime <= buyTo);
}
if (costFrom != null)
{
flowers = flowers.Where(f => f.Cost != null && f.Cost >= costFrom);
}
if (costTo != null)
{
flowers = flowers.Where(f => f.Cost != null && f.Cost <= costTo);
}
if (includePhoto == true)
{
foreach (var f in flowers)
{
f.Photos = database.Photos.Where(p =>
database.Records.Any(r =>
r.FlowerId == f.Id && r.EventId == EventCover && r.Id == p.RecordId)).ToList();
}
}
return Ok(flowers.ToArray());
}
/// <summary>
/// 移除用户的花草
/// </summary>
/// <remarks>
/// 请求示例:
///
/// DELETE /api/flower/remove
/// Authorization: authorization id
///
/// 参数:
///
/// id: int
///
/// </remarks>
/// <param name="id">花草唯一 id</param>
/// <returns>会话有效则返回操作影响的数据库行数</returns>
/// <response code="200">返回操作影响的数据库行数</response>
/// <response code="401">未找到登录会话或已过期</response>
/// <response code="403">用户已禁用</response>
/// <response code="404">未找到关联用户</response>
[Route("remove", Name = "removeFlower")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[HttpDelete]
public ActionResult<int> RemoveFlower([FromQuery][Required] int id)
{
var (result, user) = CheckPermission();
if (result != null)
{
return result;
}
if (user == null)
{
return NotFound();
}
//database.Records.Where(r => r.OwnerId == user.Id && r.FlowerId == id).ExecuteDelete();
var count = database.Flowers.Where(f => f.OwnerId == user.Id && f.Id == id).ExecuteDelete();
SaveDatabase();
return Ok(count);
}
/// <summary>
/// 批量移除用户的花草
/// </summary>
/// <remarks>
/// 请求示例:
///
/// POST /api/flower/remove
/// Authorization: authorization id
/// [
/// 2, 4, 5, 11
/// ]
///
/// </remarks>
/// <param name="ids">要移除的花草唯一 id 的数组</param>
/// <returns>会话有效则返回操作影响的数据库行数</returns>
/// <response code="200">返回操作影响的数据库行数</response>
/// <response code="401">未找到登录会话或已过期</response>
/// <response code="403">用户已禁用</response>
/// <response code="404">未找到关联用户</response>
[Route("removeany", Name = "removeFlowers")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[HttpPost]
[Consumes("application/json")]
public ActionResult<int> RemoveFlower([FromBody] int[] ids)
{
var (result, user) = CheckPermission();
if (result != null)
{
return result;
}
if (user == null)
{
return NotFound();
}
//database.Records.Where(r => r.OwnerId == user.Id && ids.Contains(r.FlowerId)).ExecuteDelete();
var count = database.Flowers.Where(f => f.OwnerId == user.Id && ids.Contains(f.Id)).ExecuteDelete();
SaveDatabase();
return Ok(count);
}
/// <summary>
/// 用户添加花草
/// </summary>
/// <remarks>
/// 请求示例:
///
/// POST /api/flower/add
/// Authorization: authorization id
/// {
/// "categoryId": 0,
/// "name": "玛格丽特",
/// "dateBuy": 1684919954743,
/// "cost": 5.00,
/// "purchase": "花鸟市场"
/// }
///
/// </remarks>
/// <param name="flower">花草参数</param>
/// <returns>添加成功则返回已添加的花草对象</returns>
/// <response code="200">返回已添加的花草对象</response>
/// <response code="401">未找到登录会话或已过期</response>
/// <response code="403">用户已禁用</response>
/// <response code="404">未找到关联用户</response>
[Route("add", Name = "addFlower")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[HttpPost]
[Consumes("application/json")]
public ActionResult<FlowerItem> AddFlower([FromBody] FlowerParameter flower)
{
var (result, user) = CheckPermission();
if (result != null)
{
return result;
}
if (user == null)
{
return NotFound();
}
var item = new FlowerItem
{
OwnerId = user.Id,
CategoryId = flower.CategoryId,
Name = flower.Name,
DateBuyUnixTime = flower.DateBuy,
Cost = flower.Cost,
Purchase = flower.Purchase
};
database.Flowers.Add(item);
SaveDatabase();
return Ok(item);
}
/// <summary>
/// 修改花草
/// </summary>
/// <remarks>
/// 请求示例:
///
/// PUT /api/flower/update
/// Authorization: authorization id
/// {
/// "id": 0,
/// "categoryId": 1,
/// "name": "姬小菊",
/// "dateBuy": 1684935276117,
/// "cost": 15.00,
/// "purchase": null
/// }
///
/// </remarks>
/// <param name="update">修改参数</param>
/// <returns>修改成功则返回已修改的花草对象</returns>
/// <response code="200">返回已修改的花草对象</response>
/// <response code="401">未找到登录会话或已过期</response>
/// <response code="403">用户已禁用</response>
/// <response code="404">未找到关联用户或者未找到将修改的花草对象</response>
[Route("update", Name = "updateFlower")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[HttpPut]
[Consumes("application/json")]
public ActionResult<FlowerItem> Update([FromBody] FlowerUpdateParameter update)
{
var (result, user) = CheckPermission();
if (result != null)
{
return result;
}
if (user == null)
{
return NotFound();
}
var flower = database.Flowers.SingleOrDefault(f => f.Id == update.Id && f.OwnerId == user.Id);
if (flower == null)
{
SaveDatabase();
return NotFound(update.Id);
}
flower.CategoryId = update.CategoryId;
flower.Name = update.Name;
flower.DateBuyUnixTime = update.DateBuy;
flower.Cost = update.Cost;
flower.Purchase = update.Purchase;
SaveDatabase();
return Ok(user);
}
/// <summary>
/// 添加花草封面
/// </summary>
/// <remarks>
/// 请求示例:
///
/// POST /api/flower/add_cover
/// Authorization: authorization id
///
/// 参数:
///
/// id: int
/// photo: IFormFile
///
/// </remarks>
/// <param name="id">花草唯一 id</param>
/// <param name="photo">封面图片</param>
/// <returns>修改成功则返回 HTTP 204</returns>
/// <response code="204">修改成功</response>
/// <response code="400">照片格式非法</response>
/// <response code="401">未找到登录会话或已过期</response>
/// <response code="403">用户已禁用</response>
/// <response code="404">未找到关联用户或者关联的花草</response>
/// <response code="413">提交正文过大</response>
[Route("add_cover", Name = "addFlowerCover")]
[ProducesResponseType(StatusCodes.Status204NoContent)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[ProducesResponseType(StatusCodes.Status413PayloadTooLarge)]
[HttpPost]
[Consumes("multipart/form-data")]
[RequestSizeLimit(5 * 1024 * 1024)]
public async Task<ActionResult> UploadCovers([Required][FromQuery] int id, [Required] IFormFile photo)
{
var (result, user) = CheckPermission();
if (result != null)
{
return result;
}
if (user == null)
{
return NotFound();
}
var flower = database.Flowers.SingleOrDefault(f => f.Id == id && f.OwnerId == user.Id);
if (flower == null)
{
SaveDatabase();
return NotFound(id);
}
if (photo.Length > 0)
{
var file = WrapFormFile(photo);
if (file == null)
{
SaveDatabase();
return BadRequest();
}
var now = user.ActiveDateUnixTime ?? DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
var record = database.Records.SingleOrDefault(r => r.FlowerId == id && r.EventId == EventCover);
if (record == null)
{
record = new RecordItem
{
OwnerId = user.Id,
FlowerId = id,
EventId = EventCover,
DateUnixTime = now,
ByUserId = user.Id,
ByUserName = user.Name
//Memo = ""
};
database.Records.Add(record);
}
var cover = new PhotoItem
{
FlowerId = id,
Record = record,
FileType = file.FileType,
FileName = file.Filename,
Path = file.Path,
DateUploadUnixTime = now
};
database.Photos.Add(cover);
try
{
await WriteToFile(user.Id, id, file);
}
catch (Exception ex)
{
SaveDatabase();
return Problem(ex.ToString(), "api/flower/add_cover");
// TODO: Logger
}
}
SaveDatabase();
return NoContent();
}
/// <summary>
/// 获取花草特定类型事件的照片列表
/// </summary>
/// <remarks>
/// 请求示例:
///
/// GET /api/flower/photos
/// Authorization: authorization id
///
/// 参数:
///
/// id: int
/// eid: int?
///
/// </remarks>
/// <param name="id">花草唯一 id</param>
/// <param name="eventId">事件类型 id0 为封面</param>
/// <returns>验证通过则返回花草特定类型事件的照片列表</returns>
/// <response code="200">返回花草特定类型事件的照片列表</response>
/// <response code="401">未找到登录会话或已过期</response>
/// <response code="403">用户已禁用</response>
/// <response code="404">未找到关联用户或者未找到花草对象</response>
[Route("photos", Name = "getFlowerPhotos")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status403Forbidden)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[HttpGet]
[ResponseCache(NoStore = true, Location = ResponseCacheLocation.None)]
public ActionResult<PhotoItem[]> GetCovers([Required][FromQuery] int id, [FromQuery(Name = "eid")] int? eventId = 0)
{
var (result, user) = CheckPermission();
if (result != null)
{
return result;
}
if (user == null)
{
return NotFound();
}
SaveDatabase();
var photos = database.Photos.Where(p => database.Records.Any(r => r.FlowerId == id && r.EventId == eventId && r.OwnerId == user.Id));
return Ok(photos);
}
}