feat: add feature wilayah indonesia api

This commit is contained in:
pahmiudahgede 2025-02-06 14:01:23 +07:00
parent 35d51b99d0
commit 1c856773a1
13 changed files with 92533 additions and 88297 deletions

View File

@ -31,9 +31,18 @@ func ConnectDatabase() {
log.Println("Database connected successfully!")
err = DB.AutoMigrate(
// ==wilayah indonesia==
&model.Province{},
&model.Regency{},
&model.District{},
&model.Village{},
// ==wilayah indonesia==
// ==main feature==
&model.User{},
&model.Role{},
&model.UserPin{},
// ==main feature==
)
if err != nil {
log.Fatalf("Error performing auto-migration: %v", err)

View File

@ -0,0 +1,27 @@
package dto
type ProvinceResponseDTO struct {
ID string `json:"id"`
Name string `json:"name"`
Regencies []RegencyResponseDTO `json:"regencies,omitempty"`
}
type RegencyResponseDTO struct {
ID string `json:"id"`
ProvinceID string `json:"province_id"`
Name string `json:"name"`
Districts []DistrictResponseDTO `json:"districts,omitempty"`
}
type DistrictResponseDTO struct {
ID string `json:"id"`
RegencyID string `json:"regency_id"`
Name string `json:"name"`
Villages []VillageResponseDTO `json:"villages,omitempty"`
}
type VillageResponseDTO struct {
ID string `json:"id"`
DistrictID string `json:"district_id"`
Name string `json:"name"`
}

View File

@ -0,0 +1,148 @@
package handler
import (
"fmt"
"strconv"
"github.com/gofiber/fiber/v2"
"github.com/pahmiudahgede/senggoldong/internal/services"
"github.com/pahmiudahgede/senggoldong/utils"
)
type WilayahIndonesiaHandler struct {
WilayahService services.WilayahIndonesiaService
}
func NewWilayahImportHandler(wilayahService services.WilayahIndonesiaService) *WilayahIndonesiaHandler {
return &WilayahIndonesiaHandler{WilayahService: wilayahService}
}
func (h *WilayahIndonesiaHandler) ImportWilayahData(c *fiber.Ctx) error {
err := h.WilayahService.ImportDataFromCSV()
if err != nil {
return utils.GenericErrorResponse(c, fiber.StatusInternalServerError, err.Error())
}
return utils.GenericErrorResponse(c, fiber.StatusCreated, "Data imported successfully")
}
func (h *WilayahIndonesiaHandler) GetAllProvinces(c *fiber.Ctx) error {
page, err := strconv.Atoi(c.Query("page", "1"))
if err != nil {
page = 1
}
limit, err := strconv.Atoi(c.Query("limit", "10"))
if err != nil {
limit = 10
}
provinces, err := h.WilayahService.GetAllProvinces(page, limit)
if err != nil {
return utils.GenericErrorResponse(c, fiber.StatusInternalServerError, fmt.Sprintf("Failed to fetch provinces: %v", err))
}
return utils.PaginatedResponse(c, provinces, page, limit, len(provinces), "Provinces fetched successfully")
}
func (h *WilayahIndonesiaHandler) GetProvinceByID(c *fiber.Ctx) error {
provinceID := c.Params("id")
province, err := h.WilayahService.GetProvinceByID(provinceID)
if err != nil {
return utils.GenericErrorResponse(c, fiber.StatusNotFound, fmt.Sprintf("Province not found: %v", err))
}
return utils.LogResponse(c, province, "Province fetched successfully")
}
func (h *WilayahIndonesiaHandler) GetAllRegencies(c *fiber.Ctx) error {
page, err := strconv.Atoi(c.Query("page", "1"))
if err != nil {
page = 1
}
limit, err := strconv.Atoi(c.Query("limit", "10"))
if err != nil {
limit = 10
}
regencies, err := h.WilayahService.GetAllRegencies(page, limit)
if err != nil {
return utils.GenericErrorResponse(c, fiber.StatusInternalServerError, fmt.Sprintf("Failed to fetch regencies: %v", err))
}
return utils.PaginatedResponse(c, regencies, page, limit, len(regencies), "Regencies fetched successfully")
}
func (h *WilayahIndonesiaHandler) GetRegencyByID(c *fiber.Ctx) error {
regencyID := c.Params("id")
regency, err := h.WilayahService.GetRegencyByID(regencyID)
if err != nil {
return utils.GenericErrorResponse(c, fiber.StatusNotFound, fmt.Sprintf("Regency not found: %v", err))
}
return utils.LogResponse(c, regency, "Regency fetched successfully")
}
func (h *WilayahIndonesiaHandler) GetAllDistricts(c *fiber.Ctx) error {
page, err := strconv.Atoi(c.Query("page", "1"))
if err != nil {
page = 1
}
limit, err := strconv.Atoi(c.Query("limit", "10"))
if err != nil {
limit = 10
}
districts, err := h.WilayahService.GetAllDistricts(page, limit)
if err != nil {
return utils.GenericErrorResponse(c, fiber.StatusInternalServerError, fmt.Sprintf("Failed to fetch districts: %v", err))
}
return utils.PaginatedResponse(c, districts, page, limit, len(districts), "Districts fetched successfully")
}
func (h *WilayahIndonesiaHandler) GetDistrictByID(c *fiber.Ctx) error {
districtID := c.Params("id")
district, err := h.WilayahService.GetDistrictByID(districtID)
if err != nil {
return utils.GenericErrorResponse(c, fiber.StatusNotFound, fmt.Sprintf("District not found: %v", err))
}
return utils.LogResponse(c, district, "District fetched successfully")
}
func (h *WilayahIndonesiaHandler) GetAllVillages(c *fiber.Ctx) error {
page, err := strconv.Atoi(c.Query("page", "1"))
if err != nil {
page = 1
}
limit, err := strconv.Atoi(c.Query("limit", "10"))
if err != nil {
limit = 10
}
villages, err := h.WilayahService.GetAllVillages(page, limit)
if err != nil {
return utils.GenericErrorResponse(c, fiber.StatusInternalServerError, fmt.Sprintf("Failed to fetch villages: %v", err))
}
return utils.PaginatedResponse(c, villages, page, limit, len(villages), "Villages fetched successfully")
}
func (h *WilayahIndonesiaHandler) GetVillageByID(c *fiber.Ctx) error {
villageID := c.Params("id")
village, err := h.WilayahService.GetVillageByID(villageID)
if err != nil {
return utils.GenericErrorResponse(c, fiber.StatusNotFound, fmt.Sprintf("Village not found: %v", err))
}
return utils.LogResponse(c, village, "Village fetched successfully")
}

View File

@ -0,0 +1,194 @@
package repositories
import (
"github.com/pahmiudahgede/senggoldong/model"
"gorm.io/gorm"
)
type WilayahIndonesiaRepository interface {
ImportProvinces(provinces []model.Province) error
ImportRegencies(regencies []model.Regency) error
ImportDistricts(districts []model.District) error
ImportVillages(villages []model.Village) error
// ================================================== //
FindAllProvinces(page, limit int) ([]model.Province, int, error)
FindProvinceByID(id string) (*model.Province, error)
FindAllRegencies(page, limit int) ([]model.Regency, int, error)
FindRegencyByID(id string) (*model.Regency, error)
FindAllDistricts(page, limit int) ([]model.District, int, error)
FindDistrictByID(id string) (*model.District, error)
FindAllVillages(page, limit int) ([]model.Village, int, error)
FindVillageByID(id string) (*model.Village, error)
}
type wilayahIndonesiaRepository struct {
DB *gorm.DB
}
func NewWilayahIndonesiaRepository(db *gorm.DB) WilayahIndonesiaRepository {
return &wilayahIndonesiaRepository{DB: db}
}
func (r *wilayahIndonesiaRepository) ImportProvinces(provinces []model.Province) error {
for _, province := range provinces {
if err := r.DB.Create(&province).Error; err != nil {
return err
}
}
return nil
}
func (r *wilayahIndonesiaRepository) ImportRegencies(regencies []model.Regency) error {
for _, regency := range regencies {
if err := r.DB.Create(&regency).Error; err != nil {
return err
}
}
return nil
}
func (r *wilayahIndonesiaRepository) ImportDistricts(districts []model.District) error {
for _, district := range districts {
if err := r.DB.Create(&district).Error; err != nil {
return err
}
}
return nil
}
func (r *wilayahIndonesiaRepository) ImportVillages(villages []model.Village) error {
for _, village := range villages {
if err := r.DB.Create(&village).Error; err != nil {
return err
}
}
return nil
}
/*
| ============================================================ |
| ============================================================ |
*/
// FindAllProvinces with Pagination
func (r *wilayahIndonesiaRepository) FindAllProvinces(page, limit int) ([]model.Province, int, error) {
var provinces []model.Province
var total int64
// Count total provinces
err := r.DB.Model(&model.Province{}).Count(&total).Error
if err != nil {
return nil, 0, err
}
// Get provinces with pagination
err = r.DB.Offset((page - 1) * limit).Limit(limit).Find(&provinces).Error
if err != nil {
return nil, 0, err
}
return provinces, int(total), nil
}
// FindProvinceByID
func (r *wilayahIndonesiaRepository) FindProvinceByID(id string) (*model.Province, error) {
var province model.Province
err := r.DB.Preload("Regencies").Where("id = ?", id).First(&province).Error
if err != nil {
return nil, err
}
return &province, nil
}
// FindAllRegencies with Pagination
func (r *wilayahIndonesiaRepository) FindAllRegencies(page, limit int) ([]model.Regency, int, error) {
var regencies []model.Regency
var total int64
// Count total regencies
err := r.DB.Model(&model.Regency{}).Count(&total).Error
if err != nil {
return nil, 0, err
}
// Get regencies with pagination
err = r.DB.Offset((page - 1) * limit).Limit(limit).Preload("Districts").Find(&regencies).Error
if err != nil {
return nil, 0, err
}
return regencies, int(total), nil
}
// FindRegencyByID
func (r *wilayahIndonesiaRepository) FindRegencyByID(id string) (*model.Regency, error) {
var regency model.Regency
err := r.DB.Preload("Districts").Where("id = ?", id).First(&regency).Error
if err != nil {
return nil, err
}
return &regency, nil
}
// FindAllDistricts with Pagination
func (r *wilayahIndonesiaRepository) FindAllDistricts(page, limit int) ([]model.District, int, error) {
var districts []model.District
var total int64
// Count total districts
err := r.DB.Model(&model.District{}).Count(&total).Error
if err != nil {
return nil, 0, err
}
// Get districts with pagination
err = r.DB.Offset((page - 1) * limit).Limit(limit).Preload("Villages").Find(&districts).Error
if err != nil {
return nil, 0, err
}
return districts, int(total), nil
}
// FindDistrictByID
func (r *wilayahIndonesiaRepository) FindDistrictByID(id string) (*model.District, error) {
var district model.District
err := r.DB.Preload("Villages").Where("id = ?", id).First(&district).Error
if err != nil {
return nil, err
}
return &district, nil
}
// FindAllVillages with Pagination
func (r *wilayahIndonesiaRepository) FindAllVillages(page, limit int) ([]model.Village, int, error) {
var villages []model.Village
var total int64
// Count total villages
err := r.DB.Model(&model.Village{}).Count(&total).Error
if err != nil {
return nil, 0, err
}
// Get villages with pagination
err = r.DB.Offset((page - 1) * limit).Limit(limit).Find(&villages).Error
if err != nil {
return nil, 0, err
}
return villages, int(total), nil
}
// FindVillageByID
func (r *wilayahIndonesiaRepository) FindVillageByID(id string) (*model.Village, error) {
var village model.Village
err := r.DB.Where("id = ?", id).First(&village).Error
if err != nil {
return nil, err
}
return &village, nil
}

View File

@ -0,0 +1,487 @@
package services
import (
"fmt"
"time"
"github.com/pahmiudahgede/senggoldong/dto"
"github.com/pahmiudahgede/senggoldong/internal/repositories"
"github.com/pahmiudahgede/senggoldong/model"
"github.com/pahmiudahgede/senggoldong/utils"
)
type WilayahIndonesiaService interface {
ImportDataFromCSV() error
GetAllProvinces(page, limit int) ([]dto.ProvinceResponseDTO, error)
GetProvinceByID(id string) (*dto.ProvinceResponseDTO, error)
GetAllRegencies(page, limit int) ([]dto.RegencyResponseDTO, error)
GetRegencyByID(id string) (*dto.RegencyResponseDTO, error)
GetAllDistricts(page, limit int) ([]dto.DistrictResponseDTO, error)
GetDistrictByID(id string) (*dto.DistrictResponseDTO, error)
GetAllVillages(page, limit int) ([]dto.VillageResponseDTO, error)
GetVillageByID(id string) (*dto.VillageResponseDTO, error)
}
type wilayahIndonesiaService struct {
WilayahRepo repositories.WilayahIndonesiaRepository
}
func NewWilayahIndonesiaService(wilayahRepo repositories.WilayahIndonesiaRepository) WilayahIndonesiaService {
return &wilayahIndonesiaService{WilayahRepo: wilayahRepo}
}
func (s *wilayahIndonesiaService) ImportDataFromCSV() error {
provinces, err := utils.ReadCSV("public/document/provinces.csv")
if err != nil {
return fmt.Errorf("failed to read provinces CSV: %v", err)
}
var provinceList []model.Province
for _, record := range provinces[1:] {
province := model.Province{
ID: record[0],
Name: record[1],
}
provinceList = append(provinceList, province)
}
if err := s.WilayahRepo.ImportProvinces(provinceList); err != nil {
return fmt.Errorf("failed to import provinces: %v", err)
}
regencies, err := utils.ReadCSV("public/document/regencies.csv")
if err != nil {
return fmt.Errorf("failed to read regencies CSV: %v", err)
}
var regencyList []model.Regency
for _, record := range regencies[1:] {
regency := model.Regency{
ID: record[0],
ProvinceID: record[1],
Name: record[2],
}
regencyList = append(regencyList, regency)
}
if err := s.WilayahRepo.ImportRegencies(regencyList); err != nil {
return fmt.Errorf("failed to import regencies: %v", err)
}
districts, err := utils.ReadCSV("public/document/districts.csv")
if err != nil {
return fmt.Errorf("failed to read districts CSV: %v", err)
}
var districtList []model.District
for _, record := range districts[1:] {
district := model.District{
ID: record[0],
RegencyID: record[1],
Name: record[2],
}
districtList = append(districtList, district)
}
if err := s.WilayahRepo.ImportDistricts(districtList); err != nil {
return fmt.Errorf("failed to import districts: %v", err)
}
villages, err := utils.ReadCSV("public/document/villages.csv")
if err != nil {
return fmt.Errorf("failed to read villages CSV: %v", err)
}
var villageList []model.Village
for _, record := range villages[1:] {
village := model.Village{
ID: record[0],
DistrictID: record[1],
Name: record[2],
}
villageList = append(villageList, village)
}
if err := s.WilayahRepo.ImportVillages(villageList); err != nil {
return fmt.Errorf("failed to import villages: %v", err)
}
return nil
}
func (s *wilayahIndonesiaService) GetAllProvinces(page, limit int) ([]dto.ProvinceResponseDTO, error) {
cacheKey := fmt.Sprintf("provinces_page_%d_limit_%d", page, limit)
cachedData, err := utils.GetJSONData(cacheKey)
if err == nil && cachedData != nil {
var provinces []dto.ProvinceResponseDTO
if data, ok := cachedData["data"].([]interface{}); ok {
for _, item := range data {
province, ok := item.(map[string]interface{})
if ok {
provinces = append(provinces, dto.ProvinceResponseDTO{
ID: province["id"].(string),
Name: province["name"].(string),
})
}
}
return provinces, nil
}
}
provinces, total, err := s.WilayahRepo.FindAllProvinces(page, limit)
if err != nil {
return nil, fmt.Errorf("failed to fetch provinces: %v", err)
}
var provinceDTOs []dto.ProvinceResponseDTO
for _, province := range provinces {
provinceDTOs = append(provinceDTOs, dto.ProvinceResponseDTO{
ID: province.ID,
Name: province.Name,
})
}
cacheData := map[string]interface{}{
"data": provinceDTOs,
"total": total,
"page": page,
"limit": limit,
}
err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24)
if err != nil {
fmt.Printf("Error caching provinces data to Redis: %v\n", err)
}
return provinceDTOs, nil
}
func (s *wilayahIndonesiaService) GetProvinceByID(id string) (*dto.ProvinceResponseDTO, error) {
cacheKey := fmt.Sprintf("province:%s", id)
cachedData, err := utils.GetJSONData(cacheKey)
if err == nil && cachedData != nil {
var province dto.ProvinceResponseDTO
if data, ok := cachedData["data"].(map[string]interface{}); ok {
province = dto.ProvinceResponseDTO{
ID: data["id"].(string),
Name: data["name"].(string),
}
return &province, nil
}
}
province, err := s.WilayahRepo.FindProvinceByID(id)
if err != nil {
return nil, fmt.Errorf("failed to fetch province: %v", err)
}
provinceDTO := &dto.ProvinceResponseDTO{
ID: province.ID,
Name: province.Name,
}
regenciesDTO := []dto.RegencyResponseDTO{}
for _, regency := range province.Regencies {
regenciesDTO = append(regenciesDTO, dto.RegencyResponseDTO{
ID: regency.ID,
ProvinceID: regency.ProvinceID,
Name: regency.Name,
})
}
provinceDTO.Regencies = regenciesDTO
cacheData := map[string]interface{}{
"data": provinceDTO,
}
err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24)
if err != nil {
fmt.Printf("Error caching province data to Redis: %v\n", err)
}
return provinceDTO, nil
}
func (s *wilayahIndonesiaService) GetAllRegencies(page, limit int) ([]dto.RegencyResponseDTO, error) {
cacheKey := fmt.Sprintf("regencies_page_%d_limit_%d", page, limit)
cachedData, err := utils.GetJSONData(cacheKey)
if err == nil && cachedData != nil {
var regencies []dto.RegencyResponseDTO
if data, ok := cachedData["data"].([]interface{}); ok {
for _, item := range data {
regency, ok := item.(map[string]interface{})
if ok {
regencies = append(regencies, dto.RegencyResponseDTO{
ID: regency["id"].(string),
ProvinceID: regency["province_id"].(string),
Name: regency["name"].(string),
})
}
}
return regencies, nil
}
}
regencies, total, err := s.WilayahRepo.FindAllRegencies(page, limit)
if err != nil {
return nil, fmt.Errorf("failed to fetch regencies: %v", err)
}
var regencyDTOs []dto.RegencyResponseDTO
for _, regency := range regencies {
regencyDTOs = append(regencyDTOs, dto.RegencyResponseDTO{
ID: regency.ID,
ProvinceID: regency.ProvinceID,
Name: regency.Name,
})
}
cacheData := map[string]interface{}{
"data": regencyDTOs,
"total": total,
"page": page,
"limit": limit,
}
err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24)
if err != nil {
fmt.Printf("Error caching regencies data to Redis: %v\n", err)
}
return regencyDTOs, nil
}
func (s *wilayahIndonesiaService) GetRegencyByID(id string) (*dto.RegencyResponseDTO, error) {
cacheKey := fmt.Sprintf("regency:%s", id)
cachedData, err := utils.GetJSONData(cacheKey)
if err == nil && cachedData != nil {
var regency dto.RegencyResponseDTO
if data, ok := cachedData["data"].(map[string]interface{}); ok {
regency = dto.RegencyResponseDTO{
ID: data["id"].(string),
ProvinceID: data["province_id"].(string),
Name: data["name"].(string),
}
return &regency, nil
}
}
regency, err := s.WilayahRepo.FindRegencyByID(id)
if err != nil {
return nil, fmt.Errorf("failed to fetch regency: %v", err)
}
regencyDTO := &dto.RegencyResponseDTO{
ID: regency.ID,
ProvinceID: regency.ProvinceID,
Name: regency.Name,
}
districtsDTO := []dto.DistrictResponseDTO{}
for _, district := range regency.Districts {
districtsDTO = append(districtsDTO, dto.DistrictResponseDTO{
ID: district.ID,
RegencyID: district.RegencyID,
Name: district.Name,
})
}
regencyDTO.Districts = districtsDTO
cacheData := map[string]interface{}{
"data": regencyDTO,
}
err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24)
if err != nil {
fmt.Printf("Error caching regency data to Redis: %v\n", err)
}
return regencyDTO, nil
}
func (s *wilayahIndonesiaService) GetAllDistricts(page, limit int) ([]dto.DistrictResponseDTO, error) {
cacheKey := fmt.Sprintf("districts_page_%d_limit_%d", page, limit)
cachedData, err := utils.GetJSONData(cacheKey)
if err == nil && cachedData != nil {
var districts []dto.DistrictResponseDTO
if data, ok := cachedData["data"].([]interface{}); ok {
for _, item := range data {
district, ok := item.(map[string]interface{})
if ok {
districts = append(districts, dto.DistrictResponseDTO{
ID: district["id"].(string),
RegencyID: district["regency_id"].(string),
Name: district["name"].(string),
})
}
}
return districts, nil
}
}
districts, total, err := s.WilayahRepo.FindAllDistricts(page, limit)
if err != nil {
return nil, fmt.Errorf("failed to fetch districts: %v", err)
}
var districtDTOs []dto.DistrictResponseDTO
for _, district := range districts {
districtDTOs = append(districtDTOs, dto.DistrictResponseDTO{
ID: district.ID,
RegencyID: district.RegencyID,
Name: district.Name,
})
}
cacheData := map[string]interface{}{
"data": districtDTOs,
"total": total,
"page": page,
"limit": limit,
}
err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24)
if err != nil {
fmt.Printf("Error caching districts data to Redis: %v\n", err)
}
return districtDTOs, nil
}
func (s *wilayahIndonesiaService) GetDistrictByID(id string) (*dto.DistrictResponseDTO, error) {
cacheKey := fmt.Sprintf("district:%s", id)
cachedData, err := utils.GetJSONData(cacheKey)
if err == nil && cachedData != nil {
var district dto.DistrictResponseDTO
if data, ok := cachedData["data"].(map[string]interface{}); ok {
district = dto.DistrictResponseDTO{
ID: data["id"].(string),
RegencyID: data["regency_id"].(string),
Name: data["name"].(string),
}
return &district, nil
}
}
district, err := s.WilayahRepo.FindDistrictByID(id)
if err != nil {
return nil, fmt.Errorf("failed to fetch district: %v", err)
}
districtDTO := &dto.DistrictResponseDTO{
ID: district.ID,
RegencyID: district.RegencyID,
Name: district.Name,
}
villagesDTO := []dto.VillageResponseDTO{}
for _, village := range district.Villages {
villagesDTO = append(villagesDTO, dto.VillageResponseDTO{
ID: village.ID,
DistrictID: village.DistrictID,
Name: village.Name,
})
}
districtDTO.Villages = villagesDTO
cacheData := map[string]interface{}{
"data": districtDTO,
}
err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24)
if err != nil {
fmt.Printf("Error caching district data to Redis: %v\n", err)
}
return districtDTO, nil
}
func (s *wilayahIndonesiaService) GetAllVillages(page, limit int) ([]dto.VillageResponseDTO, error) {
cacheKey := fmt.Sprintf("villages:%d:%d", page, limit)
cachedData, err := utils.GetJSONData(cacheKey)
if err == nil && cachedData != nil {
var villages []dto.VillageResponseDTO
if data, ok := cachedData["data"].([]interface{}); ok {
for _, item := range data {
village, ok := item.(map[string]interface{})
if ok {
villages = append(villages, dto.VillageResponseDTO{
ID: village["id"].(string),
DistrictID: village["district_id"].(string),
Name: village["name"].(string),
})
}
}
return villages, nil
}
}
villages, total, err := s.WilayahRepo.FindAllVillages(page, limit)
if err != nil {
return nil, fmt.Errorf("failed to fetch villages: %v", err)
}
var villageDTOs []dto.VillageResponseDTO
for _, village := range villages {
villageDTOs = append(villageDTOs, dto.VillageResponseDTO{
ID: village.ID,
DistrictID: village.DistrictID,
Name: village.Name,
})
}
cacheData := map[string]interface{}{
"data": villageDTOs,
"total": total,
}
err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24)
if err != nil {
fmt.Printf("Error caching village data to Redis: %v\n", err)
}
return villageDTOs, nil
}
func (s *wilayahIndonesiaService) GetVillageByID(id string) (*dto.VillageResponseDTO, error) {
cacheKey := fmt.Sprintf("village:%s", id)
cachedData, err := utils.GetJSONData(cacheKey)
if err == nil && cachedData != nil {
var villageDTO dto.VillageResponseDTO
if data, ok := cachedData["data"].(map[string]interface{}); ok {
villageDTO = dto.VillageResponseDTO{
ID: data["id"].(string),
DistrictID: data["district_id"].(string),
Name: data["name"].(string),
}
return &villageDTO, nil
}
}
village, err := s.WilayahRepo.FindVillageByID(id)
if err != nil {
return nil, fmt.Errorf("village not found: %v", err)
}
villageDTO := &dto.VillageResponseDTO{
ID: village.ID,
DistrictID: village.DistrictID,
Name: village.Name,
}
cacheData := map[string]interface{}{
"data": villageDTO,
}
err = utils.SetJSONData(cacheKey, cacheData, time.Hour*24)
if err != nil {
fmt.Printf("Error caching village data to Redis: %v\n", err)
}
return villageDTO, nil
}

