Files
GraceSolutions 4e6ed52e51 feat: Add API handlers, LDAP client, and repositories
- API response helpers and error codes
- Authentication handlers (login, logout, me, csrf)
- Auth middleware (session validation, role checks, CSRF)
- LDAP client with TLS/StartTLS support
- LDAP filter construction from conditions
- AD operations (group membership, move, create group/OU)
- Credentials repository (CRUD, test results, usage check)
- AD connections repository (CRUD, test results)
- Schedules repository (CRUD, next run tracking)
- Rules repository with nested condition groups and actions
- go-ldap/ldap/v3 dependency added
2026-04-19 10:11:16 -04:00

155 lines
3.7 KiB
Go

// Package api provides HTTP handlers for the REST API
package api
import (
"encoding/json"
"fmt"
"net/http"
)
// Response is a standard API response envelope
type Response struct {
Success bool `json:"success"`
Data interface{} `json:"data,omitempty"`
Error *ErrorInfo `json:"error,omitempty"`
Meta *Meta `json:"meta,omitempty"`
}
// ErrorInfo provides error details
type ErrorInfo struct {
Code string `json:"code"`
Message string `json:"message"`
Details string `json:"details,omitempty"`
}
// Meta provides pagination and other metadata
type Meta struct {
Page int `json:"page,omitempty"`
PageSize int `json:"pageSize,omitempty"`
TotalCount int `json:"totalCount,omitempty"`
TotalPages int `json:"totalPages,omitempty"`
}
// WriteJSON writes a JSON response
func WriteJSON(w http.ResponseWriter, status int, data interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(Response{
Success: status >= 200 && status < 300,
Data: data,
})
}
// WriteError writes an error response
func WriteError(w http.ResponseWriter, status int, code, message string) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(Response{
Success: false,
Error: &ErrorInfo{
Code: code,
Message: message,
},
})
}
// WriteErrorWithDetails writes an error response with additional details
func WriteErrorWithDetails(w http.ResponseWriter, status int, code, message, details string) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(Response{
Success: false,
Error: &ErrorInfo{
Code: code,
Message: message,
Details: details,
},
})
}
// WriteList writes a paginated list response
func WriteList(w http.ResponseWriter, data interface{}, page, pageSize, totalCount int) {
totalPages := (totalCount + pageSize - 1) / pageSize
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(Response{
Success: true,
Data: data,
Meta: &Meta{
Page: page,
PageSize: pageSize,
TotalCount: totalCount,
TotalPages: totalPages,
},
})
}
// Error codes
const (
ErrCodeBadRequest = "BAD_REQUEST"
ErrCodeUnauthorized = "UNAUTHORIZED"
ErrCodeForbidden = "FORBIDDEN"
ErrCodeNotFound = "NOT_FOUND"
ErrCodeConflict = "CONFLICT"
ErrCodeValidation = "VALIDATION_ERROR"
ErrCodeInternalError = "INTERNAL_ERROR"
ErrCodeNotImplemented = "NOT_IMPLEMENTED"
ErrCodeServiceUnavailable = "SERVICE_UNAVAILABLE"
)
// DecodeJSON decodes a JSON request body
func DecodeJSON(r *http.Request, v interface{}) error {
return json.NewDecoder(r.Body).Decode(v)
}
// Pagination helpers
type PaginationParams struct {
Page int
PageSize int
SortBy string
SortDesc bool
}
// ParsePagination parses pagination parameters from query string
func ParsePagination(r *http.Request) PaginationParams {
p := PaginationParams{
Page: 1,
PageSize: 20,
SortBy: "created_utc",
SortDesc: true,
}
// Parse page
if page := r.URL.Query().Get("page"); page != "" {
if n, err := parseInt(page); err == nil && n > 0 {
p.Page = n
}
}
// Parse pageSize
if size := r.URL.Query().Get("pageSize"); size != "" {
if n, err := parseInt(size); err == nil && n > 0 && n <= 100 {
p.PageSize = n
}
}
// Parse sort
if sort := r.URL.Query().Get("sortBy"); sort != "" {
p.SortBy = sort
}
if desc := r.URL.Query().Get("sortDesc"); desc == "true" {
p.SortDesc = true
} else if desc == "false" {
p.SortDesc = false
}
return p
}
func parseInt(s string) (int, error) {
var n int
_, err := fmt.Sscanf(s, "%d", &n)
return n, err
}