Medication Update

This commit is contained in:
meninjar
2026-04-26 08:06:57 +00:00
parent 9a15d74283
commit 24d25aa14a
37 changed files with 82527 additions and 2172 deletions
+10 -8
View File
@@ -106,7 +106,7 @@ func (r *repository) FindUserByEmail(ctx context.Context, email string) (*User,
var user User
q := query.DynamicQuery{
From: "users", // GORM default table name for User struct
From: "public.users", // Gunakan nama tabel yang eksplisit
Filters: []query.FilterGroup{{
Filters: []query.DynamicFilter{
query.CreateEqualFilter("Email", email),
@@ -117,7 +117,8 @@ func (r *repository) FindUserByEmail(ctx context.Context, email string) (*User,
if err := r.qb.ExecuteQueryRow(ctx, sqlxDB, q, &user); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, nil // Not found is not an error, service layer will handle it
// Not found is not an error, service layer will handle it
return nil, nil
}
return nil, fmt.Errorf("failed to find user by email: %w", err)
}
@@ -159,7 +160,7 @@ func (r *repository) ChangePasswordInTx(ctx context.Context, userID int64, newPa
}}
// Berikan objek transaksi 'tx' ke Query Builder
if _, err = r.qb.ExecuteUpdate(ctx, tx, "users", updateData, filters); err != nil {
if _, err = r.qb.ExecuteUpdate(ctx, tx, "public.users", updateData, filters); err != nil {
return fmt.Errorf("failed to update password in tx: %w", err)
}
@@ -170,7 +171,7 @@ func (r *repository) ChangePasswordInTx(ctx context.Context, userID int64, newPa
}
// Gunakan objek transaksi 'tx' yang sama
if _, err = r.qb.ExecuteInsert(ctx, tx, "user_activity_logs", logData); err != nil {
if _, err = r.qb.ExecuteInsert(ctx, tx, "public.user_activity_logs", logData); err != nil {
// Asumsikan tabel 'user_activity_logs' ada
return fmt.Errorf("failed to log activity in tx: %w", err)
}
@@ -187,7 +188,7 @@ func (r *repository) FindUserByID(ctx context.Context, id int64) (*User, error)
var user User
q := query.DynamicQuery{
From: "users", // GORM default table name for User struct
From: "public.users",
Filters: []query.FilterGroup{{
Filters: []query.DynamicFilter{
query.CreateEqualFilter("Id", id),
@@ -198,7 +199,8 @@ func (r *repository) FindUserByID(ctx context.Context, id int64) (*User, error)
if err := r.qb.ExecuteQueryRow(ctx, sqlxDB, q, &user); err != nil {
if errors.Is(err, sql.ErrNoRows) {
return nil, nil // Not found is not an error, service layer will handle it
// Not found is not an error, service layer will handle it
return nil, nil
}
return nil, fmt.Errorf("failed to find user by id: %w", err)
}
@@ -213,7 +215,7 @@ func (r *repository) FindRefreshToken(ctx context.Context, token string) (*Store
var stored StoredToken
q := query.DynamicQuery{
From: "refresh_tokens",
From: "public.refresh_tokens",
Filters: []query.FilterGroup{{
Filters: []query.DynamicFilter{query.CreateEqualFilter("Token", token)},
}},
@@ -238,5 +240,5 @@ func (r *repository) RevokeAndSaveTokens(ctx context.Context, oldToken string, n
// TODO: Sesuaikan dengan struktur tabel Refresh Token yang Anda miliki di database
// Ini adalah stub untuk memenuhi kontrak interface
return writeDB.WithContext(ctx).Exec("UPDATE refresh_tokens SET is_revoked = ? WHERE token = ?", true, oldToken).Error
return writeDB.WithContext(ctx).Exec("UPDATE public.refresh_tokens SET is_revoked = ? WHERE token = ?", true, oldToken).Error
}
+50 -21
View File
@@ -14,6 +14,7 @@ import (
"time"
"github.com/golang-jwt/jwt/v5"
"golang.org/x/crypto/bcrypt"
)
type StoredToken struct {
@@ -53,25 +54,39 @@ func NewService(cmdRepo CommandRepository, queryRepo QueryRepository, cache *cac
// Login mengimplementasikan otentikasi menggunakan data dummy untuk keperluan testing.
func (s *service) Login(ctx context.Context, req LoginRequest) (*LoginResponse, error) {
// Simulasi pengecekan kredensial dengan beberapa akun dummy
type dummyUser struct {
Password string
UserID string
RoleID string
Name string
// Prioritaskan pengecekan dummy users untuk development, terutama untuk akun sistem seperti worker.
if dummyUser, exists := dummyUsers[req.Email]; exists {
if dummyUser.Password == req.Password {
// Jika kredensial cocok dengan dummy user, langsung generate token.
return s.generateTokens(dummyUser.UserID, req.Email, dummyUser.RoleID, dummyUser.Name)
}
}
dummyUsers := map[string]dummyUser{
"[email protected]": {"password123", "1001", "admin", "Admin Dummy"},
"[email protected]": {"password123", "1002", "user", "User Dummy"},
"[email protected]": {"password123", "1003", "manager", "Manager Dummy"},
// Jika tidak ditemukan di dummy users atau password salah, lanjutkan pengecekan ke database.
user, err := s.queryRepo.FindUserByEmail(ctx, req.Email)
if err != nil {
// Jika terjadi error saat query, kembalikan internal error
return nil, errors.InternalError().Cause(err).Message("Gagal mencari pengguna").Build()
}
user, exists := dummyUsers[req.Email]
if !exists || user.Password != req.Password {
return nil, errors.UnauthorizedError().Message("Email atau password salah. Coba: [email protected], [email protected], [email protected] (password123)").Build()
// Jika pengguna tidak ditemukan di mana pun (dummy atau DB).
if user == nil {
return nil, errors.UnauthorizedError().Message("Email atau password salah.").Build()
}
// Jika pengguna ditemukan di database, validasi password
// Asumsi password di database di-hash menggunakan bcrypt
err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(req.Password))
if err != nil {
// Jika password tidak cocok
return nil, errors.UnauthorizedError().Message("Email atau password salah.").Build()
}
// Jika login berhasil, generate token
return s.generateTokens(fmt.Sprintf("%d", user.Id), user.Email, fmt.Sprintf("%d", *user.RoleID), user.Email)
}
func (s *service) generateTokens(userID, email, roleID, name string) (*LoginResponse, error) {
secret := os.Getenv("JWT_SECRET")
if secret == "" {
secret = "fallback_secret_key_change_in_production"
@@ -79,20 +94,20 @@ func (s *service) Login(ctx context.Context, req LoginRequest) (*LoginResponse,
// Buat Access Token baru (Umur pendek, misal 15 Menit)
accessToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"user_id": user.UserID,
"email": req.Email,
"role_id": user.RoleID,
"name": user.Name,
"user_id": userID,
"email": email,
"role_id": roleID,
"name": name,
"exp": time.Now().Add(60 * time.Minute).Unix(),
})
newAccessTokenStr, _ := accessToken.SignedString([]byte(secret))
// Buat Refresh Token baru (Umur panjang, misal 7 Hari)
refreshToken := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"user_id": user.UserID,
"email": req.Email,
"role_id": user.RoleID,
"name": user.Name,
"user_id": userID,
"email": email,
"role_id": roleID,
"name": name,
"exp": time.Now().Add(7 * 24 * time.Hour).Unix(),
})
newRefreshTokenStr, _ := refreshToken.SignedString([]byte(secret))
@@ -106,6 +121,20 @@ func (s *service) Login(ctx context.Context, req LoginRequest) (*LoginResponse,
}, nil
}
type dummyUser struct {
Password string
UserID string
RoleID string
Name string
}
var dummyUsers = map[string]dummyUser{
"[email protected]": {"password123", "1001", "admin", "Admin Dummy"},
"[email protected]": {"password123", "1002", "user", "User Dummy"},
"[email protected]": {"password123", "1003", "manager", "Manager Dummy"},
"[email protected]": {"password123", "1004", "worker", "Worker Dummy"},
}
// Register mengimplementasikan pendaftaran user dengan respons data json dummy.
func (s *service) Register(ctx context.Context, req RegisterRequest) (interface{}, error) {
// Mengembalikan response dummy seolah-olah user berhasil dibuat di DB