View File

@ -0,0 +1,34 @@
package model
type Province struct {
ID string `gorm:"primaryKey;type:varchar(255);not null" json:"id"`
Name string `gorm:"type:varchar(255);not null" json:"name"`
Regencies []Regency `gorm:"foreignKey:ProvinceID" json:"regencies"`
}
type Regency struct {
ID string `gorm:"primaryKey;type:varchar(255);not null" json:"id"`
ProvinceID string `gorm:"type:varchar(255);not null" json:"province_id"`
Name string `gorm:"type:varchar(255);not null" json:"name"`
Province Province `gorm:"foreignKey:ProvinceID" json:"province"`
Districts []District `gorm:"foreignKey:RegencyID" json:"districts"`
}
type District struct {
ID string `gorm:"primaryKey;type:varchar(255);not null" json:"id"`
RegencyID string `gorm:"type:varchar(255);not null" json:"regency_id"`
Name string `gorm:"type:varchar(255);not null" json:"name"`
Regency Regency `gorm:"foreignKey:RegencyID" json:"regency"`
Villages []Village `gorm:"foreignKey:DistrictID" json:"villages"`
}
type Village struct {
ID string `gorm:"primaryKey;type:varchar(255);not null" json:"id"`
DistrictID string `gorm:"type:varchar(255);not null" json:"district_id"`
Name string `gorm:"type:varchar(255);not null" json:"name"`
District District `gorm:"foreignKey:DistrictID" json:"district"`
}

