Fix validation, add sensor last contact field, add alert status formatting
This commit is contained in:
parent
e1b0d16ce6
commit
e6438ad0f1
|
|
@ -1,5 +1,12 @@
|
||||||
import { request } from './request'
|
import { request } from './request'
|
||||||
|
|
||||||
|
export enum AlertStatuses {
|
||||||
|
OK = 'ok',
|
||||||
|
ALERT_PENDING = 'alert_pending',
|
||||||
|
ALERTING = 'alerting',
|
||||||
|
OK_PENDING = 'ok_pending',
|
||||||
|
}
|
||||||
|
|
||||||
export type AlertInfo = {
|
export type AlertInfo = {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
|
|
@ -8,8 +15,8 @@ export type AlertInfo = {
|
||||||
customMessage: string
|
customMessage: string
|
||||||
customResolvedMessage: string
|
customResolvedMessage: string
|
||||||
triggerInterval: number
|
triggerInterval: number
|
||||||
lastStatus: string
|
lastStatus: AlertStatuses
|
||||||
lastStatusAt: string
|
lastStatusAt: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getAlerts = () => request<AlertInfo[]>('/api/alerts')
|
export const getAlerts = () => request<AlertInfo[]>('/api/alerts')
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ export const updateContactPoint = ({ id, ...body }: ContactPointInfo) =>
|
||||||
})
|
})
|
||||||
|
|
||||||
export const deleteContactPoint = (id: number) =>
|
export const deleteContactPoint = (id: number) =>
|
||||||
request<ContactPointInfo>(
|
request<void, 'void'>(
|
||||||
`/api/contact-points/${id}`,
|
`/api/contact-points/${id}`,
|
||||||
{ method: 'DELETE' },
|
{ method: 'DELETE' },
|
||||||
'void'
|
'void'
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ export const updateDashboard = ({
|
||||||
})
|
})
|
||||||
|
|
||||||
export const deleteDashboard = (id: number) =>
|
export const deleteDashboard = (id: number) =>
|
||||||
request<DashboardInfo>(
|
request<void, 'void'>(
|
||||||
`/api/dashboards/${id}`,
|
`/api/dashboards/${id}`,
|
||||||
{
|
{
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ export type SensorInfo = {
|
||||||
id: number
|
id: number
|
||||||
name: string
|
name: string
|
||||||
authKey: string
|
authKey: string
|
||||||
|
lastContactAt?: number
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getSensors = () => request<SensorInfo[]>('/api/sensors')
|
export const getSensors = () => request<SensorInfo[]>('/api/sensors')
|
||||||
|
|
@ -23,4 +24,4 @@ export const updateSensor = ({ id, ...body }: { id: number; name: string }) =>
|
||||||
})
|
})
|
||||||
|
|
||||||
export const deleteSensor = (id: number) =>
|
export const deleteSensor = (id: number) =>
|
||||||
request<SensorInfo>(`/api/sensors/${id}`, { method: 'DELETE' }, 'void')
|
request<void, 'void'>(`/api/sensors/${id}`, { method: 'DELETE' }, 'void')
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,27 @@
|
||||||
.contact-points {
|
.contact-points {
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.alert-status {
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding: 0.2rem 0.4rem;
|
||||||
|
border-radius: var(--border-radius);
|
||||||
|
display: inline-flex;
|
||||||
|
|
||||||
|
&.status-ok {
|
||||||
|
background-color: #016101;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.status-alert_pending,
|
||||||
|
&.status-ok_pending {
|
||||||
|
background-color: #ff8c00;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.status-alerting {
|
||||||
|
background-color: #d22424;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
import { AlertInfo, AlertStatuses } from '@/api/alerts'
|
||||||
|
import { cn } from '@/utils/cn'
|
||||||
|
import { formatDateTime } from '@/utils/formatDateTime'
|
||||||
|
|
||||||
|
type Props = {
|
||||||
|
alert: Pick<AlertInfo, 'lastStatus' | 'lastStatusAt'>
|
||||||
|
}
|
||||||
|
|
||||||
|
const statusToStr = {
|
||||||
|
[AlertStatuses.OK]: 'OK',
|
||||||
|
[AlertStatuses.ALERT_PENDING]: 'Alert pending',
|
||||||
|
[AlertStatuses.ALERTING]: 'Alerting',
|
||||||
|
[AlertStatuses.OK_PENDING]: 'OK pending',
|
||||||
|
} as const
|
||||||
|
|
||||||
|
export const AlertStatus = ({ alert }: Props) => {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={cn('alert-status', `status-${alert.lastStatus}`)}
|
||||||
|
title={`Last update at ${formatDateTime(alert.lastStatusAt)}`}
|
||||||
|
>
|
||||||
|
{statusToStr[alert.lastStatus]}
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@ import { useState } from 'preact/hooks'
|
||||||
import { useMutation, useQuery } from 'react-query'
|
import { useMutation, useQuery } from 'react-query'
|
||||||
import { AlertFormModal } from './components/AlertFormModal'
|
import { AlertFormModal } from './components/AlertFormModal'
|
||||||
import { NoAlerts } from '../NoAlerts'
|
import { NoAlerts } from '../NoAlerts'
|
||||||
|
import { AlertStatus } from '../AlertStatus'
|
||||||
|
|
||||||
export const AlertsTable = () => {
|
export const AlertsTable = () => {
|
||||||
const alerts = useQuery('/alerts', getAlerts, {
|
const alerts = useQuery('/alerts', getAlerts, {
|
||||||
|
|
@ -43,8 +44,8 @@ export const AlertsTable = () => {
|
||||||
{
|
{
|
||||||
key: 'lastStatus',
|
key: 'lastStatus',
|
||||||
title: 'Last status',
|
title: 'Last status',
|
||||||
render: (c) => c.lastStatus,
|
render: (c) => <AlertStatus alert={c} />,
|
||||||
width: '10rem',
|
width: '6rem',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'actions',
|
key: 'actions',
|
||||||
|
|
|
||||||
|
|
@ -53,7 +53,10 @@ export const ContactPointsTable = () => {
|
||||||
className: 'actions',
|
className: 'actions',
|
||||||
render: (c) => (
|
render: (c) => (
|
||||||
<div>
|
<div>
|
||||||
<button onClick={() => setShowDelete(c)} className="remove">
|
<button
|
||||||
|
onClick={() => setShowDelete(c)}
|
||||||
|
className="danger-variant"
|
||||||
|
>
|
||||||
<TrashIcon /> Delete
|
<TrashIcon /> Delete
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => setEdited(c)}>
|
<button onClick={() => setEdited(c)}>
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import { SensorFormModal } from './components/SensorFormModal'
|
||||||
import { useConfirmModal } from '@/contexts/ConfirmModalsContext'
|
import { useConfirmModal } from '@/contexts/ConfirmModalsContext'
|
||||||
import { SensorDetailModal } from './components/SensorDetailModal'
|
import { SensorDetailModal } from './components/SensorDetailModal'
|
||||||
import { NoSensors } from './components/NoSensors'
|
import { NoSensors } from './components/NoSensors'
|
||||||
|
import { formatDateTime } from '@/utils/formatDateTime'
|
||||||
|
|
||||||
export const SensorsPage = () => {
|
export const SensorsPage = () => {
|
||||||
const sensors = useQuery(['/sensors'], getSensors)
|
const sensors = useQuery(['/sensors'], getSensors)
|
||||||
|
|
@ -43,6 +44,13 @@ export const SensorsPage = () => {
|
||||||
columns={[
|
columns={[
|
||||||
{ key: 'type', title: 'ID', render: (c) => c.id, width: '1rem' },
|
{ key: 'type', title: 'ID', render: (c) => c.id, width: '1rem' },
|
||||||
{ key: 'name', title: 'Name', render: (c) => c.name, scale: 1 },
|
{ key: 'name', title: 'Name', render: (c) => c.name, scale: 1 },
|
||||||
|
{
|
||||||
|
key: 'lastContact',
|
||||||
|
title: 'Last Contact At',
|
||||||
|
render: (c) =>
|
||||||
|
c.lastContactAt ? formatDateTime(c.lastContactAt) : 'Never',
|
||||||
|
width: '10rem',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'actions',
|
key: 'actions',
|
||||||
title: 'Actions',
|
title: 'Actions',
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,11 @@
|
||||||
|
export const formatDateTime = (unixInSeconds: number) => {
|
||||||
|
const date = new Date(unixInSeconds * 1000)
|
||||||
|
|
||||||
|
return date.toLocaleDateString(undefined, {
|
||||||
|
year: 'numeric',
|
||||||
|
month: 'short',
|
||||||
|
day: 'numeric',
|
||||||
|
hour: 'numeric',
|
||||||
|
minute: 'numeric',
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
ALTER TABLE sensors ADD COLUMN last_contact_at INTEGER;
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
package models
|
package models
|
||||||
|
|
||||||
type SensorItem struct {
|
type SensorItem struct {
|
||||||
Id int64 `json:"id"`
|
Id int64 `json:"id" db:"id"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name" db:"name"`
|
||||||
AuthKey string `json:"authKey"`
|
AuthKey string `json:"authKey" db:"auth_key"`
|
||||||
|
LastContactAt *int64 `json:"lastContactAt" db:"last_contact_at"`
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ type postAndPutAlertsBody struct {
|
||||||
Name string `json:"name" binding:"required"`
|
Name string `json:"name" binding:"required"`
|
||||||
Condition string `json:"condition" binding:"required"`
|
Condition string `json:"condition" binding:"required"`
|
||||||
TriggerInterval int64 `json:"triggerInterval" binding:"required"`
|
TriggerInterval int64 `json:"triggerInterval" binding:"required"`
|
||||||
CustomMessage string `json:"customMessage" binding:"required"`
|
CustomMessage string `json:"customMessage"`
|
||||||
CustomResolvedMessage string `json:"customResolvedMessage" binding:"required"`
|
CustomResolvedMessage string `json:"customResolvedMessage"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetAlerts(s *app.Server) gin.HandlerFunc {
|
func GetAlerts(s *app.Server) gin.HandlerFunc {
|
||||||
|
|
@ -32,7 +32,9 @@ func GetAlerts(s *app.Server) gin.HandlerFunc {
|
||||||
func PostAlerts(s *app.Server) gin.HandlerFunc {
|
func PostAlerts(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
body := postAndPutAlertsBody{}
|
body := postAndPutAlertsBody{}
|
||||||
bindJSONBodyOrAbort(c, &body)
|
if err := bindJSONBodyOrAbort(c, &body); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
alert, err := s.Services.Alerts.Create(body.ContactPointId, body.Name, body.Condition, body.TriggerInterval, body.CustomMessage, body.CustomResolvedMessage)
|
alert, err := s.Services.Alerts.Create(body.ContactPointId, body.Name, body.Condition, body.TriggerInterval, body.CustomMessage, body.CustomResolvedMessage)
|
||||||
|
|
||||||
|
|
@ -47,10 +49,15 @@ func PostAlerts(s *app.Server) gin.HandlerFunc {
|
||||||
|
|
||||||
func PutAlert(s *app.Server) gin.HandlerFunc {
|
func PutAlert(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
alertId := getIntParamOrAbort(c, "alertId")
|
alertId, err := getIntParamOrAbort(c, "alertId")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
body := postAndPutAlertsBody{}
|
body := postAndPutAlertsBody{}
|
||||||
bindJSONBodyOrAbort(c, &body)
|
if err := bindJSONBodyOrAbort(c, &body); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
alert, err := s.Services.Alerts.Update(alertId, body.ContactPointId, body.Name, body.Condition, body.TriggerInterval, body.CustomMessage, body.CustomResolvedMessage)
|
alert, err := s.Services.Alerts.Update(alertId, body.ContactPointId, body.Name, body.Condition, body.TriggerInterval, body.CustomMessage, body.CustomResolvedMessage)
|
||||||
|
|
||||||
|
|
@ -65,7 +72,10 @@ func PutAlert(s *app.Server) gin.HandlerFunc {
|
||||||
|
|
||||||
func GetAlert(s *app.Server) gin.HandlerFunc {
|
func GetAlert(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
alertId := getIntParamOrAbort(c, "alertId")
|
alertId, err := getIntParamOrAbort(c, "alertId")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
alert, err := s.Services.Alerts.GetById(alertId)
|
alert, err := s.Services.Alerts.GetById(alertId)
|
||||||
|
|
||||||
|
|
@ -80,7 +90,10 @@ func GetAlert(s *app.Server) gin.HandlerFunc {
|
||||||
|
|
||||||
func DeleteAlert(s *app.Server) gin.HandlerFunc {
|
func DeleteAlert(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
alertId := getIntParamOrAbort(c, "alertId")
|
alertId, err := getIntParamOrAbort(c, "alertId")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err := s.Services.Alerts.DeleteById(alertId); err != nil {
|
if err := s.Services.Alerts.DeleteById(alertId); err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,9 @@ type postLoginBody struct {
|
||||||
func Login(s *app.Server) gin.HandlerFunc {
|
func Login(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
body := postLoginBody{}
|
body := postLoginBody{}
|
||||||
bindJSONBodyOrAbort(c, &body)
|
if err := bindJSONBodyOrAbort(c, &body); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if body.Password != s.Config.AuthPassword || body.Username != s.Config.AuthUsername {
|
if body.Password != s.Config.AuthPassword || body.Username != s.Config.AuthUsername {
|
||||||
c.AbortWithStatus(401)
|
c.AbortWithStatus(401)
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,10 @@ func GetContactPoints(s *app.Server) gin.HandlerFunc {
|
||||||
func PostContactPoints(s *app.Server) gin.HandlerFunc {
|
func PostContactPoints(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
body := postOrPutContactPointsBody{}
|
body := postOrPutContactPointsBody{}
|
||||||
bindJSONBodyOrAbort(c, &body)
|
|
||||||
|
|
||||||
|
if err := bindJSONBodyOrAbort(c, &body); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
contactPoint, err := s.Services.ContactPoints.Create(body.Name, body.Type, body.TypeConfig)
|
contactPoint, err := s.Services.ContactPoints.Create(body.Name, body.Type, body.TypeConfig)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -49,10 +51,15 @@ func PostContactPoints(s *app.Server) gin.HandlerFunc {
|
||||||
|
|
||||||
func PutContactPoint(s *app.Server) gin.HandlerFunc {
|
func PutContactPoint(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
contactPointId := getIntParamOrAbort(c, "contactPointId")
|
contactPointId, err := getIntParamOrAbort(c, "contactPointId")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
body := postOrPutContactPointsBody{}
|
body := postOrPutContactPointsBody{}
|
||||||
bindJSONBodyOrAbort(c, &body)
|
if err := bindJSONBodyOrAbort(c, &body); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
contactPoint, err := s.Services.ContactPoints.Update(contactPointId, body.Name, body.Type, body.TypeConfig)
|
contactPoint, err := s.Services.ContactPoints.Update(contactPointId, body.Name, body.Type, body.TypeConfig)
|
||||||
|
|
||||||
|
|
@ -67,7 +74,10 @@ func PutContactPoint(s *app.Server) gin.HandlerFunc {
|
||||||
|
|
||||||
func GetContactPoint(s *app.Server) gin.HandlerFunc {
|
func GetContactPoint(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
contactPointId := getIntParamOrAbort(c, "contactPointId")
|
contactPointId, err := getIntParamOrAbort(c, "contactPointId")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
contactPoint, err := s.Services.ContactPoints.GetById(contactPointId)
|
contactPoint, err := s.Services.ContactPoints.GetById(contactPointId)
|
||||||
|
|
||||||
|
|
@ -82,9 +92,12 @@ func GetContactPoint(s *app.Server) gin.HandlerFunc {
|
||||||
|
|
||||||
func DeleteContactPoint(s *app.Server) gin.HandlerFunc {
|
func DeleteContactPoint(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
contactPointId := getIntParamOrAbort(c, "contactPointId")
|
contactPointId, err := getIntParamOrAbort(c, "contactPointId")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err := s.Services.ContactPoints.Delete(contactPointId)
|
err = s.Services.ContactPoints.Delete(contactPointId)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
|
@ -98,7 +111,9 @@ func DeleteContactPoint(s *app.Server) gin.HandlerFunc {
|
||||||
func TestContactPoint(s *app.Server) gin.HandlerFunc {
|
func TestContactPoint(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
body := testContactPointBody{}
|
body := testContactPointBody{}
|
||||||
bindJSONBodyOrAbort(c, &body)
|
if err := bindJSONBodyOrAbort(c, &body); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err := s.Services.ContactPoints.Test(body.Type, body.TypeConfig)
|
err := s.Services.ContactPoints.Test(body.Type, body.TypeConfig)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,10 @@ func GetDashboards(s *app.Server) gin.HandlerFunc {
|
||||||
|
|
||||||
func GetDashboardById(s *app.Server) gin.HandlerFunc {
|
func GetDashboardById(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
id := getIntParamOrAbort(c, "id")
|
id, err := getIntParamOrAbort(c, "id")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
item, err := s.Services.Dashboards.GetById(id)
|
item, err := s.Services.Dashboards.GetById(id)
|
||||||
|
|
||||||
|
|
@ -54,7 +57,10 @@ func GetDashboardById(s *app.Server) gin.HandlerFunc {
|
||||||
func PostDashboard(s *app.Server) gin.HandlerFunc {
|
func PostDashboard(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
body := postDashboardBody{}
|
body := postDashboardBody{}
|
||||||
bindJSONBodyOrAbort(c, &body)
|
|
||||||
|
if err := bindJSONBodyOrAbort(c, &body); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
item, err := s.Services.Dashboards.Create(body.Name, body.Contents)
|
item, err := s.Services.Dashboards.Create(body.Name, body.Contents)
|
||||||
|
|
||||||
|
|
@ -69,11 +75,16 @@ func PostDashboard(s *app.Server) gin.HandlerFunc {
|
||||||
|
|
||||||
func PutDashboard(s *app.Server) gin.HandlerFunc {
|
func PutDashboard(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
id := getIntParamOrAbort(c, "id")
|
id, err := getIntParamOrAbort(c, "id")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
body := putDashboardBody{}
|
body := putDashboardBody{}
|
||||||
bindJSONBodyOrAbort(c, &body)
|
|
||||||
|
|
||||||
|
if err := bindJSONBodyOrAbort(c, &body); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
item, err := s.Services.Dashboards.Update(id, body.Name, body.Contents)
|
item, err := s.Services.Dashboards.Update(id, body.Name, body.Contents)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -87,9 +98,12 @@ func PutDashboard(s *app.Server) gin.HandlerFunc {
|
||||||
|
|
||||||
func DeleteDashboard(s *app.Server) gin.HandlerFunc {
|
func DeleteDashboard(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
id := getIntParamOrAbort(c, "id")
|
id, err := getIntParamOrAbort(c, "id")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err := s.Services.Dashboards.Delete(id)
|
err = s.Services.Dashboards.Delete(id)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(500, err)
|
c.AbortWithError(500, err)
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,9 @@ func PutSensorConfig(s *app.Server) gin.HandlerFunc {
|
||||||
sensor := c.Param("sensor")
|
sensor := c.Param("sensor")
|
||||||
key := c.Param("key")
|
key := c.Param("key")
|
||||||
|
|
||||||
bindJSONBodyOrAbort(c, &configValue)
|
if err := bindJSONBodyOrAbort(c, &configValue); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err := s.Services.SensorConfig.SetValue(sensor, key, configValue.Value); err != nil {
|
if err := s.Services.SensorConfig.SetValue(sensor, key, configValue.Value); err != nil {
|
||||||
c.AbortWithError(500, err)
|
c.AbortWithError(500, err)
|
||||||
|
|
|
||||||
|
|
@ -25,9 +25,14 @@ func PostSensorValues(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
var newValue postSensorValueBody
|
var newValue postSensorValueBody
|
||||||
|
|
||||||
bindJSONBodyOrAbort(c, &newValue)
|
if err := bindJSONBodyOrAbort(c, &newValue); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
sensorId := getIntParamOrAbort(c, "sensor")
|
sensorId, err := getIntParamOrAbort(c, "sensor")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if _, err := s.Services.SensorValues.Push(sensorId, newValue.Value); err != nil {
|
if _, err := s.Services.SensorValues.Push(sensorId, newValue.Value); err != nil {
|
||||||
c.AbortWithError(400, err)
|
c.AbortWithError(400, err)
|
||||||
|
|
@ -42,7 +47,10 @@ func GetSensorValues(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
var query getSensorValuesQuery
|
var query getSensorValuesQuery
|
||||||
|
|
||||||
sensorId := getIntParamOrAbort(c, "sensor")
|
sensorId, err := getIntParamOrAbort(c, "sensor")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err := c.ShouldBindQuery(&query); err != nil {
|
if err := c.ShouldBindQuery(&query); err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
|
@ -63,7 +71,10 @@ func GetSensorLatestValue(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
var query getLatestSensorValueQuery
|
var query getLatestSensorValueQuery
|
||||||
|
|
||||||
sensorId := getIntParamOrAbort(c, "sensor")
|
sensorId, err := getIntParamOrAbort(c, "sensor")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if err := c.ShouldBindQuery(&query); err != nil {
|
if err := c.ShouldBindQuery(&query); err != nil {
|
||||||
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,9 @@ func GetSensors(s *app.Server) gin.HandlerFunc {
|
||||||
func PostSensors(s *app.Server) gin.HandlerFunc {
|
func PostSensors(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
body := postOrPutSensorsBody{}
|
body := postOrPutSensorsBody{}
|
||||||
bindJSONBodyOrAbort(c, &body)
|
if err := bindJSONBodyOrAbort(c, &body); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
sensor, err := s.Services.Sensors.Create(body.Name)
|
sensor, err := s.Services.Sensors.Create(body.Name)
|
||||||
|
|
||||||
|
|
@ -44,10 +46,15 @@ func PostSensors(s *app.Server) gin.HandlerFunc {
|
||||||
|
|
||||||
func PutSensor(s *app.Server) gin.HandlerFunc {
|
func PutSensor(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
sensorId := getIntParamOrAbort(c, "sensor")
|
sensorId, err := getIntParamOrAbort(c, "sensor")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
body := postOrPutSensorsBody{}
|
body := postOrPutSensorsBody{}
|
||||||
bindJSONBodyOrAbort(c, &body)
|
if err := bindJSONBodyOrAbort(c, &body); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
sensor, err := s.Services.Sensors.Update(sensorId, body.Name)
|
sensor, err := s.Services.Sensors.Update(sensorId, body.Name)
|
||||||
|
|
||||||
|
|
@ -62,10 +69,15 @@ func PutSensor(s *app.Server) gin.HandlerFunc {
|
||||||
|
|
||||||
func GetSensor(s *app.Server) gin.HandlerFunc {
|
func GetSensor(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
sensorId := getIntParamOrAbort(c, "sensor")
|
sensorId, err := getIntParamOrAbort(c, "sensor")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
body := postOrPutSensorsBody{}
|
body := postOrPutSensorsBody{}
|
||||||
bindJSONBodyOrAbort(c, &body)
|
if err := bindJSONBodyOrAbort(c, &body); err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
sensor, err := s.Services.Sensors.GetById(sensorId)
|
sensor, err := s.Services.Sensors.GetById(sensorId)
|
||||||
|
|
||||||
|
|
@ -80,9 +92,12 @@ func GetSensor(s *app.Server) gin.HandlerFunc {
|
||||||
|
|
||||||
func DeleteSensor(s *app.Server) gin.HandlerFunc {
|
func DeleteSensor(s *app.Server) gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
sensorId := getIntParamOrAbort(c, "sensor")
|
sensorId, err := getIntParamOrAbort(c, "sensor")
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
err := s.Services.Sensors.DeleteById(sensorId)
|
err = s.Services.Sensors.DeleteById(sensorId)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithError(http.StatusInternalServerError, err)
|
c.AbortWithError(http.StatusInternalServerError, err)
|
||||||
|
|
|
||||||
|
|
@ -6,19 +6,24 @@ import (
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getIntParamOrAbort(c *gin.Context, key string) int64 {
|
func getIntParamOrAbort(c *gin.Context, key string) (int64, error) {
|
||||||
value := c.Param(key)
|
value := c.Param(key)
|
||||||
val, err := strconv.ParseInt(value, 10, 64)
|
val, err := strconv.ParseInt(value, 10, 64)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.AbortWithStatusJSON(400, gin.H{"error": "Invalid " + key})
|
c.AbortWithStatusJSON(400, gin.H{"error": "Invalid " + key})
|
||||||
|
|
||||||
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return val
|
return val, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func bindJSONBodyOrAbort(c *gin.Context, body interface{}) {
|
func bindJSONBodyOrAbort(c *gin.Context, body interface{}) error {
|
||||||
if err := c.ShouldBindJSON(body); err != nil {
|
if err := c.ShouldBindJSON(body); err != nil {
|
||||||
c.AbortWithStatusJSON(400, gin.H{"error": err.Error()})
|
c.AbortWithStatusJSON(400, gin.H{"error": err.Error()})
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,13 @@ func (s *SensorValuesService) Push(sensorId int64, value float64) (int64, error)
|
||||||
res, err := s.ctx.DB.Exec("INSERT INTO sensor_values (timestamp, sensor_id, value) VALUES (?, ?, ?)", time.Now().Unix(), sensorId, value)
|
res, err := s.ctx.DB.Exec("INSERT INTO sensor_values (timestamp, sensor_id, value) VALUES (?, ?, ?)", time.Now().Unix(), sensorId, value)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, fmt.Errorf("failed to insert sensor value: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = s.ctx.DB.Exec("UPDATE sensors SET last_contact_at = ? WHERE id = ?", time.Now().Unix(), sensorId)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return 0, fmt.Errorf("failed to update last_contact_at: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return res.LastInsertId()
|
return res.LastInsertId()
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ package services
|
||||||
import (
|
import (
|
||||||
"basic-sensor-receiver/models"
|
"basic-sensor-receiver/models"
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"database/sql"
|
|
||||||
"math/big"
|
"math/big"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -12,32 +11,10 @@ type SensorsService struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *SensorsService) GetList() ([]models.SensorItem, error) {
|
func (s *SensorsService) GetList() ([]models.SensorItem, error) {
|
||||||
sensors := make([]models.SensorItem, 0)
|
sensors := []models.SensorItem{}
|
||||||
|
|
||||||
rows, err := s.ctx.DB.Query("SELECT id, name, auth_key FROM sensors")
|
err := s.ctx.DB.Select(&sensors, "SELECT id, name, auth_key, last_contact_at FROM sensors")
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
if err == sql.ErrNoRows {
|
|
||||||
return sensors, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer rows.Close()
|
|
||||||
|
|
||||||
for rows.Next() {
|
|
||||||
item := models.SensorItem{}
|
|
||||||
|
|
||||||
err := rows.Scan(&item.Id, &item.Name, &item.AuthKey)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
sensors = append(sensors, item)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = rows.Err()
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
@ -75,9 +52,8 @@ func (s *SensorsService) Create(name string) (*models.SensorItem, error) {
|
||||||
func (s *SensorsService) GetById(id int64) (*models.SensorItem, error) {
|
func (s *SensorsService) GetById(id int64) (*models.SensorItem, error) {
|
||||||
item := models.SensorItem{}
|
item := models.SensorItem{}
|
||||||
|
|
||||||
row := s.ctx.DB.QueryRow("SELECT id, name, auth_key FROM sensors WHERE id = ?", id)
|
err := s.ctx.DB.Get(&item, "SELECT id, name, auth_key, last_contact_at FROM sensors WHERE id = $1", id)
|
||||||
|
|
||||||
err := row.Scan(&item.Id, &item.Name, &item.AuthKey)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue