// models/user.go package models import ( "time" "golang.org/x/crypto/bcrypt" "gorm.io/gorm" ) // models/user.go - добавить поле Avatar type User struct { ID uint `json:"id" gorm:"primaryKey"` Email string `json:"email" gorm:"uniqueIndex;not null"` Password string `json:"-" gorm:"not null"` FirstName string `json:"first_name" gorm:"not null"` LastName string `json:"last_name" gorm:"not null"` Avatar string `json:"avatar"` // Путь к файлу аватара Phone string `json:"phone"` Experience string `json:"experience"` Goals string `json:"goals"` Newsletter bool `json:"newsletter"` Role string `json:"role" gorm:"default:user"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` DeletedAt gorm.DeletedAt `json:"-" gorm:"index"` EmailVerified bool `json:"email_verified" gorm:"default:false"` VerifiedAt time.Time `json:"verified_at"` // Связи Workouts []Workout `json:"workouts,omitempty" gorm:"foreignKey:UserID"` PersonalBests []PersonalBest `json:"personal_bests,omitempty" gorm:"foreignKey:UserID"` Achievements []Achievement `json:"achievements,omitempty" gorm:"foreignKey:UserID"` TrainingPlans []TrainingPlan `json:"training_plans,omitempty" gorm:"foreignKey:UserID"` News []News `json:"news,omitempty" gorm:"foreignKey:AuthorID"` Comments []Comment `json:"comments,omitempty" gorm:"foreignKey:AuthorID"` Reviews []Review `json:"reviews,omitempty" gorm:"foreignKey:AuthorID"` Gallery []Gallery `json:"gallery,omitempty" gorm:"foreignKey:AuthorID"` EventRegistrations []EventRegistration `json:"event_registrations,omitempty" gorm:"foreignKey:UserID"` } type UserUpdate struct { ID uint `json:"id"` FirstName string `json:"first_name"` LastName string `json:"last_name"` Avatar string `json:"avatar"` Phone string `json:"phone"` Experience string `json:"experience"` Goals string `json:"goals"` Newsletter bool `json:"newsletter"` UpdatedAt time.Time `json:"updated_at"` } // HashPassword хеширует пароль перед сохранением func (u *User) HashPassword() error { hashedPassword, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost) if err != nil { return err } u.Password = string(hashedPassword) return nil } // CheckPassword проверяет пароль func (u *User) CheckPassword(password string) bool { err := bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password)) return err == nil } // BeforeCreate hook для GORM func (u *User) BeforeCreate(tx *gorm.DB) error { if u.CreatedAt.IsZero() { u.CreatedAt = time.Now() } if u.UpdatedAt.IsZero() { u.UpdatedAt = time.Now() } return u.HashPassword() } // BeforeUpdate hook для GORM func (u *User) BeforeUpdate(tx *gorm.DB) error { u.UpdatedAt = time.Now() return nil } // DTO для обновления профиля type UserUpdateRequest struct { FirstName string `json:"first_name" validate:"required,min=2,max=100"` LastName string `json:"last_name" validate:"required,min=2,max=100"` Phone string `json:"phone" validate:"max=20"` Experience string `json:"experience" validate:"max=50"` Goals string `json:"goals" validate:"max=100"` Newsletter bool `json:"newsletter"` } // DTO для ответа с пользователем (без sensitive данных) type UserResponse struct { ID uint `json:"id"` Email string `json:"email"` FirstName string `json:"first_name"` LastName string `json:"last_name"` Avatar string `json:"avatar"` Phone string `json:"phone"` Experience string `json:"experience"` Goals string `json:"goals"` Newsletter bool `json:"newsletter"` Role string `json:"role"` CreatedAt time.Time `json:"created_at"` } // DTO для ответа с пользователем и статистикой type UserWithStatsResponse struct { UserResponse Stats *UserStatsResponse `json:"stats,omitempty"` }