479 lines
16 KiB
Go
479 lines
16 KiB
Go
package identitycart
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"mime/multipart"
|
|
"os"
|
|
"path/filepath"
|
|
"rijig/internal/authentication"
|
|
"rijig/internal/role"
|
|
"rijig/internal/userprofile"
|
|
"rijig/model"
|
|
"rijig/utils"
|
|
"time"
|
|
)
|
|
|
|
type IdentityCardService interface {
|
|
CreateIdentityCard(ctx context.Context, userID, deviceID string, request *RequestIdentityCardDTO, cardPhoto *multipart.FileHeader) (*authentication.AuthResponse, error)
|
|
GetIdentityCardByID(ctx context.Context, id string) (*ResponseIdentityCardDTO, error)
|
|
GetIdentityCardsByUserID(ctx context.Context, userID string) ([]ResponseIdentityCardDTO, error)
|
|
UpdateIdentityCard(ctx context.Context, userID string, id string, request *RequestIdentityCardDTO, cardPhoto *multipart.FileHeader) (*ResponseIdentityCardDTO, error)
|
|
|
|
GetAllIdentityCardsByRegStatus(ctx context.Context, userRegStatus string) ([]ResponseIdentityCardDTO, error)
|
|
UpdateUserRegistrationStatusByIdentityCard(ctx context.Context, identityCardUserID string, newStatus string) error
|
|
}
|
|
|
|
type identityCardService struct {
|
|
identityRepo IdentityCardRepository
|
|
authRepo authentication.AuthenticationRepository
|
|
userRepo userprofile.UserProfileRepository
|
|
}
|
|
|
|
func NewIdentityCardService(identityRepo IdentityCardRepository, authRepo authentication.AuthenticationRepository, userRepo userprofile.UserProfileRepository) IdentityCardService {
|
|
return &identityCardService{
|
|
identityRepo,
|
|
authRepo, userRepo,
|
|
}
|
|
}
|
|
|
|
type IdentityCardWithUserDTO struct {
|
|
IdentityCard ResponseIdentityCardDTO `json:"identity_card"`
|
|
User userprofile.UserProfileResponseDTO `json:"user"`
|
|
}
|
|
|
|
func FormatResponseIdentityCard(identityCard *model.IdentityCard) (*ResponseIdentityCardDTO, error) {
|
|
createdAt, _ := utils.FormatDateToIndonesianFormat(identityCard.CreatedAt)
|
|
updatedAt, _ := utils.FormatDateToIndonesianFormat(identityCard.UpdatedAt)
|
|
|
|
return &ResponseIdentityCardDTO{
|
|
ID: identityCard.ID,
|
|
UserID: identityCard.UserID,
|
|
Identificationumber: identityCard.Identificationumber,
|
|
Placeofbirth: identityCard.Placeofbirth,
|
|
Dateofbirth: identityCard.Dateofbirth,
|
|
Gender: identityCard.Gender,
|
|
BloodType: identityCard.BloodType,
|
|
Province: identityCard.Province,
|
|
District: identityCard.District,
|
|
SubDistrict: identityCard.SubDistrict,
|
|
Hamlet: identityCard.Hamlet,
|
|
Village: identityCard.Village,
|
|
Neighbourhood: identityCard.Neighbourhood,
|
|
PostalCode: identityCard.PostalCode,
|
|
Religion: identityCard.Religion,
|
|
Maritalstatus: identityCard.Maritalstatus,
|
|
Job: identityCard.Job,
|
|
Citizenship: identityCard.Citizenship,
|
|
Validuntil: identityCard.Validuntil,
|
|
Cardphoto: identityCard.Cardphoto,
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
}, nil
|
|
}
|
|
|
|
func (s *identityCardService) saveIdentityCardImage(userID string, cardPhoto *multipart.FileHeader) (string, error) {
|
|
pathImage := "/uploads/identitycards/"
|
|
cardPhotoDir := "./public" + os.Getenv("BASE_URL") + pathImage
|
|
if _, err := os.Stat(cardPhotoDir); os.IsNotExist(err) {
|
|
|
|
if err := os.MkdirAll(cardPhotoDir, os.ModePerm); err != nil {
|
|
return "", fmt.Errorf("failed to create directory for identity card photo: %v", err)
|
|
}
|
|
}
|
|
|
|
allowedExtensions := map[string]bool{".jpg": true, ".jpeg": true, ".png": true}
|
|
extension := filepath.Ext(cardPhoto.Filename)
|
|
if !allowedExtensions[extension] {
|
|
return "", fmt.Errorf("invalid file type, only .jpg, .jpeg, and .png are allowed")
|
|
}
|
|
|
|
cardPhotoFileName := fmt.Sprintf("%s_cardphoto%s", userID, extension)
|
|
cardPhotoPath := filepath.Join(cardPhotoDir, cardPhotoFileName)
|
|
|
|
src, err := cardPhoto.Open()
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to open uploaded file: %v", err)
|
|
}
|
|
defer src.Close()
|
|
|
|
dst, err := os.Create(cardPhotoPath)
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to create card photo file: %v", err)
|
|
}
|
|
defer dst.Close()
|
|
|
|
if _, err := io.Copy(dst, src); err != nil {
|
|
return "", fmt.Errorf("failed to save card photo: %v", err)
|
|
}
|
|
|
|
cardPhotoURL := fmt.Sprintf("%s%s", pathImage, cardPhotoFileName)
|
|
|
|
return cardPhotoURL, nil
|
|
}
|
|
|
|
func deleteIdentityCardImage(imagePath string) error {
|
|
if imagePath == "" {
|
|
return nil
|
|
}
|
|
|
|
baseDir := "./public/" + os.Getenv("BASE_URL")
|
|
absolutePath := baseDir + imagePath
|
|
|
|
if _, err := os.Stat(absolutePath); os.IsNotExist(err) {
|
|
return fmt.Errorf("image file not found: %v", err)
|
|
}
|
|
|
|
err := os.Remove(absolutePath)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to delete image: %v", err)
|
|
}
|
|
|
|
log.Printf("Image deleted successfully: %s", absolutePath)
|
|
return nil
|
|
}
|
|
|
|
func (s *identityCardService) CreateIdentityCard(ctx context.Context, userID, deviceID string, request *RequestIdentityCardDTO, cardPhoto *multipart.FileHeader) (*authentication.AuthResponse, error) {
|
|
|
|
cardPhotoPath, err := s.saveIdentityCardImage(userID, cardPhoto)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to save card photo: %v", err)
|
|
}
|
|
|
|
identityCard := &model.IdentityCard{
|
|
UserID: userID,
|
|
Identificationumber: request.Identificationumber,
|
|
Placeofbirth: request.Placeofbirth,
|
|
Dateofbirth: request.Dateofbirth,
|
|
Gender: request.Gender,
|
|
BloodType: request.BloodType,
|
|
Province: request.Province,
|
|
District: request.District,
|
|
SubDistrict: request.SubDistrict,
|
|
Hamlet: request.Hamlet,
|
|
Village: request.Village,
|
|
Neighbourhood: request.Neighbourhood,
|
|
PostalCode: request.PostalCode,
|
|
Religion: request.Religion,
|
|
Maritalstatus: request.Maritalstatus,
|
|
Job: request.Job,
|
|
Citizenship: request.Citizenship,
|
|
Validuntil: request.Validuntil,
|
|
Cardphoto: cardPhotoPath,
|
|
}
|
|
|
|
_, err = s.identityRepo.CreateIdentityCard(ctx, identityCard)
|
|
if err != nil {
|
|
log.Printf("Error creating identity card: %v", err)
|
|
return nil, fmt.Errorf("failed to create identity card: %v", err)
|
|
}
|
|
|
|
user, err := s.authRepo.FindUserByID(ctx, userID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to find user: %v", err)
|
|
}
|
|
|
|
if user.Role.RoleName == "" {
|
|
return nil, fmt.Errorf("user role not found")
|
|
}
|
|
|
|
updates := map[string]interface{}{
|
|
"registration_progress": utils.ProgressDataSubmitted,
|
|
"registration_status": utils.RegStatusPending,
|
|
}
|
|
|
|
err = s.authRepo.PatchUser(ctx, userID, updates)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to update user: %v", err)
|
|
}
|
|
|
|
updated, err := s.userRepo.GetByID(ctx, userID)
|
|
if err != nil {
|
|
if errors.Is(err, userprofile.ErrUserNotFound) {
|
|
return nil, fmt.Errorf("user not found")
|
|
}
|
|
return nil, fmt.Errorf("failed to get updated user: %w", err)
|
|
}
|
|
|
|
log.Printf("Token Generation Parameters:")
|
|
log.Printf("- UserID: '%s'", user.ID)
|
|
log.Printf("- Role: '%s'", user.Role.RoleName)
|
|
log.Printf("- DeviceID: '%s'", deviceID)
|
|
log.Printf("- Registration Status: '%s'", utils.RegStatusPending)
|
|
|
|
tokenResponse, err := utils.GenerateTokenPair(
|
|
updated.ID,
|
|
updated.Role.RoleName,
|
|
deviceID,
|
|
updated.RegistrationStatus,
|
|
int(updated.RegistrationProgress),
|
|
)
|
|
if err != nil {
|
|
log.Printf("GenerateTokenPair error: %v", err)
|
|
return nil, fmt.Errorf("failed to generate token: %v", err)
|
|
}
|
|
|
|
nextStep := utils.GetNextRegistrationStep(
|
|
updated.Role.RoleName,
|
|
int(updated.RegistrationProgress),
|
|
updated.RegistrationStatus,
|
|
)
|
|
|
|
return &authentication.AuthResponse{
|
|
Message: "identity card berhasil diunggah, silakan tunggu konfirmasi dari admin dalam 1x24 jam",
|
|
AccessToken: tokenResponse.AccessToken,
|
|
RefreshToken: tokenResponse.RefreshToken,
|
|
TokenType: string(tokenResponse.TokenType),
|
|
ExpiresIn: tokenResponse.ExpiresIn,
|
|
RegistrationStatus: updated.RegistrationStatus,
|
|
NextStep: nextStep,
|
|
SessionID: tokenResponse.SessionID,
|
|
}, nil
|
|
}
|
|
|
|
func (s *identityCardService) GetIdentityCardByID(ctx context.Context, id string) (*ResponseIdentityCardDTO, error) {
|
|
identityCard, err := s.identityRepo.GetIdentityCardByID(ctx, id)
|
|
if err != nil {
|
|
log.Printf("Error fetching identity card: %v", err)
|
|
return nil, fmt.Errorf("failed to fetch identity card")
|
|
}
|
|
return FormatResponseIdentityCard(identityCard)
|
|
}
|
|
|
|
func (s *identityCardService) GetIdentityCardsByUserID(ctx context.Context, userID string) ([]ResponseIdentityCardDTO, error) {
|
|
identityCards, err := s.identityRepo.GetIdentityCardsByUserID(ctx, userID)
|
|
if err != nil {
|
|
log.Printf("Error fetching identity cards by userID: %v", err)
|
|
return nil, fmt.Errorf("failed to fetch identity cards by userID")
|
|
}
|
|
|
|
var response []ResponseIdentityCardDTO
|
|
for _, card := range identityCards {
|
|
dto, _ := FormatResponseIdentityCard(&card)
|
|
response = append(response, *dto)
|
|
}
|
|
return response, nil
|
|
}
|
|
|
|
func (s *identityCardService) UpdateIdentityCard(ctx context.Context, userID string, id string, request *RequestIdentityCardDTO, cardPhoto *multipart.FileHeader) (*ResponseIdentityCardDTO, error) {
|
|
|
|
errors, valid := request.ValidateIdentityCardInput()
|
|
if !valid {
|
|
return nil, fmt.Errorf("validation failed: %v", errors)
|
|
}
|
|
|
|
identityCard, err := s.identityRepo.GetIdentityCardByID(ctx, id)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("identity card not found: %v", err)
|
|
}
|
|
|
|
if identityCard.Cardphoto != "" {
|
|
err := deleteIdentityCardImage(identityCard.Cardphoto)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to delete old image: %v", err)
|
|
}
|
|
}
|
|
|
|
var cardPhotoPath string
|
|
if cardPhoto != nil {
|
|
cardPhotoPath, err = s.saveIdentityCardImage(userID, cardPhoto)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to save card photo: %v", err)
|
|
}
|
|
}
|
|
|
|
identityCard.Identificationumber = request.Identificationumber
|
|
identityCard.Placeofbirth = request.Placeofbirth
|
|
identityCard.Dateofbirth = request.Dateofbirth
|
|
identityCard.Gender = request.Gender
|
|
identityCard.BloodType = request.BloodType
|
|
identityCard.Province = request.Province
|
|
identityCard.District = request.District
|
|
identityCard.SubDistrict = request.SubDistrict
|
|
identityCard.Hamlet = request.Hamlet
|
|
identityCard.Village = request.Village
|
|
identityCard.Neighbourhood = request.Neighbourhood
|
|
identityCard.PostalCode = request.PostalCode
|
|
identityCard.Religion = request.Religion
|
|
identityCard.Maritalstatus = request.Maritalstatus
|
|
identityCard.Job = request.Job
|
|
identityCard.Citizenship = request.Citizenship
|
|
identityCard.Validuntil = request.Validuntil
|
|
if cardPhotoPath != "" {
|
|
identityCard.Cardphoto = cardPhotoPath
|
|
}
|
|
|
|
if err != nil {
|
|
log.Printf("Error updating identity card: %v", err)
|
|
return nil, fmt.Errorf("failed to update identity card: %v", err)
|
|
}
|
|
|
|
idcardResponseDTO, _ := FormatResponseIdentityCard(identityCard)
|
|
|
|
return idcardResponseDTO, nil
|
|
}
|
|
|
|
func (s *identityCardService) GetAllIdentityCardsByRegStatus(ctx context.Context, userRegStatus string) ([]ResponseIdentityCardDTO, error) {
|
|
identityCards, err := s.authRepo.GetIdentityCardsByUserRegStatus(ctx, userRegStatus)
|
|
if err != nil {
|
|
log.Printf("Error getting identity cards by registration status: %v", err)
|
|
return nil, fmt.Errorf("failed to get identity cards: %w", err)
|
|
}
|
|
|
|
var response []ResponseIdentityCardDTO
|
|
for _, card := range identityCards {
|
|
createdAt, _ := utils.FormatDateToIndonesianFormat(card.CreatedAt)
|
|
updatedAt, _ := utils.FormatDateToIndonesianFormat(card.UpdatedAt)
|
|
dto := ResponseIdentityCardDTO{
|
|
ID: card.ID,
|
|
UserID: card.UserID,
|
|
Identificationumber: card.Identificationumber,
|
|
Placeofbirth: card.Placeofbirth,
|
|
Dateofbirth: card.Dateofbirth,
|
|
Gender: card.Gender,
|
|
BloodType: card.BloodType,
|
|
Province: card.Province,
|
|
District: card.District,
|
|
SubDistrict: card.SubDistrict,
|
|
Hamlet: card.Hamlet,
|
|
Village: card.Village,
|
|
Neighbourhood: card.Neighbourhood,
|
|
PostalCode: card.PostalCode,
|
|
Religion: card.Religion,
|
|
Maritalstatus: card.Maritalstatus,
|
|
Job: card.Job,
|
|
Citizenship: card.Citizenship,
|
|
Validuntil: card.Validuntil,
|
|
Cardphoto: card.Cardphoto,
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
}
|
|
response = append(response, dto)
|
|
}
|
|
|
|
return response, nil
|
|
}
|
|
|
|
func (s *identityCardService) UpdateUserRegistrationStatusByIdentityCard(ctx context.Context, identityCardUserID string, newStatus string) error {
|
|
|
|
user, err := s.authRepo.FindUserByID(ctx, identityCardUserID)
|
|
if err != nil {
|
|
log.Printf("Error finding user by ID %s: %v", identityCardUserID, err)
|
|
return fmt.Errorf("user not found: %w", err)
|
|
}
|
|
|
|
updates := map[string]interface{}{
|
|
"registration_status": newStatus,
|
|
"updated_at": time.Now(),
|
|
}
|
|
|
|
switch newStatus {
|
|
case utils.RegStatusConfirmed:
|
|
updates["registration_progress"] = utils.ProgressDataSubmitted
|
|
|
|
identityCards, err := s.GetIdentityCardsByUserID(ctx, identityCardUserID)
|
|
if err != nil {
|
|
log.Printf("Error fetching identity cards for user ID %s: %v", identityCardUserID, err)
|
|
return fmt.Errorf("failed to fetch identity card data: %w", err)
|
|
}
|
|
|
|
if len(identityCards) == 0 {
|
|
log.Printf("No identity card found for user ID %s", identityCardUserID)
|
|
return fmt.Errorf("no identity card found for user")
|
|
}
|
|
|
|
identityCard := identityCards[0]
|
|
|
|
updates["name"] = identityCard.Fullname
|
|
updates["gender"] = identityCard.Gender
|
|
updates["dateofbirth"] = identityCard.Dateofbirth
|
|
updates["placeofbirth"] = identityCard.District
|
|
|
|
log.Printf("Syncing user data for ID %s: name=%s, gender=%s, dob=%s, pob=%s",
|
|
identityCardUserID, identityCard.Fullname, identityCard.Gender,
|
|
identityCard.Dateofbirth, identityCard.District)
|
|
|
|
case utils.RegStatusRejected:
|
|
updates["registration_progress"] = utils.ProgressOTPVerified
|
|
|
|
}
|
|
|
|
err = s.authRepo.PatchUser(ctx, user.ID, updates)
|
|
if err != nil {
|
|
log.Printf("Error updating user registration status for user ID %s: %v", user.ID, err)
|
|
return fmt.Errorf("failed to update user registration status: %w", err)
|
|
}
|
|
|
|
log.Printf("Successfully updated registration status for user ID %s to %s", user.ID, newStatus)
|
|
|
|
if newStatus == utils.RegStatusConfirmed {
|
|
log.Printf("User profile data synced successfully for user ID %s", user.ID)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *identityCardService) mapIdentityCardToDTO(card model.IdentityCard) ResponseIdentityCardDTO {
|
|
createdAt, _ := utils.FormatDateToIndonesianFormat(card.CreatedAt)
|
|
updatedAt, _ := utils.FormatDateToIndonesianFormat(card.UpdatedAt)
|
|
return ResponseIdentityCardDTO{
|
|
ID: card.ID,
|
|
UserID: card.UserID,
|
|
Identificationumber: card.Identificationumber,
|
|
Placeofbirth: card.Placeofbirth,
|
|
Dateofbirth: card.Dateofbirth,
|
|
Gender: card.Gender,
|
|
BloodType: card.BloodType,
|
|
Province: card.Province,
|
|
District: card.District,
|
|
SubDistrict: card.SubDistrict,
|
|
Hamlet: card.Hamlet,
|
|
Village: card.Village,
|
|
Neighbourhood: card.Neighbourhood,
|
|
PostalCode: card.PostalCode,
|
|
Religion: card.Religion,
|
|
Maritalstatus: card.Maritalstatus,
|
|
Job: card.Job,
|
|
Citizenship: card.Citizenship,
|
|
Validuntil: card.Validuntil,
|
|
Cardphoto: card.Cardphoto,
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
}
|
|
}
|
|
|
|
func (s *identityCardService) mapUserToDTO(user model.User) userprofile.UserProfileResponseDTO {
|
|
avatar := ""
|
|
if user.Avatar != nil {
|
|
avatar = *user.Avatar
|
|
}
|
|
|
|
var roleDTO role.RoleResponseDTO
|
|
if user.Role != nil {
|
|
roleDTO = role.RoleResponseDTO{
|
|
ID: user.Role.ID,
|
|
RoleName: user.Role.RoleName,
|
|
}
|
|
}
|
|
|
|
createdAt, _ := utils.FormatDateToIndonesianFormat(user.CreatedAt)
|
|
updatedAt, _ := utils.FormatDateToIndonesianFormat(user.UpdatedAt)
|
|
return userprofile.UserProfileResponseDTO{
|
|
ID: user.ID,
|
|
Avatar: avatar,
|
|
Name: user.Name,
|
|
Gender: user.Gender,
|
|
Dateofbirth: user.Dateofbirth,
|
|
Placeofbirth: user.Placeofbirth,
|
|
Phone: user.Phone,
|
|
Email: user.Email,
|
|
PhoneVerified: user.PhoneVerified,
|
|
Role: roleDTO,
|
|
CreatedAt: createdAt,
|
|
UpdatedAt: updatedAt,
|
|
}
|
|
}
|