Initial CPONE middleware implementation

This commit is contained in:
2026-08-18 13:41:38 +07:00
commit 676d930561
17 changed files with 1000 additions and 0 deletions

134
internal/http/handler.go Normal file
View File

@@ -0,0 +1,134 @@
package http
import (
"context"
"errors"
"net/http"
"regexp"
"strings"
"primaya-api/cpone-middleware/internal/repository"
)
var digitsOnly = regexp.MustCompile(`^\d+$`)
type LayananRepository interface {
MappingHarga(ctx context.Context, params repository.MappingHargaParams) ([]repository.TarifLayanan, error)
}
type Handler struct {
repo LayananRepository
}
func NewHandler(repo LayananRepository) Handler {
return Handler{repo: repo}
}
func (h Handler) MappingHarga(w http.ResponseWriter, r *http.Request) {
layananIDs := parseLayananIDs(r)
if len(layananIDs) == 0 {
WriteJSON(w, http.StatusUnprocessableEntity, Response{
Success: false,
Message: "Parameter layananID wajib diisi dan dapat berupa satu atau beberapa LayananID",
Data: nil,
})
return
}
periodeTarifID, ok := firstQueryValue(r, "periodeTarifID", "periode_tarif_id")
if !ok || strings.TrimSpace(periodeTarifID) == "" {
WriteJSON(w, http.StatusUnprocessableEntity, Response{
Success: false,
Message: "Parameter periodeTarifID wajib diisi",
Data: nil,
})
return
}
periodeTarifID = strings.TrimSpace(periodeTarifID)
if !digitsOnly.MatchString(periodeTarifID) {
WriteJSON(w, http.StatusUnprocessableEntity, Response{
Success: false,
Message: "Parameter periodeTarifID harus berupa angka",
Data: nil,
})
return
}
rows, err := h.repo.MappingHarga(r.Context(), repository.MappingHargaParams{
PeriodeTarifID: periodeTarifID,
LayananIDs: layananIDs,
Search: strings.TrimSpace(r.URL.Query().Get("search")),
})
if err != nil {
if errors.Is(err, repository.ErrTarifTableNotFound) {
WriteJSON(w, http.StatusNotFound, Response{
Success: false,
Message: "Tabel tarif dasar tidak ditemukan: harga_layanan_" + periodeTarifID,
Data: nil,
})
return
}
WriteJSON(w, http.StatusInternalServerError, Response{
Success: false,
Message: "internal server error",
Data: nil,
})
return
}
WriteJSON(w, http.StatusOK, Response{
Success: true,
Message: "ok",
Data: MappingHargaData{
PeriodeTarifID: periodeTarifID,
DetailLayanan: rows,
},
})
}
func parseLayananIDs(r *http.Request) []string {
values := queryValues(r, "layananID", "layananID[]")
if len(values) == 0 {
values = queryValues(r, "layanan_id", "layanan_id[]")
}
seen := make(map[string]struct{}, len(values))
ids := make([]string, 0, len(values))
for _, value := range values {
for _, part := range strings.Split(value, ",") {
id := strings.TrimSpace(part)
if id == "" {
continue
}
if _, exists := seen[id]; exists {
continue
}
seen[id] = struct{}{}
ids = append(ids, id)
}
}
return ids
}
func queryValues(r *http.Request, keys ...string) []string {
query := r.URL.Query()
values := make([]string, 0)
for _, key := range keys {
values = append(values, query[key]...)
}
return values
}
func firstQueryValue(r *http.Request, keys ...string) (string, bool) {
query := r.URL.Query()
for _, key := range keys {
if values, exists := query[key]; exists && len(values) > 0 {
return values[0], true
}
}
return "", false
}

View File

@@ -0,0 +1,30 @@
package http
import (
"net/http"
"strings"
)
func BearerAuth(staticToken string, next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if bearerToken(r.Header.Get("Authorization")) != staticToken {
WriteJSON(w, http.StatusUnauthorized, Response{
Success: false,
Message: "Unauthenticated.",
Data: nil,
})
return
}
next.ServeHTTP(w, r)
})
}
func bearerToken(header string) string {
const prefix = "Bearer "
if !strings.HasPrefix(header, prefix) {
return ""
}
return strings.TrimSpace(strings.TrimPrefix(header, prefix))
}

25
internal/http/response.go Normal file
View File

@@ -0,0 +1,25 @@
package http
import (
"encoding/json"
"net/http"
"primaya-api/cpone-middleware/internal/repository"
)
type Response struct {
Success bool `json:"success"`
Message string `json:"message"`
Data any `json:"data"`
}
type MappingHargaData struct {
PeriodeTarifID string `json:"PeriodeTarifID"`
DetailLayanan []repository.TarifLayanan `json:"DetailLayanan"`
}
func WriteJSON(w http.ResponseWriter, statusCode int, payload Response) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(statusCode)
_ = json.NewEncoder(w).Encode(payload)
}