Skip to content

Commit

Permalink
Add a simple comment system
Browse files Browse the repository at this point in the history
  • Loading branch information
Gsvd committed Feb 1, 2025
1 parent 03c9fcb commit 5f3d724
Show file tree
Hide file tree
Showing 12 changed files with 259 additions and 13 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.idea
tmp
node_modules
.DS_Store
.DS_Store
data/**
4 changes: 4 additions & 0 deletions cmd/gsvd.dev/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,15 @@ import (

embeded "github.com/Gsvd/gsvd.dev"
"github.com/Gsvd/gsvd.dev/internal/handlers"
"github.com/Gsvd/gsvd.dev/internal/store"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/filesystem"
"github.com/gofiber/template/html/v2"
)

func main() {
store.Init()

engine := html.NewFileSystem(http.FS(embeded.TemplateFiles), ".html")
app := fiber.New(fiber.Config{
Views: engine,
Expand Down Expand Up @@ -50,6 +53,7 @@ func main() {
app.Get("/", handlers.HomeHandler)
app.Get("/blog", handlers.BlogHandler)
app.Get("/blog/:title", handlers.BlogPostHandler)
app.Post("/blog/:id/comment", handlers.BlogCommentHandler)
app.Get("/resume", handlers.ResumeHandler)
app.Get("/contact", handlers.ContactHandler)

Expand Down
2 changes: 1 addition & 1 deletion dist/css/tailwind.min.css

Large diffs are not rendered by default.

11 changes: 9 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,24 @@ require (

require (
github.com/andybalholm/brotli v1.0.6 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/gofiber/template v1.8.2 // indirect
github.com/gofiber/utils v1.1.0 // indirect
github.com/google/uuid v1.4.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/klauspost/compress v1.17.2 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.15 // indirect
github.com/ncruces/go-strftime v0.1.9 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/rivo/uniseg v0.4.4 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasthttp v1.50.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/sys v0.22.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
modernc.org/libc v1.55.3 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.8.0 // indirect
modernc.org/sqlite v1.34.5 // indirect
)
22 changes: 18 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
github.com/andybalholm/brotli v1.0.6 h1:Yf9fFpf49Zrxb9NlQaluyE92/+X7UVHlhMNJN2sxfOI=
github.com/andybalholm/brotli v1.0.6/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/gernest/front v0.0.0-20210301115436-8a0b0a782d0a h1:z7BePknRd4Nz3CeWDhcmCkuCliM2YY/RnjWpdPUuQQo=
github.com/gernest/front v0.0.0-20210301115436-8a0b0a782d0a/go.mod h1:FwEMwQ5+xky8tbzDLj72k2RAqXnFByLNwxg+9UZDtqU=
github.com/gofiber/fiber/v2 v2.50.0 h1:ia0JaB+uw3GpNSCR5nvC5dsaxXjRU5OEu36aytx+zGw=
Expand All @@ -10,8 +12,8 @@ github.com/gofiber/template/html/v2 v2.0.5 h1:BKLJ6Qr940NjntbGmpO3zVa4nFNGDCi/If
github.com/gofiber/template/html/v2 v2.0.5/go.mod h1:RCF14eLeQDCSUPp0IGc2wbSSDv6yt+V54XB/+Unz+LM=
github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM=
github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0=
github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4=
github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
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/klauspost/compress v1.17.2 h1:RlWWUY/Dr4fL8qk9YG7DTZ7PDgME2V4csBXA8L/ixi4=
github.com/klauspost/compress v1.17.2/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
Expand All @@ -23,6 +25,10 @@ github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZ
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY=
github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis=
github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88=
Expand All @@ -36,9 +42,17 @@ github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVS
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
modernc.org/libc v1.55.3 h1:AzcW1mhlPNrRtjS5sS+eW2ISCgSOLLNyFzRh/V3Qj/U=
modernc.org/libc v1.55.3/go.mod h1:qFXepLhz+JjFThQ4kzwzOjA/y/artDeg+pcYnY+Q83w=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
modernc.org/sqlite v1.34.5 h1:Bb6SR13/fjp15jt70CL4f18JIN7p7dnMExd+UFnF15g=
modernc.org/sqlite v1.34.5/go.mod h1:YLuNmX9NKs8wRNK2ko1LW1NGYcc9FkBO69JOt1AR9JE=
45 changes: 43 additions & 2 deletions internal/handlers/blog.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"html/template"
"net/http"
"strconv"

embeded "github.com/Gsvd/gsvd.dev"
"github.com/Gsvd/gsvd.dev/internal/models"
Expand All @@ -16,7 +17,7 @@ import (
)

func BlogHandler(c *fiber.Ctx) error {
articlesMetadata, err := services.LoadArticles()
articlesMetadata, err := services.LoadMetadatas()
if err != nil {
panic(err)
}
Expand All @@ -28,7 +29,10 @@ func BlogHandler(c *fiber.Ctx) error {
}

func BlogPostHandler(c *fiber.Ctx) error {
filename := fmt.Sprintf("internal/content/%s.md", c.Params("title"))
var (
comments []models.Comment
filename = fmt.Sprintf("internal/content/%s.md", c.Params("title"))
)

fileContent, err := embeded.ContentFiles.ReadFile(filename)
if err != nil {
Expand All @@ -49,9 +53,15 @@ func BlogPostHandler(c *fiber.Ctx) error {

htmlContent := blackfriday.Run([]byte(body))

comments, err = services.LoadComments(metadata.Id)
if err != nil {
panic(err)
}

article := models.Article{
Metadata: *metadata,
Content: template.HTML(htmlContent),
Comments: comments,
}

return c.Render("internal/templates/post", fiber.Map{
Expand All @@ -60,3 +70,34 @@ func BlogPostHandler(c *fiber.Ctx) error {
"Canonical": "blog/" + metadata.Slug,
}, "internal/templates/layouts/post")
}

func BlogCommentHandler(c *fiber.Ctx) error {
var (
comment = &models.Comment{
Username: "Anonymous",
}
)

articleId, err := strconv.Atoi(c.Params("id"))
if err != nil {
return c.Status(fiber.StatusBadRequest).SendString("Invalid article Id")
}

comment.PostId = articleId

if value := c.FormValue("comment"); value != "" {
comment.Comment = value
} else {
return c.Status(fiber.StatusBadRequest).SendString("Comment is required")
}

if value := c.FormValue("username"); value != "" && len(value) <= 16 {
comment.Username = value
}

if err := services.SaveComment(comment); err != nil {
panic(err)
}

return c.Redirect(fmt.Sprintf("/blog/%s#comments", c.FormValue("slug")))
}
2 changes: 1 addition & 1 deletion internal/handlers/home.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

func HomeHandler(c *fiber.Ctx) error {
articlesMetadata, err := services.LoadArticles()
articlesMetadata, err := services.LoadMetadatas()
if err != nil {
panic(err)
}
Expand Down
1 change: 1 addition & 0 deletions internal/models/article.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ import "html/template"
type Article struct {
Metadata Metadata
Content template.HTML
Comments []Comment
}
12 changes: 12 additions & 0 deletions internal/models/comment.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package models

import "time"

type Comment struct {
Id int
Username string
PostId int
Comment string
Approved bool
CreatedAt time.Time
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ import (

embeded "github.com/Gsvd/gsvd.dev"
"github.com/Gsvd/gsvd.dev/internal/models"
"github.com/Gsvd/gsvd.dev/internal/store"
"github.com/gernest/front"
"github.com/mitchellh/mapstructure"
)

func LoadArticles() ([]models.Metadata, error) {
func LoadMetadatas() ([]models.Metadata, error) {
var metadatas []models.Metadata
articles, err := embeded.ContentFiles.ReadDir("internal/content")
if err != nil {
Expand Down Expand Up @@ -48,3 +49,47 @@ func LoadArticles() ([]models.Metadata, error) {

return metadatas, nil
}

func LoadComments(articleId int) ([]models.Comment, error) {
var comments []models.Comment

store := store.Get()
rows, err := store.Query(`
SELECT
id,
username,
comment,
approved,
created_at
FROM
comments
WHERE
post_id = ?
AND approved = TRUE
ORDER BY
created_at DESC;
`, articleId)
if err != nil {
return nil, err
}

for rows.Next() {
var comment models.Comment
if err := rows.Scan(&comment.Id, &comment.Username, &comment.Comment, &comment.Approved, &comment.CreatedAt); err != nil {
return nil, err
}
comments = append(comments, comment)
}

return comments, nil
}

func SaveComment(comment *models.Comment) error {
store := store.Get()
_, err := store.Exec(`
INSERT INTO comments (post_id, username, comment, approved)
VALUES (?, ?, ?, FALSE);
`, comment.PostId, comment.Username, comment.Comment)

return err
}
69 changes: 69 additions & 0 deletions internal/store/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package store

import (
"database/sql"
"log"
"os"
"sync"

_ "modernc.org/sqlite"
)

var (
instance *sql.DB
once sync.Once
)

func Init() *sql.DB {
once.Do(func() {
path := "./data/db.sqlite"

if _, err := os.Stat(path); os.IsNotExist(err) {
log.Println("📂 SQLite file not found. Creating database...")
if err := os.MkdirAll("data", 0755); err != nil {
log.Fatalf("Failed to create data/ directory: %v", err)
}
}

var err error
instance, err = sql.Open("sqlite", path)
if err != nil {
log.Fatalf("SQLite connection error: %v", err)
}

if err = instance.Ping(); err != nil {
log.Fatalf("SQLite ping error: %v", err)
}

createTables(instance)

log.Println("✅ SQLite initialized")
})

return instance
}

func Get() *sql.DB {
if instance == nil {
log.Fatal("🔴 SQLite not initialized. Call Init() first.")
}

return instance
}

func createTables(db *sql.DB) {
query := `
CREATE TABLE IF NOT EXISTS comments (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username VARCHAR(16) NOT NULL DEFAULT 'Anonymous',
post_id INTEGER NOT NULL,
comment TEXT NOT NULL,
approved BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
`
if _, err := db.Exec(query); err != nil {
log.Fatalf("Error creating tables: %v", err)
}
log.Println("✅ Tables created (or already exist)")
}
Loading

0 comments on commit 5f3d724

Please sign in to comment.