View File

@ -0,0 +1,34 @@
package presentation
import (
"github.com/gofiber/fiber/v2"
"github.com/pahmiudahgede/senggoldong/config"
"github.com/pahmiudahgede/senggoldong/internal/handler"
"github.com/pahmiudahgede/senggoldong/internal/repositories"
"github.com/pahmiudahgede/senggoldong/internal/services"
"github.com/pahmiudahgede/senggoldong/middleware"
"github.com/pahmiudahgede/senggoldong/utils"
)
func WilayahRouter(api fiber.Router) {
wilayahRepo := repositories.NewWilayahIndonesiaRepository(config.DB)
wilayahService := services.NewWilayahIndonesiaService(wilayahRepo)
wilayahHandler := handler.NewWilayahImportHandler(wilayahService)
wilayahAPI := api.Group("/wilayah-indonesia")
wilayahAPI.Get("/provinces", middleware.AuthMiddleware, wilayahHandler.GetAllProvinces)
wilayahAPI.Get("/provinces/:id", middleware.AuthMiddleware, wilayahHandler.GetProvinceByID)
wilayahAPI.Get("/regencies", middleware.AuthMiddleware, wilayahHandler.GetAllRegencies)
wilayahAPI.Get("/regencies/:id", middleware.AuthMiddleware, wilayahHandler.GetRegencyByID)
wilayahAPI.Get("/districts", middleware.AuthMiddleware, wilayahHandler.GetAllDistricts)
wilayahAPI.Get("/districts/:id", middleware.AuthMiddleware, wilayahHandler.GetDistrictByID)
wilayahAPI.Get("/villages", middleware.AuthMiddleware, wilayahHandler.GetAllVillages)
wilayahAPI.Get("/villages/:id", middleware.AuthMiddleware, wilayahHandler.GetVillageByID)
api.Post("/import/data-wilayah-indonesia", middleware.AuthMiddleware, middleware.RoleMiddleware(utils.RoleAdministrator), wilayahHandler.ImportWilayahData)
}

