Skip to content

Commit 8aae2b2

Browse files
committed
feat(admin): add transfer log tab and polish storage ui
1 parent def22f9 commit 8aae2b2

File tree

24 files changed

+1226
-457
lines changed

24 files changed

+1226
-457
lines changed

config.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
base:
2-
name: FileCodeBox
2+
name: 站点
33
description: 开箱即用的文件快传系统
44
keywords: FileCodeBox, 文件快递柜, 口令传送箱, 匿名口令分享文本, 文件
55
port: 12345
@@ -18,13 +18,15 @@ transfer:
1818
upload:
1919
openupload: 1
2020
uploadsize: 10485760
21-
enablechunk: 0
21+
enablechunk: 1
2222
chunksize: 2097152
2323
maxsaveseconds: 0
24+
requirelogin: 1
2425
download:
2526
enableconcurrentdownload: 1
2627
maxconcurrentdownloads: 10
2728
downloadtimeout: 300
29+
requirelogin: 0
2830
storage:
2931
type: ""
3032
storagepath: ""

docs/config.new.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,12 @@ transfer:
1717
enable_chunk: 1
1818
chunk_size: 2097152
1919
max_save_seconds: 0
20+
require_login: 0
2021
download:
2122
enable_concurrent_download: 1
2223
max_concurrent_downloads: 10
2324
download_timeout: 300
25+
require_login: 0
2426

2527
user:
2628
allow_user_registration: 1

internal/config/transfer_config.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,15 @@ type UploadConfig struct {
1313
EnableChunk int `json:"enable_chunk"` // 是否启用分片上传 0-禁用 1-启用
1414
ChunkSize int64 `json:"chunk_size"` // 分片大小(字节)
1515
MaxSaveSeconds int `json:"max_save_seconds"` // 最大保存时间(秒)
16+
RequireLogin int `json:"require_login"` // 上传是否强制登录 0-否 1-是
1617
}
1718

1819
// DownloadConfig 下载配置
1920
type DownloadConfig struct {
2021
EnableConcurrentDownload int `json:"enable_concurrent_download"` // 是否启用并发下载
2122
MaxConcurrentDownloads int `json:"max_concurrent_downloads"` // 最大并发下载数
2223
DownloadTimeout int `json:"download_timeout"` // 下载超时时间(秒)
24+
RequireLogin int `json:"require_login"` // 下载是否强制登录 0-否 1-是
2325
}
2426

2527
// TransferConfig 文件传输配置(包含上传和下载)
@@ -36,6 +38,7 @@ func NewUploadConfig() *UploadConfig {
3638
EnableChunk: 0,
3739
ChunkSize: 2 * 1024 * 1024, // 2MB
3840
MaxSaveSeconds: 0, // 0表示不限制
41+
RequireLogin: 0,
3942
}
4043
}
4144

@@ -45,6 +48,7 @@ func NewDownloadConfig() *DownloadConfig {
4548
EnableConcurrentDownload: 1, // 默认启用
4649
MaxConcurrentDownloads: 10, // 最大10个并发
4750
DownloadTimeout: 300, // 5分钟超时
51+
RequireLogin: 0,
4852
}
4953
}
5054

@@ -86,6 +90,10 @@ func (uc *UploadConfig) Validate() error {
8690
errors = append(errors, "最大保存时间不能为负数")
8791
}
8892

93+
if uc.RequireLogin != 0 && uc.RequireLogin != 1 {
94+
errors = append(errors, "上传登录开关只能是0或1")
95+
}
96+
8997
if len(errors) > 0 {
9098
return fmt.Errorf("上传配置验证失败: %s", strings.Join(errors, "; "))
9199
}
@@ -113,6 +121,10 @@ func (dc *DownloadConfig) Validate() error {
113121
errors = append(errors, "下载超时时间不能超过1小时")
114122
}
115123

124+
if dc.RequireLogin != 0 && dc.RequireLogin != 1 {
125+
errors = append(errors, "下载登录开关只能是0或1")
126+
}
127+
116128
if len(errors) > 0 {
117129
return fmt.Errorf("下载配置验证失败: %s", strings.Join(errors, "; "))
118130
}
@@ -138,6 +150,11 @@ func (uc *UploadConfig) IsChunkEnabled() bool {
138150
return uc.EnableChunk == 1
139151
}
140152

