Skip to content

Instantly share code, notes, and snippets.

@fahmifan
Created June 25, 2019 00:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save fahmifan/0dc7a00557fdfc88812c81107cadf5b6 to your computer and use it in GitHub Desktop.
Save fahmifan/0dc7a00557fdfc88812c81107cadf5b6 to your computer and use it in GitHub Desktop.
Inventory App
// 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)
}
// 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
}
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
}
// 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
}
// 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