feat (user): adjust for auth, hide pass
This commit is contained in:
@@ -47,7 +47,12 @@ corsCfg:
|
|||||||
allowedMethod:
|
allowedMethod:
|
||||||
|
|
||||||
satuSehatCfg:
|
satuSehatCfg:
|
||||||
host: localhsot:8200
|
host: localhost:8200
|
||||||
|
|
||||||
bpjsCfg:
|
bpjsCfg:
|
||||||
host: localhsot:8200
|
host: localhost:8200
|
||||||
|
|
||||||
|
corsCfg:
|
||||||
|
allowedOrigins:
|
||||||
|
- http://example.com
|
||||||
|
allowedMethod:
|
||||||
@@ -0,0 +1,15 @@
|
|||||||
|
-- Create "User" table
|
||||||
|
CREATE TABLE "public"."User" (
|
||||||
|
"Id" bigserial NOT NULL,
|
||||||
|
"CreatedAt" timestamptz NULL,
|
||||||
|
"UpdatedAt" timestamptz NULL,
|
||||||
|
"DeletedAt" timestamptz NULL,
|
||||||
|
"Name" character varying(25) NOT NULL,
|
||||||
|
"Password" character varying(255) NOT NULL,
|
||||||
|
"Status_Code" character varying(10) NOT NULL,
|
||||||
|
"FailedLoginCount" smallint NULL,
|
||||||
|
"LoginAttemptCount" bigint NULL,
|
||||||
|
"LastSuccessLogin" timestamptz NULL,
|
||||||
|
"LastAllowdLogin" timestamptz NULL,
|
||||||
|
PRIMARY KEY ("Id")
|
||||||
|
);
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
h1:TslQ6d3/z4H6DQJvWAGwP3IVSAr/qYOosLEmorZhYx0=
|
||||||
|
20250819053416.sql h1:kYIqQm8dEYH+feZEHrCekuEvwKl3h1W4zlIpPAWn3W8=
|
||||||
@@ -6,10 +6,15 @@ toolchain go1.24.6
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
ariga.io/atlas-provider-gorm v0.5.6
|
ariga.io/atlas-provider-gorm v0.5.6
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
|
github.com/google/uuid v1.6.0
|
||||||
github.com/karincake/apem v0.0.16-h
|
github.com/karincake/apem v0.0.16-h
|
||||||
github.com/karincake/dodol v0.0.1
|
github.com/karincake/dodol v0.0.1
|
||||||
github.com/karincake/getuk v0.1.0
|
github.com/karincake/getuk v0.1.0
|
||||||
|
github.com/karincake/hongkue v0.0.4
|
||||||
github.com/karincake/lepet v0.0.1
|
github.com/karincake/lepet v0.0.1
|
||||||
|
github.com/karincake/risoles v0.0.3
|
||||||
|
github.com/karincake/semprit v0.0.3
|
||||||
golang.org/x/crypto v0.41.0
|
golang.org/x/crypto v0.41.0
|
||||||
gorm.io/driver/postgres v1.5.11
|
gorm.io/driver/postgres v1.5.11
|
||||||
gorm.io/gorm v1.25.12
|
gorm.io/gorm v1.25.12
|
||||||
@@ -28,6 +33,7 @@ require (
|
|||||||
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
github.com/jackc/puddle/v2 v2.2.1 // indirect
|
||||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
github.com/jinzhu/now v1.1.5 // indirect
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
|
github.com/karincake/serabi v0.0.14 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.19 // indirect
|
github.com/mattn/go-isatty v0.0.19 // indirect
|
||||||
github.com/mattn/go-sqlite3 v1.14.28 // indirect
|
github.com/mattn/go-sqlite3 v1.14.28 // indirect
|
||||||
|
|||||||
@@ -32,6 +32,8 @@ github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8w
|
|||||||
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||||
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
|
||||||
|
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
|
||||||
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
github.com/golang-jwt/jwt/v5 v5.0.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
|
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
|
||||||
github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||||
@@ -73,8 +75,16 @@ github.com/karincake/dodol v0.0.1 h1:jUXmJh1r0Ei4fmHPZ6IUkoplW/V9d27L63JEl6zudL0
|
|||||||
github.com/karincake/dodol v0.0.1/go.mod h1:2f1NcvkvY0J3GMUkwILNDYVvRUpz0W3lpPp/Ha/Ld24=
|
github.com/karincake/dodol v0.0.1/go.mod h1:2f1NcvkvY0J3GMUkwILNDYVvRUpz0W3lpPp/Ha/Ld24=
|
||||||
github.com/karincake/getuk v0.1.0 h1:jcIsASrr0UDE528GN7Ua6n9UFyRgUypsWh8Or8wzCO0=
|
github.com/karincake/getuk v0.1.0 h1:jcIsASrr0UDE528GN7Ua6n9UFyRgUypsWh8Or8wzCO0=
|
||||||
github.com/karincake/getuk v0.1.0/go.mod h1:NVnvxSGAkQ/xuq99FzWACvY5efyKPLFla1cKB8czm7c=
|
github.com/karincake/getuk v0.1.0/go.mod h1:NVnvxSGAkQ/xuq99FzWACvY5efyKPLFla1cKB8czm7c=
|
||||||
|
github.com/karincake/hongkue v0.0.4 h1:oWthq6cDg5DvDm1Z3e7mCLOATQf+oAdtHxN9OPnCfA8=
|
||||||
|
github.com/karincake/hongkue v0.0.4/go.mod h1:YVi5Lyh3DE+GRHx2OSODOr7FwvLi8U4idvcPHO7yeag=
|
||||||
github.com/karincake/lepet v0.0.1 h1:eq/cwn5BBg0jWZ1c/MmvhFIBma0zBpVs2LwkfDOncy4=
|
github.com/karincake/lepet v0.0.1 h1:eq/cwn5BBg0jWZ1c/MmvhFIBma0zBpVs2LwkfDOncy4=
|
||||||
github.com/karincake/lepet v0.0.1/go.mod h1:U84w7olXO3BPJw2Hu6MBonFmJmPKaFjtyAj1HTu3z1A=
|
github.com/karincake/lepet v0.0.1/go.mod h1:U84w7olXO3BPJw2Hu6MBonFmJmPKaFjtyAj1HTu3z1A=
|
||||||
|
github.com/karincake/risoles v0.0.3 h1:7VBShf2yC6NqD0PotQcb0i8Xe6mJeTRrHnE0qzKf7NU=
|
||||||
|
github.com/karincake/risoles v0.0.3/go.mod h1:u4YS+rPp92ODTbGC4RUx4DxKoThnmPjBl1CNdnmKD/c=
|
||||||
|
github.com/karincake/semprit v0.0.3 h1:znleGRu73xrHk6a70+jRQgVh9VF3TAhttQz6vfgNdyM=
|
||||||
|
github.com/karincake/semprit v0.0.3/go.mod h1:nLtNmWlHkxMKG0IMzqnnfkn1L/RVYGXVW3LchfYQMu8=
|
||||||
|
github.com/karincake/serabi v0.0.14 h1:yK3nBLRXdoUNSUDIfbZqIQxnZ6U6Ij5QEO8d5QzZzsw=
|
||||||
|
github.com/karincake/serabi v0.0.14/go.mod h1:GcnPBWb+UotDxvb/a2CKwourCEyVIL4P9+YxVmZ5zgk=
|
||||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Base struct {
|
type Base struct {
|
||||||
CreatedAt time.Time `json:"createdAt" gorm:"type:timestamptz"`
|
CreatedAt time.Time `json:"createdAt" gorm:"column:CreatedAt;type:timestamptz"`
|
||||||
UpdatedAt string `json:"updatedAt" gorm:"type:timestamptz"`
|
UpdatedAt time.Time `json:"updatedAt" gorm:"column:UpdatedAt;type:timestamptz"`
|
||||||
DeteledAt gorm.DeletedAt `json:"deletedAt,omitempty"`
|
DeletedAt gorm.DeletedAt `json:"deletedAt,omitempty" gorm:"column:DeletedAt"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Main struct {
|
type Main struct {
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
package user
|
package user
|
||||||
|
|
||||||
import erc "simrs-vx/internal/domain/references/common"
|
import (
|
||||||
|
ecore "simrs-vx/internal/domain/base-entities/core"
|
||||||
|
erc "simrs-vx/internal/domain/references/common"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
type CreateDto struct {
|
type CreateDto struct {
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
@@ -22,12 +26,12 @@ type ReadDetailDto struct {
|
|||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type Updatedto struct {
|
type UpdateDto struct {
|
||||||
Id uint `json:"id"`
|
Id uint `json:"id"`
|
||||||
CreateDto
|
CreateDto
|
||||||
}
|
}
|
||||||
|
|
||||||
type Deletedto struct {
|
type DeleteDto struct {
|
||||||
Id uint `json:"id"`
|
Id uint `json:"id"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,3 +40,38 @@ type MetaDto struct {
|
|||||||
PageSize int `json:"page_size"`
|
PageSize int `json:"page_size"`
|
||||||
Count int `json:"count"`
|
Count int `json:"count"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type LoginDto struct {
|
||||||
|
Name string `json:"name" validate:"required"`
|
||||||
|
Password string `json:"password" validate:"required"`
|
||||||
|
Duration uint32 `json:"duration"` // in minutes
|
||||||
|
}
|
||||||
|
|
||||||
|
type ResponseDto struct {
|
||||||
|
ecore.Main
|
||||||
|
Name string `json:"name"`
|
||||||
|
Status_Code erc.StatusCode `json:"status_code"`
|
||||||
|
FailedLoginCount uint8 `json:"failedLoginCount"`
|
||||||
|
LastSuccessLogin *time.Time `json:"lastSuccessLogin,omitempty"`
|
||||||
|
LastAllowdLogin *time.Time `json:"lastAllowdLogin,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u User) ToResponse() ResponseDto {
|
||||||
|
resp := ResponseDto{
|
||||||
|
Name: u.Name,
|
||||||
|
Status_Code: u.Status_Code,
|
||||||
|
FailedLoginCount: u.FailedLoginCount,
|
||||||
|
LastSuccessLogin: u.LastSuccessLogin,
|
||||||
|
LastAllowdLogin: u.LastAllowdLogin,
|
||||||
|
}
|
||||||
|
resp.Main = u.Main
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
||||||
|
func ToResponseList(users []User) []ResponseDto {
|
||||||
|
resp := make([]ResponseDto, len(users))
|
||||||
|
for i, u := range users {
|
||||||
|
resp[i] = u.ToResponse()
|
||||||
|
}
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,12 +3,16 @@ package user
|
|||||||
import (
|
import (
|
||||||
ecore "simrs-vx/internal/domain/base-entities/core"
|
ecore "simrs-vx/internal/domain/base-entities/core"
|
||||||
erc "simrs-vx/internal/domain/references/common"
|
erc "simrs-vx/internal/domain/references/common"
|
||||||
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
ecore.Main // adjust this according to the needs
|
ecore.Main // adjust this according to the needs
|
||||||
Name string `json:"name" gorm:"not null;size:25"`
|
Name string `json:"name" gorm:"not null;size:25"`
|
||||||
Password string `json:"password" gorm:"not null;size:255"`
|
Password string `json:"password" gorm:"not null;size:255"`
|
||||||
Status_Code erc.StatusCode `json:"status_code" gorm:"not null;size:10"`
|
Status_Code erc.StatusCode `json:"status_code" gorm:"not null;size:10"`
|
||||||
FailedLoginCount uint8 `json:"failedLoginCount" gorm:"type:smallint"`
|
FailedLoginCount uint8 `json:"failedLoginCount" gorm:"type:smallint"`
|
||||||
|
LoginAttemptCount int `json:"-"`
|
||||||
|
LastSuccessLogin *time.Time `json:"lastSuccessLogin,omitempty"`
|
||||||
|
LastAllowdLogin *time.Time `json:"lastAllowdLogin,omitempty"`
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
SCActive StatusCode = "active"
|
SCNew StatusCode = "new"
|
||||||
SCInactive StatusCode = "inactive"
|
SCActive StatusCode = "active"
|
||||||
|
SCBlocked StatusCode = "blocked"
|
||||||
|
SCSuspended StatusCode = "suspended"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,6 +3,10 @@ package handler
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
|
/******************** main / transaction ********************/
|
||||||
|
auth "simrs-vx/internal/interface/main-handler/authentication"
|
||||||
|
user "simrs-vx/internal/interface/main-handler/user"
|
||||||
|
|
||||||
/******************** external ********************/
|
/******************** external ********************/
|
||||||
a "github.com/karincake/apem"
|
a "github.com/karincake/apem"
|
||||||
|
|
||||||
@@ -11,6 +15,8 @@ import (
|
|||||||
ssdb "simrs-vx/internal/infra/ss-db"
|
ssdb "simrs-vx/internal/infra/ss-db"
|
||||||
|
|
||||||
/******************** pkg ********************/
|
/******************** pkg ********************/
|
||||||
|
cmw "simrs-vx/pkg/cors-manager-mw"
|
||||||
|
hc "simrs-vx/pkg/handler-crud-helper"
|
||||||
handlerlogger "simrs-vx/pkg/middleware/handler-logger"
|
handlerlogger "simrs-vx/pkg/middleware/handler-logger"
|
||||||
|
|
||||||
///// Internal
|
///// Internal
|
||||||
@@ -28,6 +34,11 @@ func SetRoutes() http.Handler {
|
|||||||
/******************** Main ********************/
|
/******************** Main ********************/
|
||||||
r.HandleFunc("/", home.Home)
|
r.HandleFunc("/", home.Home)
|
||||||
|
|
||||||
|
r.HandleFunc("POST /v1/authentication/login", auth.Login)
|
||||||
|
r.HandleFunc("POST /v1/authentication/logout", auth.Logout)
|
||||||
|
|
||||||
|
hc.RegCrud(r, "/v1/user", user.O)
|
||||||
|
|
||||||
/////
|
/////
|
||||||
return handlerlogger.SetLog(r)
|
return cmw.SetCors(handlerlogger.SetLog(r))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package user
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
rw "github.com/karincake/risoles"
|
||||||
|
sf "github.com/karincake/semprit"
|
||||||
|
|
||||||
|
// ua "github.com/karincake/tumpeng/auth/svc"
|
||||||
|
|
||||||
|
e "simrs-vx/internal/domain/main-entities/user"
|
||||||
|
u "simrs-vx/internal/use-case/main-use-case/user"
|
||||||
|
)
|
||||||
|
|
||||||
|
type myBase struct{}
|
||||||
|
|
||||||
|
var O myBase
|
||||||
|
|
||||||
|
func (obj myBase) Create(w http.ResponseWriter, r *http.Request) {
|
||||||
|
dto := e.CreateDto{}
|
||||||
|
if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
res, err := u.Create(dto)
|
||||||
|
rw.DataResponse(w, res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) {
|
||||||
|
dto := e.ReadListDto{}
|
||||||
|
sf.UrlQueryParam(&dto, *r.URL)
|
||||||
|
res, err := u.ReadList(dto)
|
||||||
|
rw.DataResponse(w, res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) {
|
||||||
|
id := rw.ValidateInt(w, "id", r.PathValue("id"))
|
||||||
|
if id <= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dto := e.ReadDetailDto{}
|
||||||
|
dto.Id = uint(id)
|
||||||
|
res, err := u.ReadDetail(dto)
|
||||||
|
rw.DataResponse(w, res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (obj myBase) Update(w http.ResponseWriter, r *http.Request) {
|
||||||
|
id := rw.ValidateInt(w, "id", r.PathValue("id"))
|
||||||
|
if id <= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dto := e.UpdateDto{}
|
||||||
|
if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
dto.Id = uint(id)
|
||||||
|
res, err := u.Update(dto)
|
||||||
|
rw.DataResponse(w, res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) {
|
||||||
|
id := rw.ValidateInt(w, "id", r.PathValue("id"))
|
||||||
|
if id <= 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
dto := e.DeleteDto{}
|
||||||
|
dto.Id = uint(id)
|
||||||
|
res, err := u.Delete(dto)
|
||||||
|
rw.DataResponse(w, res, err)
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
package authentication
|
||||||
|
|
||||||
|
import (
|
||||||
|
dg "github.com/karincake/apem/db-gorm-mysql"
|
||||||
|
)
|
||||||
|
|
||||||
|
// just return the error code
|
||||||
|
func GetAndCheck(input, condition any) (eCode string) {
|
||||||
|
result := dg.I.Where(condition).Find(input)
|
||||||
|
if result.Error != nil {
|
||||||
|
return "fetch-fail"
|
||||||
|
} else if result.RowsAffected == 0 {
|
||||||
|
return "auth-login-incorrect"
|
||||||
|
}
|
||||||
|
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetDocName(id uint) string {
|
||||||
|
return "authentication"
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package authentication
|
||||||
|
|
||||||
|
type TokenType string
|
||||||
|
|
||||||
|
const AccessToken = "Access"
|
||||||
|
const RefreshToken = "Refresh"
|
||||||
|
|
||||||
|
type AuthInfo struct {
|
||||||
|
Uuid string
|
||||||
|
User_Id int
|
||||||
|
User_Name string
|
||||||
|
// User_Email string
|
||||||
|
// User_Ref_Id int
|
||||||
|
// User_Position_Code string
|
||||||
|
}
|
||||||
|
|
||||||
|
type AuthCfg struct {
|
||||||
|
AtSecretKey string `yaml:"atSecretKey"`
|
||||||
|
RtSecretKey string `yaml:"rtSecretKey"`
|
||||||
|
}
|
||||||
@@ -98,11 +98,11 @@ func Create(input e.CreateDto) (*d.Data, error) {
|
|||||||
|
|
||||||
return &d.Data{
|
return &d.Data{
|
||||||
Meta: d.II{
|
Meta: d.II{
|
||||||
"source": source,
|
"source": source,
|
||||||
"type": "list",
|
"structure": "single-data",
|
||||||
"status": "created",
|
"status": "created",
|
||||||
},
|
},
|
||||||
Data: data,
|
Data: data.ToResponse(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -145,7 +145,7 @@ func ReadList(input e.ReadListDto) (*d.Data, error) {
|
|||||||
"page_size": strconv.Itoa(metaList.PageSize),
|
"page_size": strconv.Itoa(metaList.PageSize),
|
||||||
"record_totalCount": strconv.Itoa(metaList.Count),
|
"record_totalCount": strconv.Itoa(metaList.Count),
|
||||||
},
|
},
|
||||||
Data: dataList,
|
Data: e.ToResponseList(dataList),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,7 +158,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
data, err := ReadDetailData(input, tx)
|
data, err = ReadDetailData(input, tx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -180,11 +180,11 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) {
|
|||||||
"structure": "single-data",
|
"structure": "single-data",
|
||||||
"status": "fetched",
|
"status": "fetched",
|
||||||
},
|
},
|
||||||
Data: data,
|
Data: data.ToResponse(),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Update(input e.Updatedto) (*d.Data, error) {
|
func Update(input e.UpdateDto) (*d.Data, error) {
|
||||||
rdDto := e.ReadDetailDto{Id: input.Id}
|
rdDto := e.ReadDetailDto{Id: input.Id}
|
||||||
var data *e.User
|
var data *e.User
|
||||||
var err error
|
var err error
|
||||||
@@ -224,12 +224,12 @@ func Update(input e.Updatedto) (*d.Data, error) {
|
|||||||
"structure": "single-data",
|
"structure": "single-data",
|
||||||
"status": "updated",
|
"status": "updated",
|
||||||
},
|
},
|
||||||
Data: data,
|
Data: data.ToResponse(),
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Delete(input e.Deletedto) (*d.Data, error) {
|
func Delete(input e.DeleteDto) (*d.Data, error) {
|
||||||
rdDto := e.ReadDetailDto{Id: input.Id}
|
rdDto := e.ReadDetailDto{Id: input.Id}
|
||||||
var data *e.User
|
var data *e.User
|
||||||
var err error
|
var err error
|
||||||
@@ -264,7 +264,7 @@ func Delete(input e.Deletedto) (*d.Data, error) {
|
|||||||
"structure": "single-data",
|
"structure": "single-data",
|
||||||
"status": "deleted",
|
"status": "deleted",
|
||||||
},
|
},
|
||||||
Data: data,
|
Data: data.ToResponse(),
|
||||||
}, nil
|
}, nil
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,9 +23,9 @@ func setCreate(src e.CreateDto, dst *e.User) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func setUpdate(src e.Updatedto, dst *e.User) error {
|
func setUpdate(src e.UpdateDto, dst *e.User) error {
|
||||||
dst.Name = src.CreateDto.Name
|
dst.Name = src.Name
|
||||||
dst.Status_Code = src.CreateDto.Status_Code
|
dst.Status_Code = src.Status_Code
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.User, *e.MetaDto, e
|
|||||||
Scopes(gh.Paginate(input, &pagination)).
|
Scopes(gh.Paginate(input, &pagination)).
|
||||||
Order("CreatedAt DESC")
|
Order("CreatedAt DESC")
|
||||||
|
|
||||||
if err := tx.Find(&data).Error; err != nil {
|
if err := tx.Debug().Find(&data).Error; err != nil {
|
||||||
if err == gorm.ErrRecordNotFound {
|
if err == gorm.ErrRecordNotFound {
|
||||||
return nil, &meta, nil
|
return nil, &meta, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package handlercrudhelper
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"reflect"
|
||||||
|
|
||||||
|
hk "github.com/karincake/hongkue"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RegCrud(r *http.ServeMux, path string, mwAndRouter ...any) {
|
||||||
|
sLength := len(mwAndRouter)
|
||||||
|
|
||||||
|
mwCandidates := mwAndRouter[:sLength-1]
|
||||||
|
mwList := []hk.HandlerMw{}
|
||||||
|
for i := range mwCandidates {
|
||||||
|
// have to do it manually, since casting directly results unexpected result
|
||||||
|
myType := reflect.TypeOf(mwCandidates[i])
|
||||||
|
if myType.String() != "func(http.Handler) http.Handler" {
|
||||||
|
panic("non middleware included as middleware")
|
||||||
|
}
|
||||||
|
mwList = append(mwList, mwCandidates[i].(func(http.Handler) http.Handler))
|
||||||
|
|
||||||
|
// if g, okHandler := mwCandidates[i].(func(http.Handler) http.Handler); !okHandler {
|
||||||
|
// panic("non middleware included")
|
||||||
|
// } else {
|
||||||
|
// mwList = append(mwList, g)
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
c, ok := mwAndRouter[sLength-1].(CrudBase)
|
||||||
|
if !ok {
|
||||||
|
panic("non CrudBase used in the last paramter")
|
||||||
|
}
|
||||||
|
|
||||||
|
hk.GroupRoutes(path, r, mwList, hk.MapHandlerFunc{
|
||||||
|
"POST /": c.Create,
|
||||||
|
"GET /": c.GetList,
|
||||||
|
"GET /{id}": c.GetDetail,
|
||||||
|
"PATCH /{id}": c.Update,
|
||||||
|
"DELETE /{id}": c.Delete,
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package handlercrudhelper
|
||||||
|
|
||||||
|
import "net/http"
|
||||||
|
|
||||||
|
type CrudBase interface {
|
||||||
|
Create(w http.ResponseWriter, r *http.Request)
|
||||||
|
GetList(w http.ResponseWriter, r *http.Request)
|
||||||
|
GetDetail(w http.ResponseWriter, r *http.Request)
|
||||||
|
Update(w http.ResponseWriter, r *http.Request)
|
||||||
|
Delete(w http.ResponseWriter, r *http.Request)
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@ package logger
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
|
||||||
lz "github.com/karincake/apem/logger-zerolog"
|
lz "github.com/karincake/apem/logger-zerolog"
|
||||||
d "github.com/karincake/dodol"
|
d "github.com/karincake/dodol"
|
||||||
@@ -64,3 +65,15 @@ func SetLogError(e Event, data any) error {
|
|||||||
}
|
}
|
||||||
return d.FieldError{Code: e.ErrInfo.Code, Message: msg}
|
return d.FieldError{Code: e.ErrInfo.Code, Message: msg}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func GenMessage(errCode string, errDetail ...string) string {
|
||||||
|
errMsg := ""
|
||||||
|
if len(errDetail) == 0 || errDetail[0] == "" {
|
||||||
|
errMsg = l.I.Msg(errCode)
|
||||||
|
} else if len(errDetail) == 1 && errDetail[0] != "" { // manual
|
||||||
|
errMsg = fmt.Sprintf(l.I.Msg(errCode), errDetail[0])
|
||||||
|
} else if len(errDetail) == 2 && errDetail[0] != "" && errDetail[1] != "" { // manual
|
||||||
|
errMsg = fmt.Sprintf(l.I.Msg(errCode), errDetail[0], errDetail[1])
|
||||||
|
}
|
||||||
|
return errMsg
|
||||||
|
}
|
||||||
|
|||||||
@@ -6,12 +6,10 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
l "github.com/karincake/apem/loggera"
|
lz "github.com/karincake/apem/logger-zerolog"
|
||||||
lo "github.com/karincake/apem/loggero"
|
lo "github.com/karincake/apem/loggero"
|
||||||
)
|
)
|
||||||
|
|
||||||
var Logger l.LoggerItf
|
|
||||||
|
|
||||||
type wrappedWriter struct {
|
type wrappedWriter struct {
|
||||||
http.ResponseWriter
|
http.ResponseWriter
|
||||||
statusCode int
|
statusCode int
|
||||||
@@ -31,7 +29,7 @@ func SetLog(next http.Handler) http.Handler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
next.ServeHTTP(wrapped, r)
|
next.ServeHTTP(wrapped, r)
|
||||||
Logger.Info().
|
lz.O.Info().
|
||||||
String("scope", "request").
|
String("scope", "request").
|
||||||
Int("status", wrapped.statusCode).
|
Int("status", wrapped.statusCode).
|
||||||
String("method", r.Method).
|
String("method", r.Method).
|
||||||
|
|||||||
Reference in New Issue
Block a user