feat(iot): PATCH обновляет metadata (Terraform)
iotDeviceUpdateRequest получил поле metadata; UpdateIoTDevice обновляет переданные поля (enabled и/или metadata). Добавлен store.UpdateMetadata. Хотя бы одно поле обязательно. Раньше metadata нельзя было изменить (только enabled).
This commit is contained in:
@@ -29,9 +29,11 @@ type iotDeviceCreateRequest struct {
|
||||
Metadata map[string]string `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// iotDeviceUpdateRequest — тело PATCH.
|
||||
// iotDeviceUpdateRequest — тело PATCH. Хотя бы одно поле обязательно:
|
||||
// enabled и/или metadata (metadata раньше нельзя было обновить — ревью 2026-10-10).
|
||||
type iotDeviceUpdateRequest struct {
|
||||
Enabled *bool `json:"enabled"`
|
||||
Enabled *bool `json:"enabled,omitempty"`
|
||||
Metadata map[string]string `json:"metadata,omitempty"`
|
||||
}
|
||||
|
||||
// iotDeviceResponse — ответ API. MQTTPassword заполняется ТОЛЬКО при создании
|
||||
@@ -314,20 +316,33 @@ func (h *Handler) UpdateIoTDevice(w http.ResponseWriter, r *http.Request) {
|
||||
writeJSON(w, http.StatusBadRequest, errResp("invalid JSON: "+err.Error()))
|
||||
return
|
||||
}
|
||||
if req.Enabled == nil {
|
||||
writeJSON(w, http.StatusBadRequest, errResp("enabled field is required"))
|
||||
if req.Enabled == nil && req.Metadata == nil {
|
||||
writeJSON(w, http.StatusBadRequest, errResp("enabled или metadata обязательны"))
|
||||
return
|
||||
}
|
||||
|
||||
err := h.Devices.UpdateEnabled(r.Context(), ns, name, *req.Enabled)
|
||||
if err != nil {
|
||||
if errors.Is(err, store.ErrNotFound) {
|
||||
writeJSON(w, http.StatusNotFound, errResp("iot device not found"))
|
||||
// Обновляем только переданные поля (enabled и/или metadata).
|
||||
if req.Enabled != nil {
|
||||
if err := h.Devices.UpdateEnabled(r.Context(), ns, name, *req.Enabled); err != nil {
|
||||
if errors.Is(err, store.ErrNotFound) {
|
||||
writeJSON(w, http.StatusNotFound, errResp("iot device not found"))
|
||||
return
|
||||
}
|
||||
h.Log.Error("update device enabled", "namespace", ns, "name", name, "err", err)
|
||||
writeJSON(w, http.StatusInternalServerError, errResp("failed to update device"))
|
||||
return
|
||||
}
|
||||
}
|
||||
if req.Metadata != nil {
|
||||
if err := h.Devices.UpdateMetadata(r.Context(), ns, name, req.Metadata); err != nil {
|
||||
if errors.Is(err, store.ErrNotFound) {
|
||||
writeJSON(w, http.StatusNotFound, errResp("iot device not found"))
|
||||
return
|
||||
}
|
||||
h.Log.Error("update device metadata", "namespace", ns, "name", name, "err", err)
|
||||
writeJSON(w, http.StatusInternalServerError, errResp("failed to update device"))
|
||||
return
|
||||
}
|
||||
h.Log.Error("update device", "namespace", ns, "name", name, "err", err)
|
||||
writeJSON(w, http.StatusInternalServerError, errResp("failed to update device"))
|
||||
return
|
||||
}
|
||||
|
||||
device, err := h.Devices.GetByName(r.Context(), ns, name)
|
||||
|
||||
@@ -97,6 +97,24 @@ func (s *DeviceStore) UpdateEnabled(ctx context.Context, namespace, name string,
|
||||
return nil
|
||||
}
|
||||
|
||||
// UpdateMetadata обновляет metadata устройства.
|
||||
func (s *DeviceStore) UpdateMetadata(ctx context.Context, namespace, name string, metadata map[string]string) error {
|
||||
b, err := json.Marshal(metadata)
|
||||
if err != nil {
|
||||
return fmt.Errorf("store: marshal metadata: %w", err)
|
||||
}
|
||||
res, err := s.db.ExecContext(ctx,
|
||||
`UPDATE iot_devices SET metadata = $3 WHERE namespace = $1 AND name = $2`,
|
||||
namespace, name, b)
|
||||
if err != nil {
|
||||
return fmt.Errorf("store: update metadata: %w", err)
|
||||
}
|
||||
if n, _ := res.RowsAffected(); n == 0 {
|
||||
return ErrNotFound
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete удаляет устройство.
|
||||
func (s *DeviceStore) Delete(ctx context.Context, namespace, name string) error {
|
||||
res, err := s.db.ExecContext(ctx,
|
||||
|
||||
Reference in New Issue
Block a user