cyi-box: Memphis-style toolbox admin platform
Go(fun)+SQLite backend, Vue 3 frontend. Modules: dashboard, pay gateway (Epay-compatible + CDK stock), license/card system (per-app appid, domain binding), AI memory bank with built-in MCP server (/mcp, FTS5 search, signed read links), server SSH monitor + terminal + SFTP, proxy pool with protocol-level alive checks, DB manager (mysql/pg/sqlite + SQL autocomplete + import/export), disk share, vault (AES-GCM + TOTP), bookmarks, dev tools. Generated with [Devin](https://devin.ai) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
package store
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"github.com/cyi-cc/cyi-box/backend/internal/db"
|
||||
)
|
||||
|
||||
// ---- disk 网盘 ----
|
||||
|
||||
type File struct {
|
||||
Id int64
|
||||
UserID int64
|
||||
Name string // 原始文件名
|
||||
Stored string // 落盘文件名(随机)
|
||||
Size int64
|
||||
Mime string
|
||||
CreatedAt int64
|
||||
}
|
||||
|
||||
type Share struct {
|
||||
Id int64
|
||||
Code string
|
||||
FileID int64
|
||||
UserID int64
|
||||
FileName string
|
||||
ExpiresAt int64 // 0 = 永久
|
||||
Downloads int64
|
||||
CreatedAt int64
|
||||
}
|
||||
|
||||
func fileFromRow(f db.File) File {
|
||||
return File{
|
||||
Id: f.ID, UserID: f.UserID, Name: f.Name, Stored: f.Stored,
|
||||
Size: f.Size, Mime: f.Mime, CreatedAt: f.CreatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func shareFromRow(s db.Share) Share {
|
||||
return Share{
|
||||
Id: s.ID, Code: s.Code, FileID: s.FileID, UserID: s.UserID,
|
||||
FileName: s.FileName, ExpiresAt: s.ExpiresAt,
|
||||
Downloads: s.Downloads, CreatedAt: s.CreatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Store) InsertFile(f *File) error {
|
||||
id, err := s.q.InsertFile(storeCtx, db.InsertFileParams{
|
||||
UserID: f.UserID, Name: f.Name, Stored: f.Stored,
|
||||
Size: f.Size, Mime: f.Mime, CreatedAt: time.Now().Unix(),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
f.Id = id
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) ListFiles(userID int64) ([]File, error) {
|
||||
rows, err := s.q.ListFiles(storeCtx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
files := make([]File, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
files = append(files, fileFromRow(r))
|
||||
}
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func (s *Store) GetFile(id int64) (File, error) {
|
||||
f, err := s.q.GetFile(storeCtx, id)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return File{}, ErrNotFound
|
||||
}
|
||||
return fileFromRow(f), err
|
||||
}
|
||||
|
||||
// DeleteFile 仅限属主;返回被删行数(0 = 不存在或非属主)
|
||||
func (s *Store) DeleteFile(id, userID int64) (int64, error) {
|
||||
return s.q.DeleteFile(storeCtx, db.DeleteFileParams{ID: id, UserID: userID})
|
||||
}
|
||||
|
||||
func (s *Store) InsertShare(sh *Share) error {
|
||||
sh.CreatedAt = time.Now().Unix()
|
||||
id, err := s.q.InsertShare(storeCtx, db.InsertShareParams{
|
||||
Code: sh.Code, FileID: sh.FileID, UserID: sh.UserID,
|
||||
FileName: sh.FileName, ExpiresAt: sh.ExpiresAt,
|
||||
CreatedAt: sh.CreatedAt,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
sh.Id = id
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Store) ListShares(userID int64) ([]Share, error) {
|
||||
rows, err := s.q.ListShares(storeCtx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
shares := make([]Share, 0, len(rows))
|
||||
for _, r := range rows {
|
||||
shares = append(shares, shareFromRow(r))
|
||||
}
|
||||
return shares, nil
|
||||
}
|
||||
|
||||
// ShareFileView 公开下载需要的联表视图
|
||||
type ShareFileView struct {
|
||||
Share
|
||||
Stored string
|
||||
Size int64
|
||||
Mime string
|
||||
}
|
||||
|
||||
func (s *Store) GetShareFile(code string) (ShareFileView, error) {
|
||||
r, err := s.q.GetShareByCode(storeCtx, code)
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return ShareFileView{}, ErrNotFound
|
||||
}
|
||||
if err != nil {
|
||||
return ShareFileView{}, err
|
||||
}
|
||||
return ShareFileView{
|
||||
Share: Share{
|
||||
Id: r.ID, Code: r.Code, FileID: r.FileID, UserID: r.UserID,
|
||||
FileName: r.FileName, ExpiresAt: r.ExpiresAt,
|
||||
Downloads: r.Downloads, CreatedAt: r.CreatedAt,
|
||||
},
|
||||
Stored: r.Stored, Size: r.Size, Mime: r.Mime,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *Store) DeleteShare(id, userID int64) (int64, error) {
|
||||
return s.q.DeleteShare(storeCtx, db.DeleteShareParams{ID: id, UserID: userID})
|
||||
}
|
||||
|
||||
func (s *Store) DeleteSharesByFile(fileID int64) error {
|
||||
return s.q.DeleteSharesByFile(storeCtx, fileID)
|
||||
}
|
||||
|
||||
func (s *Store) IncShareDownloads(code string) error {
|
||||
return s.q.IncShareDownloads(storeCtx, code)
|
||||
}
|
||||
Reference in New Issue
Block a user