summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--go.mod21
-rw-r--r--go.sum38
-rw-r--r--handlers/handlers.go55
-rw-r--r--main.go45
-rw-r--r--models/models.go30
-rw-r--r--templates/blog.html24
-rw-r--r--templates/create_blog.html17
7 files changed, 230 insertions, 0 deletions
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..fd32880
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,21 @@
+module wyo.town/netzah
+
+go 1.24.1
+
+require (
+ github.com/gorilla/mux v1.8.1
+ gorm.io/driver/postgres v1.6.0
+ gorm.io/gorm v1.31.0
+)
+
+require (
+ github.com/jackc/pgpassfile v1.0.0 // indirect
+ github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
+ github.com/jackc/pgx/v5 v5.6.0 // indirect
+ github.com/jackc/puddle/v2 v2.2.2 // indirect
+ github.com/jinzhu/inflection v1.0.0 // indirect
+ github.com/jinzhu/now v1.1.5 // indirect
+ golang.org/x/crypto v0.31.0 // indirect
+ golang.org/x/sync v0.10.0 // indirect
+ golang.org/x/text v0.21.0 // indirect
+)
diff --git a/go.sum b/go.sum
new file mode 100644
index 0000000..6b3246d
--- /dev/null
+++ b/go.sum
@@ -0,0 +1,38 @@
+github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
+github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
+github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY=
+github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ=
+github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
+github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
+github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
+github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
+github.com/jackc/pgx/v5 v5.6.0 h1:SWJzexBzPL5jb0GEsrPMLIsi/3jOo7RHlzTjcAeDrPY=
+github.com/jackc/pgx/v5 v5.6.0/go.mod h1:DNZ/vlrUnhWCoFGxHAG8U2ljioxukquj7utPDgtQdTw=
+github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
+github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
+github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
+github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
+github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
+github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
+github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
+github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
+github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
+github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
+github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
+github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
+github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
+golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
+golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
+golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
+golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
+gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
+gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
+gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
+gorm.io/driver/postgres v1.6.0 h1:2dxzU8xJ+ivvqTRph34QX+WrRaJlmfyPqXmoGVjMBa4=
+gorm.io/driver/postgres v1.6.0/go.mod h1:vUw0mrGgrTK+uPHEhAdV4sfFELrByKVGnaVRkXDhtWo=
+gorm.io/gorm v1.31.0 h1:0VlycGreVhK7RF/Bwt51Fk8v0xLiiiFdbGDPIZQ7mJY=
+gorm.io/gorm v1.31.0/go.mod h1:XyQVbO2k6YkOis7C2437jSit3SsDK72s7n7rsSHd+Gs=
diff --git a/handlers/handlers.go b/handlers/handlers.go
new file mode 100644
index 0000000..777ae83
--- /dev/null
+++ b/handlers/handlers.go
@@ -0,0 +1,55 @@
+package handlers
+
+import (
+ "net/http"
+ "fmt"
+ "text/template"
+ "github.com/gorilla/mux"
+ "gorm.io/driver/postgres"
+ "gorm.io/gorm"
+ "wyo.town/netzah/models"
+)
+
+// CreateBlog displays the blog creation form
+func CreateBlog(w http.ResponseWriter, r *http.Request) {
+ tmpl := template.Must(template.ParseFiles("templates/create_blog.html"))
+ tmpl.Execute(w, nil)
+}
+
+// StoreBlog handles the form submission for creating a blog
+func StoreBlog(w http.ResponseWriter, r *http.Request) {
+ dsn := "host=localhost user=_postgresql password=postGRES dbname=netzah port=5432 sslmode=disable TimeZone=US/Mountain client_encoding=UTF8"
+ db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
+ if err != nil {
+ panic("failed to connect to database")
+ }
+
+
+ if r.Method == http.MethodPost {
+ var blog models.Blog
+ blog.Title = r.FormValue("title")
+ blog.Content = r.FormValue("content")
+ db.Create(&blog)
+ http.Redirect(w, r, "/blogs/"+fmt.Sprint(blog.ID), http.StatusSeeOther)
+ }
+}
+
+// GetBlog retrieves and displays a blog by ID
+func GetBlog(w http.ResponseWriter, r *http.Request) {
+ dsn := "host=localhost user=_postgresql password=postGRES dbname=netzah port=5432 sslmode=disable TimeZone=US/Mountain client_encoding=UTF8"
+ db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
+
+ if err != nil {
+ panic("failed to connect to database")
+ }
+
+ id := mux.Vars(r)["id"]
+ var blog models.Blog
+ if err := db.First(&blog, id).Error; err != nil {
+ http.NotFound(w, r)
+ return
+ }
+ tmpl := template.Must(template.ParseFiles("templates/blog.html"))
+ tmpl.Execute(w, blog)
+}
+
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..dbccf98
--- /dev/null
+++ b/main.go
@@ -0,0 +1,45 @@
+package main
+
+import (
+ "log"
+ "fmt"
+ "net/http"
+
+ "wyo.town/netzah/models"
+ "wyo.town/netzah/handlers"
+
+ "github.com/gorilla/mux"
+ "gorm.io/driver/postgres"
+ "gorm.io/gorm"
+)
+
+func init() {
+ dsn := "host=localhost user=_postgresql password=postGRES dbname=netzah port=5432 sslmode=disable TimeZone=US/Mountain client_encoding=UTF8"
+ db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})
+ if err != nil {
+ panic("failed to connect database")
+ }
+ db.AutoMigrate(&models.User{})
+ db.AutoMigrate(&models.Blog{})
+ db.AutoMigrate(&models.Comment{})
+}
+
+func main() {
+ r := mux.NewRouter()
+
+ r.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
+ w.WriteHeader(http.StatusOK)
+ w.Write([]byte("Hello, World!"))
+ })
+
+ // Blog endpoints
+ r.HandleFunc("/blogs", handlers.CreateBlog).Methods("GET")
+ r.HandleFunc("/blogs", handlers.StoreBlog).Methods("POST")
+ r.HandleFunc("/blogs/{id}", handlers.GetBlog).Methods("GET")
+ // r.HandleFunc("/blogs/{id}", handlers.UpdateBlog).Methods("PUT")
+ // r.HandleFunc("/blogs/{id}", handlers.DeleteBlog).Methods("DELETE") // Also consider adding to handle a form submission for deletion
+ fmt.Println("Starting server on :8090")
+ if err := http.ListenAndServe(":8090", r); err != nil {
+ log.Fatal(err)
+ }
+}
diff --git a/models/models.go b/models/models.go
new file mode 100644
index 0000000..1ccf37f
--- /dev/null
+++ b/models/models.go
@@ -0,0 +1,30 @@
+package models
+
+
+type User struct {
+ ID uint `gorm:"primaryKey" json:"id"`
+ Username string `gorm:"unique;not null" json:"username"`
+ Password string `gorm:"not null" json:"-"`
+ Blogs []Blog `gorm:"foreignKey:UserID" json:"blogs"`
+ Comments []Comment `gorm:"foreignKey:UserID" json:"comments"`
+}
+
+type Blog struct {
+ ID uint `gorm:"primaryKey" json:"id"`
+ Title string `gorm:"not null" json:"title"`
+ Content string `gorm:"not null" json:"content"`
+ UserID uint `gorm:"not null" json:"user_id"`
+ User User `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"user"`
+ Comments []Comment `gorm:"foreignKey:BlogID" json:"comments"`
+}
+
+type Comment struct {
+ ID uint `gorm:"primaryKey" json:"id"`
+ Content string `gorm:"not null" json:"content"`
+ UserID uint `gorm:"not null" json:"user_id"`
+ BlogID uint `gorm:"not null" json:"blog_id"`
+ User User `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"user"`
+ Blog Blog `gorm:"constraint:OnUpdate:CASCADE,OnDelete:CASCADE;" json:"blog"`
+}
+
+
diff --git a/templates/blog.html b/templates/blog.html
new file mode 100644
index 0000000..0fc0035
--- /dev/null
+++ b/templates/blog.html
@@ -0,0 +1,24 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>{{.Title}}</title>
+</head>
+<body>
+ <h1>{{.Title}}</h1>
+ <p>{{.Content}}</p>
+ <hr>
+ <h2>Edit Blog</h2>
+ <form method="POST" action="/blogs/{{.ID}}">
+ <input type="hidden" name="_method" value="PUT">
+ <label>Title:</label><br>
+ <input type="text" name="title" value="{{.Title}}"><br>
+ <label>Content:</label><br>
+ <textarea name="content">{{.Content}}</textarea><br>
+ <input type="submit" value="Update">
+ </form>
+ <form method="POST" action="/blogs/{{.ID}}">
+ <input type="hidden" name="_method" value="DELETE">
+ <input type="submit" value="Delete">
+ </form>
+</body>
+</html>
diff --git a/templates/create_blog.html b/templates/create_blog.html
new file mode 100644
index 0000000..6912216
--- /dev/null
+++ b/templates/create_blog.html
@@ -0,0 +1,17 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <title>Create Blog</title>
+</head>
+<body>
+ <h1>Create Blog</h1>
+ <form method="POST" action="/blogs">
+ <label>Title:</label><br>
+ <input type="text" name="title"><br>
+ <label>Content:</label><br>
+ <textarea name="content"></textarea><br>
+ <input type="submit" value="Create">
+ </form>
+</body>
+</html>
+