Skip to content

Commit 369a7b2

Browse files
Add http handlers to create and get user.
Add handler to get user by nickname Add handler to create user by payload from rails frontend (json response from omniauth)
1 parent aa0636f commit 369a7b2

File tree

5 files changed

+410
-2
lines changed

5 files changed

+410
-2
lines changed

blamewarrior/users.go

-1
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ func (u User) Valid() *Validator {
4242
v.MustNotBeEmpty(u.UID, "uid must not be empty")
4343
v.MustNotBeEmpty(u.Nickname, "nickname must not be empty")
4444
v.MustNotBeEmpty(u.AvatarURL, "avatar_url must not be empty")
45-
v.MustNotBeEmpty(u.Name, "name must not be empty")
4645

4746
return v
4847
}

blamewarrior/validator.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -36,5 +36,5 @@ func (v *Validator) ErrorMessages() []string {
3636
}
3737

3838
func (v *Validator) IsValid() bool {
39-
return len(v.messages) > 0
39+
return len(v.messages) == 0
4040
}

main.go

+63
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
Copyright (C) 2017 The BlameWarrior Authors.
3+
This file is a part of BlameWarrior service.
4+
This program is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
This program is distributed in the hope that it will be useful,
9+
but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
GNU General Public License for more details.
12+
You should have received a copy of the GNU General Public License
13+
along with this program. If not, see <http://www.gnu.org/licenses/>.
14+
*/
15+
16+
package main
17+
18+
import (
19+
"log"
20+
"net/http"
21+
"os"
22+
23+
"github.com/bmizerany/pat"
24+
25+
"github.com/blamewarrior/users/blamewarrior"
26+
)
27+
28+
func main() {
29+
30+
dbName := os.Getenv("DB_NAME")
31+
if dbName == "" {
32+
log.Fatal("missing test database name (expected to be passed via ENV['DB_NAME'])")
33+
}
34+
35+
opts := &blamewarrior.DatabaseOptions{
36+
Host: os.Getenv("DB_HOST"),
37+
Port: os.Getenv("DB_PORT"),
38+
User: os.Getenv("DB_USER"),
39+
Password: os.Getenv("DB_PASSWORD"),
40+
}
41+
42+
db, err := blamewarrior.ConnectDatabase(dbName, opts)
43+
if err != nil {
44+
log.Fatalf("failed to establish connection with db %s using connection string %s: %s", dbName, opts.ConnectionString(), err)
45+
}
46+
47+
handlers := NewUserHandlers(db)
48+
49+
mux := pat.New()
50+
51+
mux.Post("/users", http.HandlerFunc(handlers.SaveUser))
52+
mux.Get("/users/:nickname", http.HandlerFunc(handlers.GetUserByNickname))
53+
54+
http.Handle("/", mux)
55+
56+
log.Printf("blamewarrior users is running on 8080 port")
57+
58+
err = http.ListenAndServe(":8080", nil)
59+
if err != nil {
60+
log.Panic(err)
61+
}
62+
63+
}

user_handlers.go

+144
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/*
2+
Copyright (C) 2017 The BlameWarrior Authors.
3+
This file is a part of BlameWarrior service.
4+
This program is free software: you can redistribute it and/or modify
5+
it under the terms of the GNU General Public License as published by
6+
the Free Software Foundation, either version 3 of the License, or
7+
(at your option) any later version.
8+
This program is distributed in the hope that it will be useful,
9+
but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
GNU General Public License for more details.
12+
You should have received a copy of the GNU General Public License
13+
along with this program. If not, see <http://www.gnu.org/licenses/>.
14+
*/
15+
16+
package main
17+
18+
import (
19+
"database/sql"
20+
"encoding/json"
21+
"io"
22+
"io/ioutil"
23+
"log"
24+
"net/http"
25+
26+
"github.com/blamewarrior/users/blamewarrior"
27+
)
28+
29+
type LoginResult struct {
30+
UID string `json:"uid"`
31+
32+
Info struct {
33+
Nickname string `json:"nickname"`
34+
Image string `json:"image"`
35+
Name string `json:"name"`
36+
} `json:"info"`
37+
38+
Credentials struct {
39+
Token string `json:token`
40+
} `json:"credentials"`
41+
}
42+
43+
type UserHandlers struct {
44+
db *sql.DB
45+
}
46+
47+
func NewUserHandlers(db *sql.DB) *UserHandlers {
48+
return &UserHandlers{db}
49+
}
50+
51+
func (handler *UserHandlers) GetUserByNickname(w http.ResponseWriter, req *http.Request) {
52+
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
53+
54+
nickname := req.URL.Query().Get(":nickname")
55+
56+
if nickname == "" {
57+
http.Error(w, "Specify correct username", http.StatusNotFound)
58+
return
59+
}
60+
61+
user, err := blamewarrior.GetUserByNickname(handler.db, nickname)
62+
63+
if err != nil {
64+
if err == blamewarrior.UserNotFound {
65+
http.Error(w, "User not found", http.StatusNotFound)
66+
return
67+
}
68+
69+
w.WriteHeader(http.StatusInternalServerError)
70+
log.Printf("%s\t%s\t%v\t%s", "GET", req.RequestURI, http.StatusInternalServerError, err)
71+
return
72+
}
73+
74+
if err := json.NewEncoder(w).Encode(user); err != nil {
75+
w.WriteHeader(http.StatusInternalServerError)
76+
log.Printf("%s\t%s\t%v\t%s", "GET", req.RequestURI, http.StatusInternalServerError, err)
77+
return
78+
}
79+
80+
w.WriteHeader(http.StatusOK)
81+
}
82+
83+
func (handler *UserHandlers) SaveUser(w http.ResponseWriter, req *http.Request) {
84+
85+
w.Header().Set("Content-Type", "application/json; charset=UTF-8")
86+
87+
body, err := requestBody(req)
88+
89+
if err != nil {
90+
http.Error(w, "Unable to parse incoming json", http.StatusBadRequest)
91+
return
92+
}
93+
94+
loginResult := &LoginResult{}
95+
96+
if err = json.Unmarshal(body, &loginResult); err != nil {
97+
http.Error(w, "Unable to parse incoming json", http.StatusBadRequest)
98+
return
99+
}
100+
101+
user := &blamewarrior.User{
102+
Token: loginResult.Credentials.Token,
103+
UID: loginResult.UID,
104+
Nickname: loginResult.Info.Nickname,
105+
AvatarURL: loginResult.Info.Image,
106+
Name: loginResult.Info.Name,
107+
}
108+
109+
validator := user.Valid()
110+
111+
if valid := validator.IsValid(); !valid {
112+
messages, err := json.Marshal(validator.ErrorMessages())
113+
114+
if err != nil {
115+
w.WriteHeader(http.StatusInternalServerError)
116+
log.Printf("%s\t%s\t%v\t%s", "POST", req.RequestURI, http.StatusInternalServerError, err)
117+
return
118+
}
119+
120+
http.Error(w, string(messages), http.StatusUnprocessableEntity)
121+
return
122+
}
123+
124+
if err = blamewarrior.SaveUser(handler.db, user); err != nil {
125+
w.WriteHeader(http.StatusInternalServerError)
126+
log.Printf("%s\t%s\t%v\t%s", "POST", req.RequestURI, http.StatusInternalServerError, err)
127+
return
128+
}
129+
130+
w.WriteHeader(http.StatusCreated)
131+
return
132+
}
133+
134+
func requestBody(r *http.Request) ([]byte, error) {
135+
body, err := ioutil.ReadAll(io.LimitReader(r.Body, 1048576))
136+
137+
if err != nil {
138+
return nil, err
139+
}
140+
if err := r.Body.Close(); err != nil {
141+
return nil, err
142+
}
143+
return body, err
144+
}

0 commit comments

Comments
 (0)