|
|
package model
import ( "errors" "fmt" "strings"
"git.aiterp.net/AiteRP/aitestory/server" "git.aiterp.net/gisle/wrouter/generate" )
// TagTypes are the allowed values for Tag.Type
var TagTypes = []string{ "Location", "Character", "Event", "Organization", "Source", "Series", "Meta", }
// Tag describes a tag
type Tag struct { ID string Type string Name string }
// Icon is the API used to get the icon for the tag.
func (tag Tag) Icon() string { return tag.Type[0:1] }
// CSSCLass gets the CSS class that colors the tag on the
// page list
func (tag Tag) CSSCLass() string { return fmt.Sprintf("ttype-%s", strings.ToLower(tag.Type)) }
// Insert adds the tag to the database, giving it a new unique ID
func (tag *Tag) Insert() error { db := server.Main.DB
// Validate tag type
if err := tag.Validate(); err != nil { return err }
// Generate an ID if none exists
if tag.ID == "" { tag.ID = generate.ID() }
// Do the thing
_, err := db.Exec("INSERT INTO `tag` (id,type,name,disabled) VALUES (?,?,?,false)", tag.ID, tag.Type, tag.Name) if err != nil { return err }
return nil }
// Update saves the entry for the tag in the database
func (tag *Tag) Update() error { db := server.Main.DB
// Validate tag type
if err := tag.Validate(); err != nil { return err }
// Do the thing
_, err := db.Exec("UPDATE `tag` SET type=?,name=? WHERE id=?", tag.Type, tag.Name, tag.ID) if err != nil { return err }
return nil }
// Delete removes a tag from the database
func (tag *Tag) Delete() error { db := server.Main.DB
// Do the thing
results, err := db.Exec("DELETE FROM `tag` WHERE id=? LIMIT 1", tag.ID) if err != nil { return err }
// Count the stuffs that were done things to
affected, err := results.RowsAffected() if err != nil { return err } if affected == 0 { return errors.New("tag not found") }
return nil }
// Validate checks the name and type, and returns an error if they're not valid. It's
// ran by Update and Insert before doing anything
func (tag *Tag) Validate() error { validType := false for _, tagType := range TagTypes { if tagType == tag.Type { validType = true break } } if !validType { return errors.New("invalid tag type") }
// Validate tag name
if len(tag.Name) == 0 || len(tag.Name) > 64 { return errors.New("invalid length") }
return nil }
// Hook returns the url friendly name, which is pretty much just
// adding underscores to it.
func (tag Tag) Hook() string { return strings.Replace(tag.Name, " ", "_", -1) }
// FindTag finds a tag by ID
func FindTag(key string, id string) (*Tag, error) { db := server.Main.DB
// Make damn sure that – should this take user data as key – it
// does not open up for a SQL injection attack
if key != "name" && key != "id" { return nil, errors.New("invalid key") }
rows, err := db.Query("SELECT id,type,name FROM `tag` WHERE "+key+"=? AND disabled=false", id) if err != nil { return nil, err } defer rows.Close() if !rows.Next() { return nil, errors.New("not found") }
tag := new(Tag) rows.Scan(&tag.ID, &tag.Type, &tag.Name) return tag, nil }
// EnsureTag finds or creates a tag.
func EnsureTag(tagType, tagName string) (*Tag, error) { // Try to find it first
tag, err := FindTag("name", tagName) if err != nil && err.Error() != "not found" { // You saw nothing
return nil, err }
// Failing that, make it
if tag == nil { tag = new(Tag) tag.Type = tagType tag.Name = tagName err = tag.Insert() if err != nil { return nil, err } }
return tag, nil }
// ListTags finds all the tags, without filter.
func ListTags() ([]Tag, error) { db := server.Main.DB
rows, err := db.Query("SELECT id,type,name FROM `tag` WHERE disabled=false") if err != nil { return nil, err } defer rows.Close()
results := make([]Tag, 0, 64) for rows.Next() { tag := Tag{} rows.Scan(&tag.ID, &tag.Type, &tag.Name) results = append(results, tag) }
return results, nil }
|