diff options
| author | Bobby <[email protected]> | 2025-06-16 10:15:15 +0530 |
|---|---|---|
| committer | Bobby <[email protected]> | 2025-06-16 10:15:15 +0530 |
| commit | 782be699f797011a6e71b345658762f7e2013636 (patch) | |
| tree | 0af72643a6188731bd09923143860e9167bba449 /models/tags.go | |
| parent | cfa8164f2468ea5a63b4cce2edb01957846b2b12 (diff) | |
| download | imageboard-782be699f797011a6e71b345658762f7e2013636.tar.xz imageboard-782be699f797011a6e71b345658762f7e2013636.zip | |
added user, image, comments, and tags models with functions
Diffstat (limited to 'models/tags.go')
| -rw-r--r-- | models/tags.go | 127 |
1 files changed, 127 insertions, 0 deletions
diff --git a/models/tags.go b/models/tags.go new file mode 100644 index 0000000..61f7013 --- /dev/null +++ b/models/tags.go @@ -0,0 +1,127 @@ +package models + +import ( + "fmt" + "imageboard/utils/validators" + "strings" + + "gorm.io/gorm" +) + +type Tag struct { + gorm.Model + Name string `gorm:"not null;uniqueIndex;size:100" json:"name"` + Type TagType `gorm:"not null;default:'general';size:20" json:"type"` + Description string `gorm:"default:'';type:text" json:"description"` + Count int `gorm:"not null;default:0" json:"count"` + IsDeleted bool `gorm:"not null;default:false" json:"is_deleted"` + ParentID *uint `gorm:"index" json:"-"` + Parent *Tag `gorm:"foreignKey:ParentID" json:"parent,omitempty"` + Children []Tag `gorm:"foreignKey:ParentID" json:"children,omitempty"` + Images []Image `gorm:"many2many:image_tags" json:"images,omitempty"` +} + +func (t *Tag) BeforeCreate(tx *gorm.DB) error { + t.Name = strings.TrimSpace(strings.ToLower(t.Name)) + t.Description = strings.TrimSpace(t.Description) + + if t.Name == "" { + return fmt.Errorf("tag name cannot be empty") + } + + if len(t.Name) < 2 || len(t.Name) > 100 { + return fmt.Errorf("tag name must be between 2 and 100 characters") + } + + if !validators.IsValidTagName(t.Name) { + return fmt.Errorf("tag name can only contain letters, numbers, and underscores") + } + + var existingTag Tag + if err := tx.Where("name = ?", t.Name).First(&existingTag).Error; err == nil { + return fmt.Errorf("tag name '%s' is already taken", t.Name) + } + + return nil +} + +func (t *Tag) BeforeUpdate(tx *gorm.DB) error { + t.Name = strings.TrimSpace(strings.ToLower(t.Name)) + t.Description = strings.TrimSpace(t.Description) + return nil +} + +func (t *Tag) GetFullPath() string { + if t.Parent == nil { + return t.Name + } + return t.Parent.GetFullPath() + ":" + t.Name +} + +func SearchTags(tx *gorm.DB, query string, limit int) ([]Tag, error) { + var tags []Tag + searchPattern := "%" + strings.TrimSpace(strings.ToLower(query)) + "%" + + err := tx.Where("name LIKE ? AND is_deleted = ?", searchPattern, false). + Order("count DESC, name ASC").Limit(limit).Find(&tags).Error + + return tags, err +} + +func SearchTagsExcluding(tx *gorm.DB, query string, imageID uint, limit int) ([]Tag, error) { + var tags []Tag + searchPattern := "%" + strings.TrimSpace(strings.ToLower(query)) + "%" + + err := tx.Where("name LIKE ? AND is_deleted = ? AND id NOT IN (?)", + searchPattern, false, + tx.Table("image_tags").Select("tag_id").Where("image_id = ?", imageID)). + Order("count DESC, name ASC").Limit(limit).Find(&tags).Error + + return tags, err +} + +func FindOrCreateTag(tx *gorm.DB, name string, tagType TagType) (*Tag, error) { + name = strings.TrimSpace(strings.ToLower(name)) + + // First check for active tag + var tag Tag + if err := tx.Where("name = ? AND is_deleted = ?", name, false).First(&tag).Error; err == nil { + return &tag, nil + } + + // Check for deleted tag and restore it + if err := tx.Where("name = ? AND is_deleted = ?", name, true).First(&tag).Error; err == nil { + tag.IsDeleted = false + tag.Type = tagType // Update type in case it changed + if err := tx.Save(&tag).Error; err != nil { + return nil, fmt.Errorf("failed to restore tag: %v", err) + } + return &tag, nil + } + + // Create new tag + tag = Tag{ + Name: name, + Type: tagType, + } + + if err := tx.Create(&tag).Error; err != nil { + return nil, err + } + + return &tag, nil +} + +func (t *Tag) DeleteTag(tx *gorm.DB) error { + if t.IsDeleted { + return fmt.Errorf("tag is already deleted") + } + + if err := tx.Model(t).Association("Images").Clear(); err != nil { + return fmt.Errorf("failed to clear image associations: %v", err) + } + + t.IsDeleted = true + t.Count = 0 + return tx.Save(t).Error +} |
