using Blahblah.FlowerStory.Server.Data; using Microsoft.AspNetCore.Mvc; using System.ComponentModel.DataAnnotations; using System.Net; namespace Blahblah.FlowerStory.Server.Controller; /// /// 图片相关服务 /// [Route("photo")] public class ImageController : BaseController { static byte[]? emptyAvatar; static byte[] EmptyAvatar => emptyAvatar ??= GetEmbeddedData("image.avatar.jpg"); /// public ImageController(FlowerDatabase database, ILogger? logger = null) : base(database, logger) { } /// /// 请求自己的头像 /// /// /// 请求示例: /// /// GET /photo/my_avatar /// Authorization: authorization id /// /// /// 认证通过则显示自己的头像 /// 返回头像 /// 认证失败 [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"); } /// /// 请求用户头像 /// /// /// 请求示例: /// /// GET /photo/avatar/2.jpg /// /// /// 用户唯一 id /// 认证通过则显示用户头像 /// 返回头像 /// 认证失败 [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"); } /// /// 请求花草照片 /// /// /// 请求示例: /// /// GET /photo/flower/1/test.jpg /// /// /// 花草唯一 id /// 照片名称 /// 是否为缩略图 /// 认证通过则显示花草照片 /// 返回花草照片 /// 认证失败 /// 未找到花草照片 [Route("flower/{fid}/{name}", Name = "getFlowerPhoto")] [ProducesResponseType(StatusCodes.Status200OK)] [ProducesResponseType(StatusCodes.Status401Unauthorized)] [ProducesResponseType(StatusCodes.Status404NotFound)] [HttpGet] public async Task 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(); } }