Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add impact functionality #504

Merged
merged 3 commits into from
Aug 12, 2024
Merged
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
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
Loading