Skip to content

Commit 6670543

Browse files
committed
Restructured project
1 parent 51c795a commit 6670543

File tree

8 files changed

+193
-108
lines changed

8 files changed

+193
-108
lines changed

main.go

Lines changed: 6 additions & 108 deletions
Original file line numberDiff line numberDiff line change
@@ -2,117 +2,15 @@ package main
22

33
import (
44
"net/http"
5-
"github.com/gorilla/mux"
6-
"github.com/gorilla/sessions"
7-
"github.com/go-redis/redis"
8-
"golang.org/x/crypto/bcrypt"
9-
"html/template"
5+
"./routes"
6+
"./models"
7+
"./utils"
108
)
119

12-
var client *redis.Client
13-
var store = sessions.NewCookieStore([]byte("t0p-s3cr3t"))
14-
var templates *template.Template
15-
1610
func main() {
17-
client = redis.NewClient(&redis.Options{
18-
Addr: "localhost:6379",
19-
})
20-
templates = template.Must(template.ParseGlob("templates/*.html"))
21-
r := mux.NewRouter()
22-
r.HandleFunc("/", AuthRequired(indexGetHandler)).Methods("GET")
23-
r.HandleFunc("/", AuthRequired(indexPostHandler)).Methods("POST")
24-
r.HandleFunc("/login", loginGetHandler).Methods("GET")
25-
r.HandleFunc("/login", loginPostHandler).Methods("POST")
26-
r.HandleFunc("/register", registerGetHandler).Methods("GET")
27-
r.HandleFunc("/register", registerPostHandler).Methods("POST")
28-
fs := http.FileServer(http.Dir("./static/"))
29-
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", fs))
11+
models.Init()
12+
utils.LoadTemplates("templates/*.html")
13+
r := routes.NewRouter()
3014
http.Handle("/", r)
3115
http.ListenAndServe(":8080", nil)
3216
}
33-
34-
func AuthRequired(handler http.HandlerFunc) http.HandlerFunc {
35-
return func(w http.ResponseWriter, r *http.Request) {
36-
session, _ := store.Get(r, "session")
37-
_, ok := session.Values["username"]
38-
if !ok {
39-
http.Redirect(w, r, "/login", 302)
40-
return
41-
}
42-
handler.ServeHTTP(w, r)
43-
}
44-
}
45-
46-
func indexGetHandler(w http.ResponseWriter, r *http.Request) {
47-
comments, err := client.LRange("comments", 0, 10).Result()
48-
if err != nil {
49-
w.WriteHeader(http.StatusInternalServerError)
50-
w.Write([]byte("Internal server error"))
51-
return
52-
}
53-
templates.ExecuteTemplate(w, "index.html", comments)
54-
}
55-
56-
func indexPostHandler(w http.ResponseWriter, r *http.Request) {
57-
r.ParseForm()
58-
comment := r.PostForm.Get("comment")
59-
err := client.LPush("comments", comment).Err()
60-
if err != nil {
61-
w.WriteHeader(http.StatusInternalServerError)
62-
w.Write([]byte("Internal server error"))
63-
return
64-
}
65-
http.Redirect(w, r, "/", 302)
66-
}
67-
68-
func loginGetHandler(w http.ResponseWriter, r *http.Request) {
69-
templates.ExecuteTemplate(w, "login.html", nil)
70-
}
71-
72-
func loginPostHandler(w http.ResponseWriter, r *http.Request) {
73-
r.ParseForm()
74-
username := r.PostForm.Get("username")
75-
password := r.PostForm.Get("password")
76-
hash, err := client.Get("user:" + username).Bytes()
77-
if err == redis.Nil {
78-
templates.ExecuteTemplate(w, "login.html", "unknown user")
79-
return
80-
} else if err != nil {
81-
w.WriteHeader(http.StatusInternalServerError)
82-
w.Write([]byte("Internal server error"))
83-
return
84-
}
85-
err = bcrypt.CompareHashAndPassword(hash, []byte(password))
86-
if err != nil {
87-
templates.ExecuteTemplate(w, "login.html", "invalid login")
88-
return
89-
}
90-
session, _ := store.Get(r, "session")
91-
session.Values["username"] = username
92-
session.Save(r, w)
93-
http.Redirect(w, r, "/", 302)
94-
}
95-
96-
func registerGetHandler(w http.ResponseWriter, r *http.Request) {
97-
templates.ExecuteTemplate(w, "register.html", nil)
98-
}
99-
100-
func registerPostHandler(w http.ResponseWriter, r *http.Request) {
101-
r.ParseForm()
102-
username := r.PostForm.Get("username")
103-
password := r.PostForm.Get("password")
104-
cost := bcrypt.DefaultCost
105-
hash, err := bcrypt.GenerateFromPassword([]byte(password), cost)
106-
if err != nil {
107-
w.WriteHeader(http.StatusInternalServerError)
108-
w.Write([]byte("Internal server error"))
109-
return
110-
}
111-
err = client.Set("user:" + username, hash, 0).Err()
112-
if err != nil {
113-
w.WriteHeader(http.StatusInternalServerError)
114-
w.Write([]byte("Internal server error"))
115-
return
116-
}
117-
http.Redirect(w, r, "/login", 302)
118-
}

