From 9a64fd75eb92d4bcce2b39cf63def90e72625841 Mon Sep 17 00:00:00 2001 From: dienruei123 <92157987+dienruei123@users.noreply.github.com> Date: Sat, 11 May 2024 21:56:58 +0800 Subject: [PATCH] Finish incident routes, modify AdminDisaster.vue (#15) --- .../app/controllers/incident.go | 89 ++++++ .../app/controllers/incident_type.go | 43 +++ .../app/models/incident.go | 81 ++++++ .../app/models/incident_type.go | 47 ++++ Taipei-City-Dashboard-BE/app/routes/router.go | 27 +- .../src/components/dialogs/IncidentReport.vue | 40 +-- .../src/store/adminStore.js | 8 +- .../src/views/admin/AdminDisaster.vue | 255 +++++++----------- 8 files changed, 406 insertions(+), 184 deletions(-) create mode 100644 Taipei-City-Dashboard-BE/app/controllers/incident.go create mode 100644 Taipei-City-Dashboard-BE/app/controllers/incident_type.go create mode 100644 Taipei-City-Dashboard-BE/app/models/incident.go create mode 100644 Taipei-City-Dashboard-BE/app/models/incident_type.go diff --git a/Taipei-City-Dashboard-BE/app/controllers/incident.go b/Taipei-City-Dashboard-BE/app/controllers/incident.go new file mode 100644 index 000000000..e292a0510 --- /dev/null +++ b/Taipei-City-Dashboard-BE/app/controllers/incident.go @@ -0,0 +1,89 @@ +package controllers + +import ( + "net/http" + + "TaipeiCityDashboardBE/app/models" + + "github.com/gin-gonic/gin" +) + +func GetIncident(c *gin.Context) { + type incidentQuery struct { + PageSize int `form:"pagesize"` + PageNum int `form:"pagenum"` + Sort string `form:"sort"` + Order string `form:"order"` + } + + // Get query parameters + var query incidentQuery + c.ShouldBindQuery(&query) + + incidents, totalIncidents, resultNum, err := models.GetAllIncident(query.PageSize, query.PageNum, query.Sort, query.Order) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"status": "success", "total": totalIncidents, "results": resultNum, "data": incidents}) +} + +func CreateIncident(c *gin.Context) { + var incident models.Incident + // var buf bytes.Buffer + // _, err := io.Copy(&buf, c.Request.Body) + // if err != nil { + // // Handle error + // c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to read request body"}) + // return + // } + + // Convert buffer to string + // requestBody := buf.String() + // fmt.Println(requestBody) + + // Bind the issue data + if err := c.ShouldBindJSON(&incident); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"status": "error", "message": err.Error()}) + return + } + + if incident.Type == "" || incident.Description == "" || incident.Distance == 0 { + c.JSON(http.StatusBadRequest, gin.H{"status": "error", "message": "title, description, distance info is required"}) + return + } + + tmpIncident, err := models.CreateIncident(incident.Type, incident.Description, incident.Distance, incident.Latitude, incident.Longitude, incident.Time) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": err.Error()}) + return + } + + c.JSON(http.StatusCreated, gin.H{"status": "success", "data": tmpIncident}) +} + +func DeleteIncident(c *gin.Context) { + var incident models.Incident + + // Bind the issue data + if err := c.ShouldBindJSON(&incident); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"status": "error", "message": err.Error()}) + return + } + + // if incident.Type == "" || incident.Description == "" || incident.Distance == 0 { + // c.JSON(http.StatusBadRequest, gin.H{"status": "error", "message": "title, description, distance info is required"}) + // return + // } + + tmpIncident, err := models.DeleteIncident(incident.ID) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": err.Error()}) + return + } + + c.JSON(http.StatusOK, gin.H{"status": "success", "data": tmpIncident}) +} + + diff --git a/Taipei-City-Dashboard-BE/app/controllers/incident_type.go b/Taipei-City-Dashboard-BE/app/controllers/incident_type.go new file mode 100644 index 000000000..0f083a67c --- /dev/null +++ b/Taipei-City-Dashboard-BE/app/controllers/incident_type.go @@ -0,0 +1,43 @@ +package controllers + +import ( + "TaipeiCityDashboardBE/app/models" + "net/http" + + "github.com/gin-gonic/gin" +) + +func CreateIncidentType(c *gin.Context) { + var incidentType models.IncidentType + + if err := c.ShouldBindJSON(&incidentType); (err != nil) || (incidentType.Type == "") { + c.JSON(http.StatusBadRequest, gin.H{"status": "error", "message": err.Error()}) + return + } + tmpIncident, err := models.CreateIncidentType(incidentType.Type) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": err.Error()}) + return + } + if tmpIncident.IsEmpty() { + c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": "Incident type " + incidentType.Type + " already exists!!"}) + return + } + c.JSON(http.StatusCreated, gin.H{"status": "success", "data": tmpIncident}) +} + + +func UpdateIncidentType(c *gin.Context) { + var incident models.Incident + + if err := c.ShouldBindJSON(&incident); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"status": "error", "message": err.Error()}) + return + } + tmpIncident, err := models.UpdateIncidentType(incident.Type) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"status": "error", "message": err.Error()}) + return + } + c.JSON(http.StatusCreated, gin.H{"status": "success", "data": tmpIncident}) +} \ No newline at end of file diff --git a/Taipei-City-Dashboard-BE/app/models/incident.go b/Taipei-City-Dashboard-BE/app/models/incident.go new file mode 100644 index 000000000..9b31fdfa8 --- /dev/null +++ b/Taipei-City-Dashboard-BE/app/models/incident.go @@ -0,0 +1,81 @@ +package models + +import ( + "fmt" +) + +type Incident struct { + ID uint `gorm:"primaryKey"` + Type string `json:"inctype"` + Description string `json:"description"` + Distance float64 `json:"distance"` + Latitude float64 `json:"latitude"` + Longitude float64 `json:"longitude"` + Time int64 `json:"reportTime"` +} + +func GetAllIncident(pageSize int, pageNum int, sort string, order string) (incidents []Incident, totalIncidents int64, resultNum int64, err error) { + tempDB := DBManager.Table("incidents") + + // Count the total amount of incidents + tempDB.Count(&totalIncidents) + + tempDB.Count(&resultNum) + + // Sort the issues + if sort != "" { + tempDB = tempDB.Order(sort + " " + order) + } + + // Paginate the issues + if pageSize > 0 { + tempDB = tempDB.Limit(pageSize) + if pageNum > 0 { + tempDB = tempDB.Offset((pageNum - 1) * pageSize) + } + } + + // Get the incidents + err = tempDB.Find(&incidents).Error + + return incidents, totalIncidents, resultNum, err +} + +func CreateIncident(incidentType, description string, distance, latitude, longitude float64, incidentTime int64) (incident Incident, err error) { + + // Create an example incident + // incident = Incident{ + // Type: "Accident", + // Description: "Car crash on the highway", + // Distance: 2.5, + // Latitude: 40.7128, + // Longitude: -74.0060, + // Time: time.Now().Unix(), + // } + incident = Incident { + Type: incidentType, + Description: description, + Distance: distance, + Latitude: latitude, + Longitude: longitude, + Time: incidentTime, + } + + // Insert the incident into the database + err = DBManager.Create(&incident).Error + + return incident, err +} + +func DeleteIncident(id uint) (incident Incident, err error) { + + if err := DBManager.Where("ID = ?", id).First(&incident, 1).Error; err != nil { + // Handle error (e.g., incident not found) + fmt.Printf("Incident not found") + return Incident{}, err + } + + // Delete the incident + err = DBManager.Delete(&incident).Error + return incident, err +} diff --git a/Taipei-City-Dashboard-BE/app/models/incident_type.go b/Taipei-City-Dashboard-BE/app/models/incident_type.go new file mode 100644 index 000000000..810e63f5d --- /dev/null +++ b/Taipei-City-Dashboard-BE/app/models/incident_type.go @@ -0,0 +1,47 @@ +package models + +import ( + "fmt" +) + +type IncidentType struct { + ID uint `gorm:"primaryKey"` + Type string `json:"type" gorm:"not null"` + Count int `json:"count"` +} + +func (m IncidentType) IsEmpty() bool { + return m.Type == "" && m.Count == 0 +} + +func CreateIncidentType(incidentType string) (newType IncidentType, err error){ + newType = IncidentType{ + Type: incidentType, + Count: 0, + } + if err := DBManager.Where("type = ?", incidentType).Error; err == nil { + fmt.Printf("Incident type " + incidentType + " already exists!!") + return IncidentType{}, nil + } + + tempDB := DBManager.Table("incident_types") + err = tempDB.Create(&newType).Error + return newType, err +} + +func UpdateIncidentType(incidentType string) (updType IncidentType, err error){ + if err := DBManager.Where("type = ?", incidentType).First(&updType, 1).Error; err != nil { + // Handle error (e.g., incident not found) + fmt.Printf("Incident type" + incidentType + " not found") + return IncidentType{}, err + } + + updType.Count += 1 + tempDB := DBManager.Table("incident_types") + if err := tempDB.Save(&updType).Error; err != nil { + // Handle error + fmt.Printf("Failed to update incident type " + incidentType) + return IncidentType{}, err + } + return updType, err +} diff --git a/Taipei-City-Dashboard-BE/app/routes/router.go b/Taipei-City-Dashboard-BE/app/routes/router.go index 1cef6d6ca..95f5cf89b 100644 --- a/Taipei-City-Dashboard-BE/app/routes/router.go +++ b/Taipei-City-Dashboard-BE/app/routes/router.go @@ -5,8 +5,6 @@ import ( "TaipeiCityDashboardBE/app/controllers" "TaipeiCityDashboardBE/app/middleware" "TaipeiCityDashboardBE/global" - "bytes" - "io" "github.com/gin-gonic/gin" @@ -34,20 +32,10 @@ func ConfigureRoutes() { configureComponentRoutes() configureDashboardRoutes() configureIssueRoutes() + configureIncidentRoutes() RouterGroup.GET("/ws", func(c *gin.Context) { serveWs(c.Writer, c.Request) }) - RouterGroup.POST("/incident", func(c *gin.Context) { - var buf bytes.Buffer - _, err := io.Copy(&buf, c.Request.Body) - if err != nil { - // Handle error - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to read request body"}) - return - } - fmt.Println(string(buf.String())) - c.JSON(http.StatusOK, gin.H{"message": "Hello, welcome to my Gin app!"}) - }) } func configureAuthRoutes() { @@ -144,6 +132,19 @@ func configureIssueRoutes() { } } +func configureIncidentRoutes() { + incidentRoutes := RouterGroup.Group("/incident") + incidentRoutes.Use(middleware.LimitAPIRequests(global.IssueLimitAPIRequestsTimes, global.LimitRequestsDuration)) + incidentRoutes.Use(middleware.LimitTotalRequests(global.IssueLimitTotalRequestsTimes, global.LimitRequestsDuration)) + { + incidentRoutes.GET("/", controllers.GetIncident) + incidentRoutes.POST("/", controllers.CreateIncident) + incidentRoutes.DELETE("/", controllers.DeleteIncident) + incidentRoutes.POST("/authorized", controllers.CreateIncidentType) + incidentRoutes.PATCH("/authorized", controllers.UpdateIncidentType) + } +} + func serveWs(w http.ResponseWriter, r *http.Request) { // Upgrade the HTTP connection to a WebSocket connection wsHandler := websocket.Handler(func(ws *websocket.Conn) { diff --git a/Taipei-City-Dashboard-FE/src/components/dialogs/IncidentReport.vue b/Taipei-City-Dashboard-FE/src/components/dialogs/IncidentReport.vue index 4f9b5eaa3..a0c2caa91 100644 --- a/Taipei-City-Dashboard-FE/src/components/dialogs/IncidentReport.vue +++ b/Taipei-City-Dashboard-FE/src/components/dialogs/IncidentReport.vue @@ -16,7 +16,7 @@ const location = ref(null); const errorMessage = ref(null); const incidentType = ref(""); const incidentDesc = ref(""); -const incidentPlace = ref(""); +const incidentDis = ref(""); const { editUser } = storeToRefs(authStore); @@ -29,11 +29,11 @@ const typeOptions = [ // Add more options as needed ]; -const placeOptions = [ - { label: "500公尺內", value: "0.5" }, - { label: "500公尺~2公里", value: "2" }, - { label: "2公里~5公里", value: "5" }, - { label: "大於5公里", value: "10" }, +const disOptions = [ + { label: "500公尺內", value: 0.5 }, + { label: "500公尺~2公里", value: 2 }, + { label: "2公里~5公里", value: 5 }, + { label: "大於5公里", value: 10 }, // Add more options as needed ]; @@ -62,17 +62,27 @@ const getCurrentLocation = () => { async function handleSubmit() { let payload = { - type: incidentType, - description: incidentDesc, - place: incidentPlace, - location: location, - reportTime: new Date(), + inctype: incidentType.value, + description: incidentDesc.value, + distance: incidentDis.value, + latitude: location.value.latitude, + longitude: location.value.longitude, + reportTime: new Date().getTime(), }; - const response = await http.post("/incident", payload); + if ( + incidentType.value == "" || + incidentDesc.value == "" || + incidentDis.value == "" + ) { + dialogStore.showNotification("fail", "Some properties are empty"); + return; + } + console.log(payload); + const response = await http.post("/incident/", payload); console.log(response); incidentType.value = ""; incidentDesc.value = ""; - incidentPlace.value = ""; + incidentDis.value = ""; dialogStore.showNotification("success", "OK!!!"); dialogStore.hideAllDialogs(); } @@ -103,9 +113,9 @@ onMounted(() => { v-model="incidentDesc" /> -