flower-story/Server/Controller/ImageController.cs
2024-10-12 14:34:11 +08:00

173 lines
5.5 KiB
C#

using Blahblah.FlowerStory.Server.Data;
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
using System.Net;
namespace Blahblah.FlowerStory.Server.Controller;
/// <summary>
/// 图片相关服务
/// </summary>
[Route("photo")]
public class ImageController(FlowerDatabase database, ILogger<ImageController>? logger = null) : BaseController<ImageController>(database, logger)
{
static byte[]? emptyAvatar;
static byte[] EmptyAvatar => emptyAvatar ??= GetEmbeddedData("image.avatar.jpg");
/// <summary>
/// 请求自己的头像
/// </summary>
/// <remarks>
/// 请求示例:
///
/// GET /photo/my_avatar
/// Authorization: authorization id
///
/// </remarks>
/// <returns>认证通过则显示自己的头像</returns>
/// <response code="200">返回头像</response>
/// <response code="401">认证失败</response>
[Route("my_avatar", Name = "getMyAvatar")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[HttpGet]
public ActionResult GetMyAvatar()
{
var (result, token) = CheckToken();
if (result != null)
{
return result;
}
if (token == null)
{
return Unauthorized();
}
var avatar = QueryUserAvatar(token.UserId);
if (avatar?.Length > 0)
{
return File(avatar, "image/jpeg");
}
return File(EmptyAvatar, "image/jpeg");
}
/// <summary>
/// 请求用户头像
/// </summary>
/// <remarks>
/// 请求示例:
///
/// GET /photo/avatar/2.jpg
///
/// </remarks>
/// <param name="uid">用户唯一 id</param>
/// <returns>认证通过则显示用户头像</returns>
/// <response code="200">返回头像</response>
/// <response code="401">认证失败</response>
[Route("avatar/{uid}.jpg", Name = "getAvatar")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[HttpGet]
public ActionResult GetAvatar([Required] int uid)
{
//var (result, token) = CheckToken();
//if (result != null)
//{
// return result;
//}
//if (token == null)
//{
// return Unauthorized();
//}
var avatar = QueryUserAvatar(uid);
if (avatar?.Length > 0)
{
return File(avatar, "image/jpeg");
}
return File(EmptyAvatar, "image/jpeg");
}
/// <summary>
/// 请求花草照片
/// </summary>
/// <remarks>
/// 请求示例:
///
/// GET /photo/flower/1/test.jpg
///
/// </remarks>
/// <param name="fid">花草唯一 id</param>
/// <param name="name">照片名称</param>
/// <param name="thumb">是否为缩略图</param>
/// <returns>认证通过则显示花草照片</returns>
/// <response code="200">返回花草照片</response>
/// <response code="401">认证失败</response>
/// <response code="404">未找到花草照片</response>
[Route("flower/{fid}/{name}", Name = "getFlowerPhoto")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status401Unauthorized)]
[ProducesResponseType(StatusCodes.Status404NotFound)]
[HttpGet]
public async Task<ActionResult> GetFlowerPhoto([Required] int fid, [Required] string name, [FromQuery] string? thumb = null)
{
//var (result, token) = CheckToken();
//if (result != null)
//{
// return result;
//}
//if (token == null)
//{
// return Unauthorized();
//}
#if PRODUCTION
var referrer = Request.Headers.Referer.ToString();
if (string.IsNullOrEmpty(referrer))
{
return BadRequest();
}
if (!referrer.StartsWith("https://app.tsanie.org"))
{
return Forbid();
}
#endif
var filename = WebUtility.UrlEncode(name);
var directory = Path.Combine(Program.DataPath, "uploads", fid.ToString());
var original = Path.Combine(directory, filename);
var thumbnail = Path.Combine(directory, $"{filename}.thumb");
if (!string.IsNullOrEmpty(thumb))
{
if (System.IO.File.Exists(thumbnail))
{
var thumbnailData = await System.IO.File.ReadAllBytesAsync(thumbnail);
return File(thumbnailData, "image/jpeg");
}
else if (System.IO.File.Exists(original))
{
try
{
var originalData = await System.IO.File.ReadAllBytesAsync(original);
var thumbnailData = CreateThumbnail(originalData);
await System.IO.File.WriteAllBytesAsync(thumbnail, thumbnailData);
return File(thumbnailData, "image/jpeg");
}
catch (Exception ex)
{
logger?.LogWarning(ex, "failed to create thumbnail for flower: {fid}, name: {name}, error: {message}", fid, name, ex.Message);
}
}
return NotFound();
}
if (System.IO.File.Exists(original))
{
var data = await System.IO.File.ReadAllBytesAsync(original);
return Path.GetExtension(original).ToLower() switch
{
".png" => File(data, "image/png"),
_ => File(data, "image/jpeg"),
};
}
return NotFound();
}
}