234 lines
6.7 KiB
Go
234 lines
6.7 KiB
Go
package repository
|
|
|
|
import (
|
|
"context"
|
|
"time"
|
|
|
|
"github.com/Wei-Shaw/sub2api/internal/service"
|
|
|
|
"github.com/Wei-Shaw/sub2api/internal/pkg/pagination"
|
|
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
type apiKeyRepository struct {
|
|
db *gorm.DB
|
|
}
|
|
|
|
func NewApiKeyRepository(db *gorm.DB) service.ApiKeyRepository {
|
|
return &apiKeyRepository{db: db}
|
|
}
|
|
|
|
func (r *apiKeyRepository) Create(ctx context.Context, key *service.ApiKey) error {
|
|
m := apiKeyModelFromService(key)
|
|
err := r.db.WithContext(ctx).Create(m).Error
|
|
if err == nil {
|
|
applyApiKeyModelToService(key, m)
|
|
}
|
|
return translatePersistenceError(err, nil, service.ErrApiKeyExists)
|
|
}
|
|
|
|
func (r *apiKeyRepository) GetByID(ctx context.Context, id int64) (*service.ApiKey, error) {
|
|
var m apiKeyModel
|
|
err := r.db.WithContext(ctx).Preload("User").Preload("Group").First(&m, id).Error
|
|
if err != nil {
|
|
return nil, translatePersistenceError(err, service.ErrApiKeyNotFound, nil)
|
|
}
|
|
return apiKeyModelToService(&m), nil
|
|
}
|
|
|
|
func (r *apiKeyRepository) GetByKey(ctx context.Context, key string) (*service.ApiKey, error) {
|
|
var m apiKeyModel
|
|
err := r.db.WithContext(ctx).Preload("User").Preload("Group").Where("key = ?", key).First(&m).Error
|
|
if err != nil {
|
|
return nil, translatePersistenceError(err, service.ErrApiKeyNotFound, nil)
|
|
}
|
|
return apiKeyModelToService(&m), nil
|
|
}
|
|
|
|
func (r *apiKeyRepository) Update(ctx context.Context, key *service.ApiKey) error {
|
|
m := apiKeyModelFromService(key)
|
|
err := r.db.WithContext(ctx).Model(m).Select("name", "group_id", "status", "updated_at").Updates(m).Error
|
|
if err == nil {
|
|
applyApiKeyModelToService(key, m)
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (r *apiKeyRepository) Delete(ctx context.Context, id int64) error {
|
|
return r.db.WithContext(ctx).Delete(&apiKeyModel{}, id).Error
|
|
}
|
|
|
|
func (r *apiKeyRepository) ListByUserID(ctx context.Context, userID int64, params pagination.PaginationParams) ([]service.ApiKey, *pagination.PaginationResult, error) {
|
|
var keys []apiKeyModel
|
|
var total int64
|
|
|
|
db := r.db.WithContext(ctx).Model(&apiKeyModel{}).Where("user_id = ?", userID)
|
|
|
|
if err := db.Count(&total).Error; err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
if err := db.Preload("Group").Offset(params.Offset()).Limit(params.Limit()).Order("id DESC").Find(&keys).Error; err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
outKeys := make([]service.ApiKey, 0, len(keys))
|
|
for i := range keys {
|
|
outKeys = append(outKeys, *apiKeyModelToService(&keys[i]))
|
|
}
|
|
|
|
return outKeys, paginationResultFromTotal(total, params), nil
|
|
}
|
|
|
|
func (r *apiKeyRepository) VerifyOwnership(ctx context.Context, userID int64, apiKeyIDs []int64) ([]int64, error) {
|
|
if len(apiKeyIDs) == 0 {
|
|
return []int64{}, nil
|
|
}
|
|
|
|
ids := make([]int64, 0, len(apiKeyIDs))
|
|
err := r.db.WithContext(ctx).
|
|
Model(&apiKeyModel{}).
|
|
Where("user_id = ? AND id IN ?", userID, apiKeyIDs).
|
|
Pluck("id", &ids).Error
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return ids, nil
|
|
}
|
|
|
|
func (r *apiKeyRepository) CountByUserID(ctx context.Context, userID int64) (int64, error) {
|
|
var count int64
|
|
err := r.db.WithContext(ctx).Model(&apiKeyModel{}).Where("user_id = ?", userID).Count(&count).Error
|
|
return count, err
|
|
}
|
|
|
|
func (r *apiKeyRepository) ExistsByKey(ctx context.Context, key string) (bool, error) {
|
|
var count int64
|
|
err := r.db.WithContext(ctx).Model(&apiKeyModel{}).Where("key = ?", key).Count(&count).Error
|
|
return count > 0, err
|
|
}
|
|
|
|
func (r *apiKeyRepository) ListByGroupID(ctx context.Context, groupID int64, params pagination.PaginationParams) ([]service.ApiKey, *pagination.PaginationResult, error) {
|
|
var keys []apiKeyModel
|
|
var total int64
|
|
|
|
db := r.db.WithContext(ctx).Model(&apiKeyModel{}).Where("group_id = ?", groupID)
|
|
|
|
if err := db.Count(&total).Error; err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
if err := db.Preload("User").Offset(params.Offset()).Limit(params.Limit()).Order("id DESC").Find(&keys).Error; err != nil {
|
|
return nil, nil, err
|
|
}
|
|
|
|
outKeys := make([]service.ApiKey, 0, len(keys))
|
|
for i := range keys {
|
|
outKeys = append(outKeys, *apiKeyModelToService(&keys[i]))
|
|
}
|
|
|
|
return outKeys, paginationResultFromTotal(total, params), nil
|
|
}
|
|
|
|
// SearchApiKeys searches API keys by user ID and/or keyword (name)
|
|
func (r *apiKeyRepository) SearchApiKeys(ctx context.Context, userID int64, keyword string, limit int) ([]service.ApiKey, error) {
|
|
var keys []apiKeyModel
|
|
|
|
db := r.db.WithContext(ctx).Model(&apiKeyModel{})
|
|
|
|
if userID > 0 {
|
|
db = db.Where("user_id = ?", userID)
|
|
}
|
|
|
|
if keyword != "" {
|
|
searchPattern := "%" + keyword + "%"
|
|
db = db.Where("name ILIKE ?", searchPattern)
|
|
}
|
|
|
|
if err := db.Limit(limit).Order("id DESC").Find(&keys).Error; err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
outKeys := make([]service.ApiKey, 0, len(keys))
|
|
for i := range keys {
|
|
outKeys = append(outKeys, *apiKeyModelToService(&keys[i]))
|
|
}
|
|
return outKeys, nil
|
|
}
|
|
|
|
// ClearGroupIDByGroupID 将指定分组的所有 API Key 的 group_id 设为 nil
|
|
func (r *apiKeyRepository) ClearGroupIDByGroupID(ctx context.Context, groupID int64) (int64, error) {
|
|
result := r.db.WithContext(ctx).Model(&apiKeyModel{}).
|
|
Where("group_id = ?", groupID).
|
|
Update("group_id", nil)
|
|
return result.RowsAffected, result.Error
|
|
}
|
|
|
|
// CountByGroupID 获取分组的 API Key 数量
|
|
func (r *apiKeyRepository) CountByGroupID(ctx context.Context, groupID int64) (int64, error) {
|
|
var count int64
|
|
err := r.db.WithContext(ctx).Model(&apiKeyModel{}).Where("group_id = ?", groupID).Count(&count).Error
|
|
return count, err
|
|
}
|
|
|
|
type apiKeyModel struct {
|
|
ID int64 `gorm:"primaryKey"`
|
|
UserID int64 `gorm:"index;not null"`
|
|
Key string `gorm:"uniqueIndex;size:128;not null"`
|
|
Name string `gorm:"size:100;not null"`
|
|
GroupID *int64 `gorm:"index"`
|
|
Status string `gorm:"size:20;default:active;not null"`
|
|
CreatedAt time.Time `gorm:"not null"`
|
|
UpdatedAt time.Time `gorm:"not null"`
|
|
DeletedAt gorm.DeletedAt `gorm:"index"`
|
|
|
|
User *userModel `gorm:"foreignKey:UserID"`
|
|
Group *groupModel `gorm:"foreignKey:GroupID"`
|
|
}
|
|
|
|
func (apiKeyModel) TableName() string { return "api_keys" }
|
|
|
|
func apiKeyModelToService(m *apiKeyModel) *service.ApiKey {
|
|
if m == nil {
|
|
return nil
|
|
}
|
|
return &service.ApiKey{
|
|
ID: m.ID,
|
|
UserID: m.UserID,
|
|
Key: m.Key,
|
|
Name: m.Name,
|
|
GroupID: m.GroupID,
|
|
Status: m.Status,
|
|
CreatedAt: m.CreatedAt,
|
|
UpdatedAt: m.UpdatedAt,
|
|
User: userModelToService(m.User),
|
|
Group: groupModelToService(m.Group),
|
|
}
|
|
}
|
|
|
|
func apiKeyModelFromService(k *service.ApiKey) *apiKeyModel {
|
|
if k == nil {
|
|
return nil
|
|
}
|
|
return &apiKeyModel{
|
|
ID: k.ID,
|
|
UserID: k.UserID,
|
|
Key: k.Key,
|
|
Name: k.Name,
|
|
GroupID: k.GroupID,
|
|
Status: k.Status,
|
|
CreatedAt: k.CreatedAt,
|
|
UpdatedAt: k.UpdatedAt,
|
|
}
|
|
}
|
|
|
|
func applyApiKeyModelToService(key *service.ApiKey, m *apiKeyModel) {
|
|
if key == nil || m == nil {
|
|
return
|
|
}
|
|
key.ID = m.ID
|
|
key.CreatedAt = m.CreatedAt
|
|
key.UpdatedAt = m.UpdatedAt
|
|
}
|