package admin import ( "net/http" "net/url" "strconv" "strings" "forge.cadoles.com/cadoles/bouncer/internal/store" "github.com/go-chi/chi/v5" "github.com/pkg/errors" "gitlab.com/wpetit/goweb/api" "gitlab.com/wpetit/goweb/logger" ) type QueryProxyResponse struct { Proxies []*store.ProxyHeader `json:"proxies"` } func (s *Server) queryProxy(w http.ResponseWriter, r *http.Request) { limit, ok := getIntQueryParam(w, r, "limit", 10) if !ok { return } offset, ok := getIntQueryParam(w, r, "offset", 0) if !ok { return } options := []store.QueryProxyOptionFunc{ store.WithProxyQueryLimit(int(limit)), store.WithProxyQueryOffset(int(offset)), } ids, ok := getStringableSliceValues[store.ProxyID](w, r, "ids", nil) if !ok { return } if ids != nil { options = append(options, store.WithProxyQueryIDs(ids...)) } ctx := r.Context() proxies, err := s.proxyRepository.QueryProxy( ctx, options..., ) if err != nil { logger.Error(ctx, "could not list proxies", logger.E(errors.WithStack(err))) api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) return } api.DataResponse(w, http.StatusOK, QueryProxyResponse{ Proxies: proxies, }) } type GetProxyResponse struct { Proxy *store.Proxy `json:"proxy"` } func (s *Server) getProxy(w http.ResponseWriter, r *http.Request) { proxyID, ok := getProxyID(w, r) if !ok { return } ctx := r.Context() proxy, err := s.proxyRepository.GetProxy(ctx, proxyID) if err != nil { if errors.Is(err, store.ErrNotFound) { api.ErrorResponse(w, http.StatusNotFound, api.ErrCodeNotFound, nil) return } logger.Error(ctx, "could not get proxy", logger.E(errors.WithStack(err))) api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) return } api.DataResponse(w, http.StatusOK, GetProxyResponse{ Proxy: proxy, }) } type DeleteProxyResponse struct { ProxyID store.ProxyID `json:"proxyId"` } func (s *Server) deleteProxy(w http.ResponseWriter, r *http.Request) { proxyID, ok := getProxyID(w, r) if !ok { return } ctx := r.Context() if err := s.proxyRepository.DeleteProxy(ctx, proxyID); err != nil { if errors.Is(err, store.ErrNotFound) { api.ErrorResponse(w, http.StatusNotFound, api.ErrCodeNotFound, nil) return } logger.Error(ctx, "could not delete proxy", logger.E(errors.WithStack(err))) api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) return } api.DataResponse(w, http.StatusOK, DeleteProxyResponse{ ProxyID: proxyID, }) } type CreateProxyRequest struct { To string `json:"to" validate:"required"` From []string `json:"from" validate:"required"` } type CreateProxyResponse struct { Proxy *store.Proxy `json:"proxy"` } func (s *Server) createProxy(w http.ResponseWriter, r *http.Request) { ctx := r.Context() createProxyReq := &CreateProxyRequest{} if ok := api.Bind(w, r, createProxyReq); !ok { return } to, err := url.Parse(createProxyReq.To) if err != nil { logger.Error(r.Context(), "could not parse to parameter", logger.E(errors.WithStack(err))) api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil) return } proxy, err := s.proxyRepository.CreateProxy(ctx, to, createProxyReq.From...) if err != nil { logger.Error(ctx, "could not update agent", logger.E(errors.WithStack(err))) api.ErrorResponse(w, http.StatusInternalServerError, api.ErrCodeUnknownError, nil) return } api.DataResponse(w, http.StatusOK, struct { Proxy *store.Proxy `json:"proxy"` }{ Proxy: proxy, }) } type UpdateProxyRequest struct{} func (s *Server) updateProxy(w http.ResponseWriter, r *http.Request) { } func getProxyID(w http.ResponseWriter, r *http.Request) (store.ProxyID, bool) { rawProxyID := chi.URLParam(r, "proxyID") proxyID, err := store.ParseProxyID(rawProxyID) if err != nil { logger.Error(r.Context(), "could not parse proxy id", logger.E(errors.WithStack(err))) api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil) return "", false } return proxyID, true } func getIntQueryParam(w http.ResponseWriter, r *http.Request, param string, defaultValue int64) (int64, bool) { rawValue := r.URL.Query().Get(param) if rawValue != "" { value, err := strconv.ParseInt(rawValue, 10, 64) if err != nil { logger.Error(r.Context(), "could not parse int param", logger.F("param", param), logger.E(errors.WithStack(err))) api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil) return 0, false } return value, true } return defaultValue, true } func getStringSliceValues(w http.ResponseWriter, r *http.Request, param string, defaultValue []string) ([]string, bool) { rawValue := r.URL.Query().Get(param) if rawValue != "" { values := strings.Split(rawValue, ",") return values, true } return defaultValue, true } func getStringableSliceValues[T ~string](w http.ResponseWriter, r *http.Request, param string, defaultValue []T) ([]T, bool) { rawValue := r.URL.Query().Get(param) if rawValue != "" { rawValues := strings.Split(rawValue, ",") ids := make([]T, 0, len(rawValues)) for _, rv := range rawValues { id, err := store.ParseID[T](rv) if err != nil { logger.Error(r.Context(), "could not parse ids slice param", logger.F("param", param), logger.E(errors.WithStack(err))) api.ErrorResponse(w, http.StatusBadRequest, api.ErrCodeMalformedRequest, nil) return nil, false } ids = append(ids, id) } return ids, true } return defaultValue, true }