add user and password hash
This commit is contained in:
parent
85dd2a3134
commit
d05b501360
3
Makefile
3
Makefile
@ -9,9 +9,8 @@ migratedown:
|
|||||||
mock-generate:
|
mock-generate:
|
||||||
mockgen -package mockdb -destination db/mock/store.go git.nochill.in/nochill/naice_pos/db/sqlc Store
|
mockgen -package mockdb -destination db/mock/store.go git.nochill.in/nochill/naice_pos/db/sqlc Store
|
||||||
|
|
||||||
|
|
||||||
sqlc:
|
sqlc:
|
||||||
sqlc generate
|
sqlc generate && make mock-generate
|
||||||
|
|
||||||
test:
|
test:
|
||||||
go test -v -cover ./...
|
go test -v -cover ./...
|
||||||
|
@ -109,7 +109,7 @@ func TestGetProductApi(t *testing.T) {
|
|||||||
func randomProduct() db.Product {
|
func randomProduct() db.Product {
|
||||||
return db.Product{
|
return db.Product{
|
||||||
ID: uuid.New(),
|
ID: uuid.New(),
|
||||||
MerchantID: uuid.MustParse("d9b0e126-991e-46ac-8c61-5efdd605f75d"),
|
MerchantID: uuid.MustParse("a848090f-0409-4386-9caa-929ae6874dbb"),
|
||||||
Name: util.RandomString(5),
|
Name: util.RandomString(5),
|
||||||
SellingPrice: util.RandomFloat(1000, 99999),
|
SellingPrice: util.RandomFloat(1000, 99999),
|
||||||
PurchasePrice: util.RandomFloat(999, 9999),
|
PurchasePrice: util.RandomFloat(999, 9999),
|
||||||
|
@ -14,6 +14,7 @@ func NewServer(store db.Store) *Server {
|
|||||||
server := &Server{store: store}
|
server := &Server{store: store}
|
||||||
router := gin.Default()
|
router := gin.Default()
|
||||||
|
|
||||||
|
router.POST("/merchants", server.createUser)
|
||||||
router.POST("/products", server.createProduct)
|
router.POST("/products", server.createProduct)
|
||||||
router.PATCH("/products", server.updateProduct)
|
router.PATCH("/products", server.updateProduct)
|
||||||
router.GET("/product/:id", server.getProduct)
|
router.GET("/product/:id", server.getProduct)
|
||||||
|
69
api/user.go
Normal file
69
api/user.go
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"database/sql"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
db "git.nochill.in/nochill/naice_pos/db/sqlc"
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/lib/pq"
|
||||||
|
)
|
||||||
|
|
||||||
|
type createUserRequest struct {
|
||||||
|
Email string `json:"email" binding:"required,email"`
|
||||||
|
Fullname string `json:"fullname" binding:"required"`
|
||||||
|
Password string `json:"password" binding:"required"`
|
||||||
|
OutletName string `json:"outlet_name" binding:"required"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type createUserResponse struct {
|
||||||
|
ID uuid.UUID `json:"id"`
|
||||||
|
IndexID int64 `json:"index_id"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Fullname string `json:"fullname"`
|
||||||
|
CreatedAt sql.NullTime `json:"created_at"`
|
||||||
|
UpdatedAt sql.NullTime `json:"updated_at"`
|
||||||
|
Outlet db.Merchant `json:"outlet"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (server *Server) createUser(ctx *gin.Context) {
|
||||||
|
var req createUserRequest
|
||||||
|
|
||||||
|
if err := ctx.ShouldBindJSON(&req); err != nil {
|
||||||
|
ctx.JSON(http.StatusBadRequest, errorResponse(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
arg := db.UserMerchantTxParams{
|
||||||
|
Email: req.Email,
|
||||||
|
Fullname: req.Fullname,
|
||||||
|
Password: req.Password,
|
||||||
|
OutletName: req.OutletName,
|
||||||
|
}
|
||||||
|
|
||||||
|
user, err := server.store.CreateUserMerchantTx(ctx, arg)
|
||||||
|
if err != nil {
|
||||||
|
if pqErr, ok := err.(*pq.Error); ok {
|
||||||
|
switch pqErr.Code.Name() {
|
||||||
|
case "foreign_key_violation", "unique_violation":
|
||||||
|
ctx.JSON(http.StatusConflict, errorResponse(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ctx.JSON(http.StatusInternalServerError, errorResponse(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
res := createUserResponse{
|
||||||
|
ID: user.OwnerProfile.ID,
|
||||||
|
IndexID: user.OwnerProfile.IndexID,
|
||||||
|
Email: user.OwnerProfile.Email,
|
||||||
|
Fullname: user.OwnerProfile.Fullname,
|
||||||
|
CreatedAt: sql.NullTime{Valid: true, Time: user.OutletProfile.CreatedAt.Time},
|
||||||
|
UpdatedAt: sql.NullTime{Valid: true, Time: user.OutletProfile.UpdatedAt.Time},
|
||||||
|
Outlet: user.OutletProfile,
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.JSON(http.StatusOK, res)
|
||||||
|
}
|
1
api/user_test.go
Normal file
1
api/user_test.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package api
|
@ -3,7 +3,7 @@ CREATE TABLE users(
|
|||||||
"index_id" bigserial not null,
|
"index_id" bigserial not null,
|
||||||
"email" varchar unique not null,
|
"email" varchar unique not null,
|
||||||
"password" varchar not null,
|
"password" varchar not null,
|
||||||
"fullname" varchar,
|
"fullname" varchar not null,
|
||||||
"created_at" timestamp default(now()),
|
"created_at" timestamp default(now()),
|
||||||
"updated_at" timestamp default(now())
|
"updated_at" timestamp default(now())
|
||||||
);
|
);
|
||||||
|
@ -51,6 +51,21 @@ func (mr *MockStoreMockRecorder) CreateCustomers(arg0, arg1 interface{}) *gomock
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateCustomers", reflect.TypeOf((*MockStore)(nil).CreateCustomers), arg0, arg1)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateCustomers", reflect.TypeOf((*MockStore)(nil).CreateCustomers), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateMerchant mocks base method.
|
||||||
|
func (m *MockStore) CreateMerchant(arg0 context.Context, arg1 db.CreateMerchantParams) (db.Merchant, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "CreateMerchant", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(db.Merchant)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateMerchant indicates an expected call of CreateMerchant.
|
||||||
|
func (mr *MockStoreMockRecorder) CreateMerchant(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateMerchant", reflect.TypeOf((*MockStore)(nil).CreateMerchant), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// CreateProduct mocks base method.
|
// CreateProduct mocks base method.
|
||||||
func (m *MockStore) CreateProduct(arg0 context.Context, arg1 db.CreateProductParams) (db.Product, error) {
|
func (m *MockStore) CreateProduct(arg0 context.Context, arg1 db.CreateProductParams) (db.Product, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
@ -111,6 +126,36 @@ func (mr *MockStoreMockRecorder) CreateSuppliers(arg0, arg1 interface{}) *gomock
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSuppliers", reflect.TypeOf((*MockStore)(nil).CreateSuppliers), arg0, arg1)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateSuppliers", reflect.TypeOf((*MockStore)(nil).CreateSuppliers), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CreateUser mocks base method.
|
||||||
|
func (m *MockStore) CreateUser(arg0 context.Context, arg1 db.CreateUserParams) (db.User, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "CreateUser", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(db.User)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateUser indicates an expected call of CreateUser.
|
||||||
|
func (mr *MockStoreMockRecorder) CreateUser(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUser", reflect.TypeOf((*MockStore)(nil).CreateUser), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateUserMerchantTx mocks base method.
|
||||||
|
func (m *MockStore) CreateUserMerchantTx(arg0 context.Context, arg1 db.UserMerchantTxParams) (db.UserMerchantTxResult, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "CreateUserMerchantTx", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(db.UserMerchantTxResult)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateUserMerchantTx indicates an expected call of CreateUserMerchantTx.
|
||||||
|
func (mr *MockStoreMockRecorder) CreateUserMerchantTx(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateUserMerchantTx", reflect.TypeOf((*MockStore)(nil).CreateUserMerchantTx), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// CustomersList mocks base method.
|
// CustomersList mocks base method.
|
||||||
func (m *MockStore) CustomersList(arg0 context.Context, arg1 db.CustomersListParams) ([]db.Customer, error) {
|
func (m *MockStore) CustomersList(arg0 context.Context, arg1 db.CustomersListParams) ([]db.Customer, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
@ -198,6 +243,21 @@ func (mr *MockStoreMockRecorder) GetMerchantByUserId(arg0, arg1 interface{}) *go
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMerchantByUserId", reflect.TypeOf((*MockStore)(nil).GetMerchantByUserId), arg0, arg1)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMerchantByUserId", reflect.TypeOf((*MockStore)(nil).GetMerchantByUserId), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetPasswordByEmail mocks base method.
|
||||||
|
func (m *MockStore) GetPasswordByEmail(arg0 context.Context, arg1 string) (string, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "GetPasswordByEmail", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(string)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPasswordByEmail indicates an expected call of GetPasswordByEmail.
|
||||||
|
func (mr *MockStoreMockRecorder) GetPasswordByEmail(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPasswordByEmail", reflect.TypeOf((*MockStore)(nil).GetPasswordByEmail), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// GetProduct mocks base method.
|
// GetProduct mocks base method.
|
||||||
func (m *MockStore) GetProduct(arg0 context.Context, arg1 uuid.UUID) (db.Product, error) {
|
func (m *MockStore) GetProduct(arg0 context.Context, arg1 uuid.UUID) (db.Product, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
@ -228,6 +288,21 @@ func (mr *MockStoreMockRecorder) GetStockForUpdateStock(arg0, arg1 interface{})
|
|||||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStockForUpdateStock", reflect.TypeOf((*MockStore)(nil).GetStockForUpdateStock), arg0, arg1)
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetStockForUpdateStock", reflect.TypeOf((*MockStore)(nil).GetStockForUpdateStock), arg0, arg1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetUserById mocks base method.
|
||||||
|
func (m *MockStore) GetUserById(arg0 context.Context, arg1 uuid.UUID) (db.User, error) {
|
||||||
|
m.ctrl.T.Helper()
|
||||||
|
ret := m.ctrl.Call(m, "GetUserById", arg0, arg1)
|
||||||
|
ret0, _ := ret[0].(db.User)
|
||||||
|
ret1, _ := ret[1].(error)
|
||||||
|
return ret0, ret1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetUserById indicates an expected call of GetUserById.
|
||||||
|
func (mr *MockStoreMockRecorder) GetUserById(arg0, arg1 interface{}) *gomock.Call {
|
||||||
|
mr.mock.ctrl.T.Helper()
|
||||||
|
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserById", reflect.TypeOf((*MockStore)(nil).GetUserById), arg0, arg1)
|
||||||
|
}
|
||||||
|
|
||||||
// ListProducts mocks base method.
|
// ListProducts mocks base method.
|
||||||
func (m *MockStore) ListProducts(arg0 context.Context, arg1 db.ListProductsParams) ([]db.Product, error) {
|
func (m *MockStore) ListProducts(arg0 context.Context, arg1 db.ListProductsParams) ([]db.Product, error) {
|
||||||
m.ctrl.T.Helper()
|
m.ctrl.T.Helper()
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
-- name: CreateMerchant :one
|
||||||
|
INSERT INTO merchants (name,owner_id)
|
||||||
|
VALUES ($1, $2)
|
||||||
|
RETURNING *;
|
||||||
|
|
||||||
-- name: GetMerchantById :one
|
-- name: GetMerchantById :one
|
||||||
SELECT * FROM merchants
|
SELECT * FROM merchants
|
||||||
WHERE id = $1;
|
WHERE id = $1;
|
@ -9,11 +9,9 @@ RETURNING *;
|
|||||||
-- name: GetPasswordByEmail :one
|
-- name: GetPasswordByEmail :one
|
||||||
SELECT password
|
SELECT password
|
||||||
FROM users
|
FROM users
|
||||||
WHERE email = $1
|
WHERE email = $1;
|
||||||
RETURNING password;
|
|
||||||
|
|
||||||
-- name: GetUserById :one
|
-- name: GetUserById :one
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM users
|
FROM users
|
||||||
WHERE id = $1
|
WHERE id = $1;
|
||||||
RETURNING *;
|
|
@ -1,7 +1,7 @@
|
|||||||
// Code generated by sqlc. DO NOT EDIT.
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
// versions:
|
// versions:
|
||||||
// sqlc v1.17.2
|
// sqlc v1.17.2
|
||||||
// source: merchant.sql
|
// source: merchants.sql
|
||||||
|
|
||||||
package db
|
package db
|
||||||
|
|
||||||
@ -11,6 +11,31 @@ import (
|
|||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
const createMerchant = `-- name: CreateMerchant :one
|
||||||
|
INSERT INTO merchants (name,owner_id)
|
||||||
|
VALUES ($1, $2)
|
||||||
|
RETURNING id, index_id, name, owner_id, created_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateMerchantParams struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
OwnerID uuid.UUID `json:"owner_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateMerchant(ctx context.Context, arg CreateMerchantParams) (Merchant, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, createMerchant, arg.Name, arg.OwnerID)
|
||||||
|
var i Merchant
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.IndexID,
|
||||||
|
&i.Name,
|
||||||
|
&i.OwnerID,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
const getMerchantById = `-- name: GetMerchantById :one
|
const getMerchantById = `-- name: GetMerchantById :one
|
||||||
SELECT id, index_id, name, owner_id, created_at, updated_at FROM merchants
|
SELECT id, index_id, name, owner_id, created_at, updated_at FROM merchants
|
||||||
WHERE id = $1
|
WHERE id = $1
|
1
db/sqlc/merchants_test.go
Normal file
1
db/sqlc/merchants_test.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package db
|
@ -114,7 +114,7 @@ type User struct {
|
|||||||
IndexID int64 `json:"index_id"`
|
IndexID int64 `json:"index_id"`
|
||||||
Email string `json:"email"`
|
Email string `json:"email"`
|
||||||
Password string `json:"password"`
|
Password string `json:"password"`
|
||||||
Fullname sql.NullString `json:"fullname"`
|
Fullname string `json:"fullname"`
|
||||||
CreatedAt sql.NullTime `json:"created_at"`
|
CreatedAt sql.NullTime `json:"created_at"`
|
||||||
UpdatedAt sql.NullTime `json:"updated_at"`
|
UpdatedAt sql.NullTime `json:"updated_at"`
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,7 @@ func createRandomProduct(t *testing.T) (Product, CreateProductParams) {
|
|||||||
stock := util.RandomFloat(10, 10000)
|
stock := util.RandomFloat(10, 10000)
|
||||||
|
|
||||||
arg := CreateProductParams{
|
arg := CreateProductParams{
|
||||||
MerchantID: uuid.MustParse("d9b0e126-991e-46ac-8c61-5efdd605f75d"),
|
MerchantID: uuid.MustParse("a848090f-0409-4386-9caa-929ae6874dbb"),
|
||||||
Name: util.RandomString(10),
|
Name: util.RandomString(10),
|
||||||
SellingPrice: sellingPrice,
|
SellingPrice: sellingPrice,
|
||||||
PurchasePrice: purchasePrice,
|
PurchasePrice: purchasePrice,
|
||||||
|
@ -12,18 +12,22 @@ import (
|
|||||||
|
|
||||||
type Querier interface {
|
type Querier interface {
|
||||||
CreateCustomers(ctx context.Context, arg CreateCustomersParams) (Customer, error)
|
CreateCustomers(ctx context.Context, arg CreateCustomersParams) (Customer, error)
|
||||||
|
CreateMerchant(ctx context.Context, arg CreateMerchantParams) (Merchant, error)
|
||||||
CreateProduct(ctx context.Context, arg CreateProductParams) (Product, error)
|
CreateProduct(ctx context.Context, arg CreateProductParams) (Product, error)
|
||||||
CreatePurchaseOrder(ctx context.Context, arg CreatePurchaseOrderParams) (PurchaseOrder, error)
|
CreatePurchaseOrder(ctx context.Context, arg CreatePurchaseOrderParams) (PurchaseOrder, error)
|
||||||
CreatePurchaseOrderDetail(ctx context.Context, arg CreatePurchaseOrderDetailParams) (PurchaseOrderDetail, error)
|
CreatePurchaseOrderDetail(ctx context.Context, arg CreatePurchaseOrderDetailParams) (PurchaseOrderDetail, error)
|
||||||
CreateSuppliers(ctx context.Context, arg CreateSuppliersParams) (Supplier, error)
|
CreateSuppliers(ctx context.Context, arg CreateSuppliersParams) (Supplier, error)
|
||||||
|
CreateUser(ctx context.Context, arg CreateUserParams) (User, error)
|
||||||
CustomersList(ctx context.Context, arg CustomersListParams) ([]Customer, error)
|
CustomersList(ctx context.Context, arg CustomersListParams) ([]Customer, error)
|
||||||
DeleteCustomer(ctx context.Context, id uuid.UUID) error
|
DeleteCustomer(ctx context.Context, id uuid.UUID) error
|
||||||
DeleteProduct(ctx context.Context, id uuid.UUID) error
|
DeleteProduct(ctx context.Context, id uuid.UUID) error
|
||||||
DeleteSupplier(ctx context.Context, id uuid.UUID) error
|
DeleteSupplier(ctx context.Context, id uuid.UUID) error
|
||||||
GetMerchantById(ctx context.Context, id uuid.UUID) (Merchant, error)
|
GetMerchantById(ctx context.Context, id uuid.UUID) (Merchant, error)
|
||||||
GetMerchantByUserId(ctx context.Context, ownerID uuid.UUID) (Merchant, error)
|
GetMerchantByUserId(ctx context.Context, ownerID uuid.UUID) (Merchant, error)
|
||||||
|
GetPasswordByEmail(ctx context.Context, email string) (string, error)
|
||||||
GetProduct(ctx context.Context, id uuid.UUID) (Product, error)
|
GetProduct(ctx context.Context, id uuid.UUID) (Product, error)
|
||||||
GetStockForUpdateStock(ctx context.Context, id uuid.UUID) (Product, error)
|
GetStockForUpdateStock(ctx context.Context, id uuid.UUID) (Product, error)
|
||||||
|
GetUserById(ctx context.Context, id uuid.UUID) (User, error)
|
||||||
ListProducts(ctx context.Context, arg ListProductsParams) ([]Product, error)
|
ListProducts(ctx context.Context, arg ListProductsParams) ([]Product, error)
|
||||||
SuppliersList(ctx context.Context, arg SuppliersListParams) ([]Supplier, error)
|
SuppliersList(ctx context.Context, arg SuppliersListParams) ([]Supplier, error)
|
||||||
UpdateCustomer(ctx context.Context, id uuid.UUID) (Customer, error)
|
UpdateCustomer(ctx context.Context, id uuid.UUID) (Customer, error)
|
||||||
|
@ -11,6 +11,7 @@ import (
|
|||||||
type Store interface {
|
type Store interface {
|
||||||
Querier
|
Querier
|
||||||
PurchaseOrderTx(ctx context.Context, arg PurchasoOrderTxParams) (PurchaseOrderTxResult, error)
|
PurchaseOrderTx(ctx context.Context, arg PurchasoOrderTxParams) (PurchaseOrderTxResult, error)
|
||||||
|
CreateUserMerchantTx(ctx context.Context, arg UserMerchantTxParams) (UserMerchantTxResult, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type SQLStore struct {
|
type SQLStore struct {
|
||||||
@ -126,3 +127,46 @@ func (store *SQLStore) PurchaseOrderTx(ctx context.Context, arg PurchasoOrderTxP
|
|||||||
|
|
||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UserMerchantTxParams struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
Fullname string `json:"fullname"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
OutletName string `json:"outlet_name"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type UserMerchantTxResult struct {
|
||||||
|
OwnerProfile User `json:"owner_profile"`
|
||||||
|
OutletProfile Merchant `json:"outlet_profile"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (store *SQLStore) CreateUserMerchantTx(ctx context.Context, arg UserMerchantTxParams) (UserMerchantTxResult, error) {
|
||||||
|
var result UserMerchantTxResult
|
||||||
|
err := store.execTx(ctx, func(q *Queries) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
result.OwnerProfile, err = q.CreateUser(ctx, CreateUserParams{
|
||||||
|
Email: arg.Email,
|
||||||
|
Password: arg.Password,
|
||||||
|
Fullname: arg.Fullname,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
result.OutletProfile, err = q.CreateMerchant(ctx, CreateMerchantParams{
|
||||||
|
Name: arg.OutletName,
|
||||||
|
OwnerID: result.OwnerProfile.ID,
|
||||||
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -44,7 +44,9 @@ func TestPurchaseOrder(t *testing.T) {
|
|||||||
|
|
||||||
products = append(products, purchaseProducts_1, purchaseProducts_2)
|
products = append(products, purchaseProducts_1, purchaseProducts_2)
|
||||||
|
|
||||||
for i := 0; i < 5; i++ {
|
tries := 3
|
||||||
|
|
||||||
|
for i := 0; i < tries; i++ {
|
||||||
go func() {
|
go func() {
|
||||||
result, err := store.PurchaseOrderTx(context.Background(), PurchasoOrderTxParams{
|
result, err := store.PurchaseOrderTx(context.Background(), PurchasoOrderTxParams{
|
||||||
MerchantID: supplier.MerchantID,
|
MerchantID: supplier.MerchantID,
|
||||||
@ -61,7 +63,7 @@ func TestPurchaseOrder(t *testing.T) {
|
|||||||
}()
|
}()
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < 5; i++ {
|
for i := 0; i < tries; i++ {
|
||||||
err := <-errs
|
err := <-errs
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
@ -75,3 +77,38 @@ func TestPurchaseOrder(t *testing.T) {
|
|||||||
require.NotZero(t, purchaseOrder.PaidNominal, product1.PurchasePrice+product2.PurchasePrice)
|
require.NotZero(t, purchaseOrder.PaidNominal, product1.PurchasePrice+product2.PurchasePrice)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCreateUserMerchant(t *testing.T) {
|
||||||
|
store := NewStore(testDB)
|
||||||
|
|
||||||
|
errs := make(chan error)
|
||||||
|
results := make(chan UserMerchantTxResult)
|
||||||
|
|
||||||
|
tries := 3
|
||||||
|
|
||||||
|
for i := 0; i < tries; i++ {
|
||||||
|
randString := util.RandomString(10)
|
||||||
|
password, err := util.HashPassword(randString)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
result, err := store.CreateUserMerchantTx(context.Background(), UserMerchantTxParams{
|
||||||
|
Email: util.RandomEmail(),
|
||||||
|
Fullname: util.RandomString(6),
|
||||||
|
Password: password,
|
||||||
|
OutletName: util.RandomString(6),
|
||||||
|
})
|
||||||
|
errs <- err
|
||||||
|
results <- result
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := 0; i < tries; i++ {
|
||||||
|
err := <-errs
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
result := <-results
|
||||||
|
require.NotEmpty(t, result)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -11,7 +11,7 @@ import (
|
|||||||
|
|
||||||
func createRandomSupplier(t *testing.T) (Supplier, CreateSuppliersParams) {
|
func createRandomSupplier(t *testing.T) (Supplier, CreateSuppliersParams) {
|
||||||
arg := CreateSuppliersParams{
|
arg := CreateSuppliersParams{
|
||||||
MerchantID: uuid.MustParse("d9b0e126-991e-46ac-8c61-5efdd605f75d"),
|
MerchantID: uuid.MustParse("a848090f-0409-4386-9caa-929ae6874dbb"),
|
||||||
Name: util.RandomString(10),
|
Name: util.RandomString(10),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
76
db/sqlc/users.sql.go
Normal file
76
db/sqlc/users.sql.go
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
// Code generated by sqlc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// sqlc v1.17.2
|
||||||
|
// source: users.sql
|
||||||
|
|
||||||
|
package db
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
)
|
||||||
|
|
||||||
|
const createUser = `-- name: CreateUser :one
|
||||||
|
INSERT INTO users (
|
||||||
|
email,
|
||||||
|
password,
|
||||||
|
fullname
|
||||||
|
) VALUES ($1, $2, $3)
|
||||||
|
RETURNING id, index_id, email, password, fullname, created_at, updated_at
|
||||||
|
`
|
||||||
|
|
||||||
|
type CreateUserParams struct {
|
||||||
|
Email string `json:"email"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
Fullname string `json:"fullname"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (q *Queries) CreateUser(ctx context.Context, arg CreateUserParams) (User, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, createUser, arg.Email, arg.Password, arg.Fullname)
|
||||||
|
var i User
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.IndexID,
|
||||||
|
&i.Email,
|
||||||
|
&i.Password,
|
||||||
|
&i.Fullname,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getPasswordByEmail = `-- name: GetPasswordByEmail :one
|
||||||
|
SELECT password
|
||||||
|
FROM users
|
||||||
|
WHERE email = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetPasswordByEmail(ctx context.Context, email string) (string, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, getPasswordByEmail, email)
|
||||||
|
var password string
|
||||||
|
err := row.Scan(&password)
|
||||||
|
return password, err
|
||||||
|
}
|
||||||
|
|
||||||
|
const getUserById = `-- name: GetUserById :one
|
||||||
|
SELECT id, index_id, email, password, fullname, created_at, updated_at
|
||||||
|
FROM users
|
||||||
|
WHERE id = $1
|
||||||
|
`
|
||||||
|
|
||||||
|
func (q *Queries) GetUserById(ctx context.Context, id uuid.UUID) (User, error) {
|
||||||
|
row := q.db.QueryRowContext(ctx, getUserById, id)
|
||||||
|
var i User
|
||||||
|
err := row.Scan(
|
||||||
|
&i.ID,
|
||||||
|
&i.IndexID,
|
||||||
|
&i.Email,
|
||||||
|
&i.Password,
|
||||||
|
&i.Fullname,
|
||||||
|
&i.CreatedAt,
|
||||||
|
&i.UpdatedAt,
|
||||||
|
)
|
||||||
|
return i, err
|
||||||
|
}
|
7
db/sqlc/users_test.go
Normal file
7
db/sqlc/users_test.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package db
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestGetUserByID(t *testing.T) {
|
||||||
|
|
||||||
|
}
|
2
go.mod
2
go.mod
@ -11,6 +11,7 @@ require (
|
|||||||
github.com/spf13/viper v1.15.0
|
github.com/spf13/viper v1.15.0
|
||||||
github.com/stretchr/testify v1.8.2
|
github.com/stretchr/testify v1.8.2
|
||||||
github.com/tabbed/pqtype v0.1.1
|
github.com/tabbed/pqtype v0.1.1
|
||||||
|
golang.org/x/crypto v0.7.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
@ -42,7 +43,6 @@ require (
|
|||||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||||
github.com/ugorji/go/codec v1.2.10 // indirect
|
github.com/ugorji/go/codec v1.2.10 // indirect
|
||||||
golang.org/x/arch v0.3.0 // indirect
|
golang.org/x/arch v0.3.0 // indirect
|
||||||
golang.org/x/crypto v0.7.0 // indirect
|
|
||||||
golang.org/x/net v0.8.0 // indirect
|
golang.org/x/net v0.8.0 // indirect
|
||||||
golang.org/x/sys v0.6.0 // indirect
|
golang.org/x/sys v0.6.0 // indirect
|
||||||
golang.org/x/text v0.8.0 // indirect
|
golang.org/x/text v0.8.0 // indirect
|
||||||
|
19
util/password.go
Normal file
19
util/password.go
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func HashPassword(password string) (string, error) {
|
||||||
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
return "", fmt.Errorf("Failed to hash password: %w", err)
|
||||||
|
}
|
||||||
|
return string(hashedPassword), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func CheckPassword(password string, hashedPassword string) error {
|
||||||
|
return bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password))
|
||||||
|
}
|
23
util/password_test.go
Normal file
23
util/password_test.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestPasswordUtil(t *testing.T) {
|
||||||
|
password := RandomString(10)
|
||||||
|
|
||||||
|
hashedPassword, err := HashPassword(password)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.NotEmpty(t, hashedPassword)
|
||||||
|
|
||||||
|
err = CheckPassword(password, hashedPassword)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
wrongPassword := RandomString(5)
|
||||||
|
err = CheckPassword(wrongPassword, hashedPassword)
|
||||||
|
require.EqualError(t, err, bcrypt.ErrMismatchedHashAndPassword.Error())
|
||||||
|
}
|
@ -1,6 +1,7 @@
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
@ -38,3 +39,7 @@ func RandomString(n int) string {
|
|||||||
|
|
||||||
return sb.String()
|
return sb.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func RandomEmail() string {
|
||||||
|
return fmt.Sprintf("%s@mail.com", RandomString(5))
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user