Created
June 25, 2019 00:57
-
-
Save fahmifan/0dc7a00557fdfc88812c81107cadf5b6 to your computer and use it in GitHub Desktop.
Inventory App
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// AuthHandler handle user auth | |
type AuthHandler interface { | |
Authorize(w http.ResponseWriter, r *http.Request) | |
Login(w http.ResponseWriter, r *http.Request) | |
} | |
type authHandler struct { | |
userService app.UserService | |
} | |
// NewAuthHandler get authHandler object | |
func NewAuthHandler(userService app.UserService) AuthHandler { | |
return &authHandler{ | |
userService, | |
} | |
} | |
// Authorize validate user auth | |
func (h *authHandler) Authorize(w http.ResponseWriter, r *http.Request) { | |
var user *models.User | |
_ = json.NewDecoder(r.Body).Decode(&user) | |
authToken := r.Header.Get("Authorization") | |
id, token, err := decodeAuthToken(authToken) | |
if err != nil { | |
log.Printf("%+v\n", err) | |
w.WriteHeader(http.StatusInternalServerError) | |
return | |
} | |
user, err = h.userService.Get(id) | |
if err != nil { | |
w.WriteHeader(http.StatusInternalServerError) | |
return | |
} | |
if token != user.Token || user.Role != user.Role { | |
w.WriteHeader(http.StatusUnauthorized) | |
return | |
} | |
w.WriteHeader(http.StatusAccepted) | |
} | |
// Login handle user authentication | |
func (h *authHandler) Login(w http.ResponseWriter, r *http.Request) { | |
var u models.User | |
_ = json.NewDecoder(r.Body).Decode(&u) | |
user, err := h.userService.UserOfName(u.Username) | |
if err != nil { | |
w.WriteHeader(http.StatusInternalServerError) | |
json.NewEncoder(w).Encode(map[string]string{"error": "system error"}) | |
return | |
} | |
if user.ID == 0 || user.Password != user.Password { | |
w.WriteHeader(http.StatusBadGateway) | |
json.NewEncoder(w).Encode(map[string]string{"error": "incorect username or password"}) | |
return | |
} | |
user.Password = "" | |
w.WriteHeader(http.StatusAccepted) | |
json.NewEncoder(w).Encode(user) | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// NewDB initialize connection & creating database | |
func NewDB() *sql.DB { | |
var conn *sql.DB | |
conn, err := sql.Open("sqlite3", "./inventory.db") | |
if err != nil { | |
log.Printf("%+v\n", errors.WithStack(err)) | |
return conn | |
} | |
return conn | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
func main() { | |
db := infra.NewDB() | |
err := db.Ping() | |
if err != nil { | |
log.Println(">>> db error") | |
panic(err) | |
} | |
defer db.Close() | |
log.Println(">>> init database") | |
err = infra.CreateTable(db) | |
if err != nil { | |
log.Fatalf(err.Error()) | |
panic(err) | |
} | |
log.Println(">>> creating table") | |
userRepo := repository.NewUserRepo(db) | |
log.Println(">>> init userRepo") | |
err = userRepo.InitUser() | |
log.Println(">>> seeding users") | |
if err != nil { | |
log.Fatalf(err.Error()) | |
} | |
userService := app.NewUserService(userRepo) | |
log.Println(">>> init userService") | |
// ********************************************* | |
// ********************************************* | |
// Test buat ambil data user 1 | |
// di db udh ada data untuk user 1 | |
log.Println(">>> test get user data") | |
user, err := userService.Get(1) | |
if err != nil { | |
log.Println(">>> failde to get user data") | |
log.Fatalf(err.Error()) | |
} | |
log.Println(">>> success get user data") | |
log.Println(user) | |
// ********************************************* | |
// ********************************************* | |
authHandler := handler.NewAuthHandler(userService) | |
log.Println(">>> init authHandler") | |
staticDir := os.Getenv("STATIC_DIR") | |
if staticDir == "" { | |
staticDir = "./static" | |
log.Println("static dir not specified") | |
} else { | |
log.Println("serve static from: " + staticDir) | |
} | |
port := os.Getenv("PORT") | |
if port == "" { | |
port = "8080" | |
} | |
router := mux.NewRouter() | |
router.HandleFunc("/api/ping", handler.Ping).Methods("GET") | |
// auth | |
router.HandleFunc("/api/auth/check", authHandler.Authorize).Methods("POST") | |
// users | |
router.HandleFunc("/api/login", authHandler.Login).Methods("POST") | |
// --- sisanya routing | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// UserRepo represent repository of the user | |
// Expect implementation of infrastructure layer | |
type UserRepo interface { | |
InitUser() error | |
Get(id int) (*models.User, error) | |
GetAll() ([]*models.User, error) | |
Save(*models.User) error | |
GetUserByUsername(user *models.User, username string) error | |
} | |
type userRepo struct { | |
db *sql.DB | |
} | |
// NewUserRepo get user repo | |
func NewUserRepo(db *sql.DB) UserRepo { | |
return &userRepo{db} | |
} | |
func (u *userRepo) InitUser() error { | |
users := [3][2]string{{"divisi", "divisi"}, {"subagumum", "pejabat"}, {"petugasBarang", "petugasBarang"}} | |
for _, user := range users { | |
user := models.User{ | |
Username: user[0], | |
FirstName: user[0], | |
LastName: user[0], | |
Role: user[1], | |
Password: "123", | |
} | |
exists, err := u.CheckUsernameExist(user) | |
if err != nil { | |
log.Fatalf("%+v\n", err) | |
return err | |
} | |
if !exists { | |
err = u.Save(&user) | |
if err != nil { | |
log.Fatalf("%+v\n", err) | |
return err | |
} | |
} | |
} | |
return nil | |
} | |
// CheckUsernameExist repo | |
func (u *userRepo) CheckUsernameExist(user models.User) (bool, error) { | |
var exists bool | |
q := fmt.Sprintf("SELECT COUNT(1) FROM users WHERE username = '%s'", user.Username) | |
err := u.db.QueryRow(q).Scan(&exists) | |
if err != nil { | |
err = errors.WithStack(err) | |
return false, err | |
} | |
return exists, nil | |
} | |
// Save user to persistance storage | |
func (u *userRepo) Save(user *models.User) error { | |
stm, err := u.db.Prepare("INSERT INTO users (username, firstname, lastname, password, role, token) VALUES (?, ?, ?, ?, ?, ?)") | |
if err != nil { | |
err = errors.Wrap(err, "create user error") | |
log.Printf("%+v\n", err) | |
return err | |
} | |
secret := time.Now().String() | |
token := base64.StdEncoding.EncodeToString([]byte(string(secret))) | |
res, err := stm.Exec(user.Username, user.FirstName, user.LastName, user.Password, user.Role, token) | |
if err != nil { | |
err = errors.Wrap(err, "create user error") | |
log.Printf("%+v\n", err) | |
return err | |
} | |
defer stm.Close() | |
id, err := res.LastInsertId() | |
user.ID = int(id) | |
return nil | |
} | |
// Get get user by id | |
func (u *userRepo) Get(userID int) (*models.User, error) { | |
var user *models.User | |
q := "SELECT id, firstname, lastname, password, role, token FROM users WHERE id = ? " | |
err := u.db.QueryRow(q, userID).Scan(&user.ID, &user.FirstName, &user.LastName, &user.Password, &user.Role, &user.Token) | |
if err != nil && err != sql.ErrNoRows { | |
err = errors.Wrap(err, "select user error") | |
log.Printf("%+v\n", err) | |
return user, err | |
} | |
return user, nil | |
} | |
// GetUserByUsername find user by given username | |
func (u *userRepo) GetUserByUsername(user *models.User, username string) error { | |
q := "SELECT id, firstname, lastname, password, role, token FROM users WHERE username= ? " | |
err := u.db.QueryRow(q, username).Scan(&user.ID, &user.FirstName, &user.LastName, &user.Password, &user.Role, &user.Token) | |
if err != nil && err != sql.ErrNoRows { | |
err = errors.Wrap(err, "select user error") | |
log.Printf("%+v\n", err) | |
return err | |
} | |
return nil | |
} | |
// GetAllUser query all users | |
func (u *userRepo) GetAll() ([]*models.User, error) { | |
users := make([]*models.User, 0) | |
q := "SELECT id, username, firstname, lastname, role, token FROM users" | |
rows, err := u.db.Query(q) | |
if err != nil { | |
err = errors.Wrap(err, "select all user error") | |
log.Printf("%+v\n", err) | |
return users, err | |
} | |
defer rows.Close() | |
var user *models.User | |
for rows.Next() { | |
if err := rows.Scan(&user.ID, &user.Username, &user.FirstName, &user.LastName, &user.Role, &user.Token); err != nil { | |
err = errors.Wrap(err, "scan users row error") | |
log.Printf("%+v\n", err) | |
return users, err | |
} | |
users = append(users, user) | |
} | |
return users, nil | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// UserService user domain service | |
type UserService interface { | |
Save(user *models.User) error | |
Get(id int) (*models.User, error) | |
GetAll() ([]*models.User, error) | |
UserOfName(username string) (*models.User, error) | |
} | |
type userService struct { | |
repo repository.UserRepo | |
} | |
// NewUserService get user service object | |
func NewUserService(repo repository.UserRepo) UserService { | |
return &userService{repo} | |
} | |
func (s *userService) Save(user *models.User) error { | |
err := s.repo.Save(user) | |
if err != nil { | |
return err | |
} | |
return nil | |
} | |
func (s *userService) Get(id int) (*models.User, error) { | |
user, err := s.repo.Get(id) | |
if err != nil { | |
return nil, err | |
} | |
return user, nil | |
} | |
func (s *userService) GetAll() ([]*models.User, error) { | |
users, err := s.repo.GetAll() | |
if err != nil { | |
return nil, err | |
} | |
return users, nil | |
} | |
func (s *userService) UserOfName(username string) (*models.User, error) { | |
var user *models.User | |
err := s.repo.GetUserByUsername(user, username) | |
if err != nil { | |
return user, err | |
} | |
return user, nil | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment