Skip to content

Commit

Permalink
Add impact functionality (#504)
Browse files Browse the repository at this point in the history
* feat(api,app) add impact functionality

* fix(app) test

* feat(api) update swagger doc
  • Loading branch information
helderbetiol committed Aug 12, 2024
1 parent b2d7215 commit 7e40fcc
Show file tree
Hide file tree
Showing 32 changed files with 2,221 additions and 240 deletions.
86 changes: 86 additions & 0 deletions API/controllers/impact.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package controllers

import (
"fmt"
"net/http"
"p3/models"
u "p3/utils"

"github.com/gorilla/mux"
)

func getImpactFiltersFromQueryParams(r *http.Request) models.ImpactFilters {
var filters models.ImpactFilters
fmt.Println(r.URL.Query())
decoder.Decode(&filters, r.URL.Query())
fmt.Println(filters)
return filters
}

// swagger:operation GET /api/impact/{id} Objects GetImpact
// Returns all objects that could directly or indirectly impacted
// by the object sent in the request.
// ---
// security:
// - bearer: []
// produces:
// - application/json
// parameters:
// - name: id
// in: path
// description: 'ID of target object.'
// required: true
// type: string
// default: "siteA"
// - name: categories
// in: query
// description: 'Categories to include on indirect impact search.
// Can be repeated to create a list.'
// - name: ptypes
// in: query
// description: 'Physical types to include on indirect impact search.
// Can be repeated to create a list.'
// - name: vtypes
// in: query
// description: 'Virtual types to include on indirect impact search.
// Can be repeated to create a list.'
// responses:
// '200':
// description: 'Request is valid.'
// '500':
// description: Server error.

func GetImpact(w http.ResponseWriter, r *http.Request) {
fmt.Println("******************************************************")
fmt.Println("FUNCTION CALL: GetImpact ")
fmt.Println("******************************************************")
DispRequestMetaData(r)

// Get user roles for permissions
user := getUserFromToken(w, r)
if user == nil {
return
}

filters := getImpactFiltersFromQueryParams(r)

// Get id of impact target
id, canParse := mux.Vars(r)["id"]
if !canParse {
w.WriteHeader(http.StatusBadRequest)
u.Respond(w, u.Message("Error while parsing path parameters"))
u.ErrLog("Error while parsing path parameters", "GET ENTITY", "", r)
return
}

data, err := models.GetImpact(id, user.Roles, filters)
if err != nil {
u.RespondWithError(w, err)
} else {
if r.Method == "OPTIONS" {
u.WriteOptionsHeader(w, "GET, HEAD")
} else {
u.Respond(w, u.RespDataWrapper("successfully got hierarchy", data))
}
}
}
161 changes: 160 additions & 1 deletion API/controllers/web.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func CreateOrUpdateProject(w http.ResponseWriter, r *http.Request) {
// default: "1234"
// responses:
// '200':
// description: Project successfully updated.
// description: Project successfully removed.
// '404':
// description: Not Found. Invalid project ID.
// '500':
Expand All @@ -194,3 +194,162 @@ func DeleteProject(w http.ResponseWriter, r *http.Request) {
}
}
}

// swagger:operation POST /api/alerts FlutterApp CreateAlert
// Create a new alert
// ---
// security:
// - bearer: []
// produces:
// - application/json
// parameters:
// - name: body
// in: body
// description: 'Mandatory: id, type.
// Optional: title, subtitle.'
// required: true
// format: object
// example: '{"id":"OBJID.WITH.ALERT","type":"minor",
// "title":"This is the title","subtitle":"More information"}'
// responses:
// '200':
// description: 'Alert successfully created.'
// '400':
// description: 'Bad Request. Invalid alert format.'
// '500':
// description: 'Internal server error.'

func CreateAlert(w http.ResponseWriter, r *http.Request) {
fmt.Println("******************************************************")
fmt.Println("FUNCTION CALL: CreateAlert ")
fmt.Println("******************************************************")

alert := &models.Alert{}
err := json.NewDecoder(r.Body).Decode(alert)
if err != nil {
w.WriteHeader(http.StatusBadRequest)
u.Respond(w, u.Message("Invalid request"))
return
}

mErr := models.AddAlert(*alert)

if mErr != nil {
u.RespondWithError(w, mErr)
} else {
if r.Method == "OPTIONS" {
u.WriteOptionsHeader(w, "GET, HEAD")
} else {
u.Respond(w, u.Message("successfully created alert"))
}
}
}

// swagger:operation GET /api/alerts FlutterApp GetAlerts
// Get a list of all alerts
// ---
// security:
// - bearer: []
// produces:
// - application/json
// responses:
// '200':
// description: 'Return all possible alerts.'
// '500':
// description: 'Internal server error.'

func GetAlerts(w http.ResponseWriter, r *http.Request) {
fmt.Println("******************************************************")
fmt.Println("FUNCTION CALL: GetAlerts ")
fmt.Println("******************************************************")

projects, err := models.GetAlerts()
if err != nil {
u.RespondWithError(w, err)
} else {
if r.Method == "OPTIONS" {
u.WriteOptionsHeader(w, "GET, HEAD")
} else {
resp := map[string]interface{}{}
resp["alerts"] = projects
u.Respond(w, u.RespDataWrapper("successfully got alerts", resp))
}
}
}

// swagger:operation GET /api/alerts/{AlertID} FlutterApp GetAlert
// Get a list of all alerts
// ---
// security:
// - bearer: []
// produces:
// - application/json
// parameters:
// - name: AlertID
// in: path
// description: 'ID of the alert to recover.'
// required: true
// type: string
// responses:
// '200':
// description: 'Return requested alert'
// '404':
// description: 'Alert not found'
// '500':
// description: 'Internal server error'

func GetAlert(w http.ResponseWriter, r *http.Request) {
fmt.Println("******************************************************")
fmt.Println("FUNCTION CALL: GetAlert ")
fmt.Println("******************************************************")

alert, err := models.GetAlert(mux.Vars(r)["id"])
if err != nil {
u.RespondWithError(w, err)
} else {
if r.Method == "OPTIONS" {
u.WriteOptionsHeader(w, "GET, HEAD")
} else {
u.Respond(w, u.RespDataWrapper("successfully got alert", alert))
}
}
}

// swagger:operation DELETE /api/alerts/{AlertID} FlutterApp DeleteAlert
// Delete an existing alert.
// ---
// security:
// - bearer: []
// produces:
// - application/json
// parameters:
// - name: AlertID
// in: path
// description: 'ID of the alert to delete.'
// required: true
// type: string
// responses:
// '200':
// description: Alert successfully removed.
// '404':
// description: Not Found. Invalid alert ID.
// '500':
// description: Internal server error

func DeleteAlert(w http.ResponseWriter, r *http.Request) {
fmt.Println("******************************************************")
fmt.Println("FUNCTION CALL: DeleteAlert ")
fmt.Println("******************************************************")

err := models.DeleteAlert(mux.Vars(r)["id"])

if err != nil {
u.RespondWithError(w, err)
} else {
if r.Method == "OPTIONS" {
u.WriteOptionsHeader(w, "GET, HEAD, DELETE")
} else {
u.Respond(w, u.Message("successfully removed alert"))
}
}
}
50 changes: 50 additions & 0 deletions API/controllers/web_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ func init() {
}

var projectsEndpoint = test_utils.GetEndpoint("projects")
var alertsEndpoint = test_utils.GetEndpoint("alerts")

func TestCreateProjectInvalidBody(t *testing.T) {
e2e.TestInvalidBody(t, "POST", projectsEndpoint, "Invalid request")
Expand Down Expand Up @@ -91,3 +92,52 @@ func TestDeleteProject(t *testing.T) {
// if we try to delete again we get an error
e2e.ValidateManagedRequest(t, "DELETE", projectsEndpoint+"/"+id, nil, http.StatusNotFound, "Project not found")
}

func TestCreateAlertInvalidBody(t *testing.T) {
e2e.TestInvalidBody(t, "POST", alertsEndpoint, "Invalid request")
}

func TestCreateAlert(t *testing.T) {
requestBody, _ := json.Marshal(map[string]any{
"id": "OBJID.WITH.ALERT",
"type": "minor",
"title": "This is the title",
"subtitle": "More information",
})

e2e.ValidateManagedRequest(t, "POST", alertsEndpoint, requestBody, http.StatusOK, "successfully created alert")
}

func TestGetAlerts(t *testing.T) {
_, id := integration.CreateTestAlert(t, "temporaryAlert", false)
response := e2e.ValidateManagedRequest(t, "GET", alertsEndpoint, nil, http.StatusOK, "successfully got alerts")

data, exists := response["data"].(map[string]interface{})
assert.True(t, exists)
alerts, exists := data["alerts"].([]interface{})
assert.True(t, exists)
assert.Equal(t, 2, len(alerts)) // temporaryAlert and OBJID.WITH.ALERT

exists = slices.ContainsFunc(alerts, func(project interface{}) bool {
return project.((map[string]interface{}))["id"] == id
})
assert.True(t, exists)
}

func TestGetAlert(t *testing.T) {
_, id := integration.CreateTestAlert(t, "tempAlert", false)
response := e2e.ValidateManagedRequest(t, "GET", alertsEndpoint+"/"+id, nil, http.StatusOK, "successfully got alert")

alert, exists := response["data"].(map[string]interface{})
assert.True(t, exists)
assert.Equal(t, id, alert["id"])
}

func TestDeleteAlert(t *testing.T) {
_, id := integration.CreateTestAlert(t, "tempAlert2", true)
println("one")
e2e.ValidateManagedRequest(t, "DELETE", alertsEndpoint+"/"+id, nil, http.StatusOK, "successfully removed alert")
println("two")
// if we try to delete again we get an error
// e2e.ValidateManagedRequest(t, "DELETE", alertsEndpoint+"/"+id, nil, http.StatusNotFound, "Alert not found")
}
1 change: 1 addition & 0 deletions API/models/entity_get_hierarchy.go
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,7 @@ func getChildrenCollections(limit int, parentEntStr string) []int {
// include AC, CABINET, CORRIDOR, PWRPNL and GROUP
// beacause of ROOM and RACK possible children
// but no need to search further than group
rangeEntities = []int{u.VIRTUALOBJ}
endEnt = u.GROUP
}

Expand Down
Loading

0 comments on commit 7e40fcc

Please sign in to comment.