From 71b1b3ad0be960e4d4ba421fb33ae83bf95282a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Z=C3=ADpek?= Date: Mon, 1 Apr 2024 12:41:04 +0200 Subject: [PATCH] Proper validation, always show menu in management pages --- .../src/assets/components/_user-layout.scss | 30 ++++++-- client/src/assets/pages/_alerts-page.scss | 3 +- client/src/assets/pages/_dashboard-page.scss | 4 +- client/src/assets/pages/_sensors-page.scss | 3 +- client/src/layouts/UserLayout/UserLayout.tsx | 39 +++++++---- .../layouts/UserLayout/components/NavLink.tsx | 19 +++++ .../UserLayout/components/UserMenu.tsx | 35 ++++++---- .../src/pages/dashboard/NewDashboardPage.tsx | 6 +- server/routes/alerts.go | 67 ++++-------------- server/routes/auth.go | 24 ++----- server/routes/contact_points.go | 70 ++++--------------- server/routes/dashboards.go | 49 +++---------- server/routes/sensor_config.go | 7 +- server/routes/sensor_values.go | 49 ++++--------- server/routes/sensors.go | 59 ++++------------ server/routes/utils.go | 24 +++++++ 16 files changed, 199 insertions(+), 289 deletions(-) create mode 100644 client/src/layouts/UserLayout/components/NavLink.tsx create mode 100644 server/routes/utils.go diff --git a/client/src/assets/components/_user-layout.scss b/client/src/assets/components/_user-layout.scss index 7859ff4..1b21b46 100644 --- a/client/src/assets/components/_user-layout.scss +++ b/client/src/assets/components/_user-layout.scss @@ -1,18 +1,27 @@ main.layout { height: 100%; - overflow: auto; display: flex; - flex-direction: column; + + > .right-content { + overflow: auto; + display: flex; + flex-direction: column; + height: 100%; + flex: 1; + } } .menu { - position: fixed; - left: 0; - top: 0; - bottom: 0; + &.as-popup { + position: fixed; + left: 0; + top: 0; + bottom: 0; + } + color: var(--box-fg-color); width: 15rem; - transition: left 0.1s; + transition: left 0.1s, margin-left 0.1s; z-index: 2; display: flex; @@ -62,6 +71,11 @@ main.layout { text-decoration: none; padding: 0.4rem 1rem; display: flex; + color: var(--box-fg-color); + + &.current { + background-color: var(--box-border-color); + } &:hover { background-color: var(--box-border-color); @@ -88,7 +102,9 @@ header.header { > .inner { display: flex; padding: 0.5rem 0.5rem 0.5rem 0; + height: 2.2rem; background-color: var(--header-bg-color); + align-items: center; > .menu-button { display: flex; diff --git a/client/src/assets/pages/_alerts-page.scss b/client/src/assets/pages/_alerts-page.scss index e7be254..0a44707 100644 --- a/client/src/assets/pages/_alerts-page.scss +++ b/client/src/assets/pages/_alerts-page.scss @@ -1,7 +1,6 @@ .alerts-page .content { width: 50rem; - padding: 1rem; - margin: 0 auto; + padding: 1rem 2rem; .contact-points { margin-bottom: 2rem; diff --git a/client/src/assets/pages/_dashboard-page.scss b/client/src/assets/pages/_dashboard-page.scss index 078ef8c..364b26a 100644 --- a/client/src/assets/pages/_dashboard-page.scss +++ b/client/src/assets/pages/_dashboard-page.scss @@ -1,9 +1,11 @@ -.dashboard { +/* +.dashboard-page { height: 100%; overflow: auto; display: flex; flex-direction: column; } +*/ .dashboard-head { display: flex; diff --git a/client/src/assets/pages/_sensors-page.scss b/client/src/assets/pages/_sensors-page.scss index 6f67790..2c0145b 100644 --- a/client/src/assets/pages/_sensors-page.scss +++ b/client/src/assets/pages/_sensors-page.scss @@ -11,8 +11,7 @@ section.content { width: 50rem; - margin: 0 auto; - padding: 1rem; + padding: 1rem 2rem; } } diff --git a/client/src/layouts/UserLayout/UserLayout.tsx b/client/src/layouts/UserLayout/UserLayout.tsx index d79a75d..893747b 100644 --- a/client/src/layouts/UserLayout/UserLayout.tsx +++ b/client/src/layouts/UserLayout/UserLayout.tsx @@ -8,24 +8,39 @@ type Props = { children: ComponentChild header?: ComponentChild className?: string + popupMenu?: boolean } -export const UserLayout = ({ children, header, className }: Props) => { - const [menuShown, setMenuShown] = useState(false) +export const UserLayout = ({ + children, + header, + className, + popupMenu = false, +}: Props) => { + const [menuShown, setMenuShown] = useState(popupMenu ? false : true) return (
-
-
-
setMenuShown(true)}> - + setMenuShown(false)} + /> +
+
+
+
setMenuShown(!menuShown)} + > + +
+ {header}
- {header} -
-
-
-
{children}
- setMenuShown(false)} /> + {/*
*/} + +
{children}
+
) } diff --git a/client/src/layouts/UserLayout/components/NavLink.tsx b/client/src/layouts/UserLayout/components/NavLink.tsx new file mode 100644 index 0000000..084157f --- /dev/null +++ b/client/src/layouts/UserLayout/components/NavLink.tsx @@ -0,0 +1,19 @@ +import { cn } from '@/utils/cn' +import { useHashRouterLocation } from '@/utils/hooks/useHashLocation' +import { ComponentChildren } from 'preact' +import { Link } from 'wouter' + +type Props = { + href: string + children: ComponentChildren +} + +export const NavLink = ({ href, children }: Props) => { + const [location] = useHashRouterLocation() + + return ( + + {children} + + ) +} diff --git a/client/src/layouts/UserLayout/components/UserMenu.tsx b/client/src/layouts/UserLayout/components/UserMenu.tsx index 44a4f03..f5e448a 100644 --- a/client/src/layouts/UserLayout/components/UserMenu.tsx +++ b/client/src/layouts/UserLayout/components/UserMenu.tsx @@ -1,33 +1,44 @@ import { CancelIcon } from '@/icons' -import { Link } from 'wouter' +import { cn } from '@/utils/cn' +import { NavLink } from './NavLink' type Props = { + popup: boolean shown: boolean onHide: () => void } -export const UserMenu = ({ shown, onHide }: Props) => { +export const UserMenu = ({ shown, popup, onHide }: Props) => { return ( <> -
+
-
- -
+ {popup && ( +
+ +
+ )}

Graphicek

-
+ {popup &&
}
- {shown &&
} + {popup && shown &&
} ) } diff --git a/client/src/pages/dashboard/NewDashboardPage.tsx b/client/src/pages/dashboard/NewDashboardPage.tsx index 226b79f..3f528e0 100644 --- a/client/src/pages/dashboard/NewDashboardPage.tsx +++ b/client/src/pages/dashboard/NewDashboardPage.tsx @@ -6,7 +6,11 @@ import { DashboardContextProvider } from './contexts/DashboardContext' export const NewDashboardPage = () => { return ( - }> + } + popupMenu + > diff --git a/server/routes/alerts.go b/server/routes/alerts.go index f7e4bd9..d3797a1 100644 --- a/server/routes/alerts.go +++ b/server/routes/alerts.go @@ -3,27 +3,17 @@ package routes import ( "basic-sensor-receiver/app" "net/http" - "strconv" "github.com/gin-gonic/gin" ) -type postAlertsBody struct { - ContactPointId int64 `json:"contactPointId"` - Name string `json:"name"` - Condition string `json:"condition"` - TriggerInterval int64 `json:"triggerInterval"` - CustomMessage string `json:"customMessage"` - CustomResolvedMessage string `json:"customResolvedMessage"` -} - -type putAlertsBody struct { - ContactPointId int64 `json:"contactPointId"` - Name string `json:"name"` - Condition string `json:"condition"` - TriggerInterval int64 `json:"triggerInterval"` - CustomMessage string `json:"customMessage"` - CustomResolvedMessage string `json:"customResolvedMessage"` +type postAndPutAlertsBody struct { + ContactPointId int64 `json:"contactPointId" binding:"required"` + Name string `json:"name" binding:"required"` + Condition string `json:"condition" binding:"required"` + TriggerInterval int64 `json:"triggerInterval" binding:"required"` + CustomMessage string `json:"customMessage" binding:"required"` + CustomResolvedMessage string `json:"customResolvedMessage" binding:"required"` } func GetAlerts(s *app.Server) gin.HandlerFunc { @@ -41,12 +31,8 @@ func GetAlerts(s *app.Server) gin.HandlerFunc { func PostAlerts(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { - body := postAlertsBody{} - - if err := c.BindJSON(&body); err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } + body := postAndPutAlertsBody{} + bindJSONBodyOrAbort(c, &body) alert, err := s.Services.Alerts.Create(body.ContactPointId, body.Name, body.Condition, body.TriggerInterval, body.CustomMessage, body.CustomResolvedMessage) @@ -61,19 +47,10 @@ func PostAlerts(s *app.Server) gin.HandlerFunc { func PutAlert(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { - body := putAlertsBody{} + alertId := getIntParamOrAbort(c, "alertId") - alertId, err := getAlertId(c) - - if err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } - - if err := c.BindJSON(&body); err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } + body := postAndPutAlertsBody{} + bindJSONBodyOrAbort(c, &body) alert, err := s.Services.Alerts.Update(alertId, body.ContactPointId, body.Name, body.Condition, body.TriggerInterval, body.CustomMessage, body.CustomResolvedMessage) @@ -88,12 +65,7 @@ func PutAlert(s *app.Server) gin.HandlerFunc { func GetAlert(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { - alertId, err := getAlertId(c) - - if err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } + alertId := getIntParamOrAbort(c, "alertId") alert, err := s.Services.Alerts.GetById(alertId) @@ -108,12 +80,7 @@ func GetAlert(s *app.Server) gin.HandlerFunc { func DeleteAlert(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { - alertId, err := getAlertId(c) - - if err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } + alertId := getIntParamOrAbort(c, "alertId") if err := s.Services.Alerts.DeleteById(alertId); err != nil { c.AbortWithError(http.StatusInternalServerError, err) @@ -123,9 +90,3 @@ func DeleteAlert(s *app.Server) gin.HandlerFunc { c.Status(http.StatusOK) } } - -func getAlertId(c *gin.Context) (int64, error) { - id := c.Param("alertId") - - return strconv.ParseInt(id, 10, 64) -} diff --git a/server/routes/auth.go b/server/routes/auth.go index 71e198c..a1c7954 100644 --- a/server/routes/auth.go +++ b/server/routes/auth.go @@ -8,18 +8,14 @@ import ( ) type postLoginBody struct { - Username string `json:"username"` - Password string `json:"password"` + Username string `json:"username" binding:"required"` + Password string `json:"password" binding:"required"` } func Login(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { body := postLoginBody{} - - if err := c.BindJSON(&body); err != nil { - c.AbortWithError(400, err) - return - } + bindJSONBodyOrAbort(c, &body) if body.Password != s.Config.AuthPassword || body.Username != s.Config.AuthUsername { c.AbortWithStatus(401) @@ -36,19 +32,7 @@ func Login(s *app.Server) gin.HandlerFunc { func Logout(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { - body := postLoginBody{} - - if err := c.BindJSON(&body); err != nil { - c.AbortWithError(400, err) - return - } - - if body.Password != s.Config.AuthPassword || body.Username != s.Config.AuthUsername { - c.AbortWithStatus(401) - return - } - - if err := s.Services.Auth.Login(c); err != nil { + if err := s.Services.Auth.Logout(c); err != nil { c.AbortWithError(500, err) } diff --git a/server/routes/contact_points.go b/server/routes/contact_points.go index ece715d..f2ecb1f 100644 --- a/server/routes/contact_points.go +++ b/server/routes/contact_points.go @@ -3,26 +3,19 @@ package routes import ( "basic-sensor-receiver/app" "net/http" - "strconv" "github.com/gin-gonic/gin" ) -type postContactPointsBody struct { - Name string `json:"name"` - Type string `json:"type"` - TypeConfig string `json:"typeConfig"` -} - -type putContactPointsBody struct { - Name string `json:"name"` - Type string `json:"type"` - TypeConfig string `json:"typeConfig"` +type postOrPutContactPointsBody struct { + Name string `json:"name" binding:"required"` + Type string `json:"type" binding:"required,oneof=telegram"` + TypeConfig string `json:"typeConfig" binding:"required"` } type testContactPointBody struct { - Type string `json:"type"` - TypeConfig string `json:"typeConfig"` + Type string `json:"type" binding:"required,oneof=telegram"` + TypeConfig string `json:"typeConfig" binding:"required"` } func GetContactPoints(s *app.Server) gin.HandlerFunc { @@ -40,12 +33,8 @@ func GetContactPoints(s *app.Server) gin.HandlerFunc { func PostContactPoints(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { - body := postContactPointsBody{} - - if err := c.BindJSON(&body); err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } + body := postOrPutContactPointsBody{} + bindJSONBodyOrAbort(c, &body) contactPoint, err := s.Services.ContactPoints.Create(body.Name, body.Type, body.TypeConfig) @@ -60,19 +49,10 @@ func PostContactPoints(s *app.Server) gin.HandlerFunc { func PutContactPoint(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { - body := putContactPointsBody{} + contactPointId := getIntParamOrAbort(c, "contactPointId") - contactPointId, err := getContactPointId(c) - - if err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } - - if err := c.BindJSON(&body); err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } + body := postOrPutContactPointsBody{} + bindJSONBodyOrAbort(c, &body) contactPoint, err := s.Services.ContactPoints.Update(contactPointId, body.Name, body.Type, body.TypeConfig) @@ -87,12 +67,7 @@ func PutContactPoint(s *app.Server) gin.HandlerFunc { func GetContactPoint(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { - contactPointId, err := getContactPointId(c) - - if err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } + contactPointId := getIntParamOrAbort(c, "contactPointId") contactPoint, err := s.Services.ContactPoints.GetById(contactPointId) @@ -107,14 +82,9 @@ func GetContactPoint(s *app.Server) gin.HandlerFunc { func DeleteContactPoint(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { - contactPointId, err := getContactPointId(c) + contactPointId := getIntParamOrAbort(c, "contactPointId") - if err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } - - err = s.Services.ContactPoints.Delete(contactPointId) + err := s.Services.ContactPoints.Delete(contactPointId) if err != nil { c.AbortWithError(http.StatusInternalServerError, err) @@ -128,11 +98,7 @@ func DeleteContactPoint(s *app.Server) gin.HandlerFunc { func TestContactPoint(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { body := testContactPointBody{} - - if err := c.BindJSON(&body); err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } + bindJSONBodyOrAbort(c, &body) err := s.Services.ContactPoints.Test(body.Type, body.TypeConfig) @@ -144,9 +110,3 @@ func TestContactPoint(s *app.Server) gin.HandlerFunc { c.AbortWithStatus(http.StatusOK) } } - -func getContactPointId(c *gin.Context) (int64, error) { - sensor := c.Param("contactPointId") - - return strconv.ParseInt(sensor, 10, 64) -} diff --git a/server/routes/dashboards.go b/server/routes/dashboards.go index ac7e1c4..d3702f3 100644 --- a/server/routes/dashboards.go +++ b/server/routes/dashboards.go @@ -4,20 +4,19 @@ import ( "basic-sensor-receiver/app" "database/sql" "net/http" - "strconv" "github.com/gin-gonic/gin" ) type postDashboardBody struct { - Id int64 `json:"id"` - Name string `json:"name"` - Contents string `json:"contents"` + Id int64 `json:"id" binding:"required"` + Name string `json:"name" binding:"required"` + Contents string `json:"contents" binding:"required"` } type putDashboardBody struct { - Name string `json:"name"` - Contents string `json:"contents"` + Name string `json:"name" binding:"required"` + Contents string `json:"contents" binding:"required"` } func GetDashboards(s *app.Server) gin.HandlerFunc { @@ -35,11 +34,7 @@ func GetDashboards(s *app.Server) gin.HandlerFunc { func GetDashboardById(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { - id, err := getIntParam(c, "id") - if err != nil { - c.AbortWithError(400, err) - return - } + id := getIntParamOrAbort(c, "id") item, err := s.Services.Dashboards.GetById(id) @@ -60,11 +55,7 @@ func GetDashboardById(s *app.Server) gin.HandlerFunc { func PostDashboard(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { body := postDashboardBody{} - - if err := c.BindJSON(&body); err != nil { - c.AbortWithError(400, err) - return - } + bindJSONBodyOrAbort(c, &body) item, err := s.Services.Dashboards.Create(body.Id, body.Name, body.Contents) @@ -79,18 +70,10 @@ func PostDashboard(s *app.Server) gin.HandlerFunc { func PutDashboard(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { - id, err := getIntParam(c, "id") - if err != nil { - c.AbortWithError(400, err) - return - } + id := getIntParamOrAbort(c, "id") body := putDashboardBody{} - - if err := c.BindJSON(&body); err != nil { - c.AbortWithError(400, err) - return - } + bindJSONBodyOrAbort(c, &body) item, err := s.Services.Dashboards.Update(id, body.Name, body.Contents) @@ -105,13 +88,9 @@ func PutDashboard(s *app.Server) gin.HandlerFunc { func DeleteDashboard(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { - id, err := getIntParam(c, "id") - if err != nil { - c.AbortWithError(400, err) - return - } + id := getIntParamOrAbort(c, "id") - err = s.Services.Dashboards.Delete(id) + err := s.Services.Dashboards.Delete(id) if err != nil { c.AbortWithError(500, err) @@ -121,9 +100,3 @@ func DeleteDashboard(s *app.Server) gin.HandlerFunc { c.Status(http.StatusOK) } } - -func getIntParam(c *gin.Context, key string) (int64, error) { - value := c.Param(key) - - return strconv.ParseInt(value, 10, 64) -} diff --git a/server/routes/sensor_config.go b/server/routes/sensor_config.go index 0f7c6ba..16d1e48 100644 --- a/server/routes/sensor_config.go +++ b/server/routes/sensor_config.go @@ -8,7 +8,7 @@ import ( ) type sensorConfigValue struct { - Value string `json:"value"` + Value string `json:"value" binding:"required"` } func PutSensorConfig(s *app.Server) gin.HandlerFunc { @@ -17,10 +17,7 @@ func PutSensorConfig(s *app.Server) gin.HandlerFunc { sensor := c.Param("sensor") key := c.Param("key") - if err := c.BindJSON(&configValue); err != nil { - c.AbortWithError(400, err) - return - } + bindJSONBodyOrAbort(c, &configValue) if err := s.Services.SensorConfig.SetValue(sensor, key, configValue.Value); err != nil { c.AbortWithError(500, err) diff --git a/server/routes/sensor_values.go b/server/routes/sensor_values.go index 5cca959..af3ec0f 100644 --- a/server/routes/sensor_values.go +++ b/server/routes/sensor_values.go @@ -4,39 +4,30 @@ import ( "basic-sensor-receiver/app" "database/sql" "net/http" - "strconv" "github.com/gin-gonic/gin" ) type postSensorValueBody struct { - Value float64 `json:"value"` + Value float64 `json:"value" binding:"required"` } type getSensorValuesQuery struct { - From int64 `form:"from"` - To int64 `form:"to"` + From int64 `form:"from" binding:"required"` + To int64 `form:"to" binding:"required"` } type getLatestSensorValueQuery struct { - To int64 `form:"to"` + To int64 `form:"to" binding:"required"` } func PostSensorValues(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { var newValue postSensorValueBody - if err := c.BindJSON(&newValue); err != nil { - c.AbortWithError(400, err) - return - } + bindJSONBodyOrAbort(c, &newValue) - sensorId, err := getSensorId(c) - - if err != nil { - c.AbortWithError(400, err) - return - } + sensorId := getIntParamOrAbort(c, "sensor") if _, err := s.Services.SensorValues.Push(sensorId, newValue.Value); err != nil { c.AbortWithError(400, err) @@ -51,15 +42,10 @@ func GetSensorValues(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { var query getSensorValuesQuery - sensorId, err := getSensorId(c) + sensorId := getIntParamOrAbort(c, "sensor") - if err != nil { - c.AbortWithError(400, err) - return - } - - if err := c.BindQuery(&query); err != nil { - c.AbortWithError(500, err) + if err := c.ShouldBindQuery(&query); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } @@ -77,15 +63,10 @@ func GetSensorLatestValue(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { var query getLatestSensorValueQuery - sensorId, err := getSensorId(c) + sensorId := getIntParamOrAbort(c, "sensor") - if err != nil { - c.AbortWithError(400, err) - return - } - - if err := c.BindQuery(&query); err != nil { - c.AbortWithError(500, err) + if err := c.ShouldBindQuery(&query); err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } @@ -104,9 +85,3 @@ func GetSensorLatestValue(s *app.Server) gin.HandlerFunc { c.JSON(http.StatusOK, value) } } - -func getSensorId(c *gin.Context) (int64, error) { - sensor := c.Param("sensor") - - return strconv.ParseInt(sensor, 10, 64) -} diff --git a/server/routes/sensors.go b/server/routes/sensors.go index 902040a..af46d10 100644 --- a/server/routes/sensors.go +++ b/server/routes/sensors.go @@ -2,17 +2,14 @@ package routes import ( "basic-sensor-receiver/app" + "log" "net/http" "github.com/gin-gonic/gin" ) -type postSensorsBody struct { - Name string `json:"name"` -} - -type putSensorsBody struct { - Name string `json:"name"` +type postOrPutSensorsBody struct { + Name string `json:"name" binding:"required"` } func GetSensors(s *app.Server) gin.HandlerFunc { @@ -20,7 +17,8 @@ func GetSensors(s *app.Server) gin.HandlerFunc { sensors, err := s.Services.Sensors.GetList() if err != nil { - c.AbortWithError(http.StatusInternalServerError, err) + log.Println(err) + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) return } @@ -30,12 +28,8 @@ func GetSensors(s *app.Server) gin.HandlerFunc { func PostSensors(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { - body := postSensorsBody{} - - if err := c.BindJSON(&body); err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } + body := postOrPutSensorsBody{} + bindJSONBodyOrAbort(c, &body) sensor, err := s.Services.Sensors.Create(body.Name) @@ -50,19 +44,10 @@ func PostSensors(s *app.Server) gin.HandlerFunc { func PutSensor(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { - body := putSensorsBody{} + sensorId := getIntParamOrAbort(c, "sensor") - sensorId, err := getSensorId(c) - - if err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } - - if err := c.BindJSON(&body); err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } + body := postOrPutSensorsBody{} + bindJSONBodyOrAbort(c, &body) sensor, err := s.Services.Sensors.Update(sensorId, body.Name) @@ -77,19 +62,10 @@ func PutSensor(s *app.Server) gin.HandlerFunc { func GetSensor(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { - body := putSensorsBody{} + sensorId := getIntParamOrAbort(c, "sensor") - sensorId, err := getSensorId(c) - - if err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } - - if err := c.BindJSON(&body); err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } + body := postOrPutSensorsBody{} + bindJSONBodyOrAbort(c, &body) sensor, err := s.Services.Sensors.GetById(sensorId) @@ -104,14 +80,9 @@ func GetSensor(s *app.Server) gin.HandlerFunc { func DeleteSensor(s *app.Server) gin.HandlerFunc { return func(c *gin.Context) { - sensorId, err := getSensorId(c) + sensorId := getIntParamOrAbort(c, "sensor") - if err != nil { - c.AbortWithError(http.StatusBadRequest, err) - return - } - - err = s.Services.Sensors.DeleteById(sensorId) + err := s.Services.Sensors.DeleteById(sensorId) if err != nil { c.AbortWithError(http.StatusInternalServerError, err) diff --git a/server/routes/utils.go b/server/routes/utils.go new file mode 100644 index 0000000..b11b7cd --- /dev/null +++ b/server/routes/utils.go @@ -0,0 +1,24 @@ +package routes + +import ( + "strconv" + + "github.com/gin-gonic/gin" +) + +func getIntParamOrAbort(c *gin.Context, key string) int64 { + value := c.Param(key) + val, err := strconv.ParseInt(value, 10, 64) + + if err != nil { + c.AbortWithStatusJSON(400, gin.H{"error": "Invalid " + key}) + } + + return val +} + +func bindJSONBodyOrAbort(c *gin.Context, body interface{}) { + if err := c.ShouldBindJSON(body); err != nil { + c.AbortWithStatusJSON(400, gin.H{"error": err.Error()}) + } +}