package system import ( "context" "time" "kra/app/system/biz" "kra/pkg/database/pagination" "gorm.io/gorm" ) type loginLogPO struct { ID uint `gorm:"primaryKey"` CreatedAt time.Time UpdatedAt time.Time DeletedAt gorm.DeletedAt `gorm:"index"` Username, IP string Status bool ErrorMessage, Agent string UserID uint } func (loginLogPO) TableName() string { return "sys_login_logs" } func (r *auditRecorderRepo) RecordLogin(ctx context.Context, v *biz.LoginLog) error { if !r.data.DatabaseReady() { // The login endpoint remains reachable before database initialization; // skip the audit write until storage is ready. return nil } return r.data.DB().WithContext(ctx).Create(&loginLogPO{Username: v.Username, IP: v.IP, Status: v.Status, ErrorMessage: v.ErrorMessage, Agent: v.Agent, UserID: v.UserID}).Error } func loginFromPO(v loginLogPO) *biz.LoginLog { return &biz.LoginLog{ID: v.ID, CreatedAt: v.CreatedAt, UpdatedAt: v.UpdatedAt, Username: v.Username, IP: v.IP, Status: v.Status, ErrorMessage: v.ErrorMessage, Agent: v.Agent, UserID: v.UserID} } func (r *auditQueryRepo) ListLogins(ctx context.Context, page, size int, q *biz.LoginLog) ([]*biz.LoginLog, int64, error) { db := r.data.DB().WithContext(ctx).Model(&loginLogPO{}) if q != nil { if q.Username != "" { db = db.Where("username LIKE ?", "%"+q.Username+"%") } if q.FilterByStatus { db = db.Where("status = ?", q.Status) } } var total int64 if err := db.Count(&total).Error; err != nil { return nil, 0, err } var pos []loginLogPO if err := pagination.ApplyRequired(db.Order("id desc"), page, size, 100).Find(&pos).Error; err != nil { return nil, 0, err } ids := make([]uint, 0, len(pos)) for _, value := range pos { if value.UserID != 0 { ids = append(ids, value.UserID) } } users := auditUsers(ctx, r.data.DB().WithContext(ctx), ids) out := make([]*biz.LoginLog, 0, len(pos)) for _, po := range pos { value := loginFromPO(po) value.User = users[po.UserID] out = append(out, value) } return out, total, nil } func (r *auditQueryRepo) FindLogin(ctx context.Context, id uint) (*biz.LoginLog, error) { var po loginLogPO if err := r.data.DB().WithContext(ctx).First(&po, id).Error; err != nil { return nil, err } return loginFromPO(po), nil } func (r *auditQueryRepo) DeleteLogins(ctx context.Context, ids []int) error { if len(ids) == 1 && ids[0] == 0 { return r.data.DB().WithContext(ctx).Delete(&loginLogPO{}).Error } return r.data.DB().WithContext(ctx).Delete(&loginLogPO{}, "id IN ?", ids).Error }