diff --git a/controllers/devices_controller.go b/controllers/devices_controller.go index d23fbbf..33abd21 100644 --- a/controllers/devices_controller.go +++ b/controllers/devices_controller.go @@ -18,6 +18,10 @@ import ( "gitlab.com/pactual1/backend/shared" ) +const ( + ContractDistanceThresholdKm = float64(10) +) + func SaveDeviceInfo(c *gin.Context) { var deviceInfo models.DeviceInfo rawData, _ := c.GetRawData() @@ -48,7 +52,7 @@ func SaveDeviceInfo(c *gin.Context) { deviceInfoBytes, _ := json.Marshal(deviceInfo) if deviceContract.BlockchainSecret == "" { deviceContract.BlockchainSecret = shared.GenerateRandomString(BlockchainSecretLength) - _, _, err := contract.UpdateContract(deviceContract) + deviceContract, _, err = contract.UpdateContract(deviceContract) if err != nil { log.Printf("SaveDeviceInfo Update Contract error: %v", err) c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not update contract secret"}) @@ -68,6 +72,16 @@ func SaveDeviceInfo(c *gin.Context) { c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not save device info in blockchain"}) return } + + if shared.DistanceKm(deviceInfo.Lat, deviceInfo.Lon, deviceContract.EndLat, deviceContract.EndLon) <= ContractDistanceThresholdKm { + deviceContract.Status = models.ContractStatusExecuted + _, _, err := contract.UpdateContract(deviceContract) + if err != nil { + log.Printf("SaveDeviceInfo Update Contract error: %v", err) + c.JSON(http.StatusInternalServerError, gin.H{"error": "Could not update contract status"}) + return + } + } } } diff --git a/database/contract/contract.go b/database/contract/contract.go index f145501..3d7f1e7 100644 --- a/database/contract/contract.go +++ b/database/contract/contract.go @@ -15,6 +15,7 @@ import ( "gitlab.com/pactual1/backend/database/device" "gitlab.com/pactual1/backend/models" "gitlab.com/pactual1/backend/services/blockchain" + "gitlab.com/pactual1/backend/services/messaging" "gitlab.com/pactual1/backend/shared" ) @@ -167,21 +168,42 @@ func UpdateContract(contract models.Contract) (models.Contract, int, error) { } // Create contract in blockchain only when it is signed - if oldContract.Status != contract.Status && contract.Status == models.ContractStatusSigned { - err = blockchain.NewService(config.AppConfig.Blockchain).CreateContract(context.Background(), shared.CovertUintToByte32(contract.ID)) - if err != nil { - log.Printf("UpdateContract Error: Could not create contract in blockchain: %v", err) - return contract, http.StatusInternalServerError, err - } + if oldContract.Status != contract.Status { - // Register devices in blockchain when contract is signed - for _, device := range devices { - err = blockchain.NewService(config.AppConfig.Blockchain).RegisterNewDeviceID(context.Background(), shared.CovertUintToByte32(contract.ID), shared.CovertUintToByte32(device.ID)) + if contract.Status == models.ContractStatusSigned { + err = blockchain.NewService(config.AppConfig.Blockchain).CreateContract(context.Background(), shared.CovertUintToByte32(contract.ID)) if err != nil { - log.Printf("UpdateContract Error: Could not register contract device in blockchain: %v", err) + log.Printf("UpdateContract Error: Could not create contract in blockchain: %v", err) return contract, http.StatusInternalServerError, err } + + // Register devices in blockchain when contract is signed + for _, device := range devices { + err = blockchain.NewService(config.AppConfig.Blockchain).RegisterNewDeviceID(context.Background(), shared.CovertUintToByte32(contract.ID), shared.CovertUintToByte32(device.ID)) + if err != nil { + log.Printf("UpdateContract Error: Could not register contract device in blockchain: %v", err) + return contract, http.StatusInternalServerError, err + } + } } + + messagingChannel := messaging.GetMessagingChannel() + + notification := models.Notification{ + Title: "Contract Alert", + NotificationType: "Contract", + Text: fmt.Sprintf("Contract %s status updated to %s", contract.Name, contract.Status), + CompanyID: int(contract.BuyerID), + } + messagingChannel <- notification + + sellerNotification := models.Notification{ + Title: "Contract Alert", + NotificationType: "Contract", + Text: fmt.Sprintf("Contract %s status updated to %s", contract.Name, contract.Status), + CompanyID: int(contract.SellerID), + } + messagingChannel <- sellerNotification } return contract, status, err @@ -243,59 +265,59 @@ func GetContractByID(contractID uint) (models.Contract, int, error) { } func CountContractsByMultipleStatusesAndTotal(companyID uint, startTime, endTime time.Time) (int64, int64, int64, map[string]map[string]int64, error) { - var activeCount, executedCount, totalCount int64 - monthlyCounts := make(map[string]map[string]int64) + var activeCount, executedCount, totalCount int64 + monthlyCounts := make(map[string]map[string]int64) - var contract models.Contract + var contract models.Contract - // Iterate through each month within the specified date range - for dt := startTime; dt.Before(endTime); dt = dt.AddDate(0, 1, 0) { - monthEnd := dt.AddDate(0, 1, 0) - if monthEnd.After(endTime) { - monthEnd = endTime - } + // Iterate through each month within the specified date range + for dt := startTime; dt.Before(endTime); dt = dt.AddDate(0, 1, 0) { + monthEnd := dt.AddDate(0, 1, 0) + if monthEnd.After(endTime) { + monthEnd = endTime + } - // Initialize monthlyCounts for the current month - monthKey := dt.Format("2006-01") - monthlyCounts[monthKey] = map[string]int64{"active": 0, "executed": 0, "total": 0} + // Initialize monthlyCounts for the current month + monthKey := dt.Format("2006-01") + monthlyCounts[monthKey] = map[string]int64{"active": 0, "executed": 0, "total": 0} - // Query for 'active' contracts for the current month - var active int64 - err := shared.GetDb().Model(&contract). - Where("status = ? AND (buyer_id = ? OR seller_id = ?) AND start_time >= ? AND end_time <= ?", "active", companyID, companyID, dt, monthEnd). - Count(&active).Error - if err != nil { - return 0, 0, 0, nil, err - } + // Query for 'active' contracts for the current month + var active int64 + err := shared.GetDb().Model(&contract). + Where("status = ? AND (buyer_id = ? OR seller_id = ?) AND start_time >= ? AND end_time <= ?", "active", companyID, companyID, dt, monthEnd). + Count(&active).Error + if err != nil { + return 0, 0, 0, nil, err + } - // Query for 'executed' contracts for the current month - var executed int64 - err = shared.GetDb().Model(&contract). - Where("status = ? AND (buyer_id = ? OR seller_id = ?) AND start_time >= ? AND end_time <= ?", "executed", companyID, companyID, dt, monthEnd). - Count(&executed).Error - if err != nil { - return 0, 0, 0, nil, err - } + // Query for 'executed' contracts for the current month + var executed int64 + err = shared.GetDb().Model(&contract). + Where("status = ? AND (buyer_id = ? OR seller_id = ?) AND start_time >= ? AND end_time <= ?", "executed", companyID, companyID, dt, monthEnd). + Count(&executed).Error + if err != nil { + return 0, 0, 0, nil, err + } - // Query for total contracts for the current month - var total int64 - err = shared.GetDb().Model(&contract). - Where("(buyer_id = ? OR seller_id = ?) AND start_time >= ? AND end_time <= ?", companyID, companyID, dt, monthEnd). - Count(&total).Error - if err != nil { - return 0, 0, 0, nil, err - } + // Query for total contracts for the current month + var total int64 + err = shared.GetDb().Model(&contract). + Where("(buyer_id = ? OR seller_id = ?) AND start_time >= ? AND end_time <= ?", companyID, companyID, dt, monthEnd). + Count(&total).Error + if err != nil { + return 0, 0, 0, nil, err + } - // Update the counts for the current month - monthlyCounts[monthKey]["active"] = active - monthlyCounts[monthKey]["executed"] = executed - monthlyCounts[monthKey]["total"] = total + // Update the counts for the current month + monthlyCounts[monthKey]["active"] = active + monthlyCounts[monthKey]["executed"] = executed + monthlyCounts[monthKey]["total"] = total - // Update the total counts - activeCount += active - executedCount += executed - totalCount += total - } + // Update the total counts + activeCount += active + executedCount += executed + totalCount += total + } - return activeCount, executedCount, totalCount, monthlyCounts, nil + return activeCount, executedCount, totalCount, monthlyCounts, nil } diff --git a/database/device/device.go b/database/device/device.go index 85267b3..adf0c8f 100644 --- a/database/device/device.go +++ b/database/device/device.go @@ -4,7 +4,6 @@ import ( "errors" "fmt" "log" - "math" "net/http" "strconv" "strings" @@ -138,38 +137,35 @@ func SaveDeviceInfoToDB(deviceInfo models.DeviceInfo, rawData []byte) (models.De return deviceInfo, device, fmt.Errorf("SaveDeviceInfo CREATE -DeviceInfo DB Error: %v", err) } - go func(deviceInfo models.DeviceInfo) { - var contract models.Contract - if err := shared.GetDb().Where("device_ids @> ARRAY[?]::integer[]", deviceInfo.DeviceID).First(&contract).Error; err != nil { - log.Printf("could not find associated contract: %v", err) + var contract models.Contract + if err := shared.GetDb().Where("device_ids @> ARRAY[?]::integer[]", deviceInfo.DeviceID).First(&contract).Error; err != nil { + log.Printf("could not find associated contract: %v", err) - } - - messagingChannel:= messaging.GetMessagingChannel() - - if deviceInfo.Temperature > contract.MaxTemp || deviceInfo.Temperature < contract.MinTemp { - - notification := models.Notification{ - Title: "Temperature Alert", - NotificationType: "Temperature", - Text: fmt.Sprintf("Device %s has a temperature outside the permitted range.", deviceInfo.ExternalDeviceID), - CompanyID: int(contract.BuyerID), } - sellerNotification := models.Notification{ - Title: "Temperature Alert", - NotificationType: "Temperature", - Text: fmt.Sprintf("Device %s has a temperature outside the permitted range.", deviceInfo.ExternalDeviceID), - CompanyID: int(contract.SellerID), - } + messagingChannel := messaging.GetMessagingChannel() - messagingChannel <- notification - messagingChannel <- sellerNotification - } - }(deviceInfo) - - + if deviceInfo.Temperature > contract.MaxTemp || deviceInfo.Temperature < contract.MinTemp { + + notification := models.Notification{ + Title: "Temperature Alert", + NotificationType: "Temperature", + Text: fmt.Sprintf("Device %s has a temperature outside the permitted range.", deviceInfo.ExternalDeviceID), + CompanyID: int(contract.BuyerID), + } + + sellerNotification := models.Notification{ + Title: "Temperature Alert", + NotificationType: "Temperature", + Text: fmt.Sprintf("Device %s has a temperature outside the permitted range.", deviceInfo.ExternalDeviceID), + CompanyID: int(contract.SellerID), + } + + messagingChannel <- notification + messagingChannel <- sellerNotification + } + }(deviceInfo) return deviceInfo, device, nil } @@ -192,136 +188,127 @@ func CountDeviceInfoByCompany(companyID uint) (int64, error) { // Count DeviceInfo entries related to these DeviceIDs if err := shared.GetDb().Model(&models.DeviceInfo{}).Where("device_id IN (?)", allDeviceIDs).Count(&count).Error; err != nil { - log.Printf("CountDeviceInfoByCompany Error: Database error: %v", err) - return 0, err + log.Printf("CountDeviceInfoByCompany Error: Database error: %v", err) + return 0, err } return count, nil } - - func CountDeviceBreachedAndNormalDevicesByCompany(companyID uint, startTime, endTime time.Time) (int64, int64, map[string]map[string]int64, error) { - var contracts []models.Contract - var allDeviceIDs []int64 - var inRangeCount, outOfRangeCount int64 - monthlyCounts := make(map[string]map[string]int64) + var contracts []models.Contract + var allDeviceIDs []int64 + var inRangeCount, outOfRangeCount int64 + monthlyCounts := make(map[string]map[string]int64) - // Fetch all contracts related to the company - if err := shared.GetDb().Where("buyer_id = ? OR seller_id = ?", companyID, companyID).Find(&contracts).Error; err != nil { - log.Printf("CountDeviceInfoByCompany Error: Database error: %v", err) - return 0, 0, nil, err - } + // Fetch all contracts related to the company + if err := shared.GetDb().Where("buyer_id = ? OR seller_id = ?", companyID, companyID).Find(&contracts).Error; err != nil { + log.Printf("CountDeviceInfoByCompany Error: Database error: %v", err) + return 0, 0, nil, err + } - // Aggregate all DeviceIDs - for _, contract := range contracts { - allDeviceIDs = append(allDeviceIDs, contract.DeviceIDs...) - } + // Aggregate all DeviceIDs + for _, contract := range contracts { + allDeviceIDs = append(allDeviceIDs, contract.DeviceIDs...) + } - // Iterate through each month within the specified date range - for dt := startTime; dt.Before(endTime); dt = dt.AddDate(0, 1, 0) { - monthEnd := dt.AddDate(0, 1, 0) - if monthEnd.After(endTime) { - monthEnd = endTime - } + // Iterate through each month within the specified date range + for dt := startTime; dt.Before(endTime); dt = dt.AddDate(0, 1, 0) { + monthEnd := dt.AddDate(0, 1, 0) + if monthEnd.After(endTime) { + monthEnd = endTime + } - startUnix := dt.Unix() - endUnix := monthEnd.Unix() + startUnix := dt.Unix() + endUnix := monthEnd.Unix() - // Initialize monthlyCounts for the current month - monthKey := dt.Format("2006-01") - monthlyCounts[monthKey] = map[string]int64{"inRange": 0, "outOfRange": 0} + // Initialize monthlyCounts for the current month + monthKey := dt.Format("2006-01") + monthlyCounts[monthKey] = map[string]int64{"inRange": 0, "outOfRange": 0} - // Count DeviceInfo entries with temperatures in range and out of range for the current month - for _, contract := range contracts { - var inRange, outOfRange int64 - err := shared.GetDb().Model(&models.DeviceInfo{}). - Where("device_id IN (?) AND temperature >= ? AND temperature <= ? AND timestamp >= ? AND timestamp <= ?", - allDeviceIDs, contract.MinTemp, contract.MaxTemp, startUnix, endUnix). - Count(&inRange).Error - if err != nil { - return 0, 0, nil, err - } + // Count DeviceInfo entries with temperatures in range and out of range for the current month + for _, contract := range contracts { + var inRange, outOfRange int64 + err := shared.GetDb().Model(&models.DeviceInfo{}). + Where("device_id IN (?) AND temperature >= ? AND temperature <= ? AND timestamp >= ? AND timestamp <= ?", + allDeviceIDs, contract.MinTemp, contract.MaxTemp, startUnix, endUnix). + Count(&inRange).Error + if err != nil { + return 0, 0, nil, err + } - err = shared.GetDb().Model(&models.DeviceInfo{}). - Where("device_id IN (?) AND (temperature < ? OR temperature > ?) AND timestamp >= ? AND timestamp <= ?", - allDeviceIDs, contract.MinTemp, contract.MaxTemp, startUnix, endUnix). - Count(&outOfRange).Error - if err != nil { - return 0, 0, nil, err - } + err = shared.GetDb().Model(&models.DeviceInfo{}). + Where("device_id IN (?) AND (temperature < ? OR temperature > ?) AND timestamp >= ? AND timestamp <= ?", + allDeviceIDs, contract.MinTemp, contract.MaxTemp, startUnix, endUnix). + Count(&outOfRange).Error + if err != nil { + return 0, 0, nil, err + } - // Update the counts for the current month - monthlyCounts[monthKey]["inRange"] += inRange - monthlyCounts[monthKey]["outOfRange"] += outOfRange + // Update the counts for the current month + monthlyCounts[monthKey]["inRange"] += inRange + monthlyCounts[monthKey]["outOfRange"] += outOfRange - // Update the total counts - inRangeCount += inRange - outOfRangeCount += outOfRange - } - } + // Update the total counts + inRangeCount += inRange + outOfRangeCount += outOfRange + } + } - return inRangeCount, outOfRangeCount, monthlyCounts, nil + return inRangeCount, outOfRangeCount, monthlyCounts, nil } - type ContractLocationMatch struct { - ContractID uint + ContractID uint DeviceInfoID uint } -const oneKmInDegrees = 0.009 // Approximately 1 km in degrees for lat/lon - -func isWithinOneKm(lat1, lon1, lat2, lon2 float64) bool { - return math.Abs(lat1-lat2) <= oneKmInDegrees && math.Abs(lon1-lon2) <= oneKmInDegrees -} func FetchMatchingContractsAndDeviceInfo(companyID uint64, startTime, endTime time.Time) ([]ContractLocationMatch, error) { - var contracts []models.Contract - var results []ContractLocationMatch - registeredDevices := make(map[uint]bool) // Map to keep track of registered devices + var contracts []models.Contract + var results []ContractLocationMatch + registeredDevices := make(map[uint]bool) // Map to keep track of registered devices - //Fetch contracts - err := shared.GetDb(). - Where("start_time >= ? AND end_time <= ? AND (buyer_id = ? OR seller_id = ?) ", startTime, endTime, companyID, companyID). - Find(&contracts).Error + //Fetch contracts + err := shared.GetDb(). + Where("start_time >= ? AND end_time <= ? AND (buyer_id = ? OR seller_id = ?) ", startTime, endTime, companyID, companyID). + Find(&contracts).Error - if err != nil { - return nil, err - } - //Loop through each contract to find matching DeviceInfo - for _, contract := range contracts { - var deviceInfos []models.DeviceInfo + if err != nil { + return nil, err + } + //Loop through each contract to find matching DeviceInfo + for _, contract := range contracts { + var deviceInfos []models.DeviceInfo - deviceIDStr := strings.Trim(strings.Join(strings.Fields(fmt.Sprint(contract.DeviceIDs)), ","), "[]") - queryString := fmt.Sprintf("device_id IN (%s) AND created_at >= ? AND created_at <= ?", deviceIDStr) - - err := shared.GetDb(). - Where(queryString, contract.StartTime, contract.EndTime). - Find(&deviceInfos).Error + deviceIDStr := strings.Trim(strings.Join(strings.Fields(fmt.Sprint(contract.DeviceIDs)), ","), "[]") + queryString := fmt.Sprintf("device_id IN (%s) AND created_at >= ? AND created_at <= ?", deviceIDStr) - if err != nil { - return nil, err - } + err := shared.GetDb(). + Where(queryString, contract.StartTime, contract.EndTime). + Find(&deviceInfos).Error - // Compare locations and created_at - for _, deviceInfo := range deviceInfos { - // Continue to the next iteration if this device has already been registered - if registeredDevices[deviceInfo.DeviceID] { - continue - } + if err != nil { + return nil, err + } - if isWithinOneKm(contract.StartLat, contract.StartLon, deviceInfo.Lat, deviceInfo.Lon) || - isWithinOneKm(contract.EndLat, contract.EndLon, deviceInfo.Lat, deviceInfo.Lon) { + // Compare locations and created_at + for _, deviceInfo := range deviceInfos { + // Continue to the next iteration if this device has already been registered + if registeredDevices[deviceInfo.DeviceID] { + continue + } - results = append(results, ContractLocationMatch{ - ContractID: contract.ID, - DeviceInfoID: deviceInfo.ID, - }) - registeredDevices[deviceInfo.DeviceID] = true // Mark this device as registered - } - } - } + if shared.DistanceKm(contract.StartLat, contract.StartLon, deviceInfo.Lat, deviceInfo.Lon) <= 1 || + shared.DistanceKm(contract.EndLat, contract.EndLon, deviceInfo.Lat, deviceInfo.Lon) <= 1 { - return results, nil + results = append(results, ContractLocationMatch{ + ContractID: contract.ID, + DeviceInfoID: deviceInfo.ID, + }) + registeredDevices[deviceInfo.DeviceID] = true // Mark this device as registered + } + } + } + + return results, nil } - diff --git a/postman/Backend.postman_collection.json b/postman/Backend.postman_collection.json new file mode 100644 index 0000000..3ac8494 --- /dev/null +++ b/postman/Backend.postman_collection.json @@ -0,0 +1,700 @@ +{ + "info": { + "_postman_id": "cae9b5db-2e4f-46c8-9f86-51c530d51c36", + "name": "Backend", + "schema": "https://schema.getpostman.com/json/collection/v2.0.0/collection.json", + "_exporter_id": "29923405", + "_collection_link": "https://pactual-toptal.postman.co/workspace/pactual-toptal-Workspace~afe12f79-75cd-428c-8cbd-e47c5f2cad3c/collection/29923405-cae9b5db-2e4f-46c8-9f86-51c530d51c36?action=share&source=collection_link&creator=29923405" + }, + "item": [ + { + "name": "Contract", + "item": [ + { + "name": "Create Contracts", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"sellerId\": 1,\n \"buyerId\": 2,\n \"description\": \"This is a sample contract.\",\n \"productId\": 3,\n \"minTemp\": -20.0,\n \"maxTemp\": 40.0,\n \"arrivalDate\": 1674019200,\n \"penaltyType\": \"AMOUNT\",\n \"penaltyValue\": 100,\n \"penaltyRec\": \"DAILY\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "{{URL}}/contracts/create" + }, + "response": [ + { + "name": "Create Contracts", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"sellerId\": 1,\n \"buyerId\": 2,\n \"description\": \"This is a sample contract.\",\n \"productId\": 3,\n \"minTemp\": -20.0,\n \"maxTemp\": 40.0,\n \"arrivalDate\": 1674019200,\n \"penaltyType\": \"AMOUNT\",\n \"penaltyValue\": 100,\n \"penaltyRec\": \"DAILY\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "{{URL}}/contracts/create" + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Fri, 06 Oct 2023 08:40:15 GMT" + }, + { + "key": "Content-Length", + "value": "61" + } + ], + "cookie": [], + "body": "{\n \"id\": 9,\n \"message\": \"Successfully received and saved contract\"\n}" + } + ] + }, + { + "name": "UpdateContract", + "request": { + "method": "PATCH", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"deviceIds\": [1,2],\n \"status\": \"active\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "{{URL}}/contracts/2" + }, + "response": [ + { + "name": "Create Contracts", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\n \"sellerId\": 1,\n \"buyerId\": 2,\n \"description\": \"This is a sample contract.\",\n \"productId\": 3,\n \"minTemp\": -20.0,\n \"maxTemp\": 40.0,\n \"arrivalDate\": 1674019200,\n \"penaltyType\": \"AMOUNT\",\n \"penaltyValue\": 100,\n \"penaltyRec\": \"DAILY\"\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": "{{URL}}/contracts/create" + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Fri, 06 Oct 2023 08:40:15 GMT" + }, + { + "key": "Content-Length", + "value": "61" + } + ], + "cookie": [], + "body": "{\n \"id\": 9,\n \"message\": \"Successfully received and saved contract\"\n}" + } + ] + }, + { + "name": "Get Contracts for Buyers", + "request": { + "method": "GET", + "header": [], + "url": "{{URL}}/contracts" + }, + "response": [ + { + "name": "Get Contracts for Buyers", + "originalRequest": { + "method": "GET", + "header": [], + "url": "{{URL}}/contracts" + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Fri, 06 Oct 2023 08:27:52 GMT" + }, + { + "key": "Content-Length", + "value": "1056" + } + ], + "cookie": [], + "body": "{\n \"data\": [\n {\n \"status\": {\n \"key\": \"Unknown\",\n \"value\": \"unknown\"\n },\n \"buyer\": {\n \"id\": 2,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 7,\n \"numberOfDevices\": 0,\n \"dateCreated\": \"2023-10-06T08:36:23.752245+02:00\"\n },\n {\n \"status\": {\n \"key\": \"Unknown\",\n \"value\": \"unknown\"\n },\n \"buyer\": {\n \"id\": 2,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 6,\n \"numberOfDevices\": 0,\n \"dateCreated\": \"2023-10-06T08:25:40.488392+02:00\"\n },\n {\n \"status\": {\n \"key\": \"Active\",\n \"value\": \"active\"\n },\n \"buyer\": {\n \"id\": 1,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 1,\n \"numberOfDevices\": 3,\n \"dateCreated\": \"2023-09-13T08:36:41.742294+02:00\"\n },\n {\n \"status\": {\n \"key\": \"Pending signature\",\n \"value\": \"pending\"\n },\n \"buyer\": {\n \"id\": 1,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 2,\n \"numberOfDevices\": 1,\n \"dateCreated\": \"2023-09-13T08:36:41.742294+02:00\"\n },\n {\n \"status\": {\n \"key\": \"Active\",\n \"value\": \"active\"\n },\n \"buyer\": {\n \"id\": 1,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 3,\n \"numberOfDevices\": 4,\n \"dateCreated\": \"2023-09-13T08:36:41.742294+02:00\"\n },\n {\n \"status\": {\n \"key\": \"Active\",\n \"value\": \"active\"\n },\n \"buyer\": {\n \"id\": 1,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 4,\n \"numberOfDevices\": 4,\n \"dateCreated\": \"2023-09-13T08:36:41.742294+02:00\"\n }\n ],\n \"total\": 6\n}" + } + ] + }, + { + "name": "Get Contracts By Id", + "request": { + "method": "GET", + "header": [], + "url": "{{URL}}/contracts/1" + }, + "response": [ + { + "name": "Get Contracts for Buyers", + "originalRequest": { + "method": "GET", + "header": [], + "url": "{{URL}}/contracts" + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Fri, 06 Oct 2023 08:27:52 GMT" + }, + { + "key": "Content-Length", + "value": "1056" + } + ], + "cookie": [], + "body": "{\n \"data\": [\n {\n \"status\": {\n \"key\": \"Unknown\",\n \"value\": \"unknown\"\n },\n \"buyer\": {\n \"id\": 2,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 7,\n \"numberOfDevices\": 0,\n \"dateCreated\": \"2023-10-06T08:36:23.752245+02:00\"\n },\n {\n \"status\": {\n \"key\": \"Unknown\",\n \"value\": \"unknown\"\n },\n \"buyer\": {\n \"id\": 2,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 6,\n \"numberOfDevices\": 0,\n \"dateCreated\": \"2023-10-06T08:25:40.488392+02:00\"\n },\n {\n \"status\": {\n \"key\": \"Active\",\n \"value\": \"active\"\n },\n \"buyer\": {\n \"id\": 1,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 1,\n \"numberOfDevices\": 3,\n \"dateCreated\": \"2023-09-13T08:36:41.742294+02:00\"\n },\n {\n \"status\": {\n \"key\": \"Pending signature\",\n \"value\": \"pending\"\n },\n \"buyer\": {\n \"id\": 1,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 2,\n \"numberOfDevices\": 1,\n \"dateCreated\": \"2023-09-13T08:36:41.742294+02:00\"\n },\n {\n \"status\": {\n \"key\": \"Active\",\n \"value\": \"active\"\n },\n \"buyer\": {\n \"id\": 1,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 3,\n \"numberOfDevices\": 4,\n \"dateCreated\": \"2023-09-13T08:36:41.742294+02:00\"\n },\n {\n \"status\": {\n \"key\": \"Active\",\n \"value\": \"active\"\n },\n \"buyer\": {\n \"id\": 1,\n \"name\": \"Nova kompanija\"\n },\n \"contractID\": 4,\n \"numberOfDevices\": 4,\n \"dateCreated\": \"2023-09-13T08:36:41.742294+02:00\"\n }\n ],\n \"total\": 6\n}" + } + ] + }, + { + "name": "GetContractStatuses", + "request": { + "method": "GET", + "header": [], + "url": "{{URL}}/contracts/statuses" + }, + "response": [ + { + "name": "GetContractStatuses", + "originalRequest": { + "method": "GET", + "header": [], + "url": "{{URL}}/contracts/statuses" + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Fri, 06 Oct 2023 08:28:42 GMT" + }, + { + "key": "Content-Length", + "value": "292" + } + ], + "cookie": [], + "body": "{\n \"data\": [\n {\n \"key\": \"active\",\n \"value\": \"Active\"\n },\n {\n \"key\": \"pending\",\n \"value\": \"Pending signature\"\n },\n {\n \"key\": \"draft\",\n \"value\": \"Draft\"\n },\n {\n \"key\": \"signed\",\n \"value\": \"Signed\"\n },\n {\n \"key\": \"ready_for_activation\",\n \"value\": \"Ready for Activation\"\n },\n {\n \"key\": \"executed\",\n \"value\": \"Executed\"\n },\n {\n \"key\": \"revoked\",\n \"value\": \"Revoked\"\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "Text Template", + "item": [ + { + "name": "List text templates", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/text_templates?offset=0&limit=20", + "host": [ + "{{URL}}" + ], + "path": [ + "text_templates" + ], + "query": [ + { + "key": "offset", + "value": "0" + }, + { + "key": "limit", + "value": "20" + } + ] + } + }, + "response": [ + { + "name": "Response", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/text_templates?offset=0&limit=20", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "text_templates" + ], + "query": [ + { + "key": "offset", + "value": "0" + }, + { + "key": "limit", + "value": "20" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Tue, 26 Sep 2023 10:27:00 GMT" + }, + { + "key": "Content-Length", + "value": "152" + } + ], + "cookie": [], + "body": "{\n \"text_templates\": [\n {\n \"ID\": 1,\n \"CreatedAt\": \"2023-09-25T16:58:33.345979Z\",\n \"UpdatedAt\": \"2023-09-25T16:58:33.345979Z\",\n \"DeletedAt\": null,\n \"Value\": \"a\"\n }\n ],\n \"total\": 1\n}" + } + ] + } + ] + }, + { + "name": "Product Template", + "item": [ + { + "name": "List product template", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/product_templates?offset=0&limit=20", + "host": [ + "{{URL}}" + ], + "path": [ + "product_templates" + ], + "query": [ + { + "key": "offset", + "value": "0" + }, + { + "key": "limit", + "value": "20" + } + ] + } + }, + "response": [ + { + "name": "Response", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/product_templates?offset=0&limit=20", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "product_templates" + ], + "query": [ + { + "key": "offset", + "value": "0" + }, + { + "key": "limit", + "value": "20" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Mon, 25 Sep 2023 16:55:54 GMT" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + } + ], + "cookie": [], + "body": "{\n \"product_templates\": [\n {\n \"ID\": 17,\n \"CreatedAt\": \"2023-09-25T16:45:01.586172Z\",\n \"UpdatedAt\": \"2023-09-25T16:45:01.586172Z\",\n \"DeletedAt\": null,\n \"Name\": \"Name\"\n },\n {\n \"ID\": 16,\n \"CreatedAt\": \"2023-09-25T16:44:45.66992Z\",\n \"UpdatedAt\": \"2023-09-25T16:44:45.66992Z\",\n \"DeletedAt\": null,\n \"Name\": \"Name\"\n },\n {\n \"ID\": 15,\n \"CreatedAt\": \"2023-09-25T16:44:38.975468Z\",\n \"UpdatedAt\": \"2023-09-25T16:44:38.975468Z\",\n \"DeletedAt\": null,\n \"Name\": \"Name\"\n },\n {\n \"ID\": 14,\n \"CreatedAt\": \"2023-09-25T16:43:55.978523Z\",\n \"UpdatedAt\": \"2023-09-25T16:43:55.978523Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 13,\n \"CreatedAt\": \"2023-09-25T16:43:49.435178Z\",\n \"UpdatedAt\": \"2023-09-25T16:43:49.435178Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 12,\n \"CreatedAt\": \"2023-09-25T16:43:15.815458Z\",\n \"UpdatedAt\": \"2023-09-25T16:43:15.815458Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 11,\n \"CreatedAt\": \"2023-09-25T16:43:03.75841Z\",\n \"UpdatedAt\": \"2023-09-25T16:43:03.75841Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 10,\n \"CreatedAt\": \"2023-09-25T16:40:26.031528Z\",\n \"UpdatedAt\": \"2023-09-25T16:40:26.031528Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 9,\n \"CreatedAt\": \"2023-09-25T16:39:54.451953Z\",\n \"UpdatedAt\": \"2023-09-25T16:39:54.451953Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 8,\n \"CreatedAt\": \"2023-09-25T16:38:34.110926Z\",\n \"UpdatedAt\": \"2023-09-25T16:38:34.110926Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 7,\n \"CreatedAt\": \"2023-09-25T16:37:05.161071Z\",\n \"UpdatedAt\": \"2023-09-25T16:37:05.161071Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 6,\n \"CreatedAt\": \"2023-09-25T16:36:19.275174Z\",\n \"UpdatedAt\": \"2023-09-25T16:36:19.275174Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 5,\n \"CreatedAt\": \"2023-09-25T16:34:20.104245Z\",\n \"UpdatedAt\": \"2023-09-25T16:34:20.104245Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 4,\n \"CreatedAt\": \"2023-09-25T16:32:59.988835Z\",\n \"UpdatedAt\": \"2023-09-25T16:32:59.988835Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 3,\n \"CreatedAt\": \"2023-09-25T16:32:55.449467Z\",\n \"UpdatedAt\": \"2023-09-25T16:32:55.449467Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 2,\n \"CreatedAt\": \"2023-09-25T16:30:27.334546Z\",\n \"UpdatedAt\": \"2023-09-25T16:30:27.334546Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 1,\n \"CreatedAt\": \"2023-09-25T16:28:28.085355Z\",\n \"UpdatedAt\": \"2023-09-25T16:28:28.085355Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n }\n ],\n \"total\": 17\n}" + } + ] + }, + { + "name": "Get Product Template by ID", + "request": { + "method": "GET", + "header": [], + "url": "{{URL}}/product_templates/1" + }, + "response": [ + { + "name": "Response", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/product_templates?offset=0&limit=20", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "product_templates" + ], + "query": [ + { + "key": "offset", + "value": "0" + }, + { + "key": "limit", + "value": "20" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Mon, 25 Sep 2023 16:55:54 GMT" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + } + ], + "cookie": [], + "body": "{\n \"product_templates\": [\n {\n \"ID\": 17,\n \"CreatedAt\": \"2023-09-25T16:45:01.586172Z\",\n \"UpdatedAt\": \"2023-09-25T16:45:01.586172Z\",\n \"DeletedAt\": null,\n \"Name\": \"Name\"\n },\n {\n \"ID\": 16,\n \"CreatedAt\": \"2023-09-25T16:44:45.66992Z\",\n \"UpdatedAt\": \"2023-09-25T16:44:45.66992Z\",\n \"DeletedAt\": null,\n \"Name\": \"Name\"\n },\n {\n \"ID\": 15,\n \"CreatedAt\": \"2023-09-25T16:44:38.975468Z\",\n \"UpdatedAt\": \"2023-09-25T16:44:38.975468Z\",\n \"DeletedAt\": null,\n \"Name\": \"Name\"\n },\n {\n \"ID\": 14,\n \"CreatedAt\": \"2023-09-25T16:43:55.978523Z\",\n \"UpdatedAt\": \"2023-09-25T16:43:55.978523Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 13,\n \"CreatedAt\": \"2023-09-25T16:43:49.435178Z\",\n \"UpdatedAt\": \"2023-09-25T16:43:49.435178Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 12,\n \"CreatedAt\": \"2023-09-25T16:43:15.815458Z\",\n \"UpdatedAt\": \"2023-09-25T16:43:15.815458Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 11,\n \"CreatedAt\": \"2023-09-25T16:43:03.75841Z\",\n \"UpdatedAt\": \"2023-09-25T16:43:03.75841Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 10,\n \"CreatedAt\": \"2023-09-25T16:40:26.031528Z\",\n \"UpdatedAt\": \"2023-09-25T16:40:26.031528Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 9,\n \"CreatedAt\": \"2023-09-25T16:39:54.451953Z\",\n \"UpdatedAt\": \"2023-09-25T16:39:54.451953Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 8,\n \"CreatedAt\": \"2023-09-25T16:38:34.110926Z\",\n \"UpdatedAt\": \"2023-09-25T16:38:34.110926Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 7,\n \"CreatedAt\": \"2023-09-25T16:37:05.161071Z\",\n \"UpdatedAt\": \"2023-09-25T16:37:05.161071Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 6,\n \"CreatedAt\": \"2023-09-25T16:36:19.275174Z\",\n \"UpdatedAt\": \"2023-09-25T16:36:19.275174Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 5,\n \"CreatedAt\": \"2023-09-25T16:34:20.104245Z\",\n \"UpdatedAt\": \"2023-09-25T16:34:20.104245Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 4,\n \"CreatedAt\": \"2023-09-25T16:32:59.988835Z\",\n \"UpdatedAt\": \"2023-09-25T16:32:59.988835Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 3,\n \"CreatedAt\": \"2023-09-25T16:32:55.449467Z\",\n \"UpdatedAt\": \"2023-09-25T16:32:55.449467Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 2,\n \"CreatedAt\": \"2023-09-25T16:30:27.334546Z\",\n \"UpdatedAt\": \"2023-09-25T16:30:27.334546Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 1,\n \"CreatedAt\": \"2023-09-25T16:28:28.085355Z\",\n \"UpdatedAt\": \"2023-09-25T16:28:28.085355Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n }\n ],\n \"total\": 17\n}" + } + ] + } + ] + }, + { + "name": "Locations", + "item": [ + { + "name": "List locations", + "request": { + "method": "GET", + "header": [], + "url": { + "raw": "{{URL}}/locations?q=abc", + "host": [ + "{{URL}}" + ], + "path": [ + "locations" + ], + "query": [ + { + "key": "q", + "value": "abc" + } + ] + } + }, + "response": [ + { + "name": "Response", + "originalRequest": { + "method": "GET", + "header": [], + "url": { + "raw": "http://localhost:8080/product_templates?offset=0&limit=20", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8080", + "path": [ + "product_templates" + ], + "query": [ + { + "key": "offset", + "value": "0" + }, + { + "key": "limit", + "value": "20" + } + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Access-Control-Allow-Credentials", + "value": "true" + }, + { + "key": "Access-Control-Allow-Headers", + "value": "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With" + }, + { + "key": "Access-Control-Allow-Methods", + "value": "POST, OPTIONS, GET, PUT" + }, + { + "key": "Access-Control-Allow-Origin", + "value": "*" + }, + { + "key": "Content-Type", + "value": "application/json; charset=utf-8" + }, + { + "key": "Date", + "value": "Mon, 25 Sep 2023 16:55:54 GMT" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + } + ], + "cookie": [], + "body": "{\n \"product_templates\": [\n {\n \"ID\": 17,\n \"CreatedAt\": \"2023-09-25T16:45:01.586172Z\",\n \"UpdatedAt\": \"2023-09-25T16:45:01.586172Z\",\n \"DeletedAt\": null,\n \"Name\": \"Name\"\n },\n {\n \"ID\": 16,\n \"CreatedAt\": \"2023-09-25T16:44:45.66992Z\",\n \"UpdatedAt\": \"2023-09-25T16:44:45.66992Z\",\n \"DeletedAt\": null,\n \"Name\": \"Name\"\n },\n {\n \"ID\": 15,\n \"CreatedAt\": \"2023-09-25T16:44:38.975468Z\",\n \"UpdatedAt\": \"2023-09-25T16:44:38.975468Z\",\n \"DeletedAt\": null,\n \"Name\": \"Name\"\n },\n {\n \"ID\": 14,\n \"CreatedAt\": \"2023-09-25T16:43:55.978523Z\",\n \"UpdatedAt\": \"2023-09-25T16:43:55.978523Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 13,\n \"CreatedAt\": \"2023-09-25T16:43:49.435178Z\",\n \"UpdatedAt\": \"2023-09-25T16:43:49.435178Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 12,\n \"CreatedAt\": \"2023-09-25T16:43:15.815458Z\",\n \"UpdatedAt\": \"2023-09-25T16:43:15.815458Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 11,\n \"CreatedAt\": \"2023-09-25T16:43:03.75841Z\",\n \"UpdatedAt\": \"2023-09-25T16:43:03.75841Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 10,\n \"CreatedAt\": \"2023-09-25T16:40:26.031528Z\",\n \"UpdatedAt\": \"2023-09-25T16:40:26.031528Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 9,\n \"CreatedAt\": \"2023-09-25T16:39:54.451953Z\",\n \"UpdatedAt\": \"2023-09-25T16:39:54.451953Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 8,\n \"CreatedAt\": \"2023-09-25T16:38:34.110926Z\",\n \"UpdatedAt\": \"2023-09-25T16:38:34.110926Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 7,\n \"CreatedAt\": \"2023-09-25T16:37:05.161071Z\",\n \"UpdatedAt\": \"2023-09-25T16:37:05.161071Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 6,\n \"CreatedAt\": \"2023-09-25T16:36:19.275174Z\",\n \"UpdatedAt\": \"2023-09-25T16:36:19.275174Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 5,\n \"CreatedAt\": \"2023-09-25T16:34:20.104245Z\",\n \"UpdatedAt\": \"2023-09-25T16:34:20.104245Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 4,\n \"CreatedAt\": \"2023-09-25T16:32:59.988835Z\",\n \"UpdatedAt\": \"2023-09-25T16:32:59.988835Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 3,\n \"CreatedAt\": \"2023-09-25T16:32:55.449467Z\",\n \"UpdatedAt\": \"2023-09-25T16:32:55.449467Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 2,\n \"CreatedAt\": \"2023-09-25T16:30:27.334546Z\",\n \"UpdatedAt\": \"2023-09-25T16:30:27.334546Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n },\n {\n \"ID\": 1,\n \"CreatedAt\": \"2023-09-25T16:28:28.085355Z\",\n \"UpdatedAt\": \"2023-09-25T16:28:28.085355Z\",\n \"DeletedAt\": null,\n \"Name\": \"a\"\n }\n ],\n \"total\": 17\n}" + } + ] + } + ] + } + ], + "event": [ + { + "listen": "prerequest", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + }, + { + "listen": "test", + "script": { + "type": "text/javascript", + "exec": [ + "" + ] + } + } + ], + "variable": [ + { + "key": "URL", + "value": "http://localhost:8080" + } + ] +} \ No newline at end of file diff --git a/NOVA.postman_collection.json b/postman/NOVA.postman_collection.json similarity index 100% rename from NOVA.postman_collection.json rename to postman/NOVA.postman_collection.json diff --git a/shared/user_data.go b/shared/user_data.go index 7df8ed5..bc2a72c 100644 --- a/shared/user_data.go +++ b/shared/user_data.go @@ -4,7 +4,28 @@ package shared +import "math" + const ( RoleAdmin string = "admin" RoleProUser string = "pro-user" ) + +func DistanceKm(lat1 float64, lng1 float64, lat2 float64, lng2 float64) float64 { + radlat1 := float64(math.Pi * lat1 / 180) + radlat2 := float64(math.Pi * lat2 / 180) + + theta := float64(lng1 - lng2) + radtheta := float64(math.Pi * theta / 180) + + dist := math.Sin(radlat1)*math.Sin(radlat2) + math.Cos(radlat1)*math.Cos(radlat2)*math.Cos(radtheta) + if dist > 1 { + dist = 1 + } + + dist = math.Acos(dist) + dist = dist * 180 / math.Pi + dist = dist * 60 * 1.1515 + + return dist * 1.609344 +}