initial commit from original sev version
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"html/template"
|
||||
|
||||
"abuse_registration_poc/internal/auth"
|
||||
"abuse_registration_poc/internal/store"
|
||||
"abuse_registration_poc/internal/web"
|
||||
)
|
||||
|
||||
type Dependencies struct {
|
||||
Store *store.MemoryStore
|
||||
Users *auth.UserStore
|
||||
Version string
|
||||
AppName string
|
||||
BaseURL string
|
||||
}
|
||||
|
||||
type Handler struct {
|
||||
store *store.MemoryStore
|
||||
users *auth.UserStore
|
||||
index *template.Template
|
||||
version string
|
||||
appName string
|
||||
baseURL string
|
||||
}
|
||||
|
||||
func New(deps Dependencies) (*Handler, error) {
|
||||
index, err := template.ParseFS(web.Templates, "templates/index.html")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &Handler{
|
||||
store: deps.Store,
|
||||
users: deps.Users,
|
||||
index: index,
|
||||
version: deps.Version,
|
||||
appName: deps.AppName,
|
||||
baseURL: deps.BaseURL,
|
||||
}, nil
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
)
|
||||
|
||||
func (h *Handler) Health(writer http.ResponseWriter, request *http.Request) {
|
||||
rows, lastReset, nextReset := h.store.Snapshot()
|
||||
WriteJSON(writer, http.StatusOK, map[string]any{
|
||||
"status": "ok",
|
||||
"service": h.appName,
|
||||
"version": h.version,
|
||||
"dataset_count": len(rows),
|
||||
"reset_interval": h.store.ResetInterval().String(),
|
||||
"last_reset": lastReset.Format(time.RFC3339),
|
||||
"next_reset": nextReset.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"abuse_registration_poc/internal/models"
|
||||
)
|
||||
|
||||
func (h *Handler) Index(writer http.ResponseWriter, request *http.Request) {
|
||||
_, _, nextReset := h.store.Snapshot()
|
||||
data := struct {
|
||||
Version string
|
||||
NextReset string
|
||||
Locations []string
|
||||
Categories []string
|
||||
Genders []string
|
||||
Statuses []string
|
||||
}{
|
||||
Version: h.version,
|
||||
NextReset: nextReset.Format(time.RFC3339),
|
||||
Locations: models.FaroeLocations,
|
||||
Categories: models.AbuseCategories,
|
||||
Genders: models.Genders,
|
||||
Statuses: models.Statuses,
|
||||
}
|
||||
|
||||
writer.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||
if err := h.index.ExecuteTemplate(writer, "index.html", data); err != nil {
|
||||
http.Error(writer, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,128 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"abuse_registration_poc/internal/models"
|
||||
)
|
||||
|
||||
func (h *Handler) DemoRegistrations(writer http.ResponseWriter, request *http.Request) {
|
||||
WriteJSON(writer, http.StatusOK, h.store.List(filterFromQuery(request)))
|
||||
}
|
||||
|
||||
func (h *Handler) ListRegistrations(writer http.ResponseWriter, request *http.Request) {
|
||||
WriteJSON(writer, http.StatusOK, h.store.List(filterFromQuery(request)))
|
||||
}
|
||||
|
||||
func (h *Handler) GetRegistration(writer http.ResponseWriter, request *http.Request, id string) {
|
||||
registration, ok := h.store.Get(id)
|
||||
if !ok {
|
||||
WriteJSON(writer, http.StatusNotFound, map[string]string{"message": "Registration not found."})
|
||||
return
|
||||
}
|
||||
WriteJSON(writer, http.StatusOK, registration)
|
||||
}
|
||||
|
||||
func (h *Handler) CreateRegistration(writer http.ResponseWriter, request *http.Request) {
|
||||
var input models.Registration
|
||||
if err := DecodeJSON(request, &input); err != nil {
|
||||
WriteJSON(writer, http.StatusBadRequest, map[string]string{"message": "Could not parse request data."})
|
||||
return
|
||||
}
|
||||
created, err := h.store.Create(input)
|
||||
if err != nil {
|
||||
WriteJSON(writer, http.StatusBadRequest, map[string]string{"message": err.Error()})
|
||||
return
|
||||
}
|
||||
WriteJSON(writer, http.StatusCreated, created)
|
||||
}
|
||||
|
||||
func (h *Handler) UpdateRegistration(writer http.ResponseWriter, request *http.Request, id string) {
|
||||
var input models.Registration
|
||||
if err := DecodeJSON(request, &input); err != nil {
|
||||
WriteJSON(writer, http.StatusBadRequest, map[string]string{"message": "Could not parse request data."})
|
||||
return
|
||||
}
|
||||
updated, ok, err := h.store.Replace(id, input)
|
||||
if err != nil {
|
||||
WriteJSON(writer, http.StatusBadRequest, map[string]string{"message": err.Error()})
|
||||
return
|
||||
}
|
||||
if !ok {
|
||||
WriteJSON(writer, http.StatusNotFound, map[string]string{"message": "Registration not found."})
|
||||
return
|
||||
}
|
||||
WriteJSON(writer, http.StatusOK, updated)
|
||||
}
|
||||
|
||||
func (h *Handler) DeleteRegistration(writer http.ResponseWriter, request *http.Request, id string) {
|
||||
if !h.store.Delete(id) {
|
||||
WriteJSON(writer, http.StatusNotFound, map[string]string{"message": "Registration not found."})
|
||||
return
|
||||
}
|
||||
WriteJSON(writer, http.StatusOK, map[string]any{"message": "Registration deleted successfully.", "id": id})
|
||||
}
|
||||
|
||||
func (h *Handler) ResetRegistrations(writer http.ResponseWriter, request *http.Request) {
|
||||
h.store.Reset()
|
||||
rows, _, nextReset := h.store.Snapshot()
|
||||
WriteJSON(writer, http.StatusOK, map[string]any{
|
||||
"message": "Dataset reset to base sample data.",
|
||||
"dataset_count": len(rows),
|
||||
"next_reset": nextReset.Format(time.RFC3339),
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) Categories(writer http.ResponseWriter, request *http.Request) {
|
||||
WriteJSON(writer, http.StatusOK, models.AbuseCategories)
|
||||
}
|
||||
|
||||
func (h *Handler) Locations(writer http.ResponseWriter, request *http.Request) {
|
||||
WriteJSON(writer, http.StatusOK, models.FaroeLocations)
|
||||
}
|
||||
|
||||
func filterFromQuery(request *http.Request) models.RegistrationFilter {
|
||||
query := request.URL.Query()
|
||||
filter := models.RegistrationFilter{
|
||||
Location: query.Get("location"),
|
||||
AbuseType: query.Get("abuse_type"),
|
||||
Gender: query.Get("gender"),
|
||||
Status: query.Get("status"),
|
||||
Search: query.Get("search"),
|
||||
Limit: queryInt(query.Get("limit"), 0),
|
||||
Offset: queryInt(query.Get("offset"), 0),
|
||||
}
|
||||
|
||||
if from, ok := queryTime(query.Get("from")); ok {
|
||||
filter.From = from
|
||||
filter.HasFrom = true
|
||||
}
|
||||
if to, ok := queryTime(query.Get("to")); ok {
|
||||
filter.To = to
|
||||
filter.HasTo = true
|
||||
}
|
||||
return filter
|
||||
}
|
||||
|
||||
func queryInt(value string, fallback int) int {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return fallback
|
||||
}
|
||||
parsed, err := strconv.Atoi(value)
|
||||
if err != nil || parsed < 0 {
|
||||
return fallback
|
||||
}
|
||||
return parsed
|
||||
}
|
||||
|
||||
func queryTime(value string) (time.Time, bool) {
|
||||
parsed, err := models.ParseInputTime(value)
|
||||
if err != nil {
|
||||
return time.Time{}, false
|
||||
}
|
||||
return parsed, true
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func WriteJSON(writer http.ResponseWriter, status int, payload any) {
|
||||
writer.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
writer.WriteHeader(status)
|
||||
_ = json.NewEncoder(writer).Encode(payload)
|
||||
}
|
||||
|
||||
func WriteText(writer http.ResponseWriter, status int, message string) {
|
||||
writer.Header().Set("Content-Type", "text/plain; charset=utf-8")
|
||||
writer.WriteHeader(status)
|
||||
_, _ = writer.Write([]byte(message))
|
||||
}
|
||||
|
||||
func DecodeJSON(request *http.Request, target any) error {
|
||||
decoder := json.NewDecoder(request.Body)
|
||||
decoder.DisallowUnknownFields()
|
||||
return decoder.Decode(target)
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"abuse_registration_poc/internal/models"
|
||||
"abuse_registration_poc/internal/utils"
|
||||
)
|
||||
|
||||
// Login mirrors the original API login handler shape: validate user credentials,
|
||||
// generate a JWT, and return {message, token}.
|
||||
func (h *Handler) Login(writer http.ResponseWriter, request *http.Request) {
|
||||
var user models.ValidateUser
|
||||
if err := DecodeJSON(request, &user); err != nil {
|
||||
log.Printf("Error parsing request data: %v", err)
|
||||
WriteJSON(writer, http.StatusBadRequest, map[string]string{"message": "Could not parse request data."})
|
||||
return
|
||||
}
|
||||
|
||||
if err := h.users.ValidateCredentials(&user); err != nil {
|
||||
log.Printf("Error validating credentials: %v", err)
|
||||
WriteJSON(writer, http.StatusUnauthorized, map[string]string{"message": "Could not authenticate user."})
|
||||
return
|
||||
}
|
||||
|
||||
token, err := utils.GenerateToken(user.UserName, user.ID, user.Role)
|
||||
if err != nil {
|
||||
log.Printf("Error generating token: %v", err)
|
||||
WriteJSON(writer, http.StatusInternalServerError, map[string]string{"message": "Could not authenticate user."})
|
||||
return
|
||||
}
|
||||
|
||||
WriteJSON(writer, http.StatusOK, map[string]string{"message": "Login successful!", "token": token})
|
||||
}
|
||||
Reference in New Issue
Block a user