package repository import ( "context" "time" "carrot_bbs/internal/model" "gorm.io/gorm" ) // LoginLogRepository 登录日志仓储 type LoginLogRepository struct { db *gorm.DB } // NewLoginLogRepository 创建登录日志仓储 func NewLoginLogRepository(db *gorm.DB) *LoginLogRepository { return &LoginLogRepository{db: db} } // CreateLoginLog 创建单条登录日志 func (r *LoginLogRepository) CreateLoginLog(ctx context.Context, log *model.LoginLog) error { return r.db.WithContext(ctx).Create(log).Error } // BatchCreateLoginLogs 批量创建登录日志 func (r *LoginLogRepository) BatchCreateLoginLogs(ctx context.Context, logs []*model.LoginLog) error { if len(logs) == 0 { return nil } return r.db.WithContext(ctx).Create(logs).Error } // GetLoginLogs 获取登录日志列表(分页) func (r *LoginLogRepository) GetLoginLogs(ctx context.Context, filters LoginFilter, page, pageSize int) ([]*model.LoginLog, int64, error) { query := r.db.WithContext(ctx).Model(&model.LoginLog{}) if filters.UserID != "" { query = query.Where("user_id = ?", filters.UserID) } if filters.Event != "" { query = query.Where("event = ?", filters.Event) } if filters.Result != "" { query = query.Where("result = ?", filters.Result) } if filters.FailReason != "" { query = query.Where("fail_reason = ?", filters.FailReason) } if filters.LoginType != "" { query = query.Where("login_type = ?", filters.LoginType) } if !filters.StartTime.IsZero() { query = query.Where("created_at >= ?", filters.StartTime) } if !filters.EndTime.IsZero() { query = query.Where("created_at <= ?", filters.EndTime) } if filters.IP != "" { query = query.Where("ip = ?", filters.IP) } var total int64 if err := query.Count(&total).Error; err != nil { return nil, 0, err } var logs []*model.LoginLog offset := (page - 1) * pageSize if err := query.Order("created_at DESC").Offset(offset).Limit(pageSize).Find(&logs).Error; err != nil { return nil, 0, err } return logs, total, nil } // GetLoginLogsByUser 获取指定用户的登录日志 func (r *LoginLogRepository) GetLoginLogsByUser(ctx context.Context, userID string, page, pageSize int) ([]*model.LoginLog, int64, error) { return r.GetLoginLogs(ctx, LoginFilter{UserID: userID}, page, pageSize) } // GetFailedLoginsByIP 获取指定IP的失败登录记录(用于风控) func (r *LoginLogRepository) GetFailedLoginsByIP(ctx context.Context, ip string, timeWindow time.Duration) (int64, error) { startTime := time.Now().Add(-timeWindow) var count int64 err := r.db.WithContext(ctx). Model(&model.LoginLog{}). Where("ip = ? AND result = ? AND created_at >= ?", ip, string(model.LoginResultFail), startTime). Count(&count).Error return count, err } // GetRecentSuccessLogins 获取最近成功的登录记录 func (r *LoginLogRepository) GetRecentSuccessLogins(ctx context.Context, userID string, limit int) ([]*model.LoginLog, error) { var logs []*model.LoginLog err := r.db.WithContext(ctx). Where("user_id = ? AND result = ? AND event = ?", userID, string(model.LoginResultSuccess), string(model.LoginEventLogin)). Order("created_at DESC"). Limit(limit). Find(&logs).Error return logs, err } // DeleteOldLogs 删除旧的登录日志(用于定时清理) func (r *LoginLogRepository) DeleteOldLogs(ctx context.Context, beforeDate string) error { return r.db.WithContext(ctx).Where("created_at < ?", beforeDate).Delete(&model.LoginLog{}).Error } // GetStatistics 获取登录日志统计 func (r *LoginLogRepository) GetStatistics(ctx context.Context, startTime, endTime string) (*LoginLogStatistics, error) { stats := &LoginLogStatistics{} query := r.db.WithContext(ctx).Model(&model.LoginLog{}) if startTime != "" { query = query.Where("created_at >= ?", startTime) } if endTime != "" { query = query.Where("created_at <= ?", endTime) } if err := query.Count(&stats.TotalCount).Error; err != nil { return nil, err } if err := query.Where("result = ?", string(model.LoginResultSuccess)).Count(&stats.SuccessCount).Error; err != nil { return nil, err } if err := query.Where("result = ?", string(model.LoginResultFail)).Count(&stats.FailCount).Error; err != nil { return nil, err } if err := query.Where("event = ?", string(model.LoginEventLogin)).Count(&stats.LoginCount).Error; err != nil { return nil, err } return stats, nil } // LoginFilter 登录日志过滤条件 type LoginFilter struct { UserID string Event string Result string FailReason string LoginType string IP string StartTime time.Time EndTime time.Time } // LoginLogStatistics 登录日志统计 type LoginLogStatistics struct { TotalCount int64 SuccessCount int64 FailCount int64 LoginCount int64 }