first commit
This commit is contained in:
274
database/models/blog.go
Normal file
274
database/models/blog.go
Normal file
@@ -0,0 +1,274 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// Note: This file maps Django models to GORM models for MySQL.
|
||||
// Image fields are stored as file path strings. Thumbnail generation and image processing
|
||||
// should be handled elsewhere (e.g., during upload) — TODO: integrate with image processing service.
|
||||
|
||||
// Category represents post categories.
|
||||
type Category struct {
|
||||
ID uint64 `gorm:"type:bigint unsigned;autoIncrement;primaryKey" json:"id"`
|
||||
Title string `gorm:"size:254;not null" json:"title"`
|
||||
Keywords string `gorm:"size:254" json:"keywords"`
|
||||
Desc string `gorm:"size:254" json:"description"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
IsActive bool `gorm:"default:true;index" json:"is_active"`
|
||||
Order int `gorm:"default:1;index" json:"order"`
|
||||
Slug string `gorm:"size:250;not null;index" json:"slug"`
|
||||
ParentID *uint64 `gorm:"type:bigint unsigned;index" json:"parent_id"`
|
||||
Parent *Category `gorm:"foreignKey:ParentID" json:"parent,omitempty"`
|
||||
Children []*Category `gorm:"foreignKey:ParentID" json:"children,omitempty"`
|
||||
Image string `gorm:"size:1024" json:"image"`
|
||||
}
|
||||
|
||||
func (Category) TableName() string {
|
||||
return "categories"
|
||||
}
|
||||
|
||||
// BeforeCreate hook to set slug
|
||||
func (c *Category) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
if c.Slug == "" {
|
||||
c.Slug, err = generateUniqueSlugForCategory(tx, c.Title)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// BeforeUpdate hook ensures slug exists
|
||||
func (c *Category) BeforeUpdate(tx *gorm.DB) (err error) {
|
||||
if c.Slug == "" {
|
||||
c.Slug, err = generateUniqueSlugForCategory(tx, c.Title)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateUniqueSlugForCategory(db *gorm.DB, title string) (string, error) {
|
||||
slug := normalizeSlug(title)
|
||||
base := slug
|
||||
var count int64
|
||||
try := 1
|
||||
for {
|
||||
db.Model(&Category{}).Where("slug = ?", slug).Count(&count)
|
||||
if count == 0 {
|
||||
return slug, nil
|
||||
}
|
||||
slug = fmt.Sprintf("%s-%d", base, try)
|
||||
try++
|
||||
if try > 1000 {
|
||||
return "", errors.New("unable to generate unique slug")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Tags model
|
||||
type Tag struct {
|
||||
ID uint64 `gorm:"type:bigint unsigned;autoIncrement;primaryKey" json:"id"`
|
||||
Tag string `gorm:"size:254;not null" json:"tag"`
|
||||
Slug string `gorm:"size:250;not null;index" json:"slug"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
IsActive bool `gorm:"default:true;index" json:"is_active"`
|
||||
}
|
||||
|
||||
func (Tag) TableName() string { return "tags" }
|
||||
|
||||
func (t *Tag) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
if t.Slug == "" {
|
||||
t.Slug, err = generateUniqueSlugForTag(tx, t.Tag)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (t *Tag) BeforeUpdate(tx *gorm.DB) (err error) {
|
||||
if t.Slug == "" {
|
||||
t.Slug, err = generateUniqueSlugForTag(tx, t.Tag)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateUniqueSlugForTag(db *gorm.DB, tag string) (string, error) {
|
||||
slug := normalizeSlug(tag)
|
||||
base := slug
|
||||
var count int64
|
||||
try := 1
|
||||
for {
|
||||
db.Model(&Tag{}).Where("slug = ?", slug).Count(&count)
|
||||
if count == 0 {
|
||||
return slug, nil
|
||||
}
|
||||
slug = fmt.Sprintf("%s-%d", base, try)
|
||||
try++
|
||||
if try > 1000 {
|
||||
return "", errors.New("unable to generate unique slug")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Post model
|
||||
type Post struct {
|
||||
ID uint64 `gorm:"type:bigint unsigned;autoIncrement;primaryKey" json:"id"`
|
||||
Title string `gorm:"size:254;not null" json:"title"`
|
||||
UserID *uint64 `gorm:"type:bigint unsigned;index" json:"user_id"`
|
||||
User *User `gorm:"foreignKey:UserID" json:"user,omitempty"`
|
||||
Content string `gorm:"type:text" json:"content"`
|
||||
Categories []*Category `gorm:"many2many:post_categories;" json:"categories"`
|
||||
Keywords string `gorm:"size:254" json:"keywords"`
|
||||
Tags []*Tag `gorm:"many2many:post_tags;" json:"tags"`
|
||||
Image string `gorm:"size:1024" json:"image"`
|
||||
Thumb string `gorm:"size:1024" json:"thumb"`
|
||||
Video string `gorm:"size:254;default:'none'" json:"video"`
|
||||
Slug string `gorm:"size:250;not null;index" json:"slug"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
IsActive bool `gorm:"default:true;index" json:"is_active"`
|
||||
IsFront bool `gorm:"default:true;index" json:"is_front"`
|
||||
ParentID *uint64 `gorm:"type:bigint unsigned;index" json:"parent_id"`
|
||||
Parent *Post `gorm:"foreignKey:ParentID" json:"parent,omitempty"`
|
||||
Children []*Post `gorm:"foreignKey:ParentID" json:"children,omitempty"`
|
||||
}
|
||||
|
||||
func (Post) TableName() string { return "posts" }
|
||||
|
||||
func (p *Post) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
if p.Slug == "" {
|
||||
p.Slug, err = generateUniqueSlugForPost(tx, p.Title)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// Note: Thumbnail generation should be handled in the upload flow.
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Post) BeforeUpdate(tx *gorm.DB) (err error) {
|
||||
if p.Slug == "" {
|
||||
p.Slug, err = generateUniqueSlugForPost(tx, p.Title)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateUniqueSlugForPost(db *gorm.DB, title string) (string, error) {
|
||||
slug := normalizeSlug(title)
|
||||
base := slug
|
||||
var count int64
|
||||
try := 1
|
||||
for {
|
||||
db.Model(&Post{}).Where("slug = ?", slug).Count(&count)
|
||||
if count == 0 {
|
||||
return slug, nil
|
||||
}
|
||||
slug = fmt.Sprintf("%s-%d", base, try)
|
||||
try++
|
||||
if try > 1000 {
|
||||
return "", errors.New("unable to generate unique slug")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CategoryView model
|
||||
type CategoryView struct {
|
||||
ID uint64 `gorm:"type:bigint unsigned;autoIncrement;primaryKey" json:"id"`
|
||||
CategoryID uint64 `gorm:"type:bigint unsigned;index" json:"category_id"`
|
||||
Category *Category `gorm:"foreignKey:CategoryID" json:"category"`
|
||||
IPAddress string `gorm:"size:45;index" json:"ip_address"`
|
||||
UserAgent string `gorm:"type:text" json:"user_agent"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
}
|
||||
|
||||
func (CategoryView) TableName() string { return "category_views" }
|
||||
|
||||
// Comment model
|
||||
type Comment struct {
|
||||
ID uint64 `gorm:"type:bigint unsigned;autoIncrement;primaryKey" json:"id"`
|
||||
UserID uint64 `gorm:"type:bigint unsigned;index" json:"user_id"`
|
||||
ProductID uint64 `gorm:"type:bigint unsigned;index" json:"product_id"`
|
||||
Product Post `gorm:"foreignKey:ProductID" json:"product"`
|
||||
Title string `gorm:"size:254" json:"title"`
|
||||
Body string `gorm:"type:text" json:"body"`
|
||||
CreatedAt time.Time `gorm:"autoCreateTime" json:"created_at"`
|
||||
UpdatedAt time.Time `gorm:"autoUpdateTime" json:"updated_at"`
|
||||
IsActive bool `gorm:"default:true;index" json:"is_active"`
|
||||
Slug string `gorm:"size:250;index" json:"slug"`
|
||||
ParentID *uint64 `gorm:"type:bigint unsigned;index" json:"parent_id"`
|
||||
Parent *Comment `gorm:"foreignKey:ParentID" json:"parent,omitempty"`
|
||||
Children []*Comment `gorm:"foreignKey:ParentID" json:"children,omitempty"`
|
||||
}
|
||||
|
||||
func (Comment) TableName() string { return "comments" }
|
||||
|
||||
func (c *Comment) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
if c.Slug == "" {
|
||||
c.Slug, err = generateUniqueSlugForComment(tx, c.Title)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Comment) BeforeUpdate(tx *gorm.DB) (err error) {
|
||||
if c.Slug == "" {
|
||||
c.Slug, err = generateUniqueSlugForComment(tx, c.Title)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func generateUniqueSlugForComment(db *gorm.DB, title string) (string, error) {
|
||||
slug := normalizeSlug(title)
|
||||
base := slug
|
||||
var count int64
|
||||
try := 1
|
||||
for {
|
||||
db.Model(&Comment{}).Where("slug = ?", slug).Count(&count)
|
||||
if count == 0 {
|
||||
return slug, nil
|
||||
}
|
||||
slug = fmt.Sprintf("%s-%d", base, try)
|
||||
try++
|
||||
if try > 1000 {
|
||||
return "", errors.New("unable to generate unique slug")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// normalizeSlug replaces Turkish characters, lowercases and makes a basic slug.
|
||||
func normalizeSlug(s string) string {
|
||||
replacer := strings.NewReplacer(
|
||||
"ı", "i",
|
||||
"İ", "i",
|
||||
"ç", "c",
|
||||
"Ç", "c",
|
||||
"ş", "s",
|
||||
"Ş", "s",
|
||||
"ö", "o",
|
||||
"Ö", "o",
|
||||
"ü", "u",
|
||||
"Ü", "u",
|
||||
" ", "-",
|
||||
)
|
||||
s = replacer.Replace(s)
|
||||
s = strings.ToLower(s)
|
||||
s = strings.TrimSpace(s)
|
||||
// remove multiple dashes
|
||||
for strings.Contains(s, "--") {
|
||||
s = strings.ReplaceAll(s, "--", "-")
|
||||
}
|
||||
// remove extension-like parts
|
||||
s = strings.Trim(s, "-._")
|
||||
// sanitize file-like chars
|
||||
s = filepath.Clean(s)
|
||||
return s
|
||||
}
|
||||
40
database/models/cors_setting.go
Normal file
40
database/models/cors_setting.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// CorsWhitelist - CORS için izin verilen origin'ler
|
||||
type CorsWhitelist struct {
|
||||
ID uint64 `gorm:"type:bigint unsigned;autoIncrement;primaryKey" json:"id"`
|
||||
Origin string `gorm:"type:varchar(255);uniqueIndex;not null" json:"origin"`
|
||||
Description string `gorm:"type:text" json:"description"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
CreatedBy string `gorm:"type:varchar(255)" json:"created_by,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// CorsBlacklist - CORS için yasaklanan origin'ler
|
||||
type CorsBlacklist struct {
|
||||
ID uint64 `gorm:"type:bigint unsigned;autoIncrement;primaryKey" json:"id"`
|
||||
Origin string `gorm:"type:varchar(255);uniqueIndex;not null" json:"origin"`
|
||||
Reason string `gorm:"type:text" json:"reason"`
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
CreatedBy string `gorm:"type:varchar(255)" json:"created_by,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// RateLimitSetting - Rate limit ayarları
|
||||
type RateLimitSetting struct {
|
||||
ID uint64 `gorm:"type:bigint unsigned;autoIncrement;primaryKey" json:"id"`
|
||||
Name string `gorm:"type:varchar(100);uniqueIndex;not null" json:"name"` // e.g., "login", "register", "api"
|
||||
Description string `gorm:"type:text" json:"description"`
|
||||
MaxRequests int64 `gorm:"not null" json:"max_requests"` // Max istek sayısı
|
||||
WindowSeconds int `gorm:"not null" json:"window_seconds"` // Zaman penceresi (saniye)
|
||||
IsActive bool `gorm:"default:true" json:"is_active"`
|
||||
UpdatedBy string `gorm:"type:varchar(255)" json:"updated_by,omitempty"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
14
database/models/role.go
Normal file
14
database/models/role.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package models
|
||||
|
||||
type Role struct {
|
||||
ID uint64 `gorm:"type:bigint unsigned;autoIncrement;primaryKey" json:"id"`
|
||||
Name string `gorm:"uniqueIndex;not null" json:"name"` // admin, user
|
||||
Description string `json:"description"`
|
||||
Permissions []Permission `gorm:"many2many:role_permissions;" json:"permissions"`
|
||||
}
|
||||
|
||||
type Permission struct {
|
||||
ID uint64 `gorm:"type:bigint unsigned;autoIncrement;primaryKey" json:"id"`
|
||||
Name string `gorm:"uniqueIndex;not null" json:"name"` // user:read, user:write
|
||||
Description string `json:"description"`
|
||||
}
|
||||
51
database/models/user.go
Normal file
51
database/models/user.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// User model structure
|
||||
type User struct {
|
||||
ID uint64 `gorm:"type:bigint unsigned;autoIncrement;primaryKey" json:"id"`
|
||||
UserName string `json:"username"`
|
||||
Email string `gorm:"uniqueIndex;not null" json:"email"`
|
||||
Password string `json:"-"` // Password shouldn't be returned in JSON
|
||||
Avatar string `gorm:"type:varchar(500)" json:"avatar,omitempty"` // Avatar URL from OAuth or uploaded
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
|
||||
// Email verification: only required for email/password registration; OAuth users are treated as verified
|
||||
// Changed to *bool to handle false values correctly with GORM defaults
|
||||
EmailVerified *bool `gorm:"default:false" json:"email_verified"` // default false for email/password registration
|
||||
EmailVerifyToken string `gorm:"index" json:"-"`
|
||||
EmailVerifiedAt *time.Time `json:"email_verified_at,omitempty"`
|
||||
|
||||
SocialAccounts []SocialAccount `gorm:"foreignKey:UserID" json:"social_accounts,omitempty"`
|
||||
Roles []Role `gorm:"many2many:user_roles;" json:"roles"`
|
||||
}
|
||||
|
||||
// Helper to safely get EmailVerified status
|
||||
func (u *User) IsEmailVerified() bool {
|
||||
if u.EmailVerified == nil {
|
||||
return false
|
||||
}
|
||||
return *u.EmailVerified
|
||||
}
|
||||
|
||||
// SocialAccount model structure
|
||||
type SocialAccount struct {
|
||||
ID uint64 `gorm:"type:bigint unsigned;autoIncrement;primaryKey" json:"id"`
|
||||
UserID uint64 `gorm:"type:bigint unsigned;not null;index" json:"user_id"`
|
||||
Provider string `gorm:"not null" json:"provider"` // google, github
|
||||
ProviderID string `gorm:"not null" json:"provider_id"`
|
||||
Email string `json:"email"`
|
||||
Name string `json:"name,omitempty"` // Full name from provider
|
||||
AvatarURL string `json:"avatar_url,omitempty"` // Avatar URL from provider
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
|
||||
// Hooks can be added here if needed
|
||||
Reference in New Issue
Block a user