diff --git a/controllers/contracts_controller.go b/controllers/contracts_controller.go index c215b3e..7ba4091 100644 --- a/controllers/contracts_controller.go +++ b/controllers/contracts_controller.go @@ -1,23 +1,27 @@ package controllers import ( - "errors" "log" "net/http" "strconv" + "time" "github.com/gin-gonic/gin" - "github.com/jinzhu/gorm" + "gitlab.com/pactual1/backend/database/contract" "gitlab.com/pactual1/backend/models" - "gitlab.com/pactual1/backend/shared" ) func GetLatestContracts(c *gin.Context) { - // Get limit and offset from query parameter with defaults + // Get limit, offset, and status from query parameters with defaults limitStr := c.DefaultQuery("limit", "99999999999999999999999999999999") offsetStr := c.DefaultQuery("offset", "0") status := c.DefaultQuery("status", models.ContractStatusActive) + // Optional search parameters + companyName := c.Query("company_name") + startTimeStr := c.Query("start_time") + deviceIDsStr := c.QueryArray("device_ids[]") // Assuming deviceIDs are passed as an array query parameter + // Convert limit and offset to int limit, err := strconv.Atoi(limitStr) if err != nil { @@ -33,29 +37,37 @@ func GetLatestContracts(c *gin.Context) { return } - // Create a slice to hold the contracts - var contracts []models.Contract - - // Count the total number of contracts - var total int64 - if err := shared.GetDb().Where("status = ?", status).Model(&models.Contract{}).Count(&total).Error; err != nil { - log.Printf("GetLatestContracts Error: Database error: %v", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"}) - return - } - - // Fetch the latest contracts from the database with LIMIT and OFFSET - if err := shared.GetDb().Where("status = ?", status).Order("created_at desc").Limit(limit).Offset(offset).Find(&contracts).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - log.Printf("GetLatestContracts Error: No contracts found: %v", err) - c.JSON(http.StatusNotFound, gin.H{"error": "No contracts found"}) - } else { - log.Printf("GetLatestContracts Error: Database error: %v", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"}) + // Convert startTime to time.Time from Unix time in seconds + var startTime time.Time + if startTimeStr != "" { + startTimeUnix, err := strconv.ParseInt(startTimeStr, 10, 64) + if err != nil { + log.Printf("GetLatestContracts Error: Invalid startTime value: %v", err) + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid startTime value"}) + return } - return + startTime = time.Unix(startTimeUnix, 0) } + // Convert deviceIDs to []int64 + var deviceIDs []int64 + for _, idStr := range deviceIDsStr { + id, err := strconv.ParseInt(idStr, 10, 64) + if err != nil { + log.Printf("GetLatestContracts Error: Invalid deviceID value: %v", err) + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid deviceID value"}) + return + } + deviceIDs = append(deviceIDs, id) + } + + // Fetch contracts + contracts, total, st, err := contract.GetContracts(status, companyName, startTime, deviceIDs,limit, offset) + + if err != nil { + c.JSON(st, gin.H{"error": err.Error()}) + return + } // Respond with the contracts and the total count c.JSON(http.StatusOK, gin.H{"total": total, "contracts": contracts}) } diff --git a/controllers/devices_controller.go b/controllers/devices_controller.go index 99091cc..626a4d5 100644 --- a/controllers/devices_controller.go +++ b/controllers/devices_controller.go @@ -3,14 +3,14 @@ package controllers import ( "encoding/json" "errors" - "fmt" "log" "net/http" "strconv" - "strings" "github.com/gin-gonic/gin" "github.com/jinzhu/gorm" + "gitlab.com/pactual1/backend/database/contract" + "gitlab.com/pactual1/backend/database/device" "gitlab.com/pactual1/backend/models" "gitlab.com/pactual1/backend/shared" ) @@ -107,11 +107,10 @@ func GetDeviceData(c *gin.Context) { return } - // Fetch the contract creation date based on contractID - var contract models.Contract - if err := shared.GetDb().Where("id = ?", contractID).First(&contract).Error; err != nil { - log.Printf("GetDeviceData Error: Could not fetch contract: %v", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not fetch contract"}) + contract , st, err := contract.GetContractByID(contractID) + + if err != nil { + c.JSON(st, gin.H{"error": err.Error()}) return } @@ -128,41 +127,13 @@ func GetDeviceData(c *gin.Context) { return } - var deviceInfos []models.DeviceInfo - // Modify your query to include filtering based on the contract's creation date - query := shared.GetDb().Where("device_id = ?", deviceID).Where("created_at >= ? AND created_at <= ?", contract.StartTime,contract.EndTime) + featureCollection, st, err := device.GetDeviceInfoForContract(deviceID, contract) - if err := query.Find(&deviceInfos).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - log.Printf("GetDeviceData Error: No device info found: %v", err) - c.JSON(http.StatusNotFound, gin.H{"error": "No device info found"}) - } else { - log.Printf("GetDeviceData Error: Database error: %v", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"}) - } + if err != nil { + c.JSON(st, gin.H{"error": err.Error()}) return } - // Create a GeoJSON feature collection - var featureCollection models.GeoJSONFeatureCollection - featureCollection.Type = "FeatureCollection" - featureCollection.Features = []models.GeoJSONFeature{} - - // Loop through each deviceInfo to create GeoJSON features - for _, info := range deviceInfos { - info.RawJSON = "" - feature := models.GeoJSONFeature{ - Type: "Feature", - DeviceInfo: &info, - Geometry: models.GeoJSONGeometry{ - Type: "Point", - Coordinates: []float64{info.Lon, info.Lat}, - }, - Properties: map[string]interface{}{}, - } - featureCollection.Features = append(featureCollection.Features, feature) - } - // Respond with the GeoJSON feature collection c.JSON(http.StatusOK, featureCollection) } @@ -187,46 +158,12 @@ func GetDevicesByContract(c *gin.Context) { } log.Printf("This is the ID: %v", contractID) - // Fetch the contract from the database - var contract models.Contract - if err := shared.GetDb().Where("id = ?", contractID).First(&contract).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - log.Printf("GetDevicesByContract Error: No contract found: %v", err) - c.JSON(http.StatusNotFound, gin.H{"error": "No contract found"}) - return - } else { - log.Printf("GetDevicesByContract Error: Database error: %v", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"}) - return - } - } - log.Printf("This is the device IDS ID: %v", contract.DeviceIDs) - // Create a slice to hold the devices - var devices []models.Device + devices, st, err := device.GetDevicesForContract(contractID) - // Convert the integer array to a comma-separated string - idStrings := []string{} - for _, id := range contract.DeviceIDs { - idStrings = append(idStrings, strconv.FormatInt(id, 10)) - } - idStr := strings.Join(idStrings, ",") - - // Construct the SQL query manually - sqlQuery := fmt.Sprintf("SELECT * FROM devices WHERE id IN (%s)", idStr) - - // Fetch devices from the database based on DeviceIDs in the contract - // Execute the query - if err := shared.GetDb().Raw(sqlQuery).Scan(&devices).Error; err != nil { - if errors.Is(err, gorm.ErrRecordNotFound) { - log.Printf("GetDevicesByContract Error: No devices found: %v", err) - c.JSON(http.StatusNotFound, gin.H{"error": "No devices found"}) - } else { - log.Printf("GetDevicesByContract Error: Database error: %v", err) - c.JSON(http.StatusInternalServerError, gin.H{"error": "Database error"}) - } + if err != nil { + c.JSON(st, gin.H{"error": err.Error()}) return } - // Respond with the devices c.JSON(http.StatusOK, devices) } diff --git a/database/contract/contract.go b/database/contract/contract.go new file mode 100644 index 0000000..d936c13 --- /dev/null +++ b/database/contract/contract.go @@ -0,0 +1,69 @@ +package contract + +import ( + "errors" + "log" + "net/http" + "time" + + "github.com/jinzhu/gorm" + "gitlab.com/pactual1/backend/models" + "gitlab.com/pactual1/backend/shared" +) + +func GetContracts(status string, companyName string, startTime time.Time, deviceIDs []int64,limit, offset int) ([]models.Contract, int64, int, error) { + // Create a slice to hold the contracts + var contracts []models.Contract + + // Initialize the query + db := shared.GetDb().Where("status = ?", status) + countDb := db + + if companyName != "" { + db = db.Joins("left join companies on companies.id = contracts.buyer_id").Where("companies.name LIKE ?", "%"+companyName+"%") + countDb = countDb.Joins("left join companies on companies.id = contracts.buyer_id").Where("companies.name LIKE ?", "%"+companyName+"%") + } + + if !startTime.IsZero() { + db = db.Where("start_time >= ?", startTime) + countDb = countDb.Where("start_time >= ?", startTime) + } + if len(deviceIDs) > 0 { + db = db.Where("device_ids && ARRAY[?]::int8[]", deviceIDs) + countDb = countDb.Where("device_ids && ARRAY[?]::int8[]", deviceIDs) + } + + // Count the total number of contracts + var total int64 + if err := countDb.Model(&models.Contract{}).Count(&total).Error; err != nil { + log.Printf("GetLatestContracts Error: Database error: %v", err) + return contracts, total, http.StatusInternalServerError, err + } + + // Fetch the latest contracts from the database with LIMIT and OFFSET + if err := db.Order("created_at desc").Limit(limit).Offset(offset).Find(&contracts).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + log.Printf("GetLatestContracts Error: No contracts found: %v", err) + return contracts, total, http.StatusNotFound, err + } else { + log.Printf("GetLatestContracts Error: Database error: %v", err) + return contracts, total, http.StatusInternalServerError, err + } + } + return contracts, total, http.StatusOK, nil +} + + + +func GetContractByID(contractID uint64) (models.Contract, int ,error) { + + // Fetch the contract creation date based on contractID + var contract models.Contract + if err := shared.GetDb().Where("id = ?", contractID).First(&contract).Error; err != nil { + log.Printf("GetDeviceData Error: Could not fetch contract: %v", err) + return contract, http.StatusInternalServerError, err + } + + return contract , http.StatusOK, nil + +} \ No newline at end of file diff --git a/database/device/device.go b/database/device/device.go new file mode 100644 index 0000000..f6dd07d --- /dev/null +++ b/database/device/device.go @@ -0,0 +1,101 @@ +package device + +import ( + "errors" + "fmt" + "log" + "net/http" + "strconv" + "strings" + + "github.com/jinzhu/gorm" + "gitlab.com/pactual1/backend/models" + "gitlab.com/pactual1/backend/shared" +) + + +func GetDevicesForContract(contractID uint64) ([]models.Device , int, error) { + + // Create a slice to hold the devices + var devices []models.Device + // Fetch the contract from the database + var contract models.Contract + if err := shared.GetDb().Where("id = ?", contractID).First(&contract).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + log.Printf("GetDevicesByContract Error: No contract found: %v", err) + return devices, http.StatusNotFound ,err + } else { + log.Printf("GetDevicesByContract Error: Database error: %v", err) + return devices, http.StatusInternalServerError, err + } + } + log.Printf("This is the device IDS ID: %v", contract.DeviceIDs) + + + // Convert the integer array to a comma-separated string + idStrings := []string{} + for _, id := range contract.DeviceIDs { + idStrings = append(idStrings, strconv.FormatInt(id, 10)) + } + idStr := strings.Join(idStrings, ",") + + // Construct the SQL query manually + sqlQuery := fmt.Sprintf("SELECT * FROM devices WHERE id IN (%s)", idStr) + + // Fetch devices from the database based on DeviceIDs in the contract + // Execute the query + if err := shared.GetDb().Raw(sqlQuery).Scan(&devices).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + log.Printf("GetDevicesByContract Error: No devices found: %v", err) + return devices, http.StatusNotFound, err + } else { + log.Printf("GetDevicesByContract Error: Database error: %v", err) + return devices, http.StatusInternalServerError, err + } + } + return devices , http.StatusOK, nil +} + +func GetDeviceInfoForContract (deviceID uint64, contract models.Contract) (models.GeoJSONFeatureCollection , int, error) { + + var deviceInfos []models.DeviceInfo + + // Create a GeoJSON feature collection + var featureCollection models.GeoJSONFeatureCollection + featureCollection.Type = "FeatureCollection" + featureCollection.Features = []models.GeoJSONFeature{} + + + // Modify your query to include filtering based on the contract's creation date + query := shared.GetDb().Where("device_id = ?", deviceID).Where("created_at >= ? AND created_at <= ?", contract.StartTime,contract.EndTime) + + if err := query.Find(&deviceInfos).Error; err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + log.Printf("GetDeviceData Error: No device info found: %v", err) + return featureCollection, http.StatusNotFound, err + } else { + log.Printf("GetDeviceData Error: Database error: %v", err) + return featureCollection, http.StatusNotFound, err + } + } + + + // Loop through each deviceInfo to create GeoJSON features + for _, info := range deviceInfos { + info.RawJSON = "" + feature := models.GeoJSONFeature{ + Type: "Feature", + DeviceInfo: &info, + Geometry: models.GeoJSONGeometry{ + Type: "Point", + Coordinates: []float64{info.Lon, info.Lat}, + }, + Properties: map[string]interface{}{}, + } + featureCollection.Features = append(featureCollection.Features, feature) + } + + return featureCollection , 0, nil + + +} \ No newline at end of file