File diff suppressed because it is too large Load Diff

View File

@ -1,34 +1,38 @@
11,ACEH
12,SUMATERA UTARA
13,SUMATERA BARAT
14,RIAU
15,JAMBI
16,SUMATERA SELATAN
17,BENGKULU
18,LAMPUNG
19,KEPULAUAN BANGKA BELITUNG
21,KEPULAUAN RIAU
31,DKI JAKARTA
32,JAWA BARAT
33,JAWA TENGAH
34,DI YOGYAKARTA
35,JAWA TIMUR
36,BANTEN
51,BALI
52,NUSA TENGGARA BARAT
53,NUSA TENGGARA TIMUR
61,KALIMANTAN BARAT
62,KALIMANTAN TENGAH
63,KALIMANTAN SELATAN
64,KALIMANTAN TIMUR
65,KALIMANTAN UTARA
71,SULAWESI UTARA
72,SULAWESI TENGAH
73,SULAWESI SELATAN
74,SULAWESI TENGGARA
75,GORONTALO
76,SULAWESI BARAT
81,MALUKU
82,MALUKU UTARA
91,PAPUA BARAT
94,PAPUA
id;name
11;ACEH
12;"SUMATERA UTARA"
13;"SUMATERA BARAT"
14;RIAU
15;JAMBI
16;"SUMATERA SELATAN"
17;BENGKULU
18;LAMPUNG
19;"KEPULAUAN BANGKA BELITUNG"
21;"KEPULAUAN RIAU"
31;"DKI JAKARTA"
32;"JAWA BARAT"
33;"JAWA TENGAH"
34;"DAERAH ISTIMEWA YOGYAKARTA"
35;"JAWA TIMUR"
36;BANTEN
51;BALI
52;"NUSA TENGGARA BARAT"
53;"NUSA TENGGARA TIMUR"
61;"KALIMANTAN BARAT"
62;"KALIMANTAN TENGAH"
63;"KALIMANTAN SELATAN"
64;"KALIMANTAN TIMUR"
65;"KALIMANTAN UTARA"
71;"SULAWESI UTARA"
72;"SULAWESI TENGAH"
73;"SULAWESI SELATAN"
74;"SULAWESI TENGGARA"
75;GORONTALO
76;"SULAWESI BARAT"
81;MALUKU
82;"MALUKU UTARA"
91;PAPUA
92;"PAPUA BARAT"
93;"PAPUA SELATAN"
94;"PAPUA TENGAH"
95;"PAPUA PEGUNUNGAN"