153+
// IsLoginRequired 判断是否需要登录才能上传
154+
func (uc *UploadConfig) IsLoginRequired() bool {
155+
return uc.RequireLogin == 1
156+
}
157+
141158
// GetUploadSizeMB 获取上传大小限制(MB)
142159
func (uc *UploadConfig) GetUploadSizeMB() float64 {
143160
return float64(uc.UploadSize) / (1024 * 1024)
@@ -161,6 +178,11 @@ func (dc *DownloadConfig) IsDownloadConcurrentEnabled() bool {
161178
return dc.EnableConcurrentDownload == 1
162179
}
163180

181+
// IsLoginRequired 判断是否需要登录才能下载
182+
func (dc *DownloadConfig) IsLoginRequired() bool {
183+
return dc.RequireLogin == 1
184+
}
185+
164186
// GetDownloadTimeoutMinutes 获取下载超时时间(分钟)
165187
func (dc *DownloadConfig) GetDownloadTimeoutMinutes() float64 {
166188
return float64(dc.DownloadTimeout) / 60
@@ -174,6 +196,7 @@ func (uc *UploadConfig) Clone() *UploadConfig {
174196
EnableChunk: uc.EnableChunk,
175197
ChunkSize: uc.ChunkSize,
176198
MaxSaveSeconds: uc.MaxSaveSeconds,
199+
RequireLogin: uc.RequireLogin,
177200
}
178201
}
179202

@@ -183,6 +206,7 @@ func (dc *DownloadConfig) Clone() *DownloadConfig {
183206
EnableConcurrentDownload: dc.EnableConcurrentDownload,
184207
MaxConcurrentDownloads: dc.MaxConcurrentDownloads,
185208
DownloadTimeout: dc.DownloadTimeout,
209+
RequireLogin: dc.RequireLogin,
186210
}
187211
}
188212

internal/database/database.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ func InitWithManager(manager *config.ConfigManager) (*gorm.DB, error) {
4545
&models.UploadChunk{},
4646
&models.User{},
4747
&models.UserSession{},
48+
&models.TransferLog{},
4849
)
4950
if err != nil {
5051
return nil, fmt.Errorf("数据库自动迁移失败: %w", err)

internal/handlers/admin.go

Lines changed: 64 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"log"
66
"net"
77
"strconv"
8+
"strings"
89
"time"
910

1011
"github.com/zy84338719/filecodebox/internal/common"
@@ -1164,7 +1165,69 @@ func tcpProbe(address string, timeout time.Duration) error {
11641165
return nil
11651166
}
11661167

1167-
// GetSystemLogs 获取系统日志
1168+
// GetTransferLogs 获取上传/下载审计日志
1169+
func (h *AdminHandler) GetTransferLogs(c *gin.Context) {
1170+
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
1171+
pageSize, _ := strconv.Atoi(c.DefaultQuery("page_size", "20"))
1172+
if page < 1 {
1173+
page = 1
1174+
}
1175+
if pageSize <= 0 {
1176+
pageSize = 20
1177+
} else if pageSize > 200 {
1178+
pageSize = 200
1179+
}
1180+
1181+
operation := strings.TrimSpace(c.DefaultQuery("operation", ""))
1182+
search := strings.TrimSpace(c.DefaultQuery("search", ""))
1183+
1184+
logs, total, err := h.service.GetTransferLogs(page, pageSize, operation, search)
1185+
if err != nil {
1186+
common.InternalServerErrorResponse(c, "获取传输日志失败: "+err.Error())
1187+
return
1188+
}
1189+
1190+
items := make([]web.TransferLogItem, 0, len(logs))
1191+
for _, record := range logs {
1192+
item := web.TransferLogItem{
1193+
ID: record.ID,
1194+
Operation: record.Operation,
1195+
FileCode: record.FileCode,
1196+
FileName: record.FileName,
1197+
FileSize: record.FileSize,
1198+
Username: record.Username,
1199+
IP: record.IP,
1200+
DurationMs: record.DurationMs,
1201+
CreatedAt: record.CreatedAt.Format(time.RFC3339),
1202+
}
1203+
if record.UserID != nil {
1204+
id := *record.UserID
1205+
item.UserID = &id
1206+
}
1207+
items = append(items, item)
1208+
}
1209+
1210+
pages := int64(0)
1211+
if pageSize > 0 {
1212+
pages = (total + int64(pageSize) - 1) / int64(pageSize)
1213+
}
1214+
if pages == 0 {
1215+
pages = 1
1216+
}
1217+
1218+
response := web.TransferLogListResponse{
1219+
Logs: items,
1220+
Pagination: web.PaginationResponse{
1221+
Page: page,
1222+
PageSize: pageSize,
1223+
Total: total,
1224+
Pages: pages,
1225+
},
1226+
}
1227+
1228+
common.SuccessResponse(c, response)
1229+
}
1230+
11681231
func (h *AdminHandler) GetSystemLogs(c *gin.Context) {
11691232
level := c.DefaultQuery("level", "")
11701233
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "100"))

internal/handlers/share.go

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package handlers
22

