diff --git a/cmd/data/articles.go b/cmd/data/articles.go index 6fdc370..0b0eb0d 100644 --- a/cmd/data/articles.go +++ b/cmd/data/articles.go @@ -9,7 +9,6 @@ type Article struct { Created time.Time Desc string Content string - Tags []string Published bool ID int64 AuthorID int64 diff --git a/cmd/data/db.go b/cmd/data/db.go index 7d5be05..5c548de 100644 --- a/cmd/data/db.go +++ b/cmd/data/db.go @@ -35,6 +35,18 @@ func OpenDB(dbName string) (*DB, error) { return &db, nil } +func (db *DB) UpdateAttribute(table string, id int64, attribute string, val interface{}) error { + query := ` + UPDATE ? + SET ? = ? + WHERE id = ? + ` + if _, err := db.Exec(query, table, attribute, val, id); err != nil { + return fmt.Errorf("error updating article in DB: %v", err) + } + return nil +} + func (db *DB) AddUser(user *User, pass string) error { hashedPass, err := bcrypt.GenerateFromPassword([]byte(pass), bcrypt.DefaultCost) if err != nil { @@ -173,7 +185,7 @@ func (db *DB) GetUser(id int64) (*User, error) { } func (db *DB) AddTag(tagName string) error { - query := "INSERT INTO tags name VALUES ?" + query := "INSERT INTO tags (name) VALUES (?)" if _, err := db.Exec(query, tagName); err != nil { return fmt.Errorf("error inserting tag into DB: %v", err) } @@ -195,21 +207,31 @@ func (db *DB) GetTagList() ([]Tag, error) { } tagList = append(tagList, tag) } + if err = rows.Err(); err != nil { + return nil, fmt.Errorf("error iterating through rows: %v", err) + } return tagList, nil } -func (db *DB) AddArticle(a *Article) error { +func (db *DB) AddArticle(a *Article) (int64, error) { query := ` INSERT INTO articles (title, description, content, published, author_id) VALUES - (?, ?, ?, ?) + (?, ?, ?, ?, ?) ` - if _, err := db.Exec(query, a.Title, a.Desc, a.Content, a.Published, a.AuthorID); err != nil { - return fmt.Errorf("error inserting article into DB: %v", err) + + result, err := db.Exec(query, a.Title, a.Desc, a.Content, a.Published, a.AuthorID) + if err != nil { + return 0, fmt.Errorf("error inserting article into DB: %v", err) } - return nil + id, err := result.LastInsertId() + if err != nil { + return 0, fmt.Errorf("error retrieving last ID: %v", err) + } + + return id, nil } func (db *DB) GetArticle(id int64) (*Article, error) { @@ -254,14 +276,27 @@ func (db *DB) GetUnpublishedArticles() ([]Article, error) { return articleList, nil } -func (db *DB) UpdateArticle(id int64, attribute string, val interface{}) error { - query := ` - UPDATE articles - SET ? = ? - WHERE id = ? - ` - if _, err := db.Exec(query, attribute, val, id); err != nil { - return fmt.Errorf("error updating article in DB: %v", err) +func (db *DB) WriteArticleTags(articleID int64, tagIDs []int64) error { + tx, err := db.Begin() + if err != nil { + return fmt.Errorf("error starting transaction: %v", err) + } + + for _, tagID := range tagIDs { + query := ` + INSERT INTO articles_tags (article_id, tag_id) + VALUES (?, ?) + ` + if _, err := tx.Exec(query, articleID, tagID); err != nil { + if rollbackErr := tx.Rollback(); rollbackErr != nil { + log.Fatalf("error: transaction error: %v, rollback error: %v", err, rollbackErr) + } + return fmt.Errorf("error inserting into articles_tags: %v", err) + } + } + + if err = tx.Commit(); err != nil { + return fmt.Errorf("error committing transaction: %v", err) } return nil } diff --git a/cmd/data/tags.go b/cmd/data/tags.go index 8cb0fff..71361eb 100644 --- a/cmd/data/tags.go +++ b/cmd/data/tags.go @@ -1,6 +1,6 @@ package data type Tag struct { - ID int64 Name string + ID int64 } diff --git a/cmd/main.go b/cmd/main.go index b115de6..ac746a7 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -48,7 +48,8 @@ func main() { store := data.NewCookieStore(key) mux := http.NewServeMux() - mux.Handle("/web/static/", http.StripPrefix("/web/static/", http.FileServer(http.Dir("web/static/")))) + mux.Handle("/web/static/", http.StripPrefix("/web/static/", + http.FileServer(http.Dir("web/static/")))) mux.HandleFunc("/", ui.HomePage(db, store)) mux.HandleFunc("GET /create-tag/", ui.CreateTag) diff --git a/cmd/ui/articles.go b/cmd/ui/articles.go index cb53e04..66551f9 100644 --- a/cmd/ui/articles.go +++ b/cmd/ui/articles.go @@ -65,9 +65,6 @@ func FinishArticle(db *data.DB, s *data.CookieStore) http.HandlerFunc { return } - r.ParseForm() - article.Tags = append(article.Tags, r.Form["tags"]...) - session, err := s.Get(r, "cookie") if err != nil { tmpl, err := template.ParseFiles("web/templates/login.html") @@ -76,7 +73,29 @@ func FinishArticle(db *data.DB, s *data.CookieStore) http.HandlerFunc { } article.AuthorID = session.Values["id"].(int64) - db.AddArticle(article) + article.ID, err = db.AddArticle(article) + if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + + r.ParseForm() + tags := make([]int64, 0) + for _, tag := range r.Form["tags"] { + tagID, err := strconv.ParseInt(tag, 10, 64) + if err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + tags = append(tags, tagID) + } + if err = db.WriteArticleTags(article.ID, tags); err != nil { + log.Println(err) + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } tmpl, err := template.ParseFiles("web/templates/hub.html") tmpl = template.Must(tmpl, err) @@ -135,7 +154,7 @@ func PublishArticle(db *data.DB, c *data.Channel, s *data.CookieStore) http.Hand return } - if err = db.UpdateArticle(id, "published", true); err != nil { + if err = db.UpdateAttribute("articles", id, "published", true); err != nil { log.Println(err) http.Error(w, err.Error(), http.StatusInternalServerError) return @@ -160,7 +179,7 @@ func PublishArticle(db *data.DB, c *data.Channel, s *data.CookieStore) http.Hand PubDate: article.Created.Format(time.RFC1123Z), Description: article.Desc, Content: &rss.Content{Value: article.Content}, - Categories: article.Tags, + // Categories: article.Tags, }) c.Save("tmp/rss.gob") diff --git a/go.mod b/go.mod index 184b8a6..e3b1fb3 100644 --- a/go.mod +++ b/go.mod @@ -5,8 +5,6 @@ go 1.22.0 require ( git.streifling.com/jason/rss v0.0.0-20240305164907-524bf9676188 github.com/go-sql-driver/mysql v1.7.1 - github.com/google/uuid v1.6.0 - github.com/gorilla/feeds v1.1.2 github.com/gorilla/sessions v1.2.2 github.com/microcosm-cc/bluemonday v1.0.26 github.com/yuin/goldmark v1.7.0 diff --git a/go.sum b/go.sum index 13ec948..e79d004 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,3 @@ -git.streifling.com/jason/rss v0.0.0-20240305152729-9d8cc6464565 h1:/eO9NTksh+9yLz3HiYNR7BJo/iMTxxW5/d9h8I6vR6E= -git.streifling.com/jason/rss v0.0.0-20240305152729-9d8cc6464565/go.mod h1:gpZF0nZbQSstMpyHD9DTAvlQEG7v4pjO5c7aIMWM4Jg= -git.streifling.com/jason/rss v0.0.0-20240305160544-c8551159fe32 h1:G25NZzsD73rOkGYgV2vPUDviB0JXk5qi+dXOwB6J56U= -git.streifling.com/jason/rss v0.0.0-20240305160544-c8551159fe32/go.mod h1:gpZF0nZbQSstMpyHD9DTAvlQEG7v4pjO5c7aIMWM4Jg= -git.streifling.com/jason/rss v0.0.0-20240305160829-6cd08bb65d2a h1:TWQ9gwe7eWjaLUrZ0CJSc+sUUOw3VoGHlR3F8mH6vqs= -git.streifling.com/jason/rss v0.0.0-20240305160829-6cd08bb65d2a/go.mod h1:gpZF0nZbQSstMpyHD9DTAvlQEG7v4pjO5c7aIMWM4Jg= git.streifling.com/jason/rss v0.0.0-20240305164907-524bf9676188 h1:C8M/j3f+cl5Y7YfGpU/ynb/SC/4tTYMDsyGFt3rswM8= git.streifling.com/jason/rss v0.0.0-20240305164907-524bf9676188/go.mod h1:gpZF0nZbQSstMpyHD9DTAvlQEG7v4pjO5c7aIMWM4Jg= github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk= @@ -12,24 +6,14 @@ github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrt github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= -github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c= -github.com/gorilla/feeds v1.1.2 h1:pxzZ5PD3RJdhFH2FsJJ4x6PqMqbgFk1+Vez4XWBW8Iw= -github.com/gorilla/feeds v1.1.2/go.mod h1:WMib8uJP3BbY+X8Szd1rA5Pzhdfh+HCCAYT2z7Fza6Y= github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= github.com/gorilla/sessions v1.2.2 h1:lqzMYz6bOfvn2WriPUjNByzeXIlVzURcPmgMczkmTjY= github.com/gorilla/sessions v1.2.2/go.mod h1:ePLdVu+jbEgHH+KWw8I1z2wqd0BAdAQh/8LRvBeoNcQ= -github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= -github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/microcosm-cc/bluemonday v1.0.26 h1:xbqSvqzQMeEHCqMi64VAs4d8uy6Mequs3rQ0k/Khz58= github.com/microcosm-cc/bluemonday v1.0.26/go.mod h1:JyzOCs9gkyQyjs+6h10UEVSe02CGwkhd72Xdqh78TWs= -github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= -github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/yuin/goldmark v1.7.0 h1:EfOIvIMZIzHdB/R/zVrikYLPPwJlfMcNczJFMs1m6sA= github.com/yuin/goldmark v1.7.0/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= diff --git a/web/templates/editor.html b/web/templates/editor.html index 303e8d6..6401141 100644 --- a/web/templates/editor.html +++ b/web/templates/editor.html @@ -5,8 +5,8 @@ {{range .}} - - + + {{end}}