middleware/middleware.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package middleware
2+
3+
import (
4+
"net/http"
5+
"../sessions"
6+
)
7+
8+
func AuthRequired(handler http.HandlerFunc) http.HandlerFunc {
9+
return func(w http.ResponseWriter, r *http.Request) {
10+
session, _ := sessions.Store.Get(r, "session")
11+
_, ok := session.Values["username"]
12+
if !ok {
13+
http.Redirect(w, r, "/login", 302)
14+
return
15+
}
16+
handler.ServeHTTP(w, r)
17+
}
18+
}

models/comment.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package models
2+
3+
func GetComments() ([]string, error) {
4+
return client.LRange("comments", 0, 10).Result()
5+
}
6+
7+
func PostComment(comment string) error {
8+
return client.LPush("comments", comment).Err()
9+
}

models/db.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package models
2+
3+
import (
4+
"github.com/go-redis/redis"
5+
)
6+
7+
var client *redis.Client
8+
9+
func Init() {
10+
client = redis.NewClient(&redis.Options{
11+
Addr: "localhost:6379",
12+
})
13+
}

models/user.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package models
2+
3+
import (
4+
"errors"
5+
"github.com/go-redis/redis"
6+
"golang.org/x/crypto/bcrypt"
7+
)
8+
9+
var (
10+
ErrUserNotFound = errors.New("user not found")
11+
ErrInvalidLogin = errors.New("invalid login")
12+
)
13+
14+
func AuthenticateUser(username, password string) error {
15+
hash, err := client.Get("user:" + username).Bytes()
16+
if err == redis.Nil {
17+
return ErrUserNotFound
18+
} else if err != nil {
19+
return err
20+
}
21+
err = bcrypt.CompareHashAndPassword(hash, []byte(password))
22+
if err != nil {
23+
return ErrInvalidLogin
24+
}
25+
return nil
26+
}
27+
28+
func RegisterUser(username, password string) error {
29+
cost := bcrypt.DefaultCost
30+
hash, err := bcrypt.GenerateFromPassword([]byte(password), cost)
31+
if err != nil {
32+
return err
33+
}
34+
return client.Set("user:" + username, hash, 0).Err()
35+
}