33
import (
4+
"time"
5+
46
"github.com/zy84338719/filecodebox/internal/common"
57
"github.com/zy84338719/filecodebox/internal/models"
68
"github.com/zy84338719/filecodebox/internal/models/web"
@@ -107,15 +109,18 @@ func (h *ShareHandler) ShareFile(c *gin.Context) {
107109
return
108110
}
109111

112+
userID := utils.GetUserIDFromContext(c)
113+
if h.service.IsUploadLoginRequired() && userID == nil {
114+
common.UnauthorizedResponse(c, "当前配置要求登录后才能上传文件")
115+
return
116+
}
117+
110118
// 解析文件
111119
file, success := utils.ParseFileFromForm(c, "file")
112120
if !success {
113121
return
114122
}
115123

116-
// 检查是否为认证用户上传
117-
userID := utils.GetUserIDFromContext(c)
118-
119124
// 构建服务层请求(这里需要适配服务层的接口)
120125
serviceReq := models.ShareFileRequest{
121126
File: file,
@@ -255,6 +260,7 @@ func (h *ShareHandler) DownloadFile(c *gin.Context) {
255260

256261
if fileCode.Text != "" {
257262
common.SuccessResponse(c, fileCode.Text)
263+
h.service.RecordDownloadLog(fileCode, userID, c.ClientIP(), 0)
258264
return
259265
}
260266

@@ -266,10 +272,13 @@ func (h *ShareHandler) DownloadFile(c *gin.Context) {
266272
return
267273
}
268274

275+
start := time.Now()
269276
if err := storageService.GetFileResponse(c, fileCode); err != nil {
270277
common.NotFoundResponse(c, "文件下载失败: "+err.Error())
271278
return
272279
}
280+
281+
h.service.RecordDownloadLog(fileCode, userID, c.ClientIP(), time.Since(start))
273282
}
274283

275284
// getDisplayFileName 获取用于显示的文件名

internal/handlers/storage.go

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,12 +49,16 @@ func (sh *StorageHandler) GetStorageInfo(c *gin.Context) {
4949
// 尝试附加路径与使用率信息
5050
switch storageType {
5151
case "local":
52-
// 本地存储使用配置中的 StoragePath
53-
detail.StoragePath = sh.storageConfig.StoragePath
52+
// 本地存储使用配置中的 StoragePath,如果未配置则回退到数据目录
53+
path := sh.storageConfig.StoragePath
54+
if path == "" {
55+
path = sh.configManager.Base.DataPath
56+
}
57+
detail.StoragePath = path
5458

5559
// 尝试读取磁盘使用率(若可用)
56-
if sh.storageConfig.StoragePath != "" {
57-
if usagePercent, err := utils.GetUsagePercent(sh.storageConfig.StoragePath); err == nil {
60+
if path != "" {
61+
if usagePercent, err := utils.GetUsagePercent(path); err == nil {
5862
val := int(usagePercent)
5963
detail.UsagePercent = &val
6064
}

internal/models/db/transfer_log.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package db
2+
3+
import "gorm.io/gorm"
4+
5+
// TransferLog 记录上传/下载操作日志
6+
// 当系统要求登录上传/下载时,用于追踪用户行为
7+
// Operation: upload 或 download
8+
// DurationMs: 针对下载记录耗时,上传默认为0
9+
// Username保留冗余信息,便于查询,即使用户被删除仍保留原始名字
10+
type TransferLog struct {
11+
gorm.Model
12+
Operation string `gorm:"size:20;index" json:"operation"`
13+
FileCodeID uint `gorm:"index" json:"file_code_id"`
14+
FileCode string `gorm:"size:255" json:"file_code"`
15+
FileName string `gorm:"size:255" json:"file_name"`
16+
FileSize int64 `json:"file_size"`
17+
UserID *uint `gorm:"index" json:"user_id"`
18+
Username string `gorm:"size:100" json:"username"`
19+
IP string `gorm:"size:45" json:"ip"`
20+
DurationMs int64 `json:"duration_ms"`
21+
}
22+
23+
// TransferLogQuery 查询条件
24+
type TransferLogQuery struct {
25+
Operation string `json:"operation"`
26+
UserID *uint `json:"user_id"`
27+
Search string `json:"search"`
28+
Page int `json:"page"`
29+
PageSize int `json:"page_size"`
30+
}

internal/models/models.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ type (
1414
UploadChunk = db.UploadChunk
1515
User = db.User
1616
UserSession = db.UserSession
17+
TransferLog = db.TransferLog
18+
TransferLogQuery = db.TransferLogQuery
1719

1820
// 服务模型别名
1921
BuildInfo = service.BuildInfo

internal/models/web/admin.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,26 @@ type AdminFileDetail struct {
251251
UploadType string `json:"upload_type"`
252252
}
253253

254+
// TransferLogItem 审计日志单条记录
255+
type TransferLogItem struct {
256+
ID uint `json:"id"`
257+
Operation string `json:"operation"`
258+
FileCode string `json:"file_code"`
259+
FileName string `json:"file_name"`
260+
FileSize int64 `json:"file_size"`
261+
UserID *uint `json:"user_id,omitempty"`
262+
Username string `json:"username"`
263+
IP string `json:"ip"`
264+
DurationMs int64 `json:"duration_ms"`
265+
CreatedAt string `json:"created_at"`
266+
}
267+
268+
// TransferLogListResponse 审计日志列表响应
269+
type TransferLogListResponse struct {
270+
Logs []TransferLogItem `json:"logs"`
271+
Pagination PaginationResponse `json:"pagination"`
272+
}
273+
254274
// MCPStatusResponse MCP状态响应
255275
type MCPStatusResponse struct {
256276
Status string `json:"status"`

0 commit comments

Comments
 (0)