feat (user): add create

This commit is contained in:
dpurbosakti
2025-08-13 14:26:14 +07:00
parent 2e88eaf793
commit 7577c87f27
12 changed files with 342 additions and 9 deletions
+2 -2
View File
@@ -1,6 +1,6 @@
package single
type Createdto struct {
type CreateDto struct {
Code string `json:"code"`
Name string `json:"name"`
Description string `json:"description"`
@@ -23,7 +23,7 @@ type ReadDetailDto struct {
type Updatedto struct {
Id uint `json:"id"`
Createdto
CreateDto
}
type Deletedto struct {
+38
View File
@@ -0,0 +1,38 @@
package user
import erc "simrs-vx/internal/domain/references/common"
type CreateDto struct {
Name string `json:"name"`
Password string `json:"password"`
Status_Code erc.StatusCode `json:"status_code"`
}
type ReadListDto struct {
Name string `json:"name"`
Status_Code erc.StatusCode `json:"status_code"`
Page int `json:"page"`
PageSize int `json:"page_size"`
NoPagination int `json:"no_pagination"`
}
type ReadDetailDto struct {
Id uint `json:"id"`
Name string `json:"name"`
}
type Updatedto struct {
Id uint `json:"id"`
CreateDto
}
type Deletedto struct {
Id uint `json:"id"`
}
type MetaDto struct {
PageNumber int `json:"page_number"`
PageSize int `json:"page_size"`
Count int64 `json:"count"`
}
@@ -0,0 +1,14 @@
package user
import (
ecore "simrs-vx/internal/domain/base-entities/core"
erc "simrs-vx/internal/domain/references/common"
)
type User struct {
ecore.Main // adjust this according to the needs
Name string `json:"name" gorm:"not null;size:25"`
Password string `json:"password" gorm:"not null;size:255"`
Status_Code erc.StatusCode `json:"status_code" gorm:"not null;size:10"`
FailedLoginCount uint `json:"failedLoginCount"`
}
@@ -23,7 +23,7 @@ const source = "crud"
func Create(input e.Createdto) (*d.Data, error) {
data := e.Single{}
setData(&data, &input)
setData(input, &data)
event := pl.Event{
Feature: "Create",
@@ -47,7 +47,7 @@ func Create(input e.Createdto) (*d.Data, error) {
event.ErrInfo = pl.ErrorInfo{
Code: "MW_PRE_FAILED", // TODO: add to lang json
Detail: fmt.Sprintf("Pre-middleware %s failed", mwName),
Raw: mwErr,
Raw: err,
}
return pl.SetLogError(event, data)
}
@@ -59,7 +59,8 @@ func Create(input e.Createdto) (*d.Data, error) {
event.Action = "DBCreate"
event.Status = "started"
pl.SetLogInfo(event, data)
if result, err := CreateData(&data, tx).Error; err != nil {
result, err := CreateData(&data, tx)
if err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-create-fail",
@@ -83,7 +84,7 @@ func Create(input e.Createdto) (*d.Data, error) {
event.ErrInfo = pl.ErrorInfo{
Code: "MW_POST_FAILED", // TODO: add to lang json
Detail: fmt.Sprintf("Post-middleware %s failed", mwName),
Raw: mwErr,
Raw: err,
}
return pl.SetLogError(event, data)
}
@@ -5,7 +5,7 @@ Any functions that are used internally by the use-case
package crud
import (
e "simrs-vx/internal/domain/main-entities/single"
e "simrs-vx/internal/domain/_template/single"
)
func setData(src e.Createdto, dst *e.Single) {
@@ -16,7 +16,7 @@ func CreateData(input *e.Single, dbx ...*gorm.DB) (*e.Single, error) {
tx = dg.I
}
if err := tx.Create(&data).Error; err != nil {
if err := tx.Create(&input).Error; err != nil {
return nil, err
}
@@ -14,7 +14,7 @@ import (
e "simrs-vx/internal/domain/main-entities/single"
)
type createMw func(input *e.Createdto, data *e.Single, tx *gorm.DB) error
type createMw func(input *e.CreateDto, data *e.Single, tx *gorm.DB) error
type readListMw func(input *e.ReadListDto, data *e.Single, tx *gorm.DB) error
type readDetailMw func(input *e.ReadDetailDto, data *e.Single, tx *gorm.DB) error
type updateMw func(input *e.ReadDetailDto, data *e.Single, tx *gorm.DB) error
@@ -0,0 +1,106 @@
package user
import (
"fmt"
e "simrs-vx/internal/domain/main-entities/user"
dg "github.com/karincake/apem/db-gorm-pg"
d "github.com/karincake/dodol"
pl "simrs-vx/pkg/logger"
"gorm.io/gorm"
)
const source = "user"
func Create(input e.CreateDto) (*d.Data, error) {
data := e.User{}
setData(input, &data)
event := pl.Event{
Feature: "Create",
Source: source,
}
// Start log
event.Action = "Create"
event.Status = "started"
pl.SetLogInfo(event, input)
err := dg.I.Transaction(func(tx *gorm.DB) error {
for i := range createPreMw {
mwName := fmt.Sprintf("createPreMw[%d]", i)
event.Action = mwName
event.Status = "started"
pl.SetLogInfo(event, data)
if err := createPreMw[i](&input, &data, tx); err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "MW_PRE_FAILED", // TODO: add to lang json
Detail: fmt.Sprintf("Pre-middleware %s failed", mwName),
Raw: err,
}
return pl.SetLogError(event, data)
}
event.Status = "completed"
pl.SetLogInfo(event, nil)
}
event.Action = "DBCreate"
event.Status = "started"
pl.SetLogInfo(event, data)
_, err := CreateData(&data, tx)
if err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "data-create-fail",
Detail: "Database insert failed",
Raw: err,
}
return pl.SetLogError(event, data)
}
event.Status = "completed"
pl.SetLogInfo(event, nil)
for i := range createPostMw {
mwName := fmt.Sprintf("createPostMw[%d]", i)
event.Action = mwName
event.Status = "started"
pl.SetLogInfo(event, input)
if err := createPostMw[i](&input, &data, tx); err != nil {
event.Status = "failed"
event.ErrInfo = pl.ErrorInfo{
Code: "MW_POST_FAILED", // TODO: add to lang json
Detail: fmt.Sprintf("Post-middleware %s failed", mwName),
Raw: err,
}
return pl.SetLogError(event, data)
}
}
event.Status = "completed"
pl.SetLogInfo(event, nil)
return nil
})
if err != nil {
return nil, err
}
return &d.Data{
Meta: d.II{
"source": source,
"type": "list",
"status": "created",
},
Data: data,
}, nil
}
@@ -0,0 +1,24 @@
/*
DESCRIPTION:
Any functions that are used internally by the use-case
*/
package user
import (
e "simrs-vx/internal/domain/main-entities/user"
p "simrs-vx/pkg/password"
)
func setData(src e.CreateDto, dst *e.User) error {
pass, err := p.Hash(src.Password)
if err != nil {
return err
}
dst.Name = src.Name
dst.Password = pass
dst.Status_Code = src.Status_Code
return nil
}
+101
View File
@@ -0,0 +1,101 @@
package user
import (
e "simrs-vx/internal/domain/main-entities/user"
dg "github.com/karincake/apem/db-gorm-pg"
gh "github.com/karincake/getuk"
"gorm.io/gorm"
)
func CreateData(input *e.User, dbx ...*gorm.DB) (*e.User, error) {
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
if err := tx.Create(&input).Error; err != nil {
return nil, err
}
return input, nil
}
func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.User, *e.MetaDto, error) {
data := []e.User{}
pagination := gh.Pagination{}
count := int64(0)
meta := e.MetaDto{}
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
tx = tx.
Model(&e.User{}).
// Joins("Patient"). // if needed
// Preload("Patient"). // if needed
Scopes(gh.Filter(input)).
Count(&count).
Scopes(gh.Paginate(input, &pagination)).
Order("CreatedAt DESC")
if err := tx.Find(&data).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, &meta, nil
}
return nil, nil, err
}
meta.Count = count
meta.PageNumber = pagination.PageNumber
meta.PageSize = pagination.PageSize
return data, &meta, nil
}
func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.User, error) {
data := e.User{}
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
if err := tx.First(&data, input.Id).Error; err != nil {
if err == gorm.ErrRecordNotFound {
return nil, nil
}
return nil, err
}
return &data, nil
}
func UpdateData(input e.User, dbx ...*gorm.DB) error {
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
return tx.Save(&input).Error
}
func DeleteData(input *e.User, dbx ...*gorm.DB) error {
var tx *gorm.DB
if len(dbx) > 0 {
tx = dbx[0]
} else {
tx = dg.I
}
return tx.Delete(input).Error
}
@@ -0,0 +1,32 @@
/*
DESCRIPTION:
A sample, part of the package that contains type, constants, and/or variables.
In this sample it also provides type and variable regarding the needs of the
middleware to separate from main use-case which has the basic CRUD
functionality. The purpose of this is to make the code more maintainable.
*/
package user
import (
"gorm.io/gorm"
e "simrs-vx/internal/domain/main-entities/user"
)
type createMw func(input *e.CreateDto, data *e.User, tx *gorm.DB) error
type readListMw func(input *e.ReadListDto, data *e.User, tx *gorm.DB) error
type readDetailMw func(input *e.ReadDetailDto, data *e.User, tx *gorm.DB) error
type updateMw func(input *e.ReadDetailDto, data *e.User, tx *gorm.DB) error
type deleteMw func(input *e.ReadDetailDto, data *e.User, tx *gorm.DB) error
var createPreMw []createMw // preprocess middleware
var createPostMw []createMw // postprocess middleware
var readListPreMw []readListMw // ..
var readListPostMw []readListMw // ..
var readDetailPreMw []readDetailMw
var readDetailPostMw []readDetailMw
var udpatePreMw []readDetailMw
var udpatePostMw []readDetailMw
var deletePreMw []readDetailMw
var deletePostMw []readDetailMw
+17
View File
@@ -0,0 +1,17 @@
package password
import (
"golang.org/x/crypto/bcrypt"
)
var Cost = 10 // can be set by consumer
func Hash(password string) (string, error) {
bytes, err := bcrypt.GenerateFromPassword([]byte(password), Cost)
return string(bytes), err
}
func Check(password, hash string) bool {
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
return err == nil
}