routes/routes.go

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package routes
2+
3+
import (
4+
"net/http"
5+
"github.com/gorilla/mux"
6+
"../middleware"
7+
"../models"
8+
"../sessions"
9+
"../utils"
10+
)
11+
12+
func NewRouter() *mux.Router {
13+
r := mux.NewRouter()
14+
r.HandleFunc("/", middleware.AuthRequired(indexGetHandler)).Methods("GET")
15+
r.HandleFunc("/", middleware.AuthRequired(indexPostHandler)).Methods("POST")
16+
r.HandleFunc("/login", loginGetHandler).Methods("GET")
17+
r.HandleFunc("/login", loginPostHandler).Methods("POST")
18+
r.HandleFunc("/register", registerGetHandler).Methods("GET")
19+
r.HandleFunc("/register", registerPostHandler).Methods("POST")
20+
fs := http.FileServer(http.Dir("./static/"))
21+
r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", fs))
22+
return r
23+
}
24+
25+
func indexGetHandler(w http.ResponseWriter, r *http.Request) {
26+
comments, err := models.GetComments()
27+
if err != nil {
28+
w.WriteHeader(http.StatusInternalServerError)
29+
w.Write([]byte("Internal server error"))
30+
return
31+
}
32+
utils.ExecuteTemplate(w, "index.html", comments)
33+
}
34+
35+
func indexPostHandler(w http.ResponseWriter, r *http.Request) {
36+
r.ParseForm()
37+
comment := r.PostForm.Get("comment")
38+
err := models.PostComment(comment)
39+
if err != nil {
40+
w.WriteHeader(http.StatusInternalServerError)
41+
w.Write([]byte("Internal server error"))
42+
return
43+
}
44+
http.Redirect(w, r, "/", 302)
45+
}
46+
47+
func loginGetHandler(w http.ResponseWriter, r *http.Request) {
48+
utils.ExecuteTemplate(w, "login.html", nil)
49+
}
50+
51+
func loginPostHandler(w http.ResponseWriter, r *http.Request) {
52+
r.ParseForm()
53+
username := r.PostForm.Get("username")
54+
password := r.PostForm.Get("password")
55+
err := models.AuthenticateUser(username, password)
56+
if err != nil {
57+
switch err {
58+
case models.ErrUserNotFound:
59+
utils.ExecuteTemplate(w, "login.html", "unknown user")
60+
case models.ErrInvalidLogin:
61+
utils.ExecuteTemplate(w, "login.html", "invalid login")
62+
default:
63+
w.WriteHeader(http.StatusInternalServerError)
64+
w.Write([]byte("Internal server error"))
65+
}
66+
return
67+
}
68+
session, _ := sessions.Store.Get(r, "session")
69+
session.Values["username"] = username
70+
session.Save(r, w)
71+
http.Redirect(w, r, "/", 302)
72+
}
73+
74+
func registerGetHandler(w http.ResponseWriter, r *http.Request) {
75+
utils.ExecuteTemplate(w, "register.html", nil)
76+
}
77+
78+
func registerPostHandler(w http.ResponseWriter, r *http.Request) {
79+
r.ParseForm()
80+
username := r.PostForm.Get("username")
81+
password := r.PostForm.Get("password")
82+
err := models.RegisterUser(username, password)
83+
if err != nil {
84+
w.WriteHeader(http.StatusInternalServerError)
85+
w.Write([]byte("Internal server error"))
86+
return
87+
}
88+
http.Redirect(w, r, "/login", 302)
89+
}

sessions/sessions.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package sessions
2+
3+
import (
4+
"github.com/gorilla/sessions"
5+
)
6+
7+
var Store = sessions.NewCookieStore([]byte("t0p-s3cr3t"))

utils/templates.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package utils
2+
3+
import (
4+
"net/http"
5+
"html/template"
6+
)
7+
8+
var templates *template.Template
9+
10+
func LoadTemplates(pattern string) {
11+
templates = template.Must(template.ParseGlob(pattern))
12+
}
13+
14+
func ExecuteTemplate(w http.ResponseWriter, tmpl string, data interface{}) {
15+
templates.ExecuteTemplate(w, tmpl, data)
16+
}

0 commit comments

Comments
 (0)