- Kompletna Go implementacija licencnog servera (19 Go fajlova) - Klijentski API: activate, deactivate, validate - Admin API: CRUD licence, stats, audit log - Admin dashboard: htmx + Go templates - RSA-2048 potpisivanje licencnih podataka - Rate limiting i API key autentifikacija - MySQL migracije i seed podaci (ESIR, ARV, LIGHT_TICKET) - Unit testovi: keygen, crypto, model, middleware (24 testa) - Dokumentacija: SPEC.md, ARCHITECTURE.md, SETUP.md, API.md, TESTING.md, README.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
42 lines
1.1 KiB
Go
42 lines
1.1 KiB
Go
package handler
|
|
|
|
import (
|
|
"dal-license-server/internal/model"
|
|
"dal-license-server/internal/service"
|
|
"encoding/json"
|
|
"net/http"
|
|
)
|
|
|
|
func writeJSON(w http.ResponseWriter, status int, data interface{}) {
|
|
w.Header().Set("Content-Type", "application/json")
|
|
w.WriteHeader(status)
|
|
json.NewEncoder(w).Encode(data)
|
|
}
|
|
|
|
func writeError(w http.ResponseWriter, status int, code, message string) {
|
|
writeJSON(w, status, model.ErrorResponse{
|
|
Error: model.ErrorDetail{Code: code, Message: message},
|
|
})
|
|
}
|
|
|
|
func writeLicenseError(w http.ResponseWriter, err error) {
|
|
if le, ok := err.(*service.LicenseError); ok {
|
|
resp := model.ErrorResponse{
|
|
Error: model.ErrorDetail{Code: le.Code, Message: le.Message, Details: le.Details},
|
|
}
|
|
writeJSON(w, http.StatusBadRequest, resp)
|
|
return
|
|
}
|
|
writeError(w, http.StatusInternalServerError, "INTERNAL_ERROR", "Interna greska servera")
|
|
}
|
|
|
|
func clientIP(r *http.Request) string {
|
|
if xff := r.Header.Get("X-Forwarded-For"); xff != "" {
|
|
return xff
|
|
}
|
|
if xri := r.Header.Get("X-Real-IP"); xri != "" {
|
|
return xri
|
|
}
|
|
return r.RemoteAddr
|
|
}
|