483 lines
16 KiB
C#
483 lines
16 KiB
C#
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)
|
|
{
|
|
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)
|
|
{
|
|
return NotFound(id);
|
|
}
|
|
if (photo.Length > 0)
|
|
{
|
|
var file = WrapFormFile(photo);
|
|
if (file == null)
|
|
{
|
|
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);
|
|
}
|
|
SaveDatabase();
|
|
|
|
try
|
|
{
|
|
await ExecuteTransaction(async token =>
|
|
{
|
|
var cover = new PhotoItem
|
|
{
|
|
FlowerId = id,
|
|
RecordId = record.Id,
|
|
FileType = file.FileType,
|
|
FileName = file.Filename,
|
|
Path = file.Path,
|
|
DateUploadUnixTime = now
|
|
};
|
|
AddPhotoItem(cover);
|
|
|
|
await WriteToFile(user.Id, id, file, token);
|
|
});
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
return Problem(ex.ToString(), "api/flower/add_cover");
|
|
// TODO: Logger
|
|
}
|
|
}
|
|
|
|
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">事件类型 id, 0 为封面</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);
|
|
}
|
|
}
|