Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
55 changes: 53 additions & 2 deletions api/internal/handler/collection_groups.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package handler

import (
"net/http"
"strconv"
"time"

"github.com/USACE/instrumentation-api/api/internal/httperr"
Expand Down Expand Up @@ -141,7 +142,7 @@ func (h *ApiHandler) UpdateCollectionGroup(c echo.Context) error {
if err != nil {
return httperr.InternalServerError(err)
}
return c.JSON(http.StatusCreated, cgUpdated)
return c.JSON(http.StatusOK, cgUpdated)
}

// DeleteCollectionGroup godoc
Expand Down Expand Up @@ -197,7 +198,57 @@ func (h *ApiHandler) AddTimeseriesToCollectionGroup(c echo.Context) error {
if err != nil {
return httperr.MalformedID(err)
}
if err := h.CollectionGroupService.AddTimeseriesToCollectionGroup(c.Request().Context(), cgID, tsID); err != nil {
var sortOrder int
soParam := c.QueryParam("sort_order")
if soParam != "" {
so64, err := strconv.ParseInt(soParam, 10, 0)
if err != nil {
return httperr.BadRequest(err)
}
sortOrder = int(so64)
}

if err := h.CollectionGroupService.AddTimeseriesToCollectionGroup(c.Request().Context(), cgID, tsID, sortOrder); err != nil {
return httperr.InternalServerError(err)
}
return c.JSON(http.StatusCreated, make(map[string]interface{}))
}

// UpdateTimeseriesCollectionGroupSortOrder godoc
//
// @Summary updates sort order for collection group timesries
// @Tags collection-groups
// @Produce json
// @Param project_id path string true "project uuid" Format(uuid)
// @Param collection_group_id path string true "collection group uuid" Format(uuid)
// @Param timeseries_id path string true "timeseries uuid" Format(uuid)
// @Param key query string false "api key"
// @Success 200 {object} map[string]interface{}
// @Failure 400 {object} echo.HTTPError
// @Failure 404 {object} echo.HTTPError
// @Failure 500 {object} echo.HTTPError
// @Router /projects/{project_id}/collection_groups/{collection_group_id}/timeseries/{timeseries_id} [put]
// @Security Bearer
func (h *ApiHandler) UpdateTimeseriesCollectionGroupSortOrder(c echo.Context) error {
cgID, err := uuid.Parse(c.Param("collection_group_id"))
if err != nil {
return httperr.MalformedID(err)
}
tsID, err := uuid.Parse(c.Param("timeseries_id"))
if err != nil {
return httperr.MalformedID(err)
}
var sortOrder int
soParam := c.QueryParam("sort_order")
if soParam != "" {
so64, err := strconv.ParseInt(soParam, 10, 0)
if err != nil {
return httperr.BadRequest(err)
}
sortOrder = int(so64)
}

if err := h.CollectionGroupService.UpdateTimeseriesCollectionGroupSortOrder(c.Request().Context(), cgID, tsID, sortOrder); err != nil {
return httperr.InternalServerError(err)
}
return c.JSON(http.StatusOK, make(map[string]interface{}))
Expand Down
48 changes: 42 additions & 6 deletions api/internal/handler/collection_groups_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,15 @@ const collectionGroupSchema = `{
"creator_id": { "type": "string" },
"create_date": { "type": "string", "format": "date-time" },
"updater_id": { "type": ["string", "null"] },
"update_date": { "type": ["string", "null"], "format": "date-time" }
"update_date": { "type": ["string", "null"], "format": "date-time" },
"sort_order": { "type": "integer" }
},
"required": ["id", "project_id", "name", "slug", "creator_id", "create_date", "updater_id", "update_date"],
"required": ["id", "project_id", "name", "slug", "creator_id", "create_date", "updater_id", "update_date", "sort_order"],
"additionalProperties": false
}`

var collectionGroupObjectLoader = gojsonschema.NewStringLoader(collectionGroupSchema)

var collectionGroupArrayLoader = gojsonschema.NewStringLoader(fmt.Sprintf(`{
"type": "array",
"items": %s
Expand All @@ -41,6 +44,7 @@ const collectionGroupDetailsSchema = `{
"create_date": { "type": "string", "format": "date-time" },
"updater_id": { "type": ["string", "null"] },
"update_date": { "type": ["string", "null"], "format": "date-time" },
"sort_order": { "type": "integer" },
"timeseries": {
"type": "array",
"items": {
Expand All @@ -60,27 +64,43 @@ const collectionGroupDetailsSchema = `{
"latest_time": {"type": "string", "format": "date-time" },
"latest_value": {"type": "number" },
"is_computed": { "type": "boolean" },
"sort_order": { "type": "integer" },
"type": { "type": "string" }
},
"required": ["id", "slug", "name", "variable", "instrument_id", "instrument", "instrument_slug", "parameter_id", "parameter", "unit_id", "unit", "latest_time", "latest_value", "is_computed", "type"],
"required": ["id", "slug", "name", "variable", "instrument_id", "instrument", "instrument_slug", "parameter_id", "parameter", "unit_id", "unit", "latest_time", "latest_value", "is_computed", "type", "sort_order"],
"additionalProperties": false
}
}
},
"required": ["id", "project_id", "name", "slug", "creator_id", "create_date", "updater_id", "update_date", "timeseries"],
"required": ["id", "project_id", "name", "slug", "creator_id", "create_date", "updater_id", "update_date", "timeseries", "sort_order"],
"additionalProperties": false
}`

var collectionGroupDetailsObjectLoader = gojsonschema.NewStringLoader(collectionGroupDetailsSchema)

const testCollectionGroupID = "30b32cb1-0936-42c4-95d1-63a7832a57db"

var createCollectionGroupBody = `{
"name": "test new collection group",
"sort_order": 2
}`

const updateCollectionGroupBody = `{
"name": "test update collection group",
"sort_order": 3
}`

func TestCollectionGroups(t *testing.T) {
objSchema, err := gojsonschema.NewSchema(collectionGroupDetailsObjectLoader)
objSchema, err := gojsonschema.NewSchema(collectionGroupObjectLoader)
assert.Nil(t, err)
if err != nil {
t.Log("invalid object schema")
}
detailsObjSchema, err := gojsonschema.NewSchema(collectionGroupDetailsObjectLoader)
assert.Nil(t, err)
if err != nil {
t.Log("invalid details object schema")
}
arrSchema, err := gojsonschema.NewSchema(collectionGroupArrayLoader)
assert.Nil(t, err)
if err != nil {
Expand All @@ -93,7 +113,7 @@ func TestCollectionGroups(t *testing.T) {
URL: fmt.Sprintf("/projects/%s/collection_groups/%s", testProjectID, testCollectionGroupID),
Method: http.MethodGet,
ExpectedStatus: http.StatusOK,
ExpectedSchema: objSchema,
ExpectedSchema: detailsObjSchema,
},
{
Name: "ListCollectionGroups",
Expand All @@ -102,6 +122,22 @@ func TestCollectionGroups(t *testing.T) {
ExpectedStatus: http.StatusOK,
ExpectedSchema: arrSchema,
},
{
Name: "CreateCollectionGroup",
URL: fmt.Sprintf("/projects/%s/collection_groups", testProjectID),
Method: http.MethodPost,
ExpectedStatus: http.StatusCreated,
ExpectedSchema: arrSchema,
Body: createCollectionGroupBody,
},
{
Name: "UpdateCollectionGroup",
URL: fmt.Sprintf("/projects/%s/collection_groups/%s", testProjectID, testCollectionGroupID),
Method: http.MethodPut,
ExpectedStatus: http.StatusOK,
ExpectedSchema: objSchema,
Body: updateCollectionGroupBody,
},
{
Name: "DeleteCollectionGroup",
URL: fmt.Sprintf("/projects/%s/collection_groups/%s", testProjectID, testCollectionGroupID),
Expand Down
18 changes: 18 additions & 0 deletions api/internal/handler/domain.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,21 @@ func (h *ApiHandler) GetDomainMap(c echo.Context) error {
}
return c.JSON(http.StatusOK, dm)
}

// ListTimezoneOptions godoc
//
// @Summary lists time zone options
// @Tags domain
// @Produce json
// @Success 200 {array} model.TimezoneOption
// @Failure 400 {object} echo.HTTPError
// @Failure 404 {object} echo.HTTPError
// @Failure 500 {object} echo.HTTPError
// @Router /domains [get]
func (h *ApiHandler) ListTimezoneOptions(c echo.Context) error {
dd, err := h.DomainService.ListTimezoneOptions(c.Request().Context())
if err != nil {
return httperr.InternalServerError(err)
}
return c.JSON(http.StatusOK, dd)
}
4 changes: 4 additions & 0 deletions api/internal/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ type ApiHandler struct {
AwareParameterService service.AwareParameterService
CollectionGroupService service.CollectionGroupService
DataloggerService service.DataloggerService
DataloggerTelemetryService service.DataloggerTelemetryService
DistrictRollupService service.DistrictRollupService
DomainService service.DomainService
EquivalencyTableService service.EquivalencyTableService
Expand Down Expand Up @@ -58,6 +59,7 @@ type ApiHandler struct {
CalculatedTimeseriesService service.CalculatedTimeseriesService
ProcessTimeseriesService service.ProcessTimeseriesService
UnitService service.UnitService
UploaderService service.UploaderService
}

func NewApi(cfg *config.ApiConfig) *ApiHandler {
Expand All @@ -80,6 +82,7 @@ func NewApi(cfg *config.ApiConfig) *ApiHandler {
AwareParameterService: service.NewAwareParameterService(db, q),
CollectionGroupService: service.NewCollectionGroupService(db, q),
DataloggerService: service.NewDataloggerService(db, q),
DataloggerTelemetryService: dataloggerTelemetryService,
DistrictRollupService: service.NewDistrictRollupService(db, q),
DomainService: service.NewDomainService(db, q),
EquivalencyTableService: service.NewEquivalencyTableService(db, q),
Expand Down Expand Up @@ -108,6 +111,7 @@ func NewApi(cfg *config.ApiConfig) *ApiHandler {
CalculatedTimeseriesService: service.NewCalculatedTimeseriesService(db, q),
ProcessTimeseriesService: service.NewProcessTimeseriesService(db, q),
UnitService: service.NewUnitService(db, q),
UploaderService: service.NewUploaderService(db, q),
}
}

Expand Down
53 changes: 53 additions & 0 deletions api/internal/handler/measurement.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package handler

import (
"log"
"net/http"
"strings"
"time"

"github.com/USACE/instrumentation-api/api/internal/httperr"
Expand Down Expand Up @@ -139,3 +141,54 @@ func (h *ApiHandler) DeleteTimeserieMeasurements(c echo.Context) error {
}
return c.JSON(http.StatusOK, make(map[string]interface{}))
}

// CreateOrUpdateTimeseriesMeasurements godoc
//
// @Summary creates one or more timeseries measurements
// @Tags measurement
// @Accept json,mpfd
// @Produce json
// @Param timeseries_measurement_collections body model.TimeseriesMeasurementCollectionCollection false "json array of timeseries measurement collections"
// @Param timeseries_measurement_collections formData file false "TOA5 file of timeseries measurement collections"
// @Success 200 {array} model.MeasurementCollection
// @Failure 400 {object} echo.HTTPError
// @Failure 404 {object} echo.HTTPError
// @Failure 500 {object} echo.HTTPError
// @Router /timeseries_measurements [post]
// @Security Bearer
func (h *ApiHandler) _CreateOrUpdateTimeseriesMeasurements(c echo.Context) error {
contentType := "application/json"
contentTypeHeader, ok := c.Request().Header["Content-Type"]
if ok && len(contentTypeHeader) > 0 {
contentType = strings.ToLower(contentTypeHeader[0])
}

if strings.Contains(contentType, "multipart/form-data") {
return h.createOrUpdateTimeseriesMeasurementsMultipartFormData(c)
}

return h.CreateOrUpdateTimeseriesMeasurements(c)
}

func (h *ApiHandler) createOrUpdateTimeseriesMeasurementsMultipartFormData(c echo.Context) error {
file, err := c.FormFile("file")
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}

src, err := file.Open()
if err != nil {
return echo.NewHTTPError(http.StatusBadRequest, err.Error())
}
defer func() {
if err := src.Close(); err != nil {
log.Printf("error closing file: %s", err.Error())
}
}()

if err := h.DataloggerTelemetryService.CreateOrUpdateDataloggerTOA5MeasurementCollection(c.Request().Context(), src); err != nil {
return echo.NewHTTPError(http.StatusInternalServerError, err.Error())
}

return c.JSON(http.StatusCreated, map[string]interface{}{})
}
Loading