mirror of
https://github.com/Rain-kl/OpenFlare.git
synced 2026-09-30 06:16:37 +08:00
200 lines
5.7 KiB
Go
200 lines
5.7 KiB
Go
// Copyright 2026 Arctel.net
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package model
|
|
|
|
import (
|
|
"crypto/rand"
|
|
"crypto/sha256"
|
|
"encoding/hex"
|
|
"fmt"
|
|
|
|
"time"
|
|
|
|
"Wavelet/core/contracts"
|
|
)
|
|
|
|
const (
|
|
tokenByteLength = 24
|
|
maskThreshold = 8
|
|
)
|
|
|
|
// User represents a user identity view.
|
|
type User struct {
|
|
ID uint64 `json:"id,string" gorm:"primaryKey"`
|
|
Username string `json:"username"`
|
|
Password string `json:"-"`
|
|
Nickname string `json:"nickname"`
|
|
Email string `json:"email"`
|
|
IsAdmin bool `json:"is_admin"`
|
|
IsActive bool `json:"is_active"`
|
|
LastLoginAt time.Time `json:"last_login_at"`
|
|
}
|
|
|
|
func (User) TableName() string {
|
|
return "w_users"
|
|
}
|
|
|
|
func (u *User) SetEncryptedPassword(pwd string) error {
|
|
u.Password = pwd
|
|
return nil
|
|
}
|
|
|
|
// AccessToken represents an access token view.
|
|
type AccessToken struct {
|
|
ID uint64 `json:"id" gorm:"primaryKey"`
|
|
UserID uint64 `json:"user_id"`
|
|
Name string `json:"name"`
|
|
Token string `json:"token"`
|
|
MaskedToken string `json:"masked_token"`
|
|
TokenHash string `json:"token_hash"`
|
|
IsAdmin bool `json:"is_admin"`
|
|
ExpiredAt time.Time `json:"expired_at"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
func (AccessToken) TableName() string {
|
|
return "w_access_tokens"
|
|
}
|
|
|
|
// AuthSource represents an authentication source view.
|
|
type AuthSource struct {
|
|
ID uint64 `json:"id"`
|
|
Name string `json:"name"`
|
|
Type string `json:"type"`
|
|
DisplayName string `json:"display_name"`
|
|
IconURL string `json:"icon_url"`
|
|
IsActive bool `json:"is_active"`
|
|
}
|
|
|
|
// TaskExecution represents task execution entity.
|
|
type TaskExecution struct {
|
|
ID uint64 `json:"id" gorm:"primaryKey"`
|
|
TaskID string `json:"task_id" gorm:"size:64;index"`
|
|
TaskType string `json:"task_type" gorm:"size:100;index"`
|
|
TaskName string `json:"task_name" gorm:"size:255"`
|
|
Status string `json:"status" gorm:"size:20;index"`
|
|
Retryable bool `json:"retryable"`
|
|
MaxRetry int `json:"max_retry"`
|
|
RetryCount int `json:"retry_count"`
|
|
Log string `json:"log" gorm:"type:text"`
|
|
ErrorMessage string `json:"error_message" gorm:"type:text"`
|
|
Result string `json:"result" gorm:"type:text"`
|
|
StartedAt *time.Time `json:"started_at"`
|
|
FinishedAt *time.Time `json:"finished_at"`
|
|
Duration int64 `json:"duration"`
|
|
Payload string `json:"payload" gorm:"type:text"`
|
|
TriggeredBy string `json:"triggered_by" gorm:"size:100"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
func (TaskExecution) TableName() string {
|
|
return "w_task_executions"
|
|
}
|
|
|
|
type UploadStatus = string
|
|
|
|
const (
|
|
UploadStatusPending UploadStatus = "pending"
|
|
UploadStatusUsed UploadStatus = "used"
|
|
UploadStatusDeleted UploadStatus = "deleted"
|
|
)
|
|
|
|
// UploadMetadata represents upload metadata JSON.
|
|
type UploadMetadata = contracts.UploadMetadataDTO
|
|
|
|
// Upload represents file upload entity.
|
|
type Upload struct {
|
|
ID uint64 `json:"id" gorm:"primaryKey"`
|
|
UserID uint64 `json:"user_id" gorm:"index"`
|
|
FileName string `json:"file_name" gorm:"size:255"`
|
|
FilePath string `json:"file_path" gorm:"size:500"`
|
|
MimeType string `json:"mime_type" gorm:"size:100"`
|
|
Size int64 `json:"size"`
|
|
Hash string `json:"hash" gorm:"size:64"`
|
|
Status string `json:"status" gorm:"type:varchar(20)"`
|
|
Type string `json:"type" gorm:"size:50;index"`
|
|
Metadata contracts.UploadMetadataDTO `json:"metadata"`
|
|
CreatedAt time.Time `json:"created_at"`
|
|
UpdatedAt time.Time `json:"updated_at"`
|
|
}
|
|
|
|
func (Upload) TableName() string {
|
|
return "w_uploads"
|
|
}
|
|
|
|
func (u *Upload) ToDTO() contracts.UploadDTO {
|
|
return contracts.UploadDTO{
|
|
ID: u.ID,
|
|
UserID: u.UserID,
|
|
FileName: u.FileName,
|
|
FilePath: u.FilePath,
|
|
MimeType: u.MimeType,
|
|
Size: u.Size,
|
|
Hash: u.Hash,
|
|
Status: u.Status,
|
|
Type: u.Type,
|
|
Metadata: u.Metadata,
|
|
CreatedAt: u.CreatedAt,
|
|
UpdatedAt: u.UpdatedAt,
|
|
}
|
|
}
|
|
|
|
func FromUploadDTO(d contracts.UploadDTO) Upload {
|
|
return Upload{
|
|
ID: d.ID,
|
|
UserID: d.UserID,
|
|
FileName: d.FileName,
|
|
FilePath: d.FilePath,
|
|
MimeType: d.MimeType,
|
|
Size: d.Size,
|
|
Hash: d.Hash,
|
|
Status: d.Status,
|
|
Type: d.Type,
|
|
Metadata: d.Metadata,
|
|
CreatedAt: d.CreatedAt,
|
|
UpdatedAt: d.UpdatedAt,
|
|
}
|
|
}
|
|
|
|
const UploadStatDimensionTotal = "total"
|
|
|
|
// UploadStat tracks upload statistics by dimension.
|
|
type UploadStat struct {
|
|
ID uint64 `gorm:"primaryKey"`
|
|
Dimension string `gorm:"size:50;not null"`
|
|
TargetID uint64 `gorm:"not null"`
|
|
TotalSize int64 `gorm:"not null"`
|
|
FileCount int `gorm:"not null"`
|
|
}
|
|
|
|
func (UploadStat) TableName() string {
|
|
return "w_upload_stats"
|
|
}
|
|
|
|
// GenerateTokenString 生成加密安全的随机 Token 值
|
|
func GenerateTokenString() (string, error) {
|
|
bytes := make([]byte, tokenByteLength)
|
|
if _, err := rand.Read(bytes); err != nil {
|
|
return "", err
|
|
}
|
|
return "at_" + hex.EncodeToString(bytes), nil
|
|
}
|
|
|
|
// HashToken 计算 Token 的 SHA-256 哈希值用于数据库存储与查询
|
|
func HashToken(token string) string {
|
|
h := sha256.New()
|
|
h.Write([]byte(token))
|
|
return hex.EncodeToString(h.Sum(nil))
|
|
}
|
|
|
|
// MaskTokenString 生成脱敏显示的 Token,仅保留前缀和最后四位
|
|
func MaskTokenString(token string) string {
|
|
if len(token) <= maskThreshold {
|
|
return "at_****"
|
|
}
|
|
return fmt.Sprintf("%s...%s", token[:7], token[len(token)-4:])
|
|
}
|