1 11 id ACEH name
2 12 11 SUMATERA UTARA ACEH
3 13 12 SUMATERA BARAT SUMATERA UTARA
4 14 13 RIAU SUMATERA BARAT
5 15 14 JAMBI RIAU
6 16 15 SUMATERA SELATAN JAMBI
7 17 16 BENGKULU SUMATERA SELATAN
8 18 17 LAMPUNG BENGKULU
9 19 18 KEPULAUAN BANGKA BELITUNG LAMPUNG
10 21 19 KEPULAUAN RIAU KEPULAUAN BANGKA BELITUNG
11 31 21 DKI JAKARTA KEPULAUAN RIAU
12 32 31 JAWA BARAT DKI JAKARTA
13 33 32 JAWA TENGAH JAWA BARAT
14 34 33 DI YOGYAKARTA JAWA TENGAH
15 35 34 JAWA TIMUR DAERAH ISTIMEWA YOGYAKARTA
16 36 35 BANTEN JAWA TIMUR
17 51 36 BALI BANTEN
18 52 51 NUSA TENGGARA BARAT BALI
19 53 52 NUSA TENGGARA TIMUR NUSA TENGGARA BARAT
20 61 53 KALIMANTAN BARAT NUSA TENGGARA TIMUR
21 62 61 KALIMANTAN TENGAH KALIMANTAN BARAT
22 63 62 KALIMANTAN SELATAN KALIMANTAN TENGAH
23 64 63 KALIMANTAN TIMUR KALIMANTAN SELATAN
24 65 64 KALIMANTAN UTARA KALIMANTAN TIMUR
25 71 65 SULAWESI UTARA KALIMANTAN UTARA
26 72 71 SULAWESI TENGAH SULAWESI UTARA
27 73 72 SULAWESI SELATAN SULAWESI TENGAH
28 74 73 SULAWESI TENGGARA SULAWESI SELATAN
29 75 74 GORONTALO SULAWESI TENGGARA
30 76 75 SULAWESI BARAT GORONTALO
31 81 76 MALUKU SULAWESI BARAT
32 82 81 MALUKU UTARA MALUKU
33 91 82 PAPUA BARAT MALUKU UTARA
34 94 91 PAPUA PAPUA
35 92 PAPUA BARAT
36 93 PAPUA SELATAN
37 94 PAPUA TENGAH
38 95 PAPUA PEGUNUNGAN

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -13,4 +13,5 @@ func SetupRoutes(app *fiber.App) {
presentation.UserProfileRouter(api)
presentation.UserPinRouter(api)
presentation.RoleRouter(api)
presentation.WilayahRouter(api)
}

View File

@ -13,9 +13,15 @@ func ReadCSV(filePath string) ([][]string, error) {
defer file.Close()
reader := csv.NewReader(file)
reader.Comma = ';'
reader.LazyQuotes = true
reader.FieldsPerRecord = -1
records, err := reader.ReadAll()
if err != nil {
return nil, err
}
return records, nil
}