diff --git a/main_dc/yalarba/api_es/internal/models/authentication.go b/main_dc/yalarba/api_es/internal/models/authentication.go new file mode 100644 index 0000000..63ef49d --- /dev/null +++ b/main_dc/yalarba/api_es/internal/models/authentication.go @@ -0,0 +1,45 @@ +package models + +import ( + +) + +// AuthRequest - запрос на аутентификацию +type AuthRequest struct { + Email string `json:"email" binding:"required,email"` + Password string `json:"password" binding:"required,min=6"` +} + +// AuthResponse - ответ с токенами +type AuthResponse struct { + AccessToken string `json:"access_token"` + RefreshToken string `json:"refresh_token"` + TokenType string `json:"token_type"` // Bearer + ExpiresIn int64 `json:"expires_in"` + User UserResponse `json:"user"` +} + +// RefreshTokenRequest - запрос на обновление токена +type RefreshTokenRequest struct { + RefreshToken string `json:"refresh_token" binding:"required"` +} + +// UserRegisterRequest - запрос на регистрацию +type UserRegisterRequest struct { + Email string `json:"email" binding:"required,email"` + Password string `json:"password" binding:"required,min=6"` + FullName string `json:"full_name" binding:"required"` + Phone string `json:"phone"` + City string `json:"city"` +} + +// PasswordResetRequest - запрос на сброс пароля +type PasswordResetRequest struct { + Email string `json:"email" binding:"required,email"` +} + +// PasswordResetConfirmRequest - подтверждение сброса пароля +type PasswordResetConfirmRequest struct { + Token string `json:"token" binding:"required"` + Password string `json:"password" binding:"required,min=6"` +} diff --git a/main_dc/yalarba/api_es/internal/models/filter.go b/main_dc/yalarba/api_es/internal/models/filter.go new file mode 100644 index 0000000..78f860a --- /dev/null +++ b/main_dc/yalarba/api_es/internal/models/filter.go @@ -0,0 +1,29 @@ +package models + +type ObjectFilter struct { + Search string `form:"search" json:"search"` + Type ObjectType `form:"type" json:"type"` + City string `form:"city" json:"city"` + MinPrice float64 `form:"min_price" json:"min_price"` + MaxPrice float64 `form:"max_price" json:"max_price"` + MinRating float64 `form:"min_rating" json:"min_rating"` + Status ObjectStatus `form:"status" json:"status"` + OwnerID uint `form:"owner_id" json:"owner_id"` + + // Пагинация + Page int `form:"page" json:"page" binding:"min=1"` + PageSize int `form:"page_size" json:"page_size" binding:"min=1,max=100"` + + // Сортировка + SortBy string `form:"sort_by" json:"sort_by"` // title, price, rating, city, created_at + SortOrder string `form:"sort_order" json:"sort_order"` // asc, desc +} + +// PaginatedResponse - общий ответ с пагинацией +type PaginatedResponse struct { + Data interface{} `json:"data"` + Total int64 `json:"total"` + Page int `json:"page"` + PageSize int `json:"page_size"` + TotalPages int `json:"total_pages"` +} \ No newline at end of file diff --git a/main_dc/yalarba/api_es/internal/models/object.go b/main_dc/yalarba/api_es/internal/models/object.go new file mode 100644 index 0000000..202b350 --- /dev/null +++ b/main_dc/yalarba/api_es/internal/models/object.go @@ -0,0 +1,121 @@ +package models + +import ( + "gorm.io/gorm" + "time" +) + +type ObjectType string + +const ( + ObjectTypeHotel ObjectType = "hotel" + ObjectTypeSanatorium ObjectType = "sanatorium" + ObjectTypeGuestHouse ObjectType = "guest_house" + ObjectTypeTour ObjectType = "tour" + ObjectTypeRestaurant ObjectType = "restaurant" + ObjectTypeMuseum ObjectType = "museum" + ObjectTypeLandmark ObjectType = "landmark" + ObjectTypeEvent ObjectType = "event" + ObjectTypeRoute ObjectType = "route" +) + +type ObjectStatus string + +const ( + ObjectStatusDraft ObjectStatus = "draft" + ObjectStatusModeration ObjectStatus = "moderation" + ObjectStatusActive ObjectStatus = "active" + ObjectStatusInactive ObjectStatus = "inactive" + ObjectStatusRejected ObjectStatus = "rejected" +) + +type Object struct { + ID uint `gorm:"primaryKey" json:"id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` + + // Основная информация + Title string `gorm:"not null" json:"title"` + Type ObjectType `gorm:"not null" json:"type"` + Description string `gorm:"type:text" json:"description"` + + // Локация + City string `gorm:"not null" json:"city"` + Address string `json:"address"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + + // Цена и условия + Price float64 `gorm:"default:0" json:"price"` + PricePeriod string `gorm:"default:'per_night'" json:"price_period"` // per_night, per_person, per_tour + + // Статус и рейтинг + Status ObjectStatus `gorm:"default:draft" json:"status"` + Rating float64 `gorm:"default:0" json:"rating"` + ReviewCount int `gorm:"default:0" json:"review_count"` + ViewCount int `gorm:"default:0" json:"view_count"` + + // Владелец + OwnerID uint `gorm:"not null" json:"owner_id"` + Owner User `gorm:"foreignKey:OwnerID" json:"owner,omitempty"` + + // Связи + Images []ObjectImage `gorm:"foreignKey:ObjectID" json:"images"` + Amenities []Amenity `gorm:"many2many:object_amenities;" json:"amenities"` + Reviews []Review `gorm:"foreignKey:ObjectID" json:"-"` +} + +// ObjectImage представляет изображения объекта +type ObjectImage struct { + ID uint `gorm:"primaryKey" json:"id"` + ObjectID uint `gorm:"not null" json:"object_id"` + URL string `gorm:"not null" json:"url"` + IsPrimary bool `gorm:"default:false" json:"is_primary"` + Order int `gorm:"default:0" json:"order"` + CreatedAt time.Time `json:"created_at"` +} + +// Amenity представляет удобства объекта +type Amenity struct { + ID uint `gorm:"primaryKey" json:"id"` + Name string `gorm:"uniqueIndex;not null" json:"name"` + Category string `json:"category"` // basic, comfort, safety, entertainment, etc. + Icon string `json:"icon"` // иконка для фронтенда + Description string `json:"description"` +} + +// ObjectAmenity связь многие-ко-многим между Object и Amenity +type ObjectAmenity struct { + ObjectID uint `gorm:"primaryKey" json:"object_id"` + AmenityID uint `gorm:"primaryKey" json:"amenity_id"` +} + +// ObjectCreateRequest - запрос на создание объекта +type ObjectCreateRequest struct { + Title string `json:"title" binding:"required"` + Type ObjectType `json:"type" binding:"required"` + Description string `json:"description" binding:"required"` + City string `json:"city" binding:"required"` + Address string `json:"address"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + Price float64 `json:"price"` + PricePeriod string `json:"price_period"` + AmenityIDs []uint `json:"amenity_ids"` +} + +// ObjectUpdateRequest - запрос на обновление объекта +type ObjectUpdateRequest struct { + Title string `json:"title"` + Type ObjectType `json:"type"` + Description string `json:"description"` + City string `json:"city"` + Address string `json:"address"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + Price float64 `json:"price"` + PricePeriod string `json:"price_period"` + Status ObjectStatus `json:"status"` + AmenityIDs []uint `json:"amenity_ids"` +} diff --git a/main_dc/yalarba/api_es/internal/models/rest_object.go b/main_dc/yalarba/api_es/internal/models/rest_object.go deleted file mode 100644 index 4081d69..0000000 --- a/main_dc/yalarba/api_es/internal/models/rest_object.go +++ /dev/null @@ -1,22 +0,0 @@ -package models - -import ( - "time" - - "gorm.io/gorm" -) - -type Rest_Object struct { - ID uint `json:"id" gorm:"primarykey"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - DeletedAt gorm.DeletedAt `json:"deleted_at,omitempty" gorm:"index"` - - ShortName string - LongName string - Description string - Type string // event || place - OwnerID uint - - -} diff --git a/main_dc/yalarba/api_es/internal/models/review.go b/main_dc/yalarba/api_es/internal/models/review.go new file mode 100644 index 0000000..7a4cfac --- /dev/null +++ b/main_dc/yalarba/api_es/internal/models/review.go @@ -0,0 +1,28 @@ +package models + +import ( + "time" +) + +type Review struct { + ID uint `gorm:"primaryKey" json:"id"` + CreatedAt time.Time `json:"created_at"` + + // Связи + ObjectID uint `gorm:"not null" json:"object_id"` + Object Object `gorm:"foreignKey:ObjectID" json:"object,omitempty"` + AuthorID uint `gorm:"not null" json:"author_id"` + Author User `gorm:"foreignKey:AuthorID" json:"author"` + + // Контент отзыва + Rating int `gorm:"not null;check:rating >= 1 AND rating <= 5" json:"rating"` + Text string `gorm:"type:text" json:"text"` + IsActive bool `gorm:"default:true" json:"is_active"` +} + +// ReviewCreateRequest - запрос на создание отзыва +type ReviewCreateRequest struct { + ObjectID uint `json:"object_id" binding:"required"` + Rating int `json:"rating" binding:"required,min=1,max=5"` + Text string `json:"text" binding:"required,min=10"` +} \ No newline at end of file diff --git a/main_dc/yalarba/api_es/internal/models/user.go b/main_dc/yalarba/api_es/internal/models/user.go index d067296..5d2d984 100644 --- a/main_dc/yalarba/api_es/internal/models/user.go +++ b/main_dc/yalarba/api_es/internal/models/user.go @@ -1,40 +1,64 @@ package models import ( - "time" - "gorm.io/gorm" + "time" ) type User struct { - ID uint `json:"id" gorm:"primarykey"` + ID uint `gorm:"primaryKey" json:"id"` CreatedAt time.Time `json:"created_at"` UpdatedAt time.Time `json:"updated_at"` - DeletedAt gorm.DeletedAt `json:"deleted_at,omitempty" gorm:"index"` + DeletedAt gorm.DeletedAt `gorm:"index" json:"-"` - Name string `json:"name" gorm:"size:100;not null"` - FullName string `json:"full_name" gorm:"size:1000"` - FirstName string `json:"first_name" gorm:"size:50"` - LastName string `json:"last_nmae" gorm:"size:50"` - Email string `json:"email" gorm:"size:255;uniqueIndex;not null"` - Password string `json:"-" gorm:"size:255;not null"` + // Основная информация + Email string `gorm:"uniqueIndex;not null" json:"email"` + PasswordHash string `gorm:"not null" json:"-"` + FullName string `gorm:"not null" json:"full_name"` + Phone string `json:"phone"` + City string `json:"city"` + + // Бизнес информация (для владельцев объектов) + OrganizationForm string `json:"organization_form"` // ИП, ООО и т.д. + OrganizationName string `json:"organization_name"` + OrganizationShort string `json:"organization_short"` + INN string `json:"inn"` // ИНН организации + PersonalINN string `json:"personal_inn"` // Личный ИНН + + // Статус + IsActive bool `gorm:"default:true" json:"is_active"` + IsVerified bool `gorm:"default:false" json:"is_verified"` + Role string `gorm:"default:user" json:"role"` // user, admin, moderator + + // Связи + Objects []Object `gorm:"foreignKey:OwnerID" json:"-"` + Reviews []Review `gorm:"foreignKey:AuthorID" json:"-"` } -type CreateUserRequest struct { - Name string `json:"name" validate:"required,min=2,max=100"` - Email string `json:"email" validate:"required,email"` - Password string `json:"password" validate:"required,min=6"` -} - -type UpdateUserRequest struct { - Name string `json:"name" validate:"omitempty,min=2,max=100"` - Email string `json:"email" validate:"omitempty,email"` +// UserStats представляет статистику пользователя +type UserStats struct { + UserID uint `gorm:"primaryKey" json:"user_id"` + TotalObjects int `gorm:"default:0" json:"total_objects"` + ActiveObjects int `gorm:"default:0" json:"active_objects"` + ModerationObjects int `gorm:"default:0" json:"moderation_objects"` + TotalReviews int `gorm:"default:0" json:"total_reviews"` } +// UserResponse - структура для ответа API (без чувствительных данных) type UserResponse struct { - ID uint `json:"id"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - Name string `json:"name"` - Email string `json:"email"` + ID uint `json:"id"` + Email string `json:"email"` + FullName string `json:"full_name"` + Phone string `json:"phone"` + City string `json:"city"` + OrganizationForm string `json:"organization_form"` + OrganizationName string `json:"organization_name"` + OrganizationShort string `json:"organization_short"` + INN string `json:"inn"` + PersonalINN string `json:"personal_inn"` + IsActive bool `json:"is_active"` + IsVerified bool `json:"is_verified"` + Role string `json:"role"` + CreatedAt time.Time `json:"created_at"` + Stats UserStats `json:"stats,omitempty"` }