feat(image): add permission setting to EditImageDialog

This commit is contained in:
ShiYu
2025-06-12 00:10:07 +08:00
parent 853efaa2fe
commit d4bf9493c1
6 changed files with 50 additions and 23 deletions
+11 -15
View File
@@ -1,4 +1,3 @@
using System.Text.Json.Serialization;
using Foxel.Controllers; using Foxel.Controllers;
using Foxel.Models; using Foxel.Models;
using Foxel.Models.DataBase; using Foxel.Models.DataBase;
@@ -8,8 +7,7 @@ using Foxel.Services.Media;
using Foxel.Services.Storage; using Foxel.Services.Storage;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using System.Text.Json; // Added for JsonSerializer in GetTelegramFile if it were kept using Foxel.Services.Configuration;
using Foxel.Services.Configuration; // Added for IConfigService
namespace Foxel.Api; namespace Foxel.Api;
@@ -17,8 +15,6 @@ namespace Foxel.Api;
[Route("api/picture")] [Route("api/picture")]
public class PictureController(IPictureService pictureService, IStorageService storageService, ILogger<PictureController> logger, IConfigService configuration) : BaseApiController public class PictureController(IPictureService pictureService, IStorageService storageService, ILogger<PictureController> logger, IConfigService configuration) : BaseApiController
{ {
private readonly ILogger<PictureController> _logger = logger;
[HttpGet("get_pictures")] [HttpGet("get_pictures")]
public async Task<ActionResult<PaginatedResult<PictureResponse>>> GetPictures( public async Task<ActionResult<PaginatedResult<PictureResponse>>> GetPictures(
[FromQuery] FilteredPicturesRequest request) [FromQuery] FilteredPicturesRequest request)
@@ -203,8 +199,8 @@ public class PictureController(IPictureService pictureService, IStorageService s
if (currentUserId == null) if (currentUserId == null)
return Error<PictureResponse>("无法识别用户信息"); return Error<PictureResponse>("无法识别用户信息");
var (picture, ownerId) = await pictureService.UpdatePictureAsync( (PictureResponse picture, int? ownerId) = await pictureService.UpdatePictureAsync(
request.Id, request.Name, request.Description, request.Tags); request.Id, request.Name, request.Description, request.Tags, (PermissionType?)request.Permission);
// 权限验证 // 权限验证
if (ownerId.HasValue && ownerId.Value != currentUserId.Value) if (ownerId.HasValue && ownerId.Value != currentUserId.Value)
@@ -281,7 +277,7 @@ public class PictureController(IPictureService pictureService, IStorageService s
var picture = await pictureService.GetPictureByIdAsync(pictureId); var picture = await pictureService.GetPictureByIdAsync(pictureId);
if (picture == null) if (picture == null)
{ {
_logger.LogWarning("GetPictureFile: Picture with ID {PictureId} not found.", pictureId); logger.LogWarning("GetPictureFile: Picture with ID {PictureId} not found.", pictureId);
return NotFound("Picture not found."); return NotFound("Picture not found.");
} }
var currentUserId = GetUserIdFromCookie(); var currentUserId = GetUserIdFromCookie();
@@ -289,7 +285,7 @@ public class PictureController(IPictureService pictureService, IStorageService s
{ {
if (currentUserId == null || picture.UserId != currentUserId.Value) if (currentUserId == null || picture.UserId != currentUserId.Value)
{ {
_logger.LogWarning("GetPictureFile: User {UserId} forbidden to access picture {PictureId}.", currentUserId, pictureId); logger.LogWarning("GetPictureFile: User {UserId} forbidden to access picture {PictureId}.", currentUserId, pictureId);
return Forbid(); return Forbid();
} }
} }
@@ -302,7 +298,7 @@ public class PictureController(IPictureService pictureService, IStorageService s
if (string.IsNullOrEmpty(tempFilePath) || !System.IO.File.Exists(tempFilePath)) if (string.IsNullOrEmpty(tempFilePath) || !System.IO.File.Exists(tempFilePath))
{ {
_logger.LogError("GetPictureFile: Failed to download file or file not found at temp path for picture ID {PictureId}. TempPath: {TempPath}", pictureId, tempFilePath); logger.LogError("GetPictureFile: Failed to download file or file not found at temp path for picture ID {PictureId}. TempPath: {TempPath}", pictureId, tempFilePath);
return StatusCode(500, "Failed to retrieve file from storage."); return StatusCode(500, "Failed to retrieve file from storage.");
} }
// 4. 确定内容类型 // 4. 确定内容类型
@@ -313,27 +309,27 @@ public class PictureController(IPictureService pictureService, IStorageService s
} }
catch (KeyNotFoundException knfEx) catch (KeyNotFoundException knfEx)
{ {
_logger.LogWarning(knfEx, "GetPictureFile: Resource not found for picture ID {PictureId}.", pictureId); logger.LogWarning(knfEx, "GetPictureFile: Resource not found for picture ID {PictureId}.", pictureId);
return NotFound($"Resource related to picture ID {pictureId} not found."); return NotFound($"Resource related to picture ID {pictureId} not found.");
} }
catch (FileNotFoundException fnfEx) catch (FileNotFoundException fnfEx)
{ {
_logger.LogWarning(fnfEx, "GetPictureFile: File not found in storage for picture ID {PictureId}.", pictureId); logger.LogWarning(fnfEx, "GetPictureFile: File not found in storage for picture ID {PictureId}.", pictureId);
return NotFound("File not found in storage."); return NotFound("File not found in storage.");
} }
catch (NotImplementedException niEx) catch (NotImplementedException niEx)
{ {
_logger.LogError(niEx, "GetPictureFile: DownloadFileAsync not implemented for the storage provider of picture ID {PictureId}.", pictureId); logger.LogError(niEx, "GetPictureFile: DownloadFileAsync not implemented for the storage provider of picture ID {PictureId}.", pictureId);
return StatusCode(501, "File download is not supported for this storage type."); return StatusCode(501, "File download is not supported for this storage type.");
} }
catch (InvalidOperationException ioEx) catch (InvalidOperationException ioEx)
{ {
_logger.LogError(ioEx, "GetPictureFile: Invalid operation for picture ID {PictureId}.", pictureId); logger.LogError(ioEx, "GetPictureFile: Invalid operation for picture ID {PictureId}.", pictureId);
return StatusCode(500, $"Error processing file request: {ioEx.Message}"); return StatusCode(500, $"Error processing file request: {ioEx.Message}");
} }
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "GetPictureFile: Error getting file for picture ID {PictureId}", pictureId); logger.LogError(ex, "GetPictureFile: Error getting file for picture ID {PictureId}", pictureId);
return StatusCode(500, "An error occurred while retrieving the file."); return StatusCode(500, "An error occurred while retrieving the file.");
} }
} }
@@ -1,6 +1,13 @@
namespace Foxel.Models.Request.Picture; using System.Collections.Generic; // Required for List<string>
public record UpdatePictureRequestWithId : UpdatePictureRequest namespace Foxel.Models.Request.Picture
{
public class UpdatePictureRequestWithId
{ {
public int Id { get; set; } public int Id { get; set; }
public string? Name { get; set; }
public string? Description { get; set; }
public List<string>? Tags { get; set; }
public int? Permission { get; set; } // Added Permission property
}
} }
+3 -1
View File
@@ -52,12 +52,14 @@ public interface IPictureService
/// <param name="name">新标题(可选)</param> /// <param name="name">新标题(可选)</param>
/// <param name="description">新描述(可选)</param> /// <param name="description">新描述(可选)</param>
/// <param name="tags">新标签(可选)</param> /// <param name="tags">新标签(可选)</param>
/// <param name="permission">权限</param>
/// <returns>更新后的图片视图模型和所有者ID</returns> /// <returns>更新后的图片视图模型和所有者ID</returns>
Task<(PictureResponse Picture, int? UserId)> UpdatePictureAsync( Task<(PictureResponse Picture, int? UserId)> UpdatePictureAsync(
int pictureId, int pictureId,
string? name = null, string? name = null,
string? description = null, string? description = null,
List<string>? tags = null); List<string>? tags = null,
PermissionType? permission = null);
/// <summary> /// <summary>
/// 收藏图片 /// 收藏图片
+7 -1
View File
@@ -788,7 +788,8 @@ public class PictureService(
int pictureId, int pictureId,
string? name = null, string? name = null,
string? description = null, string? description = null,
List<string>? tags = null) List<string>? tags = null,
PermissionType? permission = null)
{ {
await using var dbContext = await contextFactory.CreateDbContextAsync(); await using var dbContext = await contextFactory.CreateDbContextAsync();
@@ -813,6 +814,11 @@ public class PictureService(
picture.Description = description.Trim(); picture.Description = description.Trim();
} }
if (permission.HasValue)
{
picture.Permission = permission.Value;
}
// 只有当名称或描述发生变化时才更新嵌入向量 // 只有当名称或描述发生变化时才更新嵌入向量
if (!string.IsNullOrWhiteSpace(name) || !string.IsNullOrWhiteSpace(description)) if (!string.IsNullOrWhiteSpace(name) || !string.IsNullOrWhiteSpace(description))
{ {
+1
View File
@@ -88,6 +88,7 @@ export interface UpdatePictureRequest {
name?: string; name?: string;
description?: string; description?: string;
tags?: string[]; tags?: string[];
permission?: number;
} }
// 获取图片列表 // 获取图片列表
+17 -2
View File
@@ -28,7 +28,8 @@ const EditImageDialog: React.FC<EditImageDialogProps> = ({
form.setFieldsValue({ form.setFieldsValue({
name: image.name, name: image.name,
description: image.description, description: image.description,
tags: image.tags || [] tags: image.tags || [],
permission: image.permission === undefined ? 0 : image.permission // Default to Public if undefined
}); });
} }
}, [visible, image, form]); }, [visible, image, form]);
@@ -45,7 +46,8 @@ const EditImageDialog: React.FC<EditImageDialogProps> = ({
id: image.id, id: image.id,
name: values.name, name: values.name,
description: values.description, description: values.description,
tags: values.tags tags: values.tags,
permission: values.permission
}); });
if (result.success) { if (result.success) {
@@ -165,6 +167,19 @@ const EditImageDialog: React.FC<EditImageDialogProps> = ({
))} ))}
</Select> </Select>
</Form.Item> </Form.Item>
<Form.Item
name="permission"
label="权限设置"
rules={[{ required: true, message: '请选择权限' }]}
>
<Select placeholder="选择权限">
<Option value={0}></Option>
<Option value={1}></Option>
<Option value={2}></Option>
</Select>
</Form.Item>
<Form.Item className="edit-form-actions"> <Form.Item className="edit-form-actions">
<Button onClick={onClose} style={{ marginRight: 8 }}></Button> <Button onClick={onClose} style={{ marginRight: 8 }}></Button>
<Button <Button