2020-12-03 14:51:15 +01:00
|
|
|
package helpers
|
2016-01-05 00:32:53 +01:00
|
|
|
|
|
|
|
import (
|
2019-07-09 19:45:27 +02:00
|
|
|
"encoding/json"
|
2024-04-02 23:10:42 +02:00
|
|
|
"errors"
|
2024-03-20 14:01:52 +01:00
|
|
|
"fmt"
|
2024-10-26 14:56:17 +02:00
|
|
|
"github.com/semaphoreui/semaphore/services/tasks"
|
2017-02-23 00:21:49 +01:00
|
|
|
"net/http"
|
2021-10-13 16:33:07 +02:00
|
|
|
"net/url"
|
2020-12-16 20:19:20 +01:00
|
|
|
"runtime/debug"
|
2016-01-05 00:32:53 +01:00
|
|
|
"strconv"
|
|
|
|
"strings"
|
2019-07-09 19:45:27 +02:00
|
|
|
|
2021-04-15 18:46:00 +02:00
|
|
|
"github.com/gorilla/context"
|
2024-03-20 14:01:52 +01:00
|
|
|
log "github.com/sirupsen/logrus"
|
2021-04-15 18:46:00 +02:00
|
|
|
|
2024-10-26 14:56:17 +02:00
|
|
|
"github.com/semaphoreui/semaphore/db"
|
2021-04-15 18:46:00 +02:00
|
|
|
|
2019-07-09 19:45:27 +02:00
|
|
|
"github.com/gorilla/mux"
|
2016-01-05 00:32:53 +01:00
|
|
|
)
|
|
|
|
|
2020-12-03 14:51:15 +01:00
|
|
|
func Store(r *http.Request) db.Store {
|
2020-12-03 14:44:30 +01:00
|
|
|
return context.Get(r, "store").(db.Store)
|
|
|
|
}
|
|
|
|
|
2022-01-29 19:00:21 +01:00
|
|
|
func TaskPool(r *http.Request) *tasks.TaskPool {
|
|
|
|
return context.Get(r, "task_pool").(*tasks.TaskPool)
|
|
|
|
}
|
|
|
|
|
2017-02-22 23:17:36 +01:00
|
|
|
func isXHR(w http.ResponseWriter, r *http.Request) bool {
|
|
|
|
accept := r.Header.Get("Accept")
|
2018-03-27 22:12:47 +02:00
|
|
|
return !strings.Contains(accept, "text/html")
|
2016-01-05 00:32:53 +01:00
|
|
|
}
|
|
|
|
|
2024-03-20 14:01:52 +01:00
|
|
|
// GetStrParam fetches a parameter from the route variables as an integer
|
|
|
|
// redirects to a 404 or writes bad request state depending on error state
|
|
|
|
func GetStrParam(name string, w http.ResponseWriter, r *http.Request) (string, error) {
|
|
|
|
strParam, ok := mux.Vars(r)[name]
|
|
|
|
|
|
|
|
if !ok {
|
|
|
|
if !isXHR(w, r) {
|
|
|
|
http.Redirect(w, r, "/404", http.StatusFound)
|
|
|
|
} else {
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
}
|
|
|
|
|
|
|
|
return "", fmt.Errorf("parameter missed")
|
|
|
|
}
|
|
|
|
|
|
|
|
return strParam, nil
|
|
|
|
}
|
|
|
|
|
2018-03-27 22:12:47 +02:00
|
|
|
// GetIntParam fetches a parameter from the route variables as an integer
|
|
|
|
// redirects to a 404 or writes bad request state depending on error state
|
2017-02-22 23:17:36 +01:00
|
|
|
func GetIntParam(name string, w http.ResponseWriter, r *http.Request) (int, error) {
|
2017-02-23 00:21:49 +01:00
|
|
|
intParam, err := strconv.Atoi(mux.Vars(r)[name])
|
|
|
|
|
2016-01-05 00:32:53 +01:00
|
|
|
if err != nil {
|
2018-03-27 22:12:47 +02:00
|
|
|
if !isXHR(w, r) {
|
2017-02-23 00:21:49 +01:00
|
|
|
http.Redirect(w, r, "/404", http.StatusFound)
|
2016-01-05 00:32:53 +01:00
|
|
|
} else {
|
2017-02-22 23:17:36 +01:00
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
2016-01-05 00:32:53 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return 0, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return intParam, nil
|
|
|
|
}
|
2018-03-27 22:12:47 +02:00
|
|
|
|
2023-08-29 00:51:04 +02:00
|
|
|
// H just a string-to-anything map
|
2019-07-09 19:45:27 +02:00
|
|
|
type H map[string]interface{}
|
|
|
|
|
2023-08-29 00:51:04 +02:00
|
|
|
// Bind decodes json into object
|
2020-12-03 14:51:15 +01:00
|
|
|
func Bind(w http.ResponseWriter, r *http.Request, out interface{}) bool {
|
2019-07-09 19:45:27 +02:00
|
|
|
err := json.NewDecoder(r.Body).Decode(out)
|
|
|
|
if err != nil {
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
}
|
|
|
|
|
2020-12-03 14:51:15 +01:00
|
|
|
return err == nil
|
2019-07-09 19:45:27 +02:00
|
|
|
}
|
|
|
|
|
2023-08-29 00:51:04 +02:00
|
|
|
// WriteJSON writes object as JSON
|
2019-07-09 19:45:27 +02:00
|
|
|
func WriteJSON(w http.ResponseWriter, code int, out interface{}) {
|
|
|
|
w.Header().Set("content-type", "application/json")
|
|
|
|
w.WriteHeader(code)
|
|
|
|
|
|
|
|
if err := json.NewEncoder(w).Encode(out); err != nil {
|
2024-10-07 11:35:20 +02:00
|
|
|
log.Error(err)
|
|
|
|
debug.PrintStack()
|
2019-07-09 19:45:27 +02:00
|
|
|
}
|
|
|
|
}
|
2020-12-03 14:51:15 +01:00
|
|
|
|
2024-04-02 23:10:42 +02:00
|
|
|
func WriteErrorStatus(w http.ResponseWriter, err string, code int) {
|
|
|
|
WriteJSON(w, code, map[string]string{
|
|
|
|
"error": err,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2020-12-03 14:51:15 +01:00
|
|
|
func WriteError(w http.ResponseWriter, err error) {
|
2024-06-12 21:53:00 +02:00
|
|
|
if errors.Is(err, tasks.ErrInvalidSubscription) {
|
|
|
|
WriteErrorStatus(w, "You have no subscription.", http.StatusForbidden)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-04-02 23:10:42 +02:00
|
|
|
if errors.Is(err, db.ErrNotFound) {
|
2020-12-03 14:51:15 +01:00
|
|
|
w.WriteHeader(http.StatusNotFound)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2024-04-02 23:10:42 +02:00
|
|
|
if errors.Is(err, db.ErrInvalidOperation) {
|
2021-05-14 14:31:24 +02:00
|
|
|
w.WriteHeader(http.StatusConflict)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2021-11-02 20:30:45 +01:00
|
|
|
switch e := err.(type) {
|
|
|
|
case *db.ValidationError:
|
2024-04-02 23:10:42 +02:00
|
|
|
WriteErrorStatus(w, e.Error(), http.StatusBadRequest)
|
2021-11-02 20:30:45 +01:00
|
|
|
default:
|
|
|
|
log.Error(err)
|
|
|
|
debug.PrintStack()
|
|
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
|
|
}
|
2020-12-03 14:51:15 +01:00
|
|
|
}
|
2021-04-15 18:46:00 +02:00
|
|
|
|
2021-10-13 16:33:07 +02:00
|
|
|
func QueryParams(url *url.URL) db.RetrieveQueryParams {
|
|
|
|
return db.RetrieveQueryParams{
|
2022-01-29 19:00:21 +01:00
|
|
|
SortBy: url.Query().Get("sort"),
|
2021-10-13 16:33:07 +02:00
|
|
|
SortInverted: url.Query().Get("order") == "desc",
|
|
|
|
}
|
|
|